Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2025, The Board of Trustees of the University of Illinois,
2 : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
3 : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
4 : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
5 : // contributors. All rights reserved.
6 : //
7 : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
8 : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
9 : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
10 : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
11 : // derivative works, and perform publicly and display publicly, and to permit others to do so.
12 : //
13 : // Redistribution and use in source and binary forms, with or without modification, are permitted
14 : // provided that the following conditions are met:
15 : //
16 : // (1) Redistributions of source code must retain the above copyright notice, this list of
17 : // conditions and the following disclaimer.
18 : //
19 : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
20 : // conditions and the following disclaimer in the documentation and/or other materials
21 : // provided with the distribution.
22 : //
23 : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
24 : // the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
25 : // used to endorse or promote products derived from this software without specific prior
26 : // written permission.
27 : //
28 : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
29 : // without changes from the version obtained under this License, or (ii) Licensee makes a
30 : // reference solely to the software portion of its product, Licensee must refer to the
31 : // software as "EnergyPlus version X" software, where "X" is the version number Licensee
32 : // obtained under this License and may not use a different name for the software. Except as
33 : // specifically required in this Section (4), Licensee shall not use in a company name, a
34 : // product name, in advertising, publicity, or other promotional activities any name, trade
35 : // name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
36 : // similar designation, without the U.S. Department of Energy's prior written consent.
37 : //
38 : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
39 : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
40 : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
41 : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
42 : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
43 : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
44 : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
45 : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
46 : // POSSIBILITY OF SUCH DAMAGE.
47 :
48 : // C++ Headers
49 : #include <cassert>
50 : #include <cmath>
51 :
52 : // ObjexxFCL Headers
53 : #include <ObjexxFCL/Array.functions.hh>
54 : #include <ObjexxFCL/Fmath.hh>
55 :
56 : // EnergyPlus Headers
57 : #include <EnergyPlus/Autosizing/CoolingCapacitySizing.hh>
58 : #include <EnergyPlus/Autosizing/HeatingCapacitySizing.hh>
59 : #include <EnergyPlus/BranchNodeConnections.hh>
60 : #include <EnergyPlus/Construction.hh>
61 : #include <EnergyPlus/Data/EnergyPlusData.hh>
62 : #include <EnergyPlus/DataBranchAirLoopPlant.hh>
63 : #include <EnergyPlus/DataEnvironment.hh>
64 : #include <EnergyPlus/DataHVACGlobals.hh>
65 : #include <EnergyPlus/DataHeatBalFanSys.hh>
66 : #include <EnergyPlus/DataHeatBalSurface.hh>
67 : #include <EnergyPlus/DataHeatBalance.hh>
68 : #include <EnergyPlus/DataLoopNode.hh>
69 : #include <EnergyPlus/DataSizing.hh>
70 : #include <EnergyPlus/DataSurfaceLists.hh>
71 : #include <EnergyPlus/DataSurfaces.hh>
72 : #include <EnergyPlus/DataZoneEquipment.hh>
73 : #include <EnergyPlus/EMSManager.hh>
74 : #include <EnergyPlus/FluidProperties.hh>
75 : #include <EnergyPlus/General.hh>
76 : #include <EnergyPlus/GeneralRoutines.hh>
77 : #include <EnergyPlus/GlobalNames.hh>
78 : #include <EnergyPlus/HeatBalanceSurfaceManager.hh>
79 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
80 : #include <EnergyPlus/LowTempRadiantSystem.hh>
81 : #include <EnergyPlus/NodeInputManager.hh>
82 : #include <EnergyPlus/OutputProcessor.hh>
83 : #include <EnergyPlus/Plant/Enums.hh>
84 : #include <EnergyPlus/PlantUtilities.hh>
85 : #include <EnergyPlus/Psychrometrics.hh>
86 : #include <EnergyPlus/ScheduleManager.hh>
87 : #include <EnergyPlus/UtilityRoutines.hh>
88 : #include <EnergyPlus/WeatherManager.hh>
89 : #include <EnergyPlus/ZoneTempPredictorCorrector.hh>
90 :
91 : namespace EnergyPlus {
92 :
93 : namespace LowTempRadiantSystem {
94 :
95 : // Module containing the routines dealing with the low temperature radiant systems
96 :
97 : // MODULE INFORMATION:
98 : // AUTHOR Rick Strand
99 : // DATE WRITTEN November 2000
100 : // MODIFIED Rick Strand March 2001 (additional controls, etc.)
101 : // Rick Strand July 2003 (added constant flow hydronic system)
102 : // B. Griffith Sept 2010, plant upgrades, generalize fluid properties
103 : // Rick Strand August 2011 (improved condensation handling)
104 :
105 : // PURPOSE OF THIS MODULE:
106 : // The purpose of this module is to simulate low temperature radiant systems.
107 : // It is the intention of this module to cover all types of low temperature
108 : // radiant systems: wall, ceiling, floor, heating, cooling, panels, etc.
109 :
110 : // METHODOLOGY EMPLOYED:
111 : // Based on work done in IBLAST, this model has been revised for the structure
112 : // of EnergyPlus. It is still based on the QTF formulation of heat transfer
113 : // through building elements with embedded heat sources/sinks. Note that due
114 : // to the fact that a radiant system is both a building heat transfer element
115 : // and a controllable system that some iteration between the system and the
116 : // surface heat balance routine is necessary.
117 : // REFERENCES:
118 : // IBLAST-QTF research program, completed in January 1995 (unreleased)
119 : // Strand, R.K. 1995. "Heat Source Transfer Functions and Their Application to
120 : // Low Temperature Radiant Heating Systems", Ph.D. dissertation, University
121 : // of Illinois at Urbana-Champaign, Department of Mechanical and Industrial
122 : // Engineering.
123 : // Seem, J.E. 1986. "Heat Transfer in Buildings", Ph.D. dissertation, University
124 : // of Wisconsin-Madison.
125 :
126 : // OTHER NOTES: This module contains three different types of radiant system
127 : // models: (a) variable flow hydronic heating/cooling radiant system;
128 : // (b) constant flow, variable controlled temperature heating/cooling radiant
129 : // system; (c) electric resistance heating radiant system. Systems (a) and
130 : // (b) are hydronic systems--one which varies hydronic flow as the key control
131 : // parameter (a) and one which varies the inlet hydronic temperature while
132 : // keeping the flow rate through the radiant system constant (b). In system
133 : // (b), the injection rate from the main water loop is varied to obtain the
134 : // proper inlet temperature.
135 :
136 : // USE STATEMENTS:
137 : // Use statements for data only modules
138 : // Using/Aliasing
139 : using HVAC::SmallLoad;
140 : using Psychrometrics::PsyTdpFnWPb;
141 :
142 : // Data
143 : // MODULE PARAMETER DEFINITIONS:
144 : // System types:
145 : constexpr std::string_view cHydronicSystem("ZoneHVAC:LowTemperatureRadiant:VariableFlow");
146 : constexpr std::string_view cConstantFlowSystem("ZoneHVAC:LowTemperatureRadiant:ConstantFlow");
147 :
148 : // DERIVED TYPE DEFINITIONS:
149 :
150 : // MODULE VARIABLE DECLARATIONS:
151 : // Standard, run-of-the-mill variables...
152 :
153 : // Object Data
154 : constexpr std::array<std::string_view, (int)CtrlType::Num> ctrlTypeNames = {"MeanAirTemperature",
155 : "MeanRadiantTemperature",
156 : "OperativeTemperature",
157 : "OutdoorDryBulbTemperature",
158 : "OutdoorWetBulbTemperature",
159 : "SurfaceFaceTemperature",
160 : "SurfaceInteriorTemperature",
161 : "RunningMeanOutdoorDryBulbTemperature"};
162 : constexpr std::array<std::string_view, (int)CtrlType::Num> ctrlTypeNamesUC = {"MEANAIRTEMPERATURE",
163 : "MEANRADIANTTEMPERATURE",
164 : "OPERATIVETEMPERATURE",
165 : "OUTDOORDRYBULBTEMPERATURE",
166 : "OUTDOORWETBULBTEMPERATURE",
167 : "SURFACEFACETEMPERATURE",
168 : "SURFACEINTERIORTEMPERATURE",
169 : "RUNNINGMEANOUTDOORDRYBULBTEMPERATURE"};
170 :
171 : constexpr std::array<std::string_view, (int)SetpointType::Num> setpointTypeNames = {"HalfFlowPower", "ZeroFlowPower"};
172 : constexpr std::array<std::string_view, (int)SetpointType::Num> setpointTypeNamesUC = {"HALFFLOWPOWER", "ZEROFLOWPOWER"};
173 :
174 : constexpr std::array<std::string_view, (int)FluidToSlabHeatTransferType::Num> fluidToSlabHeatTransferTypeNames = {"ConvectionOnly",
175 : "ISOStandard"};
176 : constexpr std::array<std::string_view, (int)FluidToSlabHeatTransferType::Num> fluidToSlabHeatTransferTypeNamesUC = {"CONVECTIONONLY",
177 : "ISOSTANDARD"};
178 :
179 : constexpr std::array<std::string_view, (int)CondCtrlType::Num> condCtrlTypeNamesUC = {"OFF", "SIMPLEOFF", "VARIABLEOFF"};
180 :
181 : constexpr std::array<std::string_view, (int)CircuitCalc::Num> circuitCalcNames = {"OnePerSurface", "CalculateFromCircuitLength"};
182 : constexpr std::array<std::string_view, (int)CircuitCalc::Num> circuitCalcNamesUC = {"ONEPERSURFACE", "CALCULATEFROMCIRCUITLENGTH"};
183 :
184 666848 : void SimLowTempRadiantSystem(EnergyPlusData &state,
185 : std::string_view CompName, // name of the low temperature radiant system
186 : bool const FirstHVACIteration, // TRUE if 1st HVAC simulation of system timestep
187 : Real64 &LoadMet, // load met by the radiant system, in Watts
188 : int &CompIndex)
189 : {
190 :
191 : // SUBROUTINE INFORMATION:
192 : // AUTHOR Rick Strand
193 : // DATE WRITTEN November 2000
194 :
195 : // Using/Aliasing
196 :
197 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
198 : int RadSysNum; // Radiant system number/index in local derived types
199 : SystemType systemType; // Type of radiant system: hydronic, constant flow, or electric
200 666848 : bool InitErrorFound(false);
201 :
202 666848 : if (state.dataLowTempRadSys->GetInputFlag) {
203 29 : GetLowTempRadiantSystem(state);
204 29 : state.dataLowTempRadSys->GetInputFlag = false;
205 : }
206 :
207 : // Find the correct Low Temp Radiant System
208 666848 : if (CompIndex == 0) {
209 82 : RadSysNum = Util::FindItemInList(CompName, state.dataLowTempRadSys->RadSysTypes);
210 82 : if (RadSysNum == 0) {
211 0 : ShowFatalError(state, format("SimLowTempRadiantSystem: Unit not found={}", CompName));
212 : }
213 82 : CompIndex = RadSysNum;
214 82 : systemType = state.dataLowTempRadSys->RadSysTypes(RadSysNum).systemType;
215 82 : switch (systemType) {
216 46 : case SystemType::Hydronic: {
217 46 : state.dataLowTempRadSys->RadSysTypes(RadSysNum).CompIndex = Util::FindItemInList(CompName, state.dataLowTempRadSys->HydrRadSys);
218 46 : } break;
219 27 : case SystemType::ConstantFlow: {
220 27 : state.dataLowTempRadSys->RadSysTypes(RadSysNum).CompIndex = Util::FindItemInList(CompName, state.dataLowTempRadSys->CFloRadSys);
221 27 : } break;
222 9 : case SystemType::Electric: {
223 9 : state.dataLowTempRadSys->RadSysTypes(RadSysNum).CompIndex = Util::FindItemInList(CompName, state.dataLowTempRadSys->ElecRadSys);
224 9 : } break;
225 0 : default:
226 0 : break;
227 : }
228 : } else {
229 666766 : RadSysNum = CompIndex;
230 666766 : systemType = state.dataLowTempRadSys->RadSysTypes(RadSysNum).systemType;
231 666766 : if (RadSysNum > state.dataLowTempRadSys->TotalNumOfRadSystems || RadSysNum < 1) {
232 0 : ShowFatalError(state,
233 0 : format("SimLowTempRadiantSystem: Invalid CompIndex passed={}, Number of Units={}, Entered Unit name={}",
234 : RadSysNum,
235 0 : state.dataLowTempRadSys->TotalNumOfRadSystems,
236 : CompName));
237 : }
238 666766 : if (state.dataLowTempRadSys->CheckEquipName(RadSysNum)) {
239 82 : if (CompName != state.dataLowTempRadSys->RadSysTypes(RadSysNum).Name) {
240 0 : ShowFatalError(state,
241 0 : format("SimLowTempRadiantSystem: Invalid CompIndex passed={}, Unit name={}, stored Unit Name for that index={}",
242 : RadSysNum,
243 : CompName,
244 0 : state.dataLowTempRadSys->RadSysTypes(RadSysNum).Name));
245 : }
246 82 : state.dataLowTempRadSys->CheckEquipName(RadSysNum) = false;
247 : }
248 : }
249 :
250 666848 : InitLowTempRadiantSystem(state, FirstHVACIteration, state.dataLowTempRadSys->RadSysTypes(RadSysNum).CompIndex, systemType, InitErrorFound);
251 666848 : if (InitErrorFound) {
252 0 : ShowFatalError(state,
253 : "InitLowTempRadiantSystem: Preceding error is not allowed to proceed with the simulation. Correct this input problem.");
254 : }
255 :
256 : // Simulate, update, and report based on the type of radiant system
257 : {
258 : RadiantSystemBaseData *baseSystem;
259 666848 : if (systemType == SystemType::Hydronic) {
260 366056 : baseSystem = &state.dataLowTempRadSys->HydrRadSys(state.dataLowTempRadSys->RadSysTypes(RadSysNum).CompIndex);
261 300792 : } else if (systemType == SystemType::ConstantFlow) {
262 221733 : baseSystem = &state.dataLowTempRadSys->CFloRadSys(state.dataLowTempRadSys->RadSysTypes(RadSysNum).CompIndex);
263 79059 : } else if (systemType == SystemType::Electric) {
264 79059 : baseSystem = &state.dataLowTempRadSys->ElecRadSys(state.dataLowTempRadSys->RadSysTypes(RadSysNum).CompIndex);
265 : } else {
266 0 : ShowFatalError(state, format("SimLowTempRadiantSystem: Illegal system type for system {}", CompName));
267 : }
268 :
269 666848 : if ((systemType == SystemType::Hydronic) || (systemType == SystemType::ConstantFlow) || (systemType == SystemType::Electric)) {
270 666848 : baseSystem->calculateLowTemperatureRadiantSystem(state, LoadMet);
271 666848 : baseSystem->updateLowTemperatureRadiantSystemSurfaces(state);
272 666848 : baseSystem->updateLowTemperatureRadiantSystem(state); // Nothing to update for electric systems
273 666848 : baseSystem->reportLowTemperatureRadiantSystem(state);
274 : }
275 : }
276 666848 : }
277 :
278 29 : void GetLowTempRadiantSystem(EnergyPlusData &state)
279 : {
280 :
281 : // SUBROUTINE INFORMATION:
282 : // AUTHOR Rick Strand
283 : // DATE WRITTEN November 2000
284 : // MODIFIED August 2003 (added constant flow system, made input extensible)
285 :
286 : // PURPOSE OF THIS SUBROUTINE:
287 : // This subroutine reads the input for low temperature radiant systems
288 : // from the user input file. This will contain all of the information
289 : // needed to simulate a low temperature radiant system.
290 :
291 : // Using/Aliasing
292 : using BranchNodeConnections::TestCompSet;
293 : using DataSizing::AutoSize;
294 : using DataSizing::CapacityPerFloorArea;
295 : using DataSizing::CoolingDesignCapacity;
296 : using DataSizing::FractionOfAutosizedCoolingCapacity;
297 : using DataSizing::FractionOfAutosizedHeatingCapacity;
298 : using DataSizing::HeatingDesignCapacity;
299 :
300 : using NodeInputManager::GetOnlySingleNode;
301 : using namespace DataLoopNode;
302 : using namespace DataSurfaceLists;
303 :
304 : // SUBROUTINE PARAMETER DEFINITIONS:
305 29 : constexpr std::string_view RoutineName("GetLowTempRadiantSystem: "); // include trailing blank space
306 29 : constexpr std::string_view routineName = "GetLowTempRadiantSystem";
307 :
308 29 : int constexpr iHeatCAPMAlphaNum(5); // get input index to Low Temperature Radiant system heating capacity sizing method
309 29 : int constexpr iHeatDesignCapacityNumericNum(1); // get input index to Low Temperature Radiant system electric heating capacity
310 29 : int constexpr iHeatCapacityPerFloorAreaNumericNum(
311 : 2); // get input index to Low Temperature Radiant system electric heating capacity per floor area sizing
312 29 : int constexpr iHeatFracOfAutosizedCapacityNumericNum(
313 : 3); // get input index to Low Temperature Radiant system electric heating capacity sizing as fraction of autosized heating capacity
314 :
315 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
316 29 : std::string CurrentModuleObject; // for ease in getting objects
317 29 : Array1D_string Alphas; // Alpha items for object
318 29 : Array1D_string cAlphaFields; // Alpha field names
319 29 : Array1D_string cNumericFields; // Numeric field names
320 29 : Array1D_bool AssignedAsRadiantSurface; // Set to true when a surface is part of a radiant system
321 : int CheckSurfNum; // Surface number to check to see if it has already been used by a radiant system
322 29 : bool ErrorsFound(false); // Set to true if errors in input, fatal at end of routine
323 : int IOStatus; // Used in GetObjectItem
324 : int Item; // Item to be "gotten"
325 : int MaxAlphas; // Maximum number of alphas for these input keywords
326 : int MaxNumbers; // Maximum number of numbers for these input keywords
327 29 : Array1D<Real64> Numbers; // Numeric items for object
328 : int NumAlphas; // Number of Alphas for each GetObjectItem call
329 : int NumArgs; // Unused variable that is part of a subroutine call
330 : int NumNumbers; // Number of Numbers for each GetObjectItem call
331 : int SurfListNum; // Index within the SurfList derived type for a surface list name
332 : int SurfNum; // DO loop counter for surfaces
333 : int BaseNum; // Temporary number for creating RadiantSystemTypes structure
334 29 : Array1D_bool lAlphaBlanks; // Logical array, alpha field input BLANK = .TRUE.
335 29 : Array1D_bool lNumericBlanks; // Logical array, numeric field input BLANK = .TRUE.
336 :
337 29 : auto &Zone = state.dataHeatBal->Zone;
338 29 : auto &Surface = state.dataSurface->Surface;
339 :
340 29 : Array1D_string VarFlowRadDesignNames;
341 29 : Array1D_string CFlowRadDesignNames;
342 :
343 29 : MaxAlphas = 0;
344 29 : MaxNumbers = 0;
345 :
346 29 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(
347 : state, "ZoneHVAC:LowTemperatureRadiant:VariableFlow:Design", NumArgs, NumAlphas, NumNumbers);
348 29 : MaxAlphas = max(MaxAlphas, NumAlphas);
349 29 : MaxNumbers = max(MaxNumbers, NumNumbers);
350 :
351 29 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(
352 : state, "ZoneHVAC:LowTemperatureRadiant:ConstantFlow:Design", NumArgs, NumAlphas, NumNumbers);
353 29 : MaxAlphas = max(MaxAlphas, NumAlphas);
354 29 : MaxNumbers = max(MaxNumbers, NumNumbers);
355 :
356 29 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(
357 : state, "ZoneHVAC:LowTemperatureRadiant:VariableFlow", NumArgs, NumAlphas, NumNumbers);
358 29 : MaxAlphas = max(MaxAlphas, NumAlphas);
359 29 : MaxNumbers = max(MaxNumbers, NumNumbers);
360 :
361 29 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(
362 : state, "ZoneHVAC:LowTemperatureRadiant:ConstantFlow", NumArgs, NumAlphas, NumNumbers);
363 29 : MaxAlphas = max(MaxAlphas, NumAlphas);
364 29 : MaxNumbers = max(MaxNumbers, NumNumbers);
365 :
366 29 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(
367 : state, "ZoneHVAC:LowTemperatureRadiant:Electric", NumArgs, NumAlphas, NumNumbers);
368 29 : MaxAlphas = max(MaxAlphas, NumAlphas);
369 29 : MaxNumbers = max(MaxNumbers, NumNumbers);
370 :
371 29 : Alphas.allocate(MaxAlphas);
372 29 : Numbers.dimension(MaxNumbers, 0.0);
373 29 : cAlphaFields.allocate(MaxAlphas);
374 29 : cNumericFields.allocate(MaxNumbers);
375 29 : lAlphaBlanks.dimension(MaxAlphas, true);
376 29 : lNumericBlanks.dimension(MaxNumbers, true);
377 :
378 58 : state.dataLowTempRadSys->NumOfHydrLowTempRadSys =
379 29 : state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "ZoneHVAC:LowTemperatureRadiant:VariableFlow");
380 58 : state.dataLowTempRadSys->NumOfCFloLowTempRadSys =
381 29 : state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "ZoneHVAC:LowTemperatureRadiant:ConstantFlow");
382 58 : state.dataLowTempRadSys->NumOfElecLowTempRadSys =
383 29 : state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "ZoneHVAC:LowTemperatureRadiant:Electric");
384 :
385 58 : state.dataLowTempRadSys->NumOfHydrLowTempRadSysDes =
386 29 : state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "ZoneHVAC:LowTemperatureRadiant:VariableFlow:Design");
387 58 : state.dataLowTempRadSys->NumOfCFloLowTempRadSysDes =
388 29 : state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "ZoneHVAC:LowTemperatureRadiant:ConstantFlow:Design");
389 :
390 29 : state.dataLowTempRadSys->TotalNumOfRadSystems = state.dataLowTempRadSys->NumOfHydrLowTempRadSys +
391 29 : state.dataLowTempRadSys->NumOfElecLowTempRadSys +
392 29 : state.dataLowTempRadSys->NumOfCFloLowTempRadSys;
393 29 : state.dataLowTempRadSys->RadSysTypes.allocate(state.dataLowTempRadSys->TotalNumOfRadSystems);
394 29 : state.dataLowTempRadSys->LowTempRadUniqueNames.reserve(static_cast<unsigned>(state.dataLowTempRadSys->TotalNumOfRadSystems));
395 29 : state.dataLowTempRadSys->CheckEquipName.dimension(state.dataLowTempRadSys->TotalNumOfRadSystems, true);
396 :
397 29 : state.dataLowTempRadSys->HydrRadSys.allocate(state.dataLowTempRadSys->NumOfHydrLowTempRadSys);
398 29 : if (state.dataLowTempRadSys->NumOfHydrLowTempRadSys > 0) {
399 17 : auto *water = Fluid::GetWater(state);
400 17 : if (water == nullptr) {
401 0 : ShowSevereError(state, "Hydronic radiant systems: no water property data found in input");
402 0 : ErrorsFound = true;
403 : }
404 :
405 63 : for (auto &e : state.dataLowTempRadSys->HydrRadSys) {
406 46 : e.water = water;
407 : }
408 : }
409 :
410 29 : state.dataLowTempRadSys->CFloRadSys.allocate(state.dataLowTempRadSys->NumOfCFloLowTempRadSys);
411 29 : if (state.dataLowTempRadSys->NumOfCFloLowTempRadSys > 0) {
412 9 : auto *water = Fluid::GetWater(state);
413 9 : if (water == nullptr) {
414 0 : ShowSevereError(state, "Constant flow radiant systems: no water property data found in input");
415 0 : ErrorsFound = true;
416 : }
417 :
418 36 : for (auto &e : state.dataLowTempRadSys->CFloRadSys) {
419 27 : e.water = water;
420 : }
421 : }
422 :
423 29 : state.dataLowTempRadSys->ElecRadSys.allocate(state.dataLowTempRadSys->NumOfElecLowTempRadSys);
424 29 : state.dataLowTempRadSys->ElecRadSysNumericFields.allocate(state.dataLowTempRadSys->NumOfElecLowTempRadSys);
425 :
426 29 : state.dataLowTempRadSys->HydronicRadiantSysNumericFields.allocate(state.dataLowTempRadSys->NumOfHydrLowTempRadSys);
427 29 : state.dataLowTempRadSys->HydronicRadiantSysDesign.allocate(state.dataLowTempRadSys->NumOfHydrLowTempRadSysDes);
428 29 : VarFlowRadDesignNames.allocate(state.dataLowTempRadSys->NumOfHydrLowTempRadSysDes);
429 :
430 29 : state.dataLowTempRadSys->CflowRadiantSysDesign.allocate(state.dataLowTempRadSys->NumOfCFloLowTempRadSysDes);
431 29 : CFlowRadDesignNames.allocate(state.dataLowTempRadSys->NumOfCFloLowTempRadSysDes);
432 :
433 : // make sure data is gotten for surface lists
434 29 : GetNumberOfSurfaceLists(state);
435 :
436 : // Obtain all of the design data related to hydronic low temperature radiant systems...
437 29 : CurrentModuleObject = "ZoneHVAC:LowTemperatureRadiant:VariableFlow:Design";
438 60 : for (Item = 1; Item <= state.dataLowTempRadSys->NumOfHydrLowTempRadSysDes; ++Item) {
439 :
440 31 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
441 : CurrentModuleObject,
442 : Item,
443 : Alphas,
444 : NumAlphas,
445 : Numbers,
446 : NumNumbers,
447 : IOStatus,
448 : lNumericBlanks,
449 : lAlphaBlanks,
450 : cAlphaFields,
451 : cNumericFields);
452 :
453 31 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
454 :
455 31 : state.dataLowTempRadSys->HydronicRadiantSysDesign(Item).FieldNames.allocate(NumNumbers);
456 31 : state.dataLowTempRadSys->HydronicRadiantSysDesign(Item).FieldNames = "";
457 31 : state.dataLowTempRadSys->HydronicRadiantSysDesign(Item).FieldNames = cNumericFields;
458 31 : GlobalNames::VerifyUniqueInterObjectName(
459 62 : state, state.dataLowTempRadSys->LowTempRadUniqueNames, Alphas(1), CurrentModuleObject, cAlphaFields(1), ErrorsFound);
460 :
461 31 : auto &thisRadSysDesign = state.dataLowTempRadSys->HydronicRadiantSysDesign(Item);
462 :
463 : // General user input data
464 31 : thisRadSysDesign.designName = Alphas(1);
465 :
466 31 : if (lAlphaBlanks(2)) {
467 0 : thisRadSysDesign.FluidToSlabHeatTransfer = FluidToSlabHeatTransferType::ConvectionOnly;
468 31 : } else if ((thisRadSysDesign.FluidToSlabHeatTransfer = static_cast<FluidToSlabHeatTransferType>(
469 31 : getEnumValue(fluidToSlabHeatTransferTypeNamesUC, Alphas(2)))) == FluidToSlabHeatTransferType::Invalid) {
470 0 : ShowWarningInvalidKey(state, eoh, cAlphaFields(2), Alphas(2), "ConvectionOnly");
471 0 : thisRadSysDesign.FluidToSlabHeatTransfer = FluidToSlabHeatTransferType::ConvectionOnly;
472 : }
473 :
474 31 : thisRadSysDesign.TubeDiameterInner = Numbers(1);
475 31 : thisRadSysDesign.TubeDiameterOuter = Numbers(2);
476 :
477 31 : thisRadSysDesign.VarFlowTubeConductivity = Numbers(3);
478 :
479 : // Process the temperature control type
480 31 : if (lAlphaBlanks(3)) {
481 0 : thisRadSysDesign.VarFlowControlType = CtrlType::MAT;
482 31 : } else if ((thisRadSysDesign.VarFlowControlType = static_cast<CtrlType>(getEnumValue(ctrlTypeNamesUC, Alphas(3)))) == CtrlType::Invalid) {
483 0 : ShowWarningInvalidKey(state, eoh, cAlphaFields(3), Alphas(3), "MeanAirTemperature");
484 0 : thisRadSysDesign.VarFlowControlType = CtrlType::MAT;
485 : }
486 :
487 : // Process the setpoint type
488 31 : if (lAlphaBlanks(4)) {
489 0 : thisRadSysDesign.VarFlowSetpointType = SetpointType::HalfFlowPower;
490 31 : } else if ((thisRadSysDesign.VarFlowSetpointType = static_cast<SetpointType>(getEnumValue(setpointTypeNamesUC, Alphas(4)))) ==
491 : SetpointType::Invalid) {
492 0 : ShowWarningInvalidKey(state, eoh, cAlphaFields(4), Alphas(4), "HalfFlowPower");
493 0 : thisRadSysDesign.VarFlowSetpointType = SetpointType::HalfFlowPower;
494 : }
495 :
496 : // Refactor everything below to Alphas as HCMethod, etc
497 :
498 : // Determine Low Temp Radiant heating design capacity sizing method
499 31 : thisRadSysDesign.DesignHeatingCapMethodInput = Alphas(5);
500 31 : if (Util::SameString(thisRadSysDesign.DesignHeatingCapMethodInput, "HeatingDesignCapacity")) {
501 29 : thisRadSysDesign.DesignHeatingCapMethod = HeatingDesignCapacity;
502 2 : } else if (Util::SameString(thisRadSysDesign.DesignHeatingCapMethodInput, "CapacityPerFloorArea")) {
503 1 : thisRadSysDesign.DesignHeatingCapMethod = CapacityPerFloorArea;
504 1 : if (!lNumericBlanks(4)) {
505 1 : thisRadSysDesign.DesignScaledHeatingCapacity = Numbers(4);
506 1 : if (thisRadSysDesign.DesignScaledHeatingCapacity <= 0.0) {
507 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, thisRadSysDesign.designName));
508 0 : ShowContinueError(state, format("Input for {} = {}", cAlphaFields(5), thisRadSysDesign.DesignHeatingCapMethodInput));
509 0 : ShowContinueError(state, format("Illegal {} = {:.7T}", cNumericFields(4), Numbers(4)));
510 0 : ErrorsFound = true;
511 1 : } else if (thisRadSysDesign.DesignScaledHeatingCapacity == AutoSize) {
512 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, thisRadSysDesign.designName));
513 0 : ShowContinueError(state, format("Input for {} = {}", cAlphaFields(5), thisRadSysDesign.DesignHeatingCapMethodInput));
514 0 : ShowContinueError(state, format("Illegal {} = Autosize", cNumericFields(4)));
515 0 : ErrorsFound = true;
516 : }
517 : } else {
518 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, thisRadSysDesign.Name));
519 0 : ShowContinueError(state, format("Input for {} = {}", cAlphaFields(5), thisRadSysDesign.DesignHeatingCapMethodInput));
520 0 : ShowContinueError(state, format("Blank field not allowed for {}", cNumericFields(4)));
521 0 : ErrorsFound = true;
522 : }
523 1 : } else if (Util::SameString(thisRadSysDesign.DesignHeatingCapMethodInput, "FractionOfAutosizedHeatingCapacity")) {
524 1 : thisRadSysDesign.DesignHeatingCapMethod = FractionOfAutosizedHeatingCapacity;
525 1 : if (!lNumericBlanks(5)) {
526 1 : thisRadSysDesign.DesignScaledHeatingCapacity = Numbers(5);
527 1 : if (thisRadSysDesign.DesignScaledHeatingCapacity < 0.0) {
528 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, thisRadSysDesign.designName));
529 0 : ShowContinueError(state, format("Illegal {} = {:.7T}", cNumericFields(5), Numbers(5)));
530 0 : ErrorsFound = true;
531 : }
532 : } else {
533 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, thisRadSysDesign.designName));
534 0 : ShowContinueError(state, format("Input for {} = {}", cAlphaFields(5), thisRadSysDesign.DesignHeatingCapMethodInput));
535 0 : ShowContinueError(state, format("Blank field not allowed for {}", cNumericFields(5)));
536 0 : ErrorsFound = true;
537 : }
538 : } else {
539 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, thisRadSysDesign.designName));
540 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(5), thisRadSysDesign.DesignHeatingCapMethodInput));
541 0 : ErrorsFound = true;
542 : }
543 :
544 31 : thisRadSysDesign.HotThrottlRange = Numbers(6);
545 :
546 31 : if (lAlphaBlanks(6)) {
547 31 : } else if ((thisRadSysDesign.heatSetptSched = Sched::GetSchedule(state, Alphas(6))) == nullptr) {
548 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(6), Alphas(6));
549 0 : ErrorsFound = true;
550 : }
551 :
552 : // Determine Low Temp Radiant cooling design capacity sizing method
553 31 : thisRadSysDesign.DesignCoolingCapMethodInput = Alphas(7);
554 31 : if (Util::SameString(thisRadSysDesign.DesignCoolingCapMethodInput, "CoolingDesignCapacity")) {
555 29 : thisRadSysDesign.DesignCoolingCapMethod = CoolingDesignCapacity;
556 2 : } else if (Util::SameString(thisRadSysDesign.DesignCoolingCapMethodInput, "CapacityPerFloorArea")) {
557 1 : thisRadSysDesign.DesignCoolingCapMethod = CapacityPerFloorArea;
558 1 : if (!lNumericBlanks(7)) {
559 1 : thisRadSysDesign.DesignScaledCoolingCapacity = Numbers(7);
560 1 : if (thisRadSysDesign.DesignScaledCoolingCapacity <= 0.0) {
561 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, thisRadSysDesign.designName));
562 0 : ShowContinueError(state, format("Input for {} = {}", cAlphaFields(7), thisRadSysDesign.DesignCoolingCapMethodInput));
563 0 : ShowContinueError(state, format("Illegal {} = {:.7T}", cNumericFields(7), thisRadSysDesign.DesignScaledCoolingCapacity));
564 0 : ErrorsFound = true;
565 1 : } else if (thisRadSysDesign.DesignScaledCoolingCapacity == AutoSize) {
566 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, thisRadSysDesign.designName));
567 0 : ShowContinueError(state, format("Input for {} = {}", cAlphaFields(7), thisRadSysDesign.DesignCoolingCapMethodInput));
568 0 : ShowContinueError(state, format("Illegal {} = Autosize", cNumericFields(7)));
569 0 : ErrorsFound = true;
570 : }
571 : } else {
572 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, thisRadSysDesign.designName));
573 0 : ShowContinueError(state, format("Input for {} = {}", cAlphaFields(7), thisRadSysDesign.DesignCoolingCapMethodInput));
574 0 : ShowContinueError(state, format("Blank field not allowed for {}", cNumericFields(7)));
575 0 : ErrorsFound = true;
576 : }
577 1 : } else if (Util::SameString(thisRadSysDesign.DesignCoolingCapMethodInput, "FractionOfAutosizedCoolingCapacity")) {
578 1 : thisRadSysDesign.DesignCoolingCapMethod = FractionOfAutosizedCoolingCapacity;
579 1 : if (!lNumericBlanks(8)) {
580 1 : thisRadSysDesign.DesignScaledCoolingCapacity = Numbers(8);
581 1 : if (thisRadSysDesign.DesignScaledCoolingCapacity < 0.0) {
582 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, thisRadSysDesign.designName));
583 0 : ShowContinueError(state, format("Illegal {} = {:.7T}", cNumericFields(8), Numbers(8)));
584 0 : ErrorsFound = true;
585 : }
586 : } else {
587 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, thisRadSysDesign.designName));
588 0 : ShowContinueError(state, format("Input for {} = {}", cAlphaFields(7), thisRadSysDesign.DesignCoolingCapMethodInput));
589 0 : ShowContinueError(state, format("Blank field not allowed for {}", cNumericFields(8)));
590 0 : ErrorsFound = true;
591 : }
592 : } else {
593 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, thisRadSysDesign.designName));
594 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(7), thisRadSysDesign.DesignCoolingCapMethodInput));
595 0 : ErrorsFound = true;
596 : }
597 :
598 31 : thisRadSysDesign.ColdThrottlRange = Numbers(9);
599 :
600 31 : if (lAlphaBlanks(8)) {
601 30 : } else if ((thisRadSysDesign.coolSetptSched = Sched::GetSchedule(state, Alphas(8))) == nullptr) {
602 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(8), Alphas(8));
603 0 : ErrorsFound = true;
604 : }
605 :
606 31 : if (lAlphaBlanks(9)) {
607 17 : thisRadSysDesign.condCtrlType = CondCtrlType::SimpleOff;
608 14 : } else if ((thisRadSysDesign.condCtrlType = static_cast<CondCtrlType>(getEnumValue(condCtrlTypeNamesUC, Alphas(9)))) ==
609 : CondCtrlType::Invalid) {
610 0 : ShowWarningInvalidKey(state, eoh, cAlphaFields(9), Alphas(9), "SimpleOff");
611 0 : thisRadSysDesign.condCtrlType = CondCtrlType::SimpleOff;
612 : }
613 :
614 31 : thisRadSysDesign.CondDewPtDeltaT = Numbers(10);
615 :
616 31 : if (lAlphaBlanks(10)) {
617 3 : } else if ((thisRadSysDesign.changeoverDelaySched = Sched::GetSchedule(state, Alphas(10))) == nullptr) {
618 0 : ShowWarningItemNotFound(state, eoh, cAlphaFields(10), Alphas(10), "No changeover delay will be used for this radiant system.");
619 : }
620 :
621 31 : VarFlowRadDesignNames(Item) = Alphas(1);
622 : }
623 :
624 : // Obtain all of the user data related to hydronic low temperature radiant systems...
625 29 : BaseNum = 0;
626 29 : CurrentModuleObject = "ZoneHVAC:LowTemperatureRadiant:VariableFlow";
627 75 : for (Item = 1; Item <= state.dataLowTempRadSys->NumOfHydrLowTempRadSys; ++Item) {
628 :
629 46 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
630 : CurrentModuleObject,
631 : Item,
632 : Alphas,
633 : NumAlphas,
634 : Numbers,
635 : NumNumbers,
636 : IOStatus,
637 : lNumericBlanks,
638 : lAlphaBlanks,
639 : cAlphaFields,
640 : cNumericFields);
641 :
642 46 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
643 :
644 46 : state.dataLowTempRadSys->HydronicRadiantSysNumericFields(Item).FieldNames.allocate(NumNumbers);
645 46 : state.dataLowTempRadSys->HydronicRadiantSysNumericFields(Item).FieldNames = "";
646 46 : state.dataLowTempRadSys->HydronicRadiantSysNumericFields(Item).FieldNames = cNumericFields;
647 46 : GlobalNames::VerifyUniqueInterObjectName(
648 92 : state, state.dataLowTempRadSys->LowTempRadUniqueNames, Alphas(1), CurrentModuleObject, cAlphaFields(1), ErrorsFound);
649 :
650 46 : ++BaseNum;
651 46 : state.dataLowTempRadSys->RadSysTypes(BaseNum).Name = Alphas(1);
652 46 : state.dataLowTempRadSys->RadSysTypes(BaseNum).systemType = SystemType::Hydronic;
653 :
654 46 : auto &thisRadSys = state.dataLowTempRadSys->HydrRadSys(Item);
655 :
656 : // General user input data
657 46 : thisRadSys.Name = Alphas(1);
658 :
659 92 : Util::setDesignObjectNameAndPointer(state,
660 46 : thisRadSys.designObjectName,
661 46 : thisRadSys.DesignObjectPtr,
662 46 : Alphas(2),
663 : VarFlowRadDesignNames,
664 : CurrentModuleObject,
665 46 : Alphas(1),
666 : ErrorsFound);
667 46 : if (ErrorsFound) {
668 0 : break;
669 : }
670 46 : VarFlowRadDesignData variableFlowDesignDataObject{state.dataLowTempRadSys->HydronicRadiantSysDesign(
671 46 : thisRadSys.DesignObjectPtr)}; // Contains the data for variable flow hydronic systems
672 :
673 46 : if (lAlphaBlanks(3)) {
674 0 : thisRadSys.availSched = Sched::GetScheduleAlwaysOn(state);
675 46 : } else if ((thisRadSys.availSched = Sched::GetSchedule(state, Alphas(3))) == nullptr) {
676 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(3), Alphas(3));
677 0 : ErrorsFound = true;
678 : }
679 :
680 46 : thisRadSys.ZoneName = Alphas(4);
681 46 : thisRadSys.ZonePtr = Util::FindItemInList(Alphas(4), Zone);
682 46 : if (thisRadSys.ZonePtr == 0) {
683 0 : ShowSevereError(state, format("{}Invalid {} = {}", RoutineName, cAlphaFields(3), Alphas(4)));
684 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, Alphas(1)));
685 0 : ErrorsFound = true;
686 : }
687 :
688 46 : thisRadSys.SurfListName = Alphas(5);
689 46 : SurfListNum = 0;
690 46 : if (state.dataSurfLists->NumOfSurfaceLists > 0) {
691 4 : SurfListNum = Util::FindItemInList(thisRadSys.SurfListName, state.dataSurfLists->SurfList);
692 : }
693 46 : if (SurfListNum > 0) { // Found a valid surface list
694 3 : thisRadSys.NumOfSurfaces = state.dataSurfLists->SurfList(SurfListNum).NumOfSurfaces;
695 3 : thisRadSys.SurfacePtr.allocate(thisRadSys.NumOfSurfaces);
696 3 : thisRadSys.SurfaceName.allocate(thisRadSys.NumOfSurfaces);
697 3 : thisRadSys.SurfaceFrac.allocate(thisRadSys.NumOfSurfaces);
698 3 : thisRadSys.NumCircuits.allocate(thisRadSys.NumOfSurfaces);
699 18 : for (SurfNum = 1; SurfNum <= state.dataSurfLists->SurfList(SurfListNum).NumOfSurfaces; ++SurfNum) {
700 15 : thisRadSys.SurfacePtr(SurfNum) = state.dataSurfLists->SurfList(SurfListNum).SurfPtr(SurfNum);
701 15 : thisRadSys.SurfaceName(SurfNum) = state.dataSurfLists->SurfList(SurfListNum).SurfName(SurfNum);
702 15 : thisRadSys.SurfaceFrac(SurfNum) = state.dataSurfLists->SurfList(SurfListNum).SurfFlowFrac(SurfNum);
703 15 : if (thisRadSys.SurfacePtr(SurfNum) > 0) {
704 15 : state.dataSurface->surfIntConv(thisRadSys.SurfacePtr(SurfNum)).hasActiveInIt = true;
705 : }
706 : }
707 : } else { // User entered a single surface name rather than a surface list
708 43 : thisRadSys.NumOfSurfaces = 1;
709 43 : thisRadSys.SurfacePtr.allocate(thisRadSys.NumOfSurfaces);
710 43 : thisRadSys.SurfaceName.allocate(thisRadSys.NumOfSurfaces);
711 43 : thisRadSys.SurfaceFrac.allocate(thisRadSys.NumOfSurfaces);
712 43 : thisRadSys.NumCircuits.allocate(thisRadSys.NumOfSurfaces);
713 43 : thisRadSys.SurfaceName(1) = thisRadSys.SurfListName;
714 43 : thisRadSys.SurfacePtr(1) = Util::FindItemInList(thisRadSys.SurfaceName(1), Surface);
715 43 : thisRadSys.SurfaceFrac(1) = 1.0;
716 43 : thisRadSys.NumCircuits(1) = 0.0;
717 : // Error checking for single surfaces
718 43 : if (thisRadSys.SurfacePtr(1) == 0) {
719 0 : ShowSevereError(state, format("{}Invalid {} = {}", RoutineName, cAlphaFields(5), Alphas(5)));
720 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, Alphas(1)));
721 0 : ErrorsFound = true;
722 43 : } else if (state.dataSurface->SurfIsRadSurfOrVentSlabOrPool(thisRadSys.SurfacePtr(1))) {
723 0 : ShowSevereError(state, format("{}{}=\"{}\", Invalid Surface", RoutineName, CurrentModuleObject, Alphas(1)));
724 0 : ShowContinueError(state,
725 0 : format("{}=\"{}\" has been used in another radiant system or ventilated slab.", cAlphaFields(5), Alphas(5)));
726 0 : ErrorsFound = true;
727 : }
728 43 : if (thisRadSys.SurfacePtr(1) != 0) {
729 43 : state.dataSurface->surfIntConv(thisRadSys.SurfacePtr(1)).hasActiveInIt = true;
730 43 : state.dataSurface->surfIntConv(thisRadSys.SurfacePtr(1)).hasActiveInIt = true; // Ummmm ... what?
731 : }
732 : }
733 :
734 : // Error checking for zones and construction information
735 46 : thisRadSys.errorCheckZonesAndConstructions(state, ErrorsFound);
736 :
737 46 : thisRadSys.TubeLength = Numbers(1);
738 :
739 : // Determine Low Temp Radiant heating design capacity sizing method
740 46 : if (variableFlowDesignDataObject.DesignHeatingCapMethod == HeatingDesignCapacity) {
741 44 : thisRadSys.HeatingCapMethod = HeatingDesignCapacity;
742 44 : if (!lNumericBlanks(2)) {
743 44 : thisRadSys.ScaledHeatingCapacity = Numbers(2);
744 44 : if (thisRadSys.ScaledHeatingCapacity < 0.0 && thisRadSys.ScaledHeatingCapacity != AutoSize) {
745 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, thisRadSys.Name));
746 0 : ShowContinueError(state, format("Illegal {} = {:.7T}", cNumericFields(2), Numbers(2)));
747 0 : ErrorsFound = true;
748 : }
749 : } else {
750 0 : if ((!lAlphaBlanks(6)) || (!lAlphaBlanks(7))) {
751 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, thisRadSys.Name));
752 0 : ShowContinueError(state, "Input for Heating Design Capacity Method = HeatingDesignCapacity");
753 0 : ShowContinueError(state, format("Blank field not allowed for {}", cNumericFields(2)));
754 0 : ErrorsFound = true;
755 : }
756 : }
757 2 : } else if (variableFlowDesignDataObject.DesignHeatingCapMethod == CapacityPerFloorArea) {
758 1 : thisRadSys.HeatingCapMethod = CapacityPerFloorArea;
759 1 : thisRadSys.ScaledHeatingCapacity = variableFlowDesignDataObject.DesignScaledHeatingCapacity;
760 1 : } else if (variableFlowDesignDataObject.DesignHeatingCapMethod == FractionOfAutosizedHeatingCapacity) {
761 1 : thisRadSys.HeatingCapMethod = FractionOfAutosizedHeatingCapacity;
762 1 : thisRadSys.ScaledHeatingCapacity = variableFlowDesignDataObject.DesignScaledHeatingCapacity;
763 : }
764 :
765 : // Heating user input data
766 46 : thisRadSys.WaterVolFlowMaxHeat = Numbers(3);
767 :
768 46 : thisRadSys.HotWaterInNode = GetOnlySingleNode(state,
769 46 : Alphas(6),
770 : ErrorsFound,
771 : DataLoopNode::ConnectionObjectType::ZoneHVACLowTemperatureRadiantVariableFlow,
772 46 : Alphas(1),
773 : DataLoopNode::NodeFluidType::Water,
774 : DataLoopNode::ConnectionType::Inlet,
775 : NodeInputManager::CompFluidStream::Primary,
776 : ObjectIsNotParent);
777 :
778 46 : thisRadSys.HotWaterOutNode = GetOnlySingleNode(state,
779 46 : Alphas(7),
780 : ErrorsFound,
781 : DataLoopNode::ConnectionObjectType::ZoneHVACLowTemperatureRadiantVariableFlow,
782 46 : Alphas(1),
783 : DataLoopNode::NodeFluidType::Water,
784 : DataLoopNode::ConnectionType::Outlet,
785 : NodeInputManager::CompFluidStream::Primary,
786 : ObjectIsNotParent);
787 :
788 46 : if ((!lAlphaBlanks(6)) || (!lAlphaBlanks(7))) {
789 92 : TestCompSet(state, CurrentModuleObject, Alphas(1), Alphas(6), Alphas(7), "Hot Water Nodes");
790 : }
791 52 : if ((thisRadSys.WaterVolFlowMaxHeat == AutoSize) &&
792 6 : (lAlphaBlanks(6) || lAlphaBlanks(7) || (thisRadSys.HotWaterInNode <= 0) || (thisRadSys.HotWaterOutNode <= 0) ||
793 6 : (variableFlowDesignDataObject.heatSetptSched == nullptr))) {
794 0 : ShowSevereError(state, "Hydronic radiant systems may not be autosized without specification of nodes or schedules.");
795 0 : ShowContinueError(state, format("Occurs in {} (heating input) = {}", CurrentModuleObject, Alphas(1)));
796 0 : ErrorsFound = true;
797 : }
798 :
799 : // Determine Low Temp Radiant cooling design capacity sizing method
800 46 : if (variableFlowDesignDataObject.DesignCoolingCapMethod == CoolingDesignCapacity) {
801 44 : thisRadSys.CoolingCapMethod = CoolingDesignCapacity;
802 44 : if (!lNumericBlanks(4)) {
803 44 : thisRadSys.ScaledCoolingCapacity = Numbers(4);
804 44 : if (thisRadSys.ScaledCoolingCapacity < 0.0 && thisRadSys.ScaledCoolingCapacity != AutoSize) {
805 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, thisRadSys.Name));
806 0 : ShowContinueError(state, format("Illegal {} = {:.7T}", cNumericFields(4), Numbers(4)));
807 0 : ErrorsFound = true;
808 : }
809 : } else {
810 0 : if ((!lAlphaBlanks(8)) || (!lAlphaBlanks(9))) {
811 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, thisRadSys.Name));
812 0 : ShowContinueError(state, "Input for Cooling Design Capacity Method = CoolingDesignCapacity");
813 0 : ShowContinueError(state, format("Blank field not allowed for {}", cNumericFields(4)));
814 0 : ErrorsFound = true;
815 : }
816 : }
817 2 : } else if (variableFlowDesignDataObject.DesignCoolingCapMethod == CapacityPerFloorArea) {
818 1 : thisRadSys.CoolingCapMethod = CapacityPerFloorArea;
819 1 : thisRadSys.ScaledCoolingCapacity = variableFlowDesignDataObject.DesignScaledCoolingCapacity;
820 1 : } else if (variableFlowDesignDataObject.DesignCoolingCapMethod == FractionOfAutosizedCoolingCapacity) {
821 1 : thisRadSys.CoolingCapMethod = FractionOfAutosizedCoolingCapacity;
822 1 : thisRadSys.ScaledCoolingCapacity = variableFlowDesignDataObject.DesignScaledCoolingCapacity;
823 : }
824 :
825 : // Cooling user input data
826 46 : thisRadSys.WaterVolFlowMaxCool = Numbers(5);
827 :
828 46 : thisRadSys.ColdWaterInNode = GetOnlySingleNode(state,
829 46 : Alphas(8),
830 : ErrorsFound,
831 : DataLoopNode::ConnectionObjectType::ZoneHVACLowTemperatureRadiantVariableFlow,
832 46 : Alphas(1),
833 : DataLoopNode::NodeFluidType::Water,
834 : DataLoopNode::ConnectionType::Inlet,
835 : NodeInputManager::CompFluidStream::Secondary,
836 : ObjectIsNotParent);
837 :
838 46 : thisRadSys.ColdWaterOutNode = GetOnlySingleNode(state,
839 46 : Alphas(9),
840 : ErrorsFound,
841 : DataLoopNode::ConnectionObjectType::ZoneHVACLowTemperatureRadiantVariableFlow,
842 46 : Alphas(1),
843 : DataLoopNode::NodeFluidType::Water,
844 : DataLoopNode::ConnectionType::Outlet,
845 : NodeInputManager::CompFluidStream::Secondary,
846 : ObjectIsNotParent);
847 :
848 46 : if ((!lAlphaBlanks(8)) || (!lAlphaBlanks(9))) {
849 86 : TestCompSet(state, CurrentModuleObject, Alphas(1), Alphas(8), Alphas(9), "Chilled Water Nodes");
850 : }
851 :
852 46 : if (lAlphaBlanks(10)) {
853 46 : thisRadSys.NumCircCalcMethod = CircuitCalc::OneCircuit;
854 0 : } else if ((thisRadSys.NumCircCalcMethod = static_cast<CircuitCalc>(getEnumValue(circuitCalcNamesUC, Alphas(10)))) ==
855 : CircuitCalc::Invalid) {
856 0 : ShowWarningInvalidKey(state, eoh, cAlphaFields(10), Alphas(10), "OnePerSurface");
857 0 : thisRadSys.NumCircCalcMethod = CircuitCalc::OneCircuit;
858 : }
859 :
860 46 : thisRadSys.changeoverDelaySched = variableFlowDesignDataObject.changeoverDelaySched;
861 :
862 46 : thisRadSys.CircLength = Numbers(6);
863 :
864 52 : if ((thisRadSys.WaterVolFlowMaxCool == AutoSize) &&
865 6 : (variableFlowDesignDataObject.DesignCoolingCapMethod == 0 || lAlphaBlanks(8) || lAlphaBlanks(9) ||
866 6 : (thisRadSys.ColdWaterInNode <= 0) || (thisRadSys.ColdWaterOutNode <= 0) ||
867 6 : (variableFlowDesignDataObject.coolSetptSched == nullptr))) {
868 0 : ShowSevereError(state, "Hydronic radiant systems may not be autosized without specification of nodes or schedules");
869 0 : ShowContinueError(state, format("Occurs in {} (cooling input) ={}", CurrentModuleObject, Alphas(1)));
870 0 : ErrorsFound = true;
871 : }
872 46 : }
873 :
874 : // Obtain all of the design data related to Constant flow low temperature radiant systems...
875 29 : CurrentModuleObject = "ZoneHVAC:LowTemperatureRadiant:ConstantFlow:Design";
876 52 : for (Item = 1; Item <= state.dataLowTempRadSys->NumOfCFloLowTempRadSysDes; ++Item) {
877 :
878 23 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
879 : CurrentModuleObject,
880 : Item,
881 : Alphas,
882 : NumAlphas,
883 : Numbers,
884 : NumNumbers,
885 : IOStatus,
886 : lNumericBlanks,
887 : lAlphaBlanks,
888 : cAlphaFields,
889 : cNumericFields);
890 :
891 23 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
892 :
893 23 : state.dataLowTempRadSys->CflowRadiantSysDesign(Item).FieldNames.allocate(NumNumbers);
894 23 : state.dataLowTempRadSys->CflowRadiantSysDesign(Item).FieldNames = "";
895 23 : state.dataLowTempRadSys->CflowRadiantSysDesign(Item).FieldNames = cNumericFields;
896 23 : GlobalNames::VerifyUniqueInterObjectName(
897 46 : state, state.dataLowTempRadSys->LowTempRadUniqueNames, Alphas(1), CurrentModuleObject, cAlphaFields(1), ErrorsFound);
898 :
899 23 : auto &thisRadSysDesign = state.dataLowTempRadSys->CflowRadiantSysDesign(Item);
900 :
901 : // General user input data
902 23 : thisRadSysDesign.designName = Alphas(1);
903 :
904 23 : if (lAlphaBlanks(2)) {
905 0 : thisRadSysDesign.FluidToSlabHeatTransfer = FluidToSlabHeatTransferType::ConvectionOnly;
906 23 : } else if ((thisRadSysDesign.FluidToSlabHeatTransfer = static_cast<FluidToSlabHeatTransferType>(
907 23 : getEnumValue(fluidToSlabHeatTransferTypeNamesUC, Alphas(2)))) == FluidToSlabHeatTransferType::Invalid) {
908 0 : ShowWarningInvalidKey(state, eoh, cAlphaFields(2), Alphas(2), "ConvectionOnly");
909 0 : thisRadSysDesign.FluidToSlabHeatTransfer = FluidToSlabHeatTransferType::ConvectionOnly;
910 : }
911 :
912 23 : thisRadSysDesign.TubeDiameterInner = Numbers(1);
913 23 : thisRadSysDesign.TubeDiameterOuter = Numbers(2);
914 23 : thisRadSysDesign.ConstFlowTubeConductivity = Numbers(3);
915 :
916 : // Process the temperature control type
917 23 : if (lAlphaBlanks(3)) {
918 0 : thisRadSysDesign.ConstFlowControlType = CtrlType::MAT;
919 23 : } else if ((thisRadSysDesign.ConstFlowControlType = static_cast<CtrlType>(getEnumValue(ctrlTypeNamesUC, Alphas(3)))) ==
920 : CtrlType::Invalid) {
921 0 : ShowWarningInvalidKey(state, eoh, cAlphaFields(3), Alphas(3), "MeanAirTemperature");
922 0 : thisRadSysDesign.ConstFlowControlType = CtrlType::MAT;
923 23 : } else if (thisRadSysDesign.ConstFlowControlType == CtrlType::RunningMeanODB) {
924 3 : state.dataLowTempRadSys->anyRadiantSystemUsingRunningMeanAverage = true;
925 : }
926 :
927 23 : thisRadSysDesign.runningMeanOutdoorAirTemperatureWeightingFactor = Numbers(4);
928 23 : thisRadSysDesign.MotorEffic = Numbers(5);
929 23 : thisRadSysDesign.FracMotorLossToFluid = Numbers(6);
930 :
931 23 : if (lAlphaBlanks(4)) {
932 1 : thisRadSysDesign.condCtrlType = CondCtrlType::SimpleOff;
933 22 : } else if ((thisRadSysDesign.condCtrlType = static_cast<CondCtrlType>(getEnumValue(condCtrlTypeNamesUC, Alphas(4)))) ==
934 : CondCtrlType::Invalid) {
935 0 : ShowWarningInvalidKey(state, eoh, cAlphaFields(4), Alphas(4), "SimpleOff");
936 0 : thisRadSysDesign.condCtrlType = CondCtrlType::SimpleOff;
937 : }
938 :
939 23 : thisRadSysDesign.CondDewPtDeltaT = Numbers(7);
940 :
941 23 : if (lAlphaBlanks(5)) {
942 3 : } else if ((thisRadSysDesign.changeoverDelaySched = Sched::GetSchedule(state, Alphas(5))) == nullptr) {
943 0 : ShowWarningItemNotFound(state, eoh, cAlphaFields(5), Alphas(5), "No changeover delay will be used for this radiant system.");
944 : }
945 23 : CFlowRadDesignNames(Item) = Alphas(1);
946 : }
947 :
948 : // Obtain all of the user data related to constant flow (hydronic) low temperature radiant systems...
949 29 : CurrentModuleObject = "ZoneHVAC:LowTemperatureRadiant:ConstantFlow";
950 56 : for (Item = 1; Item <= state.dataLowTempRadSys->NumOfCFloLowTempRadSys; ++Item) {
951 :
952 27 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
953 : CurrentModuleObject,
954 : Item,
955 : Alphas,
956 : NumAlphas,
957 : Numbers,
958 : NumNumbers,
959 : IOStatus,
960 : lNumericBlanks,
961 : lAlphaBlanks,
962 : cAlphaFields,
963 : cNumericFields);
964 :
965 27 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
966 :
967 27 : GlobalNames::VerifyUniqueInterObjectName(
968 54 : state, state.dataLowTempRadSys->LowTempRadUniqueNames, Alphas(1), CurrentModuleObject, cAlphaFields(1), ErrorsFound);
969 27 : ++BaseNum;
970 27 : state.dataLowTempRadSys->RadSysTypes(BaseNum).Name = Alphas(1);
971 27 : state.dataLowTempRadSys->RadSysTypes(BaseNum).systemType = SystemType::ConstantFlow;
972 :
973 : // General user input data
974 27 : auto &thisCFloSys = state.dataLowTempRadSys->CFloRadSys(Item);
975 :
976 27 : thisCFloSys.Name = Alphas(1);
977 54 : Util::setDesignObjectNameAndPointer(state,
978 27 : thisCFloSys.designObjectName,
979 27 : thisCFloSys.DesignObjectPtr,
980 27 : Alphas(2),
981 : CFlowRadDesignNames,
982 : CurrentModuleObject,
983 27 : Alphas(1),
984 : ErrorsFound);
985 27 : if (ErrorsFound) {
986 0 : break;
987 : }
988 : ConstantFlowRadDesignData ConstantFlowRadDesignDataObject{
989 27 : state.dataLowTempRadSys->CflowRadiantSysDesign(thisCFloSys.DesignObjectPtr)}; // Contains the data for variable flow hydronic systems
990 :
991 27 : if (lAlphaBlanks(3)) {
992 0 : thisCFloSys.availSched = Sched::GetScheduleAlwaysOn(state);
993 27 : } else if ((thisCFloSys.availSched = Sched::GetSchedule(state, Alphas(3))) == nullptr) {
994 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(3), Alphas(3));
995 0 : ErrorsFound = true;
996 : }
997 :
998 27 : thisCFloSys.ZoneName = Alphas(4);
999 27 : thisCFloSys.ZonePtr = Util::FindItemInList(Alphas(4), Zone);
1000 27 : if (thisCFloSys.ZonePtr == 0) {
1001 0 : ShowSevereError(state, format("{}Invalid {} = {}", RoutineName, cAlphaFields(4), Alphas(4)));
1002 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1003 0 : ErrorsFound = true;
1004 : }
1005 :
1006 27 : thisCFloSys.SurfListName = Alphas(5);
1007 27 : SurfListNum = 0;
1008 27 : if (state.dataSurfLists->NumOfSurfaceLists > 0) {
1009 0 : SurfListNum = Util::FindItemInList(thisCFloSys.SurfListName, state.dataSurfLists->SurfList);
1010 : }
1011 27 : if (SurfListNum > 0) { // Found a valid surface list
1012 0 : thisCFloSys.NumOfSurfaces = state.dataSurfLists->SurfList(SurfListNum).NumOfSurfaces;
1013 0 : thisCFloSys.SurfacePtr.allocate(thisCFloSys.NumOfSurfaces);
1014 0 : thisCFloSys.SurfaceName.allocate(thisCFloSys.NumOfSurfaces);
1015 0 : thisCFloSys.SurfaceFrac.allocate(thisCFloSys.NumOfSurfaces);
1016 0 : thisCFloSys.NumCircuits.allocate(thisCFloSys.NumOfSurfaces);
1017 0 : state.dataLowTempRadSys->MaxCloNumOfSurfaces = max(state.dataLowTempRadSys->MaxCloNumOfSurfaces, thisCFloSys.NumOfSurfaces);
1018 0 : for (SurfNum = 1; SurfNum <= state.dataSurfLists->SurfList(SurfListNum).NumOfSurfaces; ++SurfNum) {
1019 0 : thisCFloSys.SurfacePtr(SurfNum) = state.dataSurfLists->SurfList(SurfListNum).SurfPtr(SurfNum);
1020 0 : thisCFloSys.SurfaceName(SurfNum) = state.dataSurfLists->SurfList(SurfListNum).SurfName(SurfNum);
1021 0 : thisCFloSys.SurfaceFrac(SurfNum) = state.dataSurfLists->SurfList(SurfListNum).SurfFlowFrac(SurfNum);
1022 0 : thisCFloSys.NumCircuits(SurfNum) = 0.0;
1023 0 : if (thisCFloSys.SurfacePtr(SurfNum) != 0) {
1024 0 : state.dataSurface->surfIntConv(thisCFloSys.SurfacePtr(SurfNum)).hasActiveInIt = true;
1025 : }
1026 : }
1027 : } else { // User entered a single surface name rather than a surface list
1028 27 : thisCFloSys.NumOfSurfaces = 1;
1029 27 : thisCFloSys.SurfacePtr.allocate(thisCFloSys.NumOfSurfaces);
1030 27 : thisCFloSys.SurfaceName.allocate(thisCFloSys.NumOfSurfaces);
1031 27 : thisCFloSys.SurfaceFrac.allocate(thisCFloSys.NumOfSurfaces);
1032 27 : thisCFloSys.NumCircuits.allocate(thisCFloSys.NumOfSurfaces);
1033 27 : state.dataLowTempRadSys->MaxCloNumOfSurfaces = max(state.dataLowTempRadSys->MaxCloNumOfSurfaces, thisCFloSys.NumOfSurfaces);
1034 27 : thisCFloSys.SurfaceName(1) = thisCFloSys.SurfListName;
1035 27 : thisCFloSys.SurfacePtr(1) = Util::FindItemInList(thisCFloSys.SurfaceName(1), Surface);
1036 27 : thisCFloSys.SurfaceFrac(1) = 1.0;
1037 27 : thisCFloSys.NumCircuits(1) = 0.0;
1038 : // Error checking for single surfaces
1039 27 : if (thisCFloSys.SurfacePtr(1) == 0) {
1040 0 : ShowSevereError(state, format("{}Invalid {} = {}", RoutineName, cAlphaFields(4), Alphas(4)));
1041 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1042 0 : ErrorsFound = true;
1043 27 : } else if (state.dataSurface->SurfIsRadSurfOrVentSlabOrPool(thisCFloSys.SurfacePtr(1))) {
1044 0 : ShowSevereError(state, format("{}{}=\"{}\", Invalid Surface", RoutineName, CurrentModuleObject, Alphas(1)));
1045 0 : ShowContinueError(state,
1046 0 : format("{}=\"{}\" has been used in another radiant system or ventilated slab.", cAlphaFields(5), Alphas(5)));
1047 0 : ErrorsFound = true;
1048 : }
1049 27 : if (thisCFloSys.SurfacePtr(1) != 0) {
1050 27 : state.dataSurface->surfIntConv(thisCFloSys.SurfacePtr(1)).hasActiveInIt = true;
1051 27 : state.dataSurface->SurfIsRadSurfOrVentSlabOrPool(thisCFloSys.SurfacePtr(1)) = true;
1052 : }
1053 : }
1054 :
1055 : // Error checking for zones and construction information
1056 27 : thisCFloSys.errorCheckZonesAndConstructions(state, ErrorsFound);
1057 :
1058 27 : thisCFloSys.TubeLength = Numbers(1);
1059 :
1060 : // Process pump input for constant flow (hydronic) radiant system
1061 27 : thisCFloSys.WaterVolFlowMax = Numbers(2);
1062 :
1063 27 : if (lAlphaBlanks(6)) {
1064 0 : } else if ((thisCFloSys.volFlowSched = Sched::GetSchedule(state, Alphas(6))) == nullptr) {
1065 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(6), Alphas(6));
1066 0 : ErrorsFound = true;
1067 : }
1068 27 : thisCFloSys.NomPumpHead = Numbers(3);
1069 27 : thisCFloSys.NomPowerUse = Numbers(4);
1070 :
1071 : // Heating user input data
1072 27 : thisCFloSys.HotWaterInNode = GetOnlySingleNode(state,
1073 27 : Alphas(7),
1074 : ErrorsFound,
1075 : DataLoopNode::ConnectionObjectType::ZoneHVACLowTemperatureRadiantConstantFlow,
1076 27 : Alphas(1),
1077 : DataLoopNode::NodeFluidType::Water,
1078 : DataLoopNode::ConnectionType::Inlet,
1079 : NodeInputManager::CompFluidStream::Primary,
1080 : ObjectIsNotParent);
1081 :
1082 27 : thisCFloSys.HotWaterOutNode = GetOnlySingleNode(state,
1083 27 : Alphas(8),
1084 : ErrorsFound,
1085 : DataLoopNode::ConnectionObjectType::ZoneHVACLowTemperatureRadiantConstantFlow,
1086 27 : Alphas(1),
1087 : DataLoopNode::NodeFluidType::Water,
1088 : DataLoopNode::ConnectionType::Outlet,
1089 : NodeInputManager::CompFluidStream::Primary,
1090 : ObjectIsNotParent);
1091 :
1092 27 : if ((!lAlphaBlanks(7)) || (!lAlphaBlanks(8))) {
1093 54 : TestCompSet(state, CurrentModuleObject, Alphas(1), Alphas(7), Alphas(8), "Hot Water Nodes");
1094 : }
1095 :
1096 27 : if (lAlphaBlanks(9)) {
1097 27 : } else if ((thisCFloSys.hotWaterHiTempSched = Sched::GetSchedule(state, Alphas(9))) == nullptr) {
1098 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(9), Alphas(9));
1099 0 : ErrorsFound = true;
1100 : }
1101 :
1102 27 : if (lAlphaBlanks(10)) {
1103 27 : } else if ((thisCFloSys.hotWaterLoTempSched = Sched::GetSchedule(state, Alphas(10))) == nullptr) {
1104 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(10), Alphas(10));
1105 0 : ErrorsFound = true;
1106 : }
1107 :
1108 : // This may look like a weird thing to do, but it's equivalent to a nested if and also uses less nesting
1109 27 : if (lAlphaBlanks(11)) {
1110 27 : } else if ((thisCFloSys.hotCtrlHiTempSched = Sched::GetSchedule(state, Alphas(11))) == nullptr) {
1111 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(11), Alphas(11));
1112 0 : ErrorsFound = true;
1113 : }
1114 :
1115 27 : if (lAlphaBlanks(12)) {
1116 27 : } else if ((thisCFloSys.hotCtrlLoTempSched = Sched::GetSchedule(state, Alphas(12))) == nullptr) {
1117 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(12), Alphas(12));
1118 0 : ErrorsFound = true;
1119 : }
1120 :
1121 : // Cooling user input data
1122 27 : thisCFloSys.ColdWaterInNode = GetOnlySingleNode(state,
1123 27 : Alphas(13),
1124 : ErrorsFound,
1125 : DataLoopNode::ConnectionObjectType::ZoneHVACLowTemperatureRadiantConstantFlow,
1126 27 : Alphas(1),
1127 : DataLoopNode::NodeFluidType::Water,
1128 : DataLoopNode::ConnectionType::Inlet,
1129 : NodeInputManager::CompFluidStream::Secondary,
1130 : ObjectIsNotParent);
1131 :
1132 27 : thisCFloSys.ColdWaterOutNode = GetOnlySingleNode(state,
1133 27 : Alphas(14),
1134 : ErrorsFound,
1135 : DataLoopNode::ConnectionObjectType::ZoneHVACLowTemperatureRadiantConstantFlow,
1136 27 : Alphas(1),
1137 : DataLoopNode::NodeFluidType::Water,
1138 : DataLoopNode::ConnectionType::Outlet,
1139 : NodeInputManager::CompFluidStream::Secondary,
1140 : ObjectIsNotParent);
1141 :
1142 27 : if ((!lAlphaBlanks(13)) || (!lAlphaBlanks(14))) {
1143 48 : TestCompSet(state, CurrentModuleObject, Alphas(1), Alphas(13), Alphas(14), "Chilled Water Nodes");
1144 : }
1145 :
1146 27 : if (lAlphaBlanks(15)) {
1147 24 : } else if ((thisCFloSys.coldWaterHiTempSched = Sched::GetSchedule(state, Alphas(15))) == nullptr) {
1148 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(15), Alphas(15));
1149 0 : ErrorsFound = true;
1150 : }
1151 :
1152 27 : if (lAlphaBlanks(16)) {
1153 24 : } else if ((thisCFloSys.coldWaterLoTempSched = Sched::GetSchedule(state, Alphas(16))) == nullptr) {
1154 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(16), Alphas(16));
1155 0 : ErrorsFound = true;
1156 : }
1157 :
1158 27 : if (lAlphaBlanks(17)) {
1159 24 : } else if ((thisCFloSys.coldCtrlHiTempSched = Sched::GetSchedule(state, Alphas(17))) == nullptr) {
1160 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(17), Alphas(17));
1161 0 : ErrorsFound = true;
1162 : }
1163 :
1164 27 : if (lAlphaBlanks(18)) {
1165 24 : } else if ((thisCFloSys.coldCtrlLoTempSched = Sched::GetSchedule(state, Alphas(18))) == nullptr) {
1166 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(18), Alphas(18));
1167 0 : ErrorsFound = true;
1168 : }
1169 :
1170 27 : if (lAlphaBlanks(19)) {
1171 27 : thisCFloSys.NumCircCalcMethod = CircuitCalc::OneCircuit;
1172 0 : } else if ((thisCFloSys.NumCircCalcMethod = static_cast<CircuitCalc>(getEnumValue(circuitCalcNamesUC, Alphas(19)))) ==
1173 : CircuitCalc::Invalid) {
1174 0 : ShowWarningInvalidKey(state, eoh, cAlphaFields(19), Alphas(19), "OnePerSurface");
1175 0 : thisCFloSys.NumCircCalcMethod = CircuitCalc::OneCircuit;
1176 : }
1177 :
1178 27 : thisCFloSys.changeoverDelaySched = ConstantFlowRadDesignDataObject.changeoverDelaySched;
1179 :
1180 27 : thisCFloSys.CircLength = Numbers(5);
1181 27 : }
1182 :
1183 : // Obtain all of the user data related to electric low temperature radiant systems...
1184 29 : CurrentModuleObject = "ZoneHVAC:LowTemperatureRadiant:Electric";
1185 :
1186 38 : for (Item = 1; Item <= state.dataLowTempRadSys->NumOfElecLowTempRadSys; ++Item) {
1187 :
1188 9 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1189 : CurrentModuleObject,
1190 : Item,
1191 : Alphas,
1192 : NumAlphas,
1193 : Numbers,
1194 : NumNumbers,
1195 : IOStatus,
1196 : lNumericBlanks,
1197 : lAlphaBlanks,
1198 : cAlphaFields,
1199 : cNumericFields);
1200 :
1201 9 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
1202 :
1203 9 : state.dataLowTempRadSys->ElecRadSysNumericFields(Item).FieldNames.allocate(NumNumbers);
1204 9 : state.dataLowTempRadSys->ElecRadSysNumericFields(Item).FieldNames = "";
1205 9 : state.dataLowTempRadSys->ElecRadSysNumericFields(Item).FieldNames = cNumericFields;
1206 :
1207 9 : GlobalNames::VerifyUniqueInterObjectName(
1208 18 : state, state.dataLowTempRadSys->LowTempRadUniqueNames, Alphas(1), CurrentModuleObject, cAlphaFields(1), ErrorsFound);
1209 9 : ++BaseNum;
1210 9 : state.dataLowTempRadSys->RadSysTypes(BaseNum).Name = Alphas(1);
1211 9 : state.dataLowTempRadSys->RadSysTypes(BaseNum).systemType = SystemType::Electric;
1212 :
1213 : // General user input data
1214 9 : auto &thisElecSys = state.dataLowTempRadSys->ElecRadSys(Item);
1215 :
1216 9 : thisElecSys.Name = Alphas(1);
1217 :
1218 9 : if (lAlphaBlanks(2)) {
1219 0 : thisElecSys.availSched = Sched::GetScheduleAlwaysOn(state);
1220 9 : } else if ((thisElecSys.availSched = Sched::GetSchedule(state, Alphas(2))) == nullptr) {
1221 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
1222 0 : ErrorsFound = true;
1223 : }
1224 :
1225 9 : thisElecSys.ZoneName = Alphas(3);
1226 9 : thisElecSys.ZonePtr = Util::FindItemInList(Alphas(3), Zone);
1227 9 : if (thisElecSys.ZonePtr == 0) {
1228 0 : ShowSevereError(state, format("{}Invalid {} = {}", RoutineName, cAlphaFields(3), Alphas(3)));
1229 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1230 0 : ErrorsFound = true;
1231 : }
1232 :
1233 9 : thisElecSys.SurfListName = Alphas(4);
1234 9 : SurfListNum = 0;
1235 9 : if (state.dataSurfLists->NumOfSurfaceLists > 0) {
1236 0 : SurfListNum = Util::FindItemInList(thisElecSys.SurfListName, state.dataSurfLists->SurfList);
1237 : }
1238 9 : if (SurfListNum > 0) { // Found a valid surface list
1239 0 : thisElecSys.NumOfSurfaces = state.dataSurfLists->SurfList(SurfListNum).NumOfSurfaces;
1240 0 : thisElecSys.SurfacePtr.allocate(thisElecSys.NumOfSurfaces);
1241 0 : thisElecSys.SurfaceName.allocate(thisElecSys.NumOfSurfaces);
1242 0 : thisElecSys.SurfaceFrac.allocate(thisElecSys.NumOfSurfaces);
1243 0 : for (SurfNum = 1; SurfNum <= state.dataSurfLists->SurfList(SurfListNum).NumOfSurfaces; ++SurfNum) {
1244 0 : thisElecSys.SurfacePtr(SurfNum) = state.dataSurfLists->SurfList(SurfListNum).SurfPtr(SurfNum);
1245 0 : thisElecSys.SurfaceName(SurfNum) = state.dataSurfLists->SurfList(SurfListNum).SurfName(SurfNum);
1246 0 : thisElecSys.SurfaceFrac(SurfNum) = state.dataSurfLists->SurfList(SurfListNum).SurfFlowFrac(SurfNum);
1247 : }
1248 : } else { // User entered a single surface name rather than a surface list
1249 9 : thisElecSys.NumOfSurfaces = 1;
1250 9 : thisElecSys.SurfacePtr.allocate(thisElecSys.NumOfSurfaces);
1251 9 : thisElecSys.SurfaceName.allocate(thisElecSys.NumOfSurfaces);
1252 9 : thisElecSys.SurfaceFrac.allocate(thisElecSys.NumOfSurfaces);
1253 9 : thisElecSys.SurfaceName(1) = thisElecSys.SurfListName;
1254 9 : thisElecSys.SurfacePtr(1) = Util::FindItemInList(thisElecSys.SurfaceName(1), Surface);
1255 9 : thisElecSys.SurfaceFrac(1) = 1.0;
1256 : // Error checking for single surfaces
1257 9 : if (thisElecSys.SurfacePtr(1) == 0) {
1258 0 : ShowSevereError(state, format("{}Invalid {} = {}", RoutineName, cAlphaFields(4), Alphas(4)));
1259 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1260 0 : ErrorsFound = true;
1261 9 : } else if (state.dataSurface->SurfIsRadSurfOrVentSlabOrPool(thisElecSys.SurfacePtr(1))) {
1262 0 : ShowSevereError(state, format("{}{}=\"{}\", Invalid Surface", RoutineName, CurrentModuleObject, Alphas(1)));
1263 0 : ShowContinueError(state,
1264 0 : format("{}=\"{}\" has been used in another radiant system or ventilated slab.", cAlphaFields(4), Alphas(4)));
1265 0 : ErrorsFound = true;
1266 : }
1267 9 : if (thisElecSys.SurfacePtr(1) != 0) {
1268 9 : state.dataSurface->SurfIsRadSurfOrVentSlabOrPool(state.dataLowTempRadSys->ElecRadSys(Item).SurfacePtr(1)) = true;
1269 : }
1270 : }
1271 :
1272 : // Error checking for zones and construction information
1273 9 : thisElecSys.errorCheckZonesAndConstructions(state, ErrorsFound);
1274 :
1275 : // Heating user input data
1276 : // Determine Low Temp Radiant heating design capacity sizing method
1277 9 : if (Util::SameString(Alphas(iHeatCAPMAlphaNum), "HeatingDesignCapacity")) {
1278 5 : thisElecSys.HeatingCapMethod = HeatingDesignCapacity;
1279 5 : if (!lNumericBlanks(iHeatDesignCapacityNumericNum)) {
1280 5 : thisElecSys.ScaledHeatingCapacity = Numbers(iHeatDesignCapacityNumericNum);
1281 5 : thisElecSys.MaxElecPower = thisElecSys.ScaledHeatingCapacity;
1282 5 : if (thisElecSys.ScaledHeatingCapacity < 0.0 && thisElecSys.ScaledHeatingCapacity != AutoSize) {
1283 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, thisElecSys.Name));
1284 0 : ShowContinueError(
1285 : state,
1286 0 : format("Illegal {} = {:.7T}", cNumericFields(iHeatDesignCapacityNumericNum), Numbers(iHeatDesignCapacityNumericNum)));
1287 0 : ErrorsFound = true;
1288 : }
1289 : } else {
1290 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, thisElecSys.Name));
1291 0 : ShowContinueError(state, format("Input for {} = {}", cAlphaFields(iHeatCAPMAlphaNum), Alphas(iHeatCAPMAlphaNum)));
1292 0 : ShowContinueError(state, format("Blank field not allowed for {}", cNumericFields(iHeatDesignCapacityNumericNum)));
1293 0 : ErrorsFound = true;
1294 : }
1295 4 : } else if (Util::SameString(Alphas(iHeatCAPMAlphaNum), "CapacityPerFloorArea")) {
1296 2 : thisElecSys.HeatingCapMethod = CapacityPerFloorArea;
1297 2 : if (!lNumericBlanks(iHeatCapacityPerFloorAreaNumericNum)) {
1298 2 : thisElecSys.ScaledHeatingCapacity = Numbers(iHeatCapacityPerFloorAreaNumericNum);
1299 2 : thisElecSys.MaxElecPower = thisElecSys.ScaledHeatingCapacity;
1300 2 : if (thisElecSys.ScaledHeatingCapacity <= 0.0) {
1301 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, thisElecSys.Name));
1302 0 : ShowContinueError(state, format("Input for {} = {}", cAlphaFields(iHeatCAPMAlphaNum), Alphas(iHeatCAPMAlphaNum)));
1303 0 : ShowContinueError(state,
1304 0 : format("Illegal {} = {:.7T}",
1305 : cNumericFields(iHeatCapacityPerFloorAreaNumericNum),
1306 : Numbers(iHeatCapacityPerFloorAreaNumericNum)));
1307 0 : ErrorsFound = true;
1308 2 : } else if (thisElecSys.ScaledHeatingCapacity == AutoSize) {
1309 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, thisElecSys.Name));
1310 0 : ShowContinueError(state, format("Input for {} = {}", cAlphaFields(iHeatCAPMAlphaNum), Alphas(iHeatCAPMAlphaNum)));
1311 0 : ShowContinueError(state, format("Illegal {} = Autosize", cNumericFields(iHeatCapacityPerFloorAreaNumericNum)));
1312 0 : ErrorsFound = true;
1313 : }
1314 : } else {
1315 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, thisElecSys.Name));
1316 0 : ShowContinueError(state, format("Input for {} = {}", cAlphaFields(iHeatCAPMAlphaNum), Alphas(iHeatCAPMAlphaNum)));
1317 0 : ShowContinueError(state, format("Blank field not allowed for {}", cNumericFields(iHeatCapacityPerFloorAreaNumericNum)));
1318 0 : ErrorsFound = true;
1319 : }
1320 2 : } else if (Util::SameString(Alphas(iHeatCAPMAlphaNum), "FractionOfAutosizedHeatingCapacity")) {
1321 2 : thisElecSys.HeatingCapMethod = FractionOfAutosizedHeatingCapacity;
1322 2 : if (!lNumericBlanks(iHeatFracOfAutosizedCapacityNumericNum)) {
1323 2 : thisElecSys.ScaledHeatingCapacity = Numbers(iHeatFracOfAutosizedCapacityNumericNum);
1324 2 : thisElecSys.MaxElecPower = thisElecSys.ScaledHeatingCapacity;
1325 2 : if (thisElecSys.ScaledHeatingCapacity < 0.0) {
1326 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, thisElecSys.Name));
1327 0 : ShowContinueError(state,
1328 0 : format("Illegal {} = {:.7T}",
1329 : cNumericFields(iHeatFracOfAutosizedCapacityNumericNum),
1330 : Numbers(iHeatFracOfAutosizedCapacityNumericNum)));
1331 0 : ErrorsFound = true;
1332 : }
1333 : } else {
1334 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, thisElecSys.Name));
1335 0 : ShowContinueError(state, format("Input for {} = {}", cAlphaFields(iHeatCAPMAlphaNum), Alphas(iHeatCAPMAlphaNum)));
1336 0 : ShowContinueError(state, format("Blank field not allowed for {}", cNumericFields(iHeatFracOfAutosizedCapacityNumericNum)));
1337 0 : ErrorsFound = true;
1338 : }
1339 : } else {
1340 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, thisElecSys.Name));
1341 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(iHeatCAPMAlphaNum), Alphas(iHeatCAPMAlphaNum)));
1342 0 : ErrorsFound = true;
1343 : }
1344 :
1345 : // Process the temperature control type
1346 9 : if (lAlphaBlanks(6)) {
1347 0 : thisElecSys.controlType = CtrlType::MAT;
1348 9 : } else if ((thisElecSys.controlType = static_cast<CtrlType>(getEnumValue(ctrlTypeNamesUC, Alphas(6)))) == CtrlType::Invalid) {
1349 0 : ShowWarningInvalidKey(state, eoh, cAlphaFields(6), Alphas(6), "MeanAirTemperature");
1350 0 : thisElecSys.controlType = CtrlType::MAT;
1351 : }
1352 :
1353 : // Process the setpoint type
1354 9 : if (lAlphaBlanks(7)) {
1355 0 : thisElecSys.setpointType = SetpointType::HalfFlowPower;
1356 9 : } else if ((thisElecSys.setpointType = static_cast<SetpointType>(getEnumValue(setpointTypeNamesUC, Alphas(7)))) ==
1357 : SetpointType::Invalid) {
1358 0 : ShowWarningInvalidKey(state, eoh, cAlphaFields(7), Alphas(7), "HalfFlowPower");
1359 0 : thisElecSys.setpointType = SetpointType::HalfFlowPower;
1360 : }
1361 :
1362 9 : thisElecSys.ThrottlRange = Numbers(4);
1363 :
1364 9 : if (lAlphaBlanks(8)) {
1365 0 : ShowSevereEmptyField(state, eoh, cAlphaFields(8));
1366 0 : ErrorsFound = true;
1367 9 : } else if ((thisElecSys.setptSched = Sched::GetSchedule(state, Alphas(8))) == nullptr) {
1368 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(8), Alphas(8));
1369 0 : ErrorsFound = true;
1370 : }
1371 : }
1372 :
1373 : // Check to see if any surface is included in more than one radiant system. This is not allowed
1374 : // and thus indicative that there is an error in the input file. This is to make sure that two
1375 : // different radiant systems are competing for the same surface. Allowing this to happen would
1376 : // result in lost energy somewhere and the situation really is not physically possible anyway.
1377 29 : AssignedAsRadiantSurface.dimension(state.dataSurface->TotSurfaces, false);
1378 :
1379 75 : for (Item = 1; Item <= state.dataLowTempRadSys->NumOfHydrLowTempRadSys; ++Item) {
1380 104 : for (SurfNum = 1; SurfNum <= state.dataLowTempRadSys->HydrRadSys(Item).NumOfSurfaces; ++SurfNum) {
1381 58 : CheckSurfNum = state.dataLowTempRadSys->HydrRadSys(Item).SurfacePtr(SurfNum);
1382 58 : if (CheckSurfNum == 0) {
1383 0 : continue;
1384 : }
1385 58 : if (AssignedAsRadiantSurface(CheckSurfNum)) {
1386 0 : ShowSevereError(
1387 0 : state, format("Surface {} is referenced by more than one radiant system--this is not allowed", Surface(CheckSurfNum).Name));
1388 0 : ErrorsFound = true;
1389 : } else {
1390 58 : AssignedAsRadiantSurface(CheckSurfNum) = true;
1391 : }
1392 : // Also check the other side of interzone partitions
1393 58 : if ((Surface(CheckSurfNum).ExtBoundCond > 0) && (Surface(CheckSurfNum).ExtBoundCond != CheckSurfNum)) {
1394 1 : if (AssignedAsRadiantSurface(Surface(CheckSurfNum).ExtBoundCond)) {
1395 0 : ShowSevereError(state,
1396 0 : format("Interzone surface {} is referenced by more than one radiant system--this is not allowed",
1397 0 : Surface(Surface(CheckSurfNum).ExtBoundCond).Name));
1398 0 : ErrorsFound = true;
1399 : } else {
1400 1 : AssignedAsRadiantSurface(Surface(CheckSurfNum).ExtBoundCond) = true;
1401 : }
1402 : }
1403 : }
1404 : }
1405 :
1406 56 : for (Item = 1; Item <= state.dataLowTempRadSys->NumOfCFloLowTempRadSys; ++Item) {
1407 54 : for (SurfNum = 1; SurfNum <= state.dataLowTempRadSys->CFloRadSys(Item).NumOfSurfaces; ++SurfNum) {
1408 27 : CheckSurfNum = state.dataLowTempRadSys->CFloRadSys(Item).SurfacePtr(SurfNum);
1409 27 : if (CheckSurfNum == 0) {
1410 0 : continue;
1411 : }
1412 27 : if (AssignedAsRadiantSurface(CheckSurfNum)) {
1413 0 : ShowSevereError(
1414 0 : state, format("Surface {} is referenced by more than one radiant system--this is not allowed", Surface(CheckSurfNum).Name));
1415 0 : ErrorsFound = true;
1416 : } else {
1417 27 : AssignedAsRadiantSurface(CheckSurfNum) = true;
1418 : }
1419 : // Also check the other side of interzone partitions
1420 27 : if ((Surface(CheckSurfNum).ExtBoundCond > 0) && (Surface(CheckSurfNum).ExtBoundCond != CheckSurfNum)) {
1421 0 : if (AssignedAsRadiantSurface(Surface(CheckSurfNum).ExtBoundCond)) {
1422 0 : ShowSevereError(state,
1423 0 : format("Interzone surface {} is referenced by more than one radiant system--this is not allowed",
1424 0 : Surface(Surface(CheckSurfNum).ExtBoundCond).Name));
1425 0 : ErrorsFound = true;
1426 : } else {
1427 0 : AssignedAsRadiantSurface(Surface(CheckSurfNum).ExtBoundCond) = true;
1428 : }
1429 : }
1430 : }
1431 : }
1432 :
1433 38 : for (Item = 1; Item <= state.dataLowTempRadSys->NumOfElecLowTempRadSys; ++Item) {
1434 18 : for (SurfNum = 1; SurfNum <= state.dataLowTempRadSys->ElecRadSys(Item).NumOfSurfaces; ++SurfNum) {
1435 9 : CheckSurfNum = state.dataLowTempRadSys->ElecRadSys(Item).SurfacePtr(SurfNum);
1436 9 : if (CheckSurfNum == 0) {
1437 0 : continue;
1438 : }
1439 9 : if (AssignedAsRadiantSurface(CheckSurfNum)) {
1440 0 : ShowSevereError(
1441 0 : state, format("Surface {} is referenced by more than one radiant system--this is not allowed", Surface(CheckSurfNum).Name));
1442 0 : ErrorsFound = true;
1443 : } else {
1444 9 : AssignedAsRadiantSurface(CheckSurfNum) = true;
1445 : }
1446 : // Also check the other side of interzone partitions
1447 9 : if ((Surface(CheckSurfNum).ExtBoundCond > 0) && (Surface(CheckSurfNum).ExtBoundCond != CheckSurfNum)) {
1448 0 : if (AssignedAsRadiantSurface(Surface(CheckSurfNum).ExtBoundCond)) {
1449 0 : ShowSevereError(state,
1450 0 : format("Interzone surface {} is referenced by more than one radiant system--this is not allowed",
1451 0 : Surface(Surface(CheckSurfNum).ExtBoundCond).Name));
1452 0 : ErrorsFound = true;
1453 : } else {
1454 0 : AssignedAsRadiantSurface(Surface(CheckSurfNum).ExtBoundCond) = true;
1455 : }
1456 : }
1457 : }
1458 : }
1459 :
1460 29 : AssignedAsRadiantSurface.deallocate();
1461 29 : Alphas.deallocate();
1462 29 : Numbers.deallocate();
1463 29 : cAlphaFields.deallocate();
1464 29 : cNumericFields.deallocate();
1465 29 : lAlphaBlanks.deallocate();
1466 29 : lNumericBlanks.deallocate();
1467 :
1468 29 : if (ErrorsFound) {
1469 0 : ShowFatalError(state, format("{}Errors found in input. Preceding conditions cause termination.", RoutineName));
1470 : }
1471 :
1472 : // Set up the output variables for low temperature radiant systems
1473 : // ZoneHVAC:LowTemperatureRadiant:VariableFlow (HydrRadSys)
1474 75 : for (Item = 1; Item <= state.dataLowTempRadSys->NumOfHydrLowTempRadSys; ++Item) {
1475 :
1476 46 : auto &thisHydrSys = state.dataLowTempRadSys->HydrRadSys(Item);
1477 :
1478 92 : SetupOutputVariable(state,
1479 : "Zone Radiant HVAC Heating Rate",
1480 : Constant::Units::W,
1481 46 : thisHydrSys.HeatPower,
1482 : OutputProcessor::TimeStepType::System,
1483 : OutputProcessor::StoreType::Average,
1484 46 : thisHydrSys.Name);
1485 92 : SetupOutputVariable(state,
1486 : "Zone Radiant HVAC Heating Energy",
1487 : Constant::Units::J,
1488 46 : thisHydrSys.HeatEnergy,
1489 : OutputProcessor::TimeStepType::System,
1490 : OutputProcessor::StoreType::Sum,
1491 46 : thisHydrSys.Name,
1492 : Constant::eResource::EnergyTransfer,
1493 : OutputProcessor::Group::HVAC,
1494 : OutputProcessor::EndUseCat::HeatingCoils);
1495 92 : SetupOutputVariable(state,
1496 : "Zone Radiant HVAC Heating Fluid Energy",
1497 : Constant::Units::J,
1498 46 : thisHydrSys.HeatEnergy,
1499 : OutputProcessor::TimeStepType::System,
1500 : OutputProcessor::StoreType::Sum,
1501 46 : thisHydrSys.Name,
1502 : Constant::eResource::PlantLoopHeatingDemand,
1503 : OutputProcessor::Group::HVAC,
1504 : OutputProcessor::EndUseCat::HeatingCoils);
1505 92 : SetupOutputVariable(state,
1506 : "Zone Radiant HVAC Cooling Rate",
1507 : Constant::Units::W,
1508 46 : thisHydrSys.CoolPower,
1509 : OutputProcessor::TimeStepType::System,
1510 : OutputProcessor::StoreType::Average,
1511 46 : thisHydrSys.Name);
1512 :
1513 92 : SetupOutputVariable(state,
1514 : "Zone Radiant HVAC Cooling Energy",
1515 : Constant::Units::J,
1516 46 : thisHydrSys.CoolEnergy,
1517 : OutputProcessor::TimeStepType::System,
1518 : OutputProcessor::StoreType::Sum,
1519 46 : thisHydrSys.Name,
1520 : Constant::eResource::EnergyTransfer,
1521 : OutputProcessor::Group::HVAC,
1522 : OutputProcessor::EndUseCat::CoolingCoils);
1523 92 : SetupOutputVariable(state,
1524 : "Zone Radiant HVAC Cooling Fluid Energy",
1525 : Constant::Units::J,
1526 46 : thisHydrSys.CoolEnergy,
1527 : OutputProcessor::TimeStepType::System,
1528 : OutputProcessor::StoreType::Sum,
1529 46 : thisHydrSys.Name,
1530 : Constant::eResource::PlantLoopCoolingDemand,
1531 : OutputProcessor::Group::HVAC,
1532 : OutputProcessor::EndUseCat::CoolingCoils);
1533 92 : SetupOutputVariable(state,
1534 : "Zone Radiant HVAC Mass Flow Rate",
1535 : Constant::Units::kg_s,
1536 46 : thisHydrSys.WaterMassFlowRate,
1537 : OutputProcessor::TimeStepType::System,
1538 : OutputProcessor::StoreType::Average,
1539 46 : thisHydrSys.Name);
1540 92 : SetupOutputVariable(state,
1541 : "Zone Radiant HVAC Inlet Temperature",
1542 : Constant::Units::C,
1543 46 : thisHydrSys.WaterInletTemp,
1544 : OutputProcessor::TimeStepType::System,
1545 : OutputProcessor::StoreType::Average,
1546 46 : thisHydrSys.Name);
1547 92 : SetupOutputVariable(state,
1548 : "Zone Radiant HVAC Outlet Temperature",
1549 : Constant::Units::C,
1550 46 : thisHydrSys.WaterOutletTemp,
1551 : OutputProcessor::TimeStepType::System,
1552 : OutputProcessor::StoreType::Average,
1553 46 : thisHydrSys.Name);
1554 92 : SetupOutputVariable(state,
1555 : "Zone Radiant HVAC Moisture Condensation Time",
1556 : Constant::Units::s,
1557 46 : thisHydrSys.CondCausedTimeOff,
1558 : OutputProcessor::TimeStepType::System,
1559 : OutputProcessor::StoreType::Sum,
1560 46 : thisHydrSys.Name);
1561 46 : SetupOutputVariable(state,
1562 : "Zone Radiant HVAC Operation Mode",
1563 : Constant::Units::None,
1564 46 : (int &)thisHydrSys.opMode,
1565 : OutputProcessor::TimeStepType::System,
1566 : OutputProcessor::StoreType::Average,
1567 46 : thisHydrSys.Name);
1568 46 : if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
1569 0 : SetupEMSInternalVariable(state,
1570 : "Hydronic Low Temp Radiant Design Water Volume Flow Rate for Heating",
1571 : thisHydrSys.Name,
1572 : "[m3/s]",
1573 0 : thisHydrSys.WaterVolFlowMaxHeat);
1574 0 : SetupEMSInternalVariable(state,
1575 : "Hydronic Low Temp Radiant Design Water Volume Flow Rate for Cooling",
1576 : thisHydrSys.Name,
1577 : "[m3/s]",
1578 0 : thisHydrSys.WaterVolFlowMaxCool);
1579 0 : SetupEMSActuator(state,
1580 : "Hydronic Low Temp Radiant",
1581 : thisHydrSys.Name,
1582 : "Water Mass Flow Rate",
1583 : "[kg/s]",
1584 0 : thisHydrSys.EMSOverrideOnWaterMdot,
1585 0 : thisHydrSys.EMSWaterMdotOverrideValue);
1586 : }
1587 : }
1588 :
1589 : // Set up the output variables for low temperature radiant systems
1590 : // ZoneHVAC:LowTemperatureRadiant:ConstantFlow (CFloRadSys)
1591 56 : for (Item = 1; Item <= state.dataLowTempRadSys->NumOfCFloLowTempRadSys; ++Item) {
1592 :
1593 27 : auto &thisCFloSys = state.dataLowTempRadSys->CFloRadSys(Item);
1594 :
1595 54 : SetupOutputVariable(state,
1596 : "Zone Radiant HVAC Heating Rate",
1597 : Constant::Units::W,
1598 27 : thisCFloSys.HeatPower,
1599 : OutputProcessor::TimeStepType::System,
1600 : OutputProcessor::StoreType::Average,
1601 27 : thisCFloSys.Name);
1602 54 : SetupOutputVariable(state,
1603 : "Zone Radiant HVAC Heating Energy",
1604 : Constant::Units::J,
1605 27 : thisCFloSys.HeatEnergy,
1606 : OutputProcessor::TimeStepType::System,
1607 : OutputProcessor::StoreType::Sum,
1608 27 : thisCFloSys.Name,
1609 : Constant::eResource::EnergyTransfer,
1610 : OutputProcessor::Group::HVAC,
1611 : OutputProcessor::EndUseCat::HeatingCoils);
1612 54 : SetupOutputVariable(state,
1613 : "Zone Radiant HVAC Heating Fluid Heat Transfer Energy",
1614 : Constant::Units::J,
1615 27 : thisCFloSys.HeatEnergy,
1616 : OutputProcessor::TimeStepType::System,
1617 : OutputProcessor::StoreType::Sum,
1618 27 : thisCFloSys.Name,
1619 : Constant::eResource::PlantLoopHeatingDemand,
1620 : OutputProcessor::Group::HVAC,
1621 : OutputProcessor::EndUseCat::HeatingCoils);
1622 54 : SetupOutputVariable(state,
1623 : "Zone Radiant HVAC Cooling Rate",
1624 : Constant::Units::W,
1625 27 : thisCFloSys.CoolPower,
1626 : OutputProcessor::TimeStepType::System,
1627 : OutputProcessor::StoreType::Average,
1628 27 : thisCFloSys.Name);
1629 54 : SetupOutputVariable(state,
1630 : "Zone Radiant HVAC Cooling Energy",
1631 : Constant::Units::J,
1632 27 : thisCFloSys.CoolEnergy,
1633 : OutputProcessor::TimeStepType::System,
1634 : OutputProcessor::StoreType::Sum,
1635 27 : thisCFloSys.Name,
1636 : Constant::eResource::EnergyTransfer,
1637 : OutputProcessor::Group::HVAC,
1638 : OutputProcessor::EndUseCat::CoolingCoils);
1639 54 : SetupOutputVariable(state,
1640 : "Zone Radiant HVAC Cooling Fluid Heat Transfer Energy",
1641 : Constant::Units::J,
1642 27 : thisCFloSys.CoolEnergy,
1643 : OutputProcessor::TimeStepType::System,
1644 : OutputProcessor::StoreType::Sum,
1645 27 : thisCFloSys.Name,
1646 : Constant::eResource::PlantLoopCoolingDemand,
1647 : OutputProcessor::Group::HVAC,
1648 : OutputProcessor::EndUseCat::CoolingCoils);
1649 54 : SetupOutputVariable(state,
1650 : "Zone Radiant HVAC Mass Flow Rate",
1651 : Constant::Units::kg_s,
1652 27 : thisCFloSys.WaterMassFlowRate,
1653 : OutputProcessor::TimeStepType::System,
1654 : OutputProcessor::StoreType::Average,
1655 27 : thisCFloSys.Name);
1656 54 : SetupOutputVariable(state,
1657 : "Zone Radiant HVAC Injection Mass Flow Rate",
1658 : Constant::Units::kg_s,
1659 27 : thisCFloSys.WaterInjectionRate,
1660 : OutputProcessor::TimeStepType::System,
1661 : OutputProcessor::StoreType::Average,
1662 27 : thisCFloSys.Name);
1663 54 : SetupOutputVariable(state,
1664 : "Zone Radiant HVAC Recirculation Mass Flow Rate",
1665 : Constant::Units::kg_s,
1666 27 : thisCFloSys.WaterRecircRate,
1667 : OutputProcessor::TimeStepType::System,
1668 : OutputProcessor::StoreType::Average,
1669 27 : thisCFloSys.Name);
1670 54 : SetupOutputVariable(state,
1671 : "Zone Radiant HVAC Inlet Temperature",
1672 : Constant::Units::C,
1673 27 : thisCFloSys.WaterInletTemp,
1674 : OutputProcessor::TimeStepType::System,
1675 : OutputProcessor::StoreType::Average,
1676 27 : thisCFloSys.Name);
1677 54 : SetupOutputVariable(state,
1678 : "Zone Radiant HVAC Outlet Temperature",
1679 : Constant::Units::C,
1680 27 : thisCFloSys.WaterOutletTemp,
1681 : OutputProcessor::TimeStepType::System,
1682 : OutputProcessor::StoreType::Average,
1683 27 : thisCFloSys.Name);
1684 54 : SetupOutputVariable(state,
1685 : "Zone Radiant HVAC Pump Inlet Temperature",
1686 : Constant::Units::C,
1687 27 : thisCFloSys.PumpInletTemp,
1688 : OutputProcessor::TimeStepType::System,
1689 : OutputProcessor::StoreType::Average,
1690 27 : thisCFloSys.Name);
1691 54 : SetupOutputVariable(state,
1692 : "Zone Radiant HVAC Pump Electricity Rate",
1693 : Constant::Units::W,
1694 27 : thisCFloSys.PumpPower,
1695 : OutputProcessor::TimeStepType::System,
1696 : OutputProcessor::StoreType::Average,
1697 27 : thisCFloSys.Name);
1698 54 : SetupOutputVariable(state,
1699 : "Zone Radiant HVAC Pump Electricity Energy",
1700 : Constant::Units::J,
1701 27 : thisCFloSys.PumpEnergy,
1702 : OutputProcessor::TimeStepType::System,
1703 : OutputProcessor::StoreType::Sum,
1704 27 : thisCFloSys.Name,
1705 : Constant::eResource::Electricity,
1706 : OutputProcessor::Group::Plant,
1707 : OutputProcessor::EndUseCat::Pumps);
1708 54 : SetupOutputVariable(state,
1709 : "Zone Radiant HVAC Pump Mass Flow Rate",
1710 : Constant::Units::kg_s,
1711 27 : thisCFloSys.PumpMassFlowRate,
1712 : OutputProcessor::TimeStepType::System,
1713 : OutputProcessor::StoreType::Average,
1714 27 : thisCFloSys.Name);
1715 54 : SetupOutputVariable(state,
1716 : "Zone Radiant HVAC Pump Fluid Heat Gain Rate",
1717 : Constant::Units::W,
1718 27 : thisCFloSys.PumpHeattoFluid,
1719 : OutputProcessor::TimeStepType::System,
1720 : OutputProcessor::StoreType::Average,
1721 27 : thisCFloSys.Name);
1722 54 : SetupOutputVariable(state,
1723 : "Zone Radiant HVAC Pump Fluid Heat Gain Energy",
1724 : Constant::Units::J,
1725 27 : thisCFloSys.PumpHeattoFluidEnergy,
1726 : OutputProcessor::TimeStepType::System,
1727 : OutputProcessor::StoreType::Sum,
1728 27 : thisCFloSys.Name);
1729 54 : SetupOutputVariable(state,
1730 : "Zone Radiant HVAC Moisture Condensation Time",
1731 : Constant::Units::s,
1732 27 : thisCFloSys.CondCausedTimeOff,
1733 : OutputProcessor::TimeStepType::System,
1734 : OutputProcessor::StoreType::Sum,
1735 27 : thisCFloSys.Name);
1736 27 : SetupOutputVariable(state,
1737 : "Zone Radiant HVAC Operation Mode",
1738 : Constant::Units::None,
1739 27 : (int &)thisCFloSys.opMode,
1740 : OutputProcessor::TimeStepType::System,
1741 : OutputProcessor::StoreType::Average,
1742 27 : thisCFloSys.Name);
1743 27 : if (state.dataLowTempRadSys->anyRadiantSystemUsingRunningMeanAverage) {
1744 6 : SetupOutputVariable(state,
1745 : "Zone Radiant HVAC Running Mean Outdoor Dry-Bulb Temperature",
1746 : Constant::Units::C,
1747 3 : thisCFloSys.todayRunningMeanOutdoorDryBulbTemperature,
1748 : OutputProcessor::TimeStepType::System,
1749 : OutputProcessor::StoreType::Average,
1750 3 : thisCFloSys.Name);
1751 6 : SetupOutputVariable(state,
1752 : "Zone Radiant HVAC Previous Day Running Mean Outdoor Dry-Bulb Temperature",
1753 : Constant::Units::C,
1754 3 : thisCFloSys.yesterdayRunningMeanOutdoorDryBulbTemperature,
1755 : OutputProcessor::TimeStepType::System,
1756 : OutputProcessor::StoreType::Average,
1757 3 : thisCFloSys.Name);
1758 6 : SetupOutputVariable(state,
1759 : "Zone Radiant HVAC Previous Day Average Outdoor Dry-Bulb Temperature",
1760 : Constant::Units::C,
1761 3 : thisCFloSys.yesterdayAverageOutdoorDryBulbTemperature,
1762 : OutputProcessor::TimeStepType::System,
1763 : OutputProcessor::StoreType::Average,
1764 3 : thisCFloSys.Name);
1765 : }
1766 27 : if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
1767 0 : SetupEMSInternalVariable(
1768 0 : state, "Constant Flow Low Temp Radiant Design Water Mass Flow Rate", thisCFloSys.Name, "[m3/s]", thisCFloSys.WaterVolFlowMax);
1769 0 : SetupEMSActuator(state,
1770 : "Constant Flow Low Temp Radiant",
1771 : thisCFloSys.Name,
1772 : "Water Mass Flow Rate",
1773 : "[kg/s]",
1774 0 : thisCFloSys.EMSOverrideOnWaterMdot,
1775 0 : thisCFloSys.EMSWaterMdotOverrideValue);
1776 : }
1777 : }
1778 :
1779 38 : for (Item = 1; Item <= state.dataLowTempRadSys->NumOfElecLowTempRadSys; ++Item) {
1780 : // Set up the output variables for low temperature radiant systems
1781 : // ZoneHVAC:LowTemperatureRadiant:Electric (ElecRadSys)
1782 :
1783 9 : auto &thisElecSys = state.dataLowTempRadSys->ElecRadSys(Item);
1784 :
1785 18 : SetupOutputVariable(state,
1786 : "Zone Radiant HVAC Electricity Rate",
1787 : Constant::Units::W,
1788 9 : thisElecSys.ElecPower,
1789 : OutputProcessor::TimeStepType::System,
1790 : OutputProcessor::StoreType::Average,
1791 9 : thisElecSys.Name);
1792 18 : SetupOutputVariable(state,
1793 : "Zone Radiant HVAC Electricity Energy",
1794 : Constant::Units::J,
1795 9 : thisElecSys.ElecEnergy,
1796 : OutputProcessor::TimeStepType::System,
1797 : OutputProcessor::StoreType::Sum,
1798 9 : thisElecSys.Name,
1799 : Constant::eResource::Electricity,
1800 : OutputProcessor::Group::HVAC,
1801 : OutputProcessor::EndUseCat::Heating);
1802 18 : SetupOutputVariable(state,
1803 : "Zone Radiant HVAC Heating Rate",
1804 : Constant::Units::W,
1805 9 : thisElecSys.HeatPower,
1806 : OutputProcessor::TimeStepType::System,
1807 : OutputProcessor::StoreType::Average,
1808 9 : thisElecSys.Name);
1809 18 : SetupOutputVariable(state,
1810 : "Zone Radiant HVAC Heating Energy",
1811 : Constant::Units::J,
1812 9 : thisElecSys.HeatEnergy,
1813 : OutputProcessor::TimeStepType::System,
1814 : OutputProcessor::StoreType::Sum,
1815 9 : thisElecSys.Name,
1816 : Constant::eResource::EnergyTransfer,
1817 : OutputProcessor::Group::HVAC,
1818 : OutputProcessor::EndUseCat::HeatingCoils);
1819 : }
1820 29 : }
1821 :
1822 82 : void RadiantSystemBaseData::errorCheckZonesAndConstructions(EnergyPlusData &state, bool &errorsFound)
1823 : {
1824 82 : auto &Zone = state.dataHeatBal->Zone;
1825 82 : auto &Surface = state.dataSurface->Surface;
1826 :
1827 82 : Real64 zoneMultipliers = 0.0;
1828 82 : Real64 zoneMultipliersSurface = 0.0;
1829 82 : Real64 zoneMultiplersTolerance = 0.001;
1830 176 : for (int SurfNum = 1; SurfNum <= this->NumOfSurfaces; ++SurfNum) {
1831 :
1832 94 : if (this->SurfacePtr(SurfNum) == 0) {
1833 0 : continue; // invalid surface -- detected earlier
1834 : }
1835 :
1836 94 : if (state.dataGlobal->DisplayExtraWarnings) {
1837 : // check zone numbers--ok if they are not the same
1838 : // group warning issued earlier, show detailed warning here
1839 0 : if (Surface(this->SurfacePtr(SurfNum)).Zone != this->ZonePtr) {
1840 0 : ShowWarningError(state,
1841 : "A surface referenced in a Low Temperature Radiant System is not in same zone as the radiant system itself");
1842 0 : ShowContinueError(state, format("Surface = {}", Surface(this->SurfacePtr(SurfNum)).Name));
1843 0 : ShowContinueError(state,
1844 0 : format("Surface in Zone = {}. Radiant System in Zone = {}",
1845 0 : Zone(Surface(this->SurfacePtr(SurfNum)).Zone).Name,
1846 0 : this->ZoneName));
1847 0 : ShowContinueError(state, format("Occurs in Low Temperature Radiant System = {}", this->Name));
1848 0 : ShowContinueError(state, "If this is intentionally a radiant system with surfaces in more than one thermal zone,");
1849 0 : ShowContinueError(state, "then ignore this warning message. Otherwise, check the surfaces in this radiant system.");
1850 : }
1851 : }
1852 :
1853 : // check zone multipliers--these must be the same
1854 94 : if (SurfNum == 1) {
1855 82 : zoneMultipliers = double(Zone(this->ZonePtr).Multiplier) * double(Zone(this->ZonePtr).ListMultiplier);
1856 : }
1857 94 : zoneMultipliersSurface = double(Zone(Surface(this->SurfacePtr(SurfNum)).Zone).Multiplier) *
1858 94 : double(Zone(Surface(this->SurfacePtr(SurfNum)).Zone).ListMultiplier);
1859 94 : if (std::abs(zoneMultipliers - zoneMultipliersSurface) > zoneMultiplersTolerance) {
1860 0 : ShowSevereError(state, "The zone multipliers are not the same for all surfaces contained in this radiant system");
1861 0 : ShowContinueError(state, "This is not allowed and must be fixed for the simulation to run.");
1862 0 : ShowContinueError(state, format("Occurs in Low Temperature Radiant System = {}", this->Name));
1863 0 : errorsFound = true;
1864 : }
1865 :
1866 : // make sure that this construction is defined with a source/sink--this must be the case or it can't serve as a radiant system surface
1867 94 : if (!state.dataConstruction->Construct(Surface(this->SurfacePtr(SurfNum)).Construction).SourceSinkPresent) {
1868 0 : ShowSevereError(state, "Construction referenced in Radiant System Surface does not have a source/sink present");
1869 0 : ShowContinueError(state,
1870 0 : format("Surface name= {} Construction name = {}",
1871 0 : Surface(this->SurfacePtr(SurfNum)).Name,
1872 0 : state.dataConstruction->Construct(Surface(this->SurfacePtr(SurfNum)).Construction).Name));
1873 0 : ShowContinueError(state, "Construction needs to be referenced by a \"ConstructionProperty:InternalHeatSource\" object.");
1874 0 : errorsFound = true;
1875 : }
1876 : }
1877 82 : }
1878 :
1879 666848 : void InitLowTempRadiantSystem(EnergyPlusData &state,
1880 : bool const FirstHVACIteration, // TRUE if 1st HVAC simulation of system timestep
1881 : int const RadSysNum, // Index for the low temperature radiant system under consideration within the derived types
1882 : SystemType const systemType, // Type of radiant system: hydronic, constant flow, or electric
1883 : bool &InitErrorsFound)
1884 : {
1885 :
1886 : // SUBROUTINE INFORMATION:
1887 : // AUTHOR Rick Strand
1888 : // DATE WRITTEN November 2000
1889 :
1890 : // Using/Aliasing
1891 :
1892 : using DataSizing::AutoSize;
1893 : using DataZoneEquipment::CheckZoneEquipmentList;
1894 :
1895 : using PlantUtilities::InitComponentNodes;
1896 : using PlantUtilities::ScanPlantLoopsForObject;
1897 : using PlantUtilities::SetComponentFlowRate;
1898 :
1899 : // SUBROUTINE PARAMETER DEFINITIONS:
1900 666848 : Real64 constexpr ZeroTol(0.0000001); // Smallest non-zero value allowed
1901 666848 : constexpr std::string_view RoutineName("InitLowTempRadiantSystem");
1902 :
1903 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1904 : Real64 CurrentFlowSchedule; // Schedule value for flow fraction in a constant flow radiant system
1905 : Real64 TotalEffic; // Intermediate calculation variable for total pump efficiency
1906 : Real64 mdot; // local fluid mass flow rate
1907 : Real64 rho; // local fluid density
1908 : bool errFlag;
1909 :
1910 666848 : InitErrorsFound = false;
1911 :
1912 666848 : auto const &Surface = state.dataSurface->Surface;
1913 :
1914 666848 : if (state.dataLowTempRadSys->MyOneTimeFlag) {
1915 29 : state.dataLowTempRadSys->MyEnvrnFlagHydr.allocate(state.dataLowTempRadSys->NumOfHydrLowTempRadSys);
1916 29 : state.dataLowTempRadSys->MyEnvrnFlagCFlo.allocate(state.dataLowTempRadSys->NumOfCFloLowTempRadSys);
1917 29 : state.dataLowTempRadSys->MyEnvrnFlagElec.allocate(state.dataLowTempRadSys->NumOfElecLowTempRadSys);
1918 29 : state.dataLowTempRadSys->MyPlantScanFlagHydr.allocate(state.dataLowTempRadSys->NumOfHydrLowTempRadSys);
1919 29 : state.dataLowTempRadSys->MyPlantScanFlagCFlo.allocate(state.dataLowTempRadSys->NumOfCFloLowTempRadSys);
1920 29 : state.dataLowTempRadSys->MyPlantScanFlagHydr = true;
1921 29 : state.dataLowTempRadSys->MyPlantScanFlagCFlo = true;
1922 29 : state.dataLowTempRadSys->MyEnvrnFlagHydr = true;
1923 29 : state.dataLowTempRadSys->MyEnvrnFlagCFlo = true;
1924 29 : state.dataLowTempRadSys->MyEnvrnFlagElec = true;
1925 29 : state.dataLowTempRadSys->MyOneTimeFlag = false;
1926 : }
1927 :
1928 666848 : if (state.dataLowTempRadSys->FirstTimeInit) {
1929 :
1930 75 : for (auto &thisLTRSys : state.dataLowTempRadSys->HydrRadSys) {
1931 46 : thisLTRSys.QRadSysSrcAvg.dimension(thisLTRSys.NumOfSurfaces, 0.0);
1932 46 : thisLTRSys.LastQRadSysSrc.dimension(thisLTRSys.NumOfSurfaces, 0.0);
1933 46 : thisLTRSys.LastSysTimeElapsed = 0.0;
1934 46 : thisLTRSys.LastTimeStepSys = 0.0;
1935 : }
1936 56 : for (auto &thisCFLTRSys : state.dataLowTempRadSys->CFloRadSys) {
1937 27 : thisCFLTRSys.QRadSysSrcAvg.dimension(thisCFLTRSys.NumOfSurfaces, 0.0);
1938 27 : thisCFLTRSys.LastQRadSysSrc.dimension(thisCFLTRSys.NumOfSurfaces, 0.0);
1939 27 : thisCFLTRSys.LastSysTimeElapsed = 0.0;
1940 27 : thisCFLTRSys.LastTimeStepSys = 0.0;
1941 : }
1942 38 : for (auto &thisELTRSys : state.dataLowTempRadSys->ElecRadSys) {
1943 9 : thisELTRSys.QRadSysSrcAvg.dimension(thisELTRSys.NumOfSurfaces, 0.0);
1944 9 : thisELTRSys.LastQRadSysSrc.dimension(thisELTRSys.NumOfSurfaces, 0.0);
1945 9 : thisELTRSys.LastSysTimeElapsed = 0.0;
1946 9 : thisELTRSys.LastTimeStepSys = 0.0;
1947 : }
1948 29 : state.dataLowTempRadSys->MySizeFlagHydr.allocate(state.dataLowTempRadSys->NumOfHydrLowTempRadSys);
1949 29 : state.dataLowTempRadSys->MySizeFlagCFlo.allocate(state.dataLowTempRadSys->NumOfCFloLowTempRadSys);
1950 29 : state.dataLowTempRadSys->MySizeFlagElec.allocate(state.dataLowTempRadSys->NumOfElecLowTempRadSys);
1951 29 : state.dataLowTempRadSys->MySizeFlagHydr = true;
1952 29 : state.dataLowTempRadSys->MySizeFlagCFlo = true;
1953 29 : state.dataLowTempRadSys->MySizeFlagElec = true;
1954 :
1955 : // Initialize total areas and ZeroLTRSource for all radiant systems
1956 75 : for (auto &thisHRadSys : state.dataLowTempRadSys->HydrRadSys) {
1957 46 : thisHRadSys.ZeroLTRSourceSumHATsurf = 0.0;
1958 46 : thisHRadSys.TotalSurfaceArea = 0.0;
1959 104 : for (int SurfNum = 1; SurfNum <= thisHRadSys.NumOfSurfaces; ++SurfNum) {
1960 58 : thisHRadSys.TotalSurfaceArea += Surface(thisHRadSys.SurfacePtr(SurfNum)).Area;
1961 : }
1962 : }
1963 56 : for (auto &thisCFLRadSys : state.dataLowTempRadSys->CFloRadSys) {
1964 27 : thisCFLRadSys.ZeroLTRSourceSumHATsurf = 0.0;
1965 27 : thisCFLRadSys.TotalSurfaceArea = 0.0;
1966 54 : for (int SurfNum = 1; SurfNum <= thisCFLRadSys.NumOfSurfaces; ++SurfNum) {
1967 27 : thisCFLRadSys.TotalSurfaceArea += Surface(thisCFLRadSys.SurfacePtr(SurfNum)).Area;
1968 : }
1969 : }
1970 38 : for (auto &thisERadSys : state.dataLowTempRadSys->ElecRadSys) {
1971 9 : thisERadSys.ZeroLTRSourceSumHATsurf = 0.0;
1972 9 : thisERadSys.TotalSurfaceArea = 0.0;
1973 18 : for (int SurfNum = 1; SurfNum <= thisERadSys.NumOfSurfaces; ++SurfNum) {
1974 9 : thisERadSys.TotalSurfaceArea += Surface(thisERadSys.SurfacePtr(SurfNum)).Area;
1975 : }
1976 : }
1977 :
1978 29 : Real64 MotorEffic(0.0);
1979 29 : if (systemType == SystemType::ConstantFlow) {
1980 : // Is there a reason why we were making a copy of this object?
1981 9 : MotorEffic =
1982 9 : state.dataLowTempRadSys->CflowRadiantSysDesign(state.dataLowTempRadSys->CFloRadSys(RadSysNum).DesignObjectPtr).MotorEffic;
1983 : }
1984 :
1985 : // Check pump parameters for constant flow hydronic radiant systems
1986 56 : for (auto &thisCFLRadSys : state.dataLowTempRadSys->CFloRadSys) {
1987 : // Calculate the efficiency for each pump: The calculation
1988 : // is based on the PMPSIM code in the ASHRAE Secondary Toolkit
1989 27 : if ((thisCFLRadSys.NomPowerUse > ZeroTol) && (MotorEffic > ZeroTol) && (thisCFLRadSys.WaterVolFlowMax != AutoSize)) {
1990 26 : TotalEffic = thisCFLRadSys.WaterVolFlowMax * thisCFLRadSys.NomPumpHead / thisCFLRadSys.NomPowerUse;
1991 26 : thisCFLRadSys.PumpEffic = TotalEffic / MotorEffic;
1992 26 : constexpr std::string_view fmt = "Check input. Calc Pump Efficiency={:.5R}% {}, for pump in radiant system {}";
1993 26 : Real64 pumpEfficiency = thisCFLRadSys.PumpEffic * 100.0;
1994 26 : if (thisCFLRadSys.PumpEffic < 0.50) {
1995 3 : ShowWarningError(state, format(fmt, pumpEfficiency, "which is less than 50%", thisCFLRadSys.Name));
1996 23 : } else if ((thisCFLRadSys.PumpEffic > 0.95) && (thisCFLRadSys.PumpEffic <= 1.0)) {
1997 0 : ShowWarningError(state, format(fmt, pumpEfficiency, "is approaching 100%", thisCFLRadSys.Name));
1998 23 : } else if (thisCFLRadSys.PumpEffic > 1.0) {
1999 0 : ShowSevereError(state, format(fmt, pumpEfficiency, "which is bigger than 100%", thisCFLRadSys.Name));
2000 0 : InitErrorsFound = true;
2001 : }
2002 26 : } else {
2003 : // Autosize is not an error but it does not need to check pump efficiency here
2004 1 : if (thisCFLRadSys.WaterVolFlowMax != AutoSize) {
2005 0 : ShowSevereError(state,
2006 0 : format("Check input. Pump nominal power and motor efficiency cannot be 0, for pump={}", thisCFLRadSys.Name));
2007 0 : InitErrorsFound = true;
2008 : }
2009 : }
2010 : }
2011 :
2012 29 : state.dataLowTempRadSys->FirstTimeInit = false;
2013 : }
2014 :
2015 666848 : if (systemType == SystemType::Hydronic) {
2016 366056 : if (state.dataLowTempRadSys->MyPlantScanFlagHydr(RadSysNum) && allocated(state.dataPlnt->PlantLoop)) {
2017 46 : errFlag = false;
2018 46 : if (state.dataLowTempRadSys->HydrRadSys(RadSysNum).HotWaterInNode > 0) {
2019 138 : ScanPlantLoopsForObject(state,
2020 46 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).Name,
2021 : DataPlant::PlantEquipmentType::LowTempRadiant_VarFlow,
2022 46 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).HWPlantLoc,
2023 : errFlag,
2024 : _,
2025 : _,
2026 : _,
2027 46 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).HotWaterInNode,
2028 : _);
2029 46 : if (errFlag) {
2030 0 : ShowFatalError(state, "InitLowTempRadiantSystem: Program terminated due to previous condition(s).");
2031 : }
2032 : }
2033 46 : if (state.dataLowTempRadSys->HydrRadSys(RadSysNum).ColdWaterInNode > 0) {
2034 129 : ScanPlantLoopsForObject(state,
2035 43 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).Name,
2036 : DataPlant::PlantEquipmentType::LowTempRadiant_VarFlow,
2037 43 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).CWPlantLoc,
2038 : errFlag,
2039 : _,
2040 : _,
2041 : _,
2042 43 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).ColdWaterInNode,
2043 : _);
2044 43 : if (errFlag) {
2045 0 : ShowFatalError(state, "InitLowTempRadiantSystem: Program terminated due to previous condition(s).");
2046 : }
2047 : }
2048 46 : state.dataLowTempRadSys->MyPlantScanFlagHydr(RadSysNum) = false;
2049 366010 : } else if (state.dataLowTempRadSys->MyPlantScanFlagHydr(RadSysNum) && !state.dataGlobal->AnyPlantInModel) {
2050 0 : state.dataLowTempRadSys->MyPlantScanFlagHydr(RadSysNum) = false;
2051 : }
2052 :
2053 300792 : } else if (systemType == SystemType::ConstantFlow) {
2054 221733 : if (state.dataLowTempRadSys->MyPlantScanFlagCFlo(RadSysNum) && allocated(state.dataPlnt->PlantLoop)) {
2055 27 : errFlag = false;
2056 27 : if (state.dataLowTempRadSys->CFloRadSys(RadSysNum).HotWaterInNode > 0) {
2057 81 : ScanPlantLoopsForObject(state,
2058 27 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).Name,
2059 : DataPlant::PlantEquipmentType::LowTempRadiant_ConstFlow,
2060 27 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).HWPlantLoc,
2061 : errFlag,
2062 : _,
2063 : _,
2064 : _,
2065 27 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).HotWaterInNode,
2066 : _);
2067 27 : if (errFlag) {
2068 0 : ShowFatalError(state, "InitLowTempRadiantSystem: Program terminated due to previous condition(s).");
2069 : }
2070 : }
2071 27 : if (state.dataLowTempRadSys->CFloRadSys(RadSysNum).ColdWaterInNode > 0) {
2072 72 : ScanPlantLoopsForObject(state,
2073 24 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).Name,
2074 : DataPlant::PlantEquipmentType::LowTempRadiant_ConstFlow,
2075 24 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).CWPlantLoc,
2076 : errFlag,
2077 : _,
2078 : _,
2079 : _,
2080 24 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).ColdWaterInNode,
2081 : _);
2082 24 : if (errFlag) {
2083 0 : ShowFatalError(state, "InitLowTempRadiantSystem: Program terminated due to previous condition(s).");
2084 : }
2085 : }
2086 27 : state.dataLowTempRadSys->MyPlantScanFlagCFlo(RadSysNum) = false;
2087 221706 : } else if (state.dataLowTempRadSys->MyPlantScanFlagCFlo(RadSysNum) && !state.dataGlobal->AnyPlantInModel) {
2088 0 : state.dataLowTempRadSys->MyPlantScanFlagCFlo(RadSysNum) = false;
2089 : }
2090 : }
2091 :
2092 : // need to check all units to see if they are on Zone Equipment List or issue warning
2093 666848 : if (!state.dataLowTempRadSys->ZoneEquipmentListChecked && state.dataZoneEquip->ZoneEquipInputsFilled) {
2094 29 : state.dataLowTempRadSys->ZoneEquipmentListChecked = true;
2095 111 : for (auto &thisRadSys : state.dataLowTempRadSys->RadSysTypes) {
2096 82 : switch (thisRadSys.systemType) {
2097 46 : case SystemType::Hydronic: {
2098 46 : if (CheckZoneEquipmentList(state, "ZoneHVAC:LowTemperatureRadiant:VariableFlow", thisRadSys.Name)) {
2099 46 : continue;
2100 : }
2101 0 : ShowSevereError(state,
2102 0 : format("InitLowTempRadiantSystem: Unit=[ZoneHVAC:LowTemperatureRadiant:VariableFlow,{}] is not on any "
2103 : "ZoneHVAC:EquipmentList. It will not be simulated.",
2104 0 : thisRadSys.Name));
2105 0 : } break;
2106 27 : case SystemType::ConstantFlow: {
2107 27 : if (CheckZoneEquipmentList(state, "ZoneHVAC:LowTemperatureRadiant:ConstantFlow", thisRadSys.Name)) {
2108 27 : continue;
2109 : }
2110 0 : ShowSevereError(state,
2111 0 : format("InitLowTempRadiantSystem: Unit=[ZoneHVAC:LowTemperatureRadiant:ConstantFlow,{}] is not on any "
2112 : "ZoneHVAC:EquipmentList. It will not be simulated.",
2113 0 : thisRadSys.Name));
2114 0 : } break;
2115 9 : case SystemType::Electric: {
2116 9 : if (CheckZoneEquipmentList(state, "ZoneHVAC:LowTemperatureRadiant:Electric", thisRadSys.Name)) {
2117 9 : continue;
2118 : }
2119 0 : ShowSevereError(state,
2120 0 : format("InitLowTempRadiantSystem: Unit=[ZoneHVAC:LowTemperatureRadiant:Electric,{}] is not on any "
2121 : "ZoneHVAC:EquipmentList. It will not be simulated.",
2122 0 : thisRadSys.Name));
2123 0 : } break;
2124 0 : default: { // Illegal system, but checked earlier
2125 0 : } break;
2126 : }
2127 : }
2128 : }
2129 :
2130 666848 : if (!state.dataGlobal->SysSizingCalc && (systemType == SystemType::Hydronic)) {
2131 366010 : if (state.dataLowTempRadSys->MySizeFlagHydr(RadSysNum) && !state.dataLowTempRadSys->MyPlantScanFlagHydr(RadSysNum)) {
2132 : // for each radiant system do the sizing once.
2133 46 : SizeLowTempRadiantSystem(state, RadSysNum, systemType);
2134 46 : state.dataLowTempRadSys->MySizeFlagHydr(RadSysNum) = false;
2135 :
2136 46 : Sched::Schedule *coldSetptSched = nullptr, *hotSetptSched = nullptr;
2137 46 : if (systemType == SystemType::Hydronic) {
2138 46 : VarFlowRadDesignData variableFlowDesignDataObject{state.dataLowTempRadSys->HydronicRadiantSysDesign(
2139 46 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).DesignObjectPtr)}; // Contains the data for variable flow hydronic systems;
2140 46 : coldSetptSched = variableFlowDesignDataObject.coolSetptSched;
2141 46 : hotSetptSched = variableFlowDesignDataObject.heatSetptSched;
2142 46 : }
2143 :
2144 : // Can this system actually do cooling?
2145 46 : if ((state.dataLowTempRadSys->HydrRadSys(RadSysNum).WaterVolFlowMaxCool > 0.0) &&
2146 43 : (state.dataLowTempRadSys->HydrRadSys(RadSysNum).ColdWaterInNode > 0) &&
2147 89 : (state.dataLowTempRadSys->HydrRadSys(RadSysNum).ColdWaterOutNode > 0) && (coldSetptSched != nullptr)) {
2148 43 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).CoolingSystem = true;
2149 : }
2150 :
2151 : // Can this system actually do heating?
2152 46 : if ((state.dataLowTempRadSys->HydrRadSys(RadSysNum).WaterVolFlowMaxHeat > 0.0) &&
2153 46 : (state.dataLowTempRadSys->HydrRadSys(RadSysNum).HotWaterInNode > 0) &&
2154 92 : (state.dataLowTempRadSys->HydrRadSys(RadSysNum).HotWaterOutNode > 0) && (hotSetptSched != nullptr)) {
2155 46 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).HeatingSystem = true;
2156 : }
2157 :
2158 : // set design mass flow rates
2159 46 : if (state.dataLowTempRadSys->HydrRadSys(RadSysNum).HotWaterInNode > 0) {
2160 46 : rho = state.dataPlnt->PlantLoop(state.dataLowTempRadSys->HydrRadSys(RadSysNum).HWPlantLoc.loopNum)
2161 46 : .glycol->getDensity(state, Constant::HWInitConvTemp, RoutineName);
2162 46 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).WaterFlowMaxHeat =
2163 46 : rho * state.dataLowTempRadSys->HydrRadSys(RadSysNum).WaterVolFlowMaxHeat;
2164 138 : InitComponentNodes(state,
2165 : 0.0,
2166 46 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).WaterFlowMaxHeat,
2167 46 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).HotWaterInNode,
2168 46 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).HotWaterOutNode);
2169 : }
2170 46 : if (state.dataLowTempRadSys->HydrRadSys(RadSysNum).ColdWaterInNode > 0) {
2171 43 : rho = state.dataPlnt->PlantLoop(state.dataLowTempRadSys->HydrRadSys(RadSysNum).CWPlantLoc.loopNum)
2172 43 : .glycol->getDensity(state, Constant::CWInitConvTemp, RoutineName);
2173 43 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).WaterFlowMaxCool =
2174 43 : rho * state.dataLowTempRadSys->HydrRadSys(RadSysNum).WaterVolFlowMaxCool;
2175 129 : InitComponentNodes(state,
2176 : 0.0,
2177 43 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).WaterFlowMaxCool,
2178 43 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).ColdWaterInNode,
2179 43 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).ColdWaterOutNode);
2180 : }
2181 : }
2182 : }
2183 :
2184 666848 : if (!state.dataGlobal->SysSizingCalc && (systemType == SystemType::ConstantFlow)) {
2185 221730 : if (state.dataLowTempRadSys->MySizeFlagCFlo(RadSysNum) && !state.dataLowTempRadSys->MyPlantScanFlagCFlo(RadSysNum)) {
2186 : // for each radiant system do the sizing once.
2187 27 : SizeLowTempRadiantSystem(state, RadSysNum, systemType);
2188 :
2189 : // set design mass flow rates
2190 27 : if (state.dataLowTempRadSys->CFloRadSys(RadSysNum).HotWaterInNode > 0) {
2191 27 : rho = state.dataPlnt->PlantLoop(state.dataLowTempRadSys->CFloRadSys(RadSysNum).HWPlantLoc.loopNum)
2192 27 : .glycol->getDensity(state, Constant::HWInitConvTemp, RoutineName);
2193 27 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).HotDesignWaterMassFlowRate =
2194 27 : rho * state.dataLowTempRadSys->CFloRadSys(RadSysNum).WaterVolFlowMax;
2195 81 : InitComponentNodes(state,
2196 : 0.0,
2197 27 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).HotDesignWaterMassFlowRate,
2198 27 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).HotWaterInNode,
2199 27 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).HotWaterOutNode);
2200 : }
2201 27 : if (state.dataLowTempRadSys->CFloRadSys(RadSysNum).ColdWaterInNode > 0) {
2202 24 : rho = state.dataPlnt->PlantLoop(state.dataLowTempRadSys->CFloRadSys(RadSysNum).CWPlantLoc.loopNum)
2203 24 : .glycol->getDensity(state, Constant::CWInitConvTemp, RoutineName);
2204 24 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).ColdDesignWaterMassFlowRate =
2205 24 : rho * state.dataLowTempRadSys->CFloRadSys(RadSysNum).WaterVolFlowMax;
2206 72 : InitComponentNodes(state,
2207 : 0.0,
2208 24 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).ColdDesignWaterMassFlowRate,
2209 24 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).ColdWaterInNode,
2210 24 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).ColdWaterOutNode);
2211 : }
2212 27 : state.dataLowTempRadSys->MySizeFlagCFlo(RadSysNum) = false;
2213 : }
2214 : }
2215 :
2216 666848 : if (!state.dataGlobal->SysSizingCalc && (systemType == SystemType::Electric)) {
2217 79053 : if (state.dataLowTempRadSys->MySizeFlagElec(RadSysNum)) {
2218 : // for each radiant system do the sizing once.
2219 9 : SizeLowTempRadiantSystem(state, RadSysNum, systemType);
2220 9 : state.dataLowTempRadSys->MySizeFlagElec(RadSysNum) = false;
2221 : }
2222 : }
2223 :
2224 666848 : if (state.dataGlobal->BeginEnvrnFlag && state.dataLowTempRadSys->MyEnvrnFlagGeneral) {
2225 160 : if (systemType == SystemType::Hydronic) {
2226 89 : auto &thisLTR = state.dataLowTempRadSys->HydrRadSys(RadSysNum);
2227 89 : thisLTR.ZeroLTRSourceSumHATsurf = 0.0;
2228 89 : thisLTR.QRadSysSrcAvg = 0.0;
2229 89 : thisLTR.LastQRadSysSrc = 0.0;
2230 89 : thisLTR.LastSysTimeElapsed = 0.0;
2231 89 : thisLTR.LastTimeStepSys = 0.0;
2232 71 : } else if (systemType == SystemType::ConstantFlow) {
2233 56 : auto &thisLTR = state.dataLowTempRadSys->CFloRadSys(RadSysNum);
2234 56 : thisLTR.ZeroLTRSourceSumHATsurf = 0.0;
2235 56 : thisLTR.QRadSysSrcAvg = 0.0;
2236 56 : thisLTR.LastQRadSysSrc = 0.0;
2237 56 : thisLTR.LastSysTimeElapsed = 0.0;
2238 56 : thisLTR.LastTimeStepSys = 0.0;
2239 15 : } else if (systemType == SystemType::Electric) {
2240 15 : auto &thisLTR = state.dataLowTempRadSys->ElecRadSys(RadSysNum);
2241 15 : thisLTR.ZeroLTRSourceSumHATsurf = 0.0;
2242 15 : thisLTR.QRadSysSrcAvg = 0.0;
2243 15 : thisLTR.LastQRadSysSrc = 0.0;
2244 15 : thisLTR.LastSysTimeElapsed = 0.0;
2245 15 : thisLTR.LastTimeStepSys = 0.0;
2246 : }
2247 160 : state.dataLowTempRadSys->MyEnvrnFlagGeneral = false;
2248 : }
2249 666848 : if (!state.dataGlobal->BeginEnvrnFlag) {
2250 664095 : state.dataLowTempRadSys->MyEnvrnFlagGeneral = true;
2251 : }
2252 :
2253 : // If we are at the beginning of a new environment OR the warmup period is done and the simulation is starting,
2254 : // then the various changeover variables need to be reset so that we are starting from scratch.
2255 1332092 : if ((state.dataGlobal->BeginEnvrnFlag && FirstHVACIteration) ||
2256 665244 : (!state.dataGlobal->WarmupFlag && state.dataGlobal->BeginDayFlag && FirstHVACIteration && state.dataGlobal->DayOfSim == 1)) {
2257 : // Reset values related to changeover
2258 1792 : if (systemType == SystemType::Hydronic) {
2259 1000 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).lastOpMode = OpMode::None;
2260 1000 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).lastDayOfSim = 0;
2261 1000 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).lastHourOfDay = 0;
2262 1000 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).lastTimeStep = 0;
2263 : }
2264 1792 : if (systemType == SystemType::ConstantFlow) {
2265 642 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).lastOpMode = OpMode::None;
2266 642 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).lastDayOfSim = 0;
2267 642 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).lastHourOfDay = 0;
2268 642 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).lastTimeStep = 0;
2269 : }
2270 : }
2271 :
2272 666848 : if (systemType == SystemType::Hydronic) {
2273 366056 : if (state.dataGlobal->BeginEnvrnFlag && state.dataLowTempRadSys->MyEnvrnFlagHydr(RadSysNum)) {
2274 242 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).HeatPower = 0.0;
2275 242 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).HeatEnergy = 0.0;
2276 242 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).CoolPower = 0.0;
2277 242 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).CoolEnergy = 0.0;
2278 242 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).WaterInletTemp = 0.0;
2279 242 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).WaterOutletTemp = 0.0;
2280 242 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).WaterMassFlowRate = 0.0;
2281 :
2282 242 : if (!state.dataLowTempRadSys->MyPlantScanFlagHydr(RadSysNum)) {
2283 242 : if (state.dataLowTempRadSys->HydrRadSys(RadSysNum).HotWaterInNode > 0) {
2284 726 : InitComponentNodes(state,
2285 : 0.0,
2286 242 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).WaterFlowMaxHeat,
2287 242 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).HotWaterInNode,
2288 242 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).HotWaterOutNode);
2289 : }
2290 242 : if (state.dataLowTempRadSys->HydrRadSys(RadSysNum).ColdWaterInNode > 0) {
2291 681 : InitComponentNodes(state,
2292 : 0.0,
2293 227 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).WaterFlowMaxCool,
2294 227 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).ColdWaterInNode,
2295 227 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).ColdWaterOutNode);
2296 : }
2297 : }
2298 242 : state.dataLowTempRadSys->MyEnvrnFlagHydr(RadSysNum) = false;
2299 : }
2300 : } // NumOfHydrLowTempRadSys > 0
2301 666848 : if (!state.dataGlobal->BeginEnvrnFlag && systemType == SystemType::Hydronic) {
2302 364488 : state.dataLowTempRadSys->MyEnvrnFlagHydr(RadSysNum) = true;
2303 : }
2304 :
2305 666848 : if (systemType == SystemType::ConstantFlow) {
2306 221733 : if (state.dataGlobal->BeginEnvrnFlag && state.dataLowTempRadSys->MyEnvrnFlagCFlo(RadSysNum)) {
2307 168 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).WaterInletTemp = 0.0;
2308 168 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).WaterOutletTemp = 0.0;
2309 168 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).PumpInletTemp = 0.0;
2310 168 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).WaterMassFlowRate = 0.0;
2311 168 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).WaterInjectionRate = 0.0;
2312 168 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).WaterRecircRate = 0.0;
2313 168 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).HeatPower = 0.0;
2314 168 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).HeatEnergy = 0.0;
2315 168 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).CoolPower = 0.0;
2316 168 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).CoolEnergy = 0.0;
2317 168 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).PumpPower = 0.0;
2318 168 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).PumpMassFlowRate = 0.0;
2319 168 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).PumpHeattoFluid = 0.0;
2320 :
2321 168 : if (!state.dataLowTempRadSys->MyPlantScanFlagCFlo(RadSysNum)) {
2322 168 : if (state.dataLowTempRadSys->CFloRadSys(RadSysNum).HotWaterInNode > 0) {
2323 504 : InitComponentNodes(state,
2324 : 0.0,
2325 168 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).HotDesignWaterMassFlowRate,
2326 168 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).HotWaterInNode,
2327 168 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).HotWaterOutNode);
2328 : }
2329 168 : if (state.dataLowTempRadSys->CFloRadSys(RadSysNum).ColdWaterInNode > 0) {
2330 459 : InitComponentNodes(state,
2331 : 0.0,
2332 153 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).ColdDesignWaterMassFlowRate,
2333 153 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).ColdWaterInNode,
2334 153 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).ColdWaterOutNode);
2335 : }
2336 : }
2337 168 : state.dataLowTempRadSys->MyEnvrnFlagCFlo(RadSysNum) = false;
2338 : }
2339 :
2340 221733 : if (state.dataLowTempRadSys->anyRadiantSystemUsingRunningMeanAverage) {
2341 26424 : if (state.dataGlobal->BeginDayFlag && state.dataLowTempRadSys->CFloRadSys(RadSysNum).setRunningMeanValuesAtBeginningOfDay) {
2342 78 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).calculateRunningMeanAverageTemperature(state, RadSysNum);
2343 78 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).setRunningMeanValuesAtBeginningOfDay = false; // only set these once per system
2344 26346 : } else if (!state.dataGlobal->BeginDayFlag && !state.dataLowTempRadSys->CFloRadSys(RadSysNum).setRunningMeanValuesAtBeginningOfDay) {
2345 78 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).setRunningMeanValuesAtBeginningOfDay =
2346 : true; // reset so that the next time BeginDayFlag is true this can get set
2347 : }
2348 : }
2349 :
2350 : } // NumOfCFloLowTempRadSys > 0
2351 666848 : if (!state.dataGlobal->BeginEnvrnFlag && systemType == SystemType::ConstantFlow) {
2352 220767 : state.dataLowTempRadSys->MyEnvrnFlagCFlo(RadSysNum) = true;
2353 : }
2354 :
2355 666848 : if (systemType == SystemType::Electric) {
2356 79059 : if (state.dataGlobal->BeginEnvrnFlag && state.dataLowTempRadSys->MyEnvrnFlagElec(RadSysNum)) {
2357 45 : state.dataLowTempRadSys->ElecRadSys(RadSysNum).HeatPower = 0.0;
2358 45 : state.dataLowTempRadSys->ElecRadSys(RadSysNum).HeatEnergy = 0.0;
2359 45 : state.dataLowTempRadSys->ElecRadSys(RadSysNum).ElecPower = 0.0;
2360 45 : state.dataLowTempRadSys->ElecRadSys(RadSysNum).ElecEnergy = 0.0;
2361 : }
2362 79059 : state.dataLowTempRadSys->MyEnvrnFlagElec(RadSysNum) = false;
2363 : }
2364 666848 : if (!state.dataGlobal->BeginEnvrnFlag && systemType == SystemType::Electric) {
2365 78840 : state.dataLowTempRadSys->MyEnvrnFlagElec(RadSysNum) = true;
2366 : }
2367 :
2368 666848 : if (systemType == SystemType::ConstantFlow) {
2369 :
2370 : // Can this system actually do heating?
2371 221733 : if ((state.dataLowTempRadSys->CFloRadSys(RadSysNum).WaterVolFlowMax > 0.0) &&
2372 221732 : (state.dataLowTempRadSys->CFloRadSys(RadSysNum).HotWaterInNode > 0) &&
2373 221732 : (state.dataLowTempRadSys->CFloRadSys(RadSysNum).HotWaterOutNode > 0) &&
2374 221732 : (state.dataLowTempRadSys->CFloRadSys(RadSysNum).hotWaterHiTempSched != nullptr) &&
2375 221732 : (state.dataLowTempRadSys->CFloRadSys(RadSysNum).hotWaterLoTempSched != nullptr) &&
2376 665197 : (state.dataLowTempRadSys->CFloRadSys(RadSysNum).hotCtrlHiTempSched != nullptr) &&
2377 221732 : (state.dataLowTempRadSys->CFloRadSys(RadSysNum).hotCtrlLoTempSched != nullptr)) {
2378 221732 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).HeatingSystem = true;
2379 : }
2380 :
2381 : // Can this system actually do cooling?
2382 221733 : if ((state.dataLowTempRadSys->CFloRadSys(RadSysNum).WaterVolFlowMax > 0.0) &&
2383 221732 : (state.dataLowTempRadSys->CFloRadSys(RadSysNum).ColdWaterInNode > 0) &&
2384 208097 : (state.dataLowTempRadSys->CFloRadSys(RadSysNum).ColdWaterOutNode > 0) &&
2385 208097 : (state.dataLowTempRadSys->CFloRadSys(RadSysNum).coldWaterHiTempSched != nullptr) &&
2386 208097 : (state.dataLowTempRadSys->CFloRadSys(RadSysNum).coldWaterLoTempSched != nullptr) &&
2387 651562 : (state.dataLowTempRadSys->CFloRadSys(RadSysNum).coldCtrlHiTempSched != nullptr) &&
2388 208097 : (state.dataLowTempRadSys->CFloRadSys(RadSysNum).coldCtrlLoTempSched != nullptr)) {
2389 208097 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).CoolingSystem = true;
2390 : }
2391 : }
2392 :
2393 666848 : if (state.dataGlobal->BeginTimeStepFlag && FirstHVACIteration) { // This is the first pass through in a particular time step
2394 :
2395 254744 : switch (systemType) {
2396 140501 : case SystemType::Hydronic: {
2397 140501 : int ZoneNum = state.dataLowTempRadSys->HydrRadSys(RadSysNum).ZonePtr;
2398 140501 : auto &thisLTR = state.dataLowTempRadSys->HydrRadSys(RadSysNum);
2399 140501 : thisLTR.ZeroLTRSourceSumHATsurf =
2400 140501 : state.dataHeatBal->Zone(ZoneNum).sumHATsurf(state); // Set this to figure what part of the load the radiant system meets
2401 140501 : thisLTR.QRadSysSrcAvg = 0.0; // Initialize this variable to zero (radiant system defaults to off)
2402 140501 : thisLTR.LastQRadSysSrc = 0.0; // At the start of a time step, reset to zero so average calculation can begin again
2403 140501 : thisLTR.LastSysTimeElapsed = 0.0; // At the start of a time step, reset to zero so average calculation can begin again
2404 140501 : thisLTR.LastTimeStepSys = 0.0; // At the start of a time step, reset to zero so average calculation can begin again }
2405 140501 : } break;
2406 81915 : case SystemType::ConstantFlow: {
2407 81915 : int ZoneNum = state.dataLowTempRadSys->CFloRadSys(RadSysNum).ZonePtr;
2408 81915 : auto &thisLTR = state.dataLowTempRadSys->CFloRadSys(RadSysNum);
2409 81915 : thisLTR.ZeroLTRSourceSumHATsurf =
2410 81915 : state.dataHeatBal->Zone(ZoneNum).sumHATsurf(state); // Set this to figure what part of the load the radiant system meets
2411 81915 : thisLTR.QRadSysSrcAvg = 0.0; // Initialize this variable to zero (radiant system defaults to off)
2412 81915 : thisLTR.LastQRadSysSrc = 0.0; // At the start of a time step, reset to zero so average calculation can begin again
2413 81915 : thisLTR.LastSysTimeElapsed = 0.0; // At the start of a time step, reset to zero so average calculation can begin again
2414 81915 : thisLTR.LastTimeStepSys = 0.0; // At the start of a time step, reset to zero so average calculation can begin again }
2415 81915 : } break;
2416 32328 : case SystemType::Electric: {
2417 32328 : int ZoneNum = state.dataLowTempRadSys->ElecRadSys(RadSysNum).ZonePtr;
2418 32328 : auto &thisLTR = state.dataLowTempRadSys->ElecRadSys(RadSysNum);
2419 32328 : thisLTR.ZeroLTRSourceSumHATsurf =
2420 32328 : state.dataHeatBal->Zone(ZoneNum).sumHATsurf(state); // Set this to figure what part of the load the radiant system meets
2421 32328 : thisLTR.QRadSysSrcAvg = 0.0; // Initialize this variable to zero (radiant system defaults to off)
2422 32328 : thisLTR.LastQRadSysSrc = 0.0; // At the start of a time step, reset to zero so average calculation can begin again
2423 32328 : thisLTR.LastSysTimeElapsed = 0.0; // At the start of a time step, reset to zero so average calculation can begin again
2424 32328 : thisLTR.LastTimeStepSys = 0.0; // At the start of a time step, reset to zero so average calculation can begin again }
2425 32328 : } break;
2426 0 : default: {
2427 0 : ShowSevereError(state, "Radiant system entered without specification of type: electric, constant flow, or hydronic?");
2428 0 : ShowContinueError(state, format("Occurs in Radiant System={}", state.dataLowTempRadSys->HydrRadSys(RadSysNum).Name));
2429 0 : ShowFatalError(state, "Preceding condition causes termination.");
2430 0 : } break;
2431 : }
2432 :
2433 : } // ...for first pass through in a particular time step.
2434 :
2435 666848 : switch (systemType) {
2436 :
2437 366056 : case SystemType::Hydronic: {
2438 :
2439 : // Initialize the appropriate node data
2440 366056 : if (state.dataLowTempRadSys->HydrRadSys(RadSysNum).HeatingSystem) {
2441 366010 : mdot = 0.0;
2442 732020 : SetComponentFlowRate(state,
2443 : mdot,
2444 366010 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).HotWaterInNode,
2445 366010 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).HotWaterOutNode,
2446 366010 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).HWPlantLoc);
2447 : }
2448 366056 : if (state.dataLowTempRadSys->HydrRadSys(RadSysNum).CoolingSystem) {
2449 351205 : mdot = 0.0;
2450 702410 : SetComponentFlowRate(state,
2451 : mdot,
2452 351205 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).ColdWaterInNode,
2453 351205 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).ColdWaterOutNode,
2454 351205 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).CWPlantLoc);
2455 : }
2456 366056 : if (state.dataLowTempRadSys->HydrRadSys(RadSysNum).opMode != OpMode::None && FirstHVACIteration) {
2457 124999 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).updateOperatingModeHistory(state);
2458 : }
2459 :
2460 366056 : } break;
2461 :
2462 221733 : case SystemType::ConstantFlow: {
2463 221733 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).WaterMassFlowRate = 0.0;
2464 : // Initialize the appropriate node data
2465 221733 : if (state.dataLowTempRadSys->CFloRadSys(RadSysNum).HeatingSystem) {
2466 221732 : if (state.dataLowTempRadSys->CFloRadSys(RadSysNum).volFlowSched != nullptr) {
2467 0 : CurrentFlowSchedule = state.dataLowTempRadSys->CFloRadSys(RadSysNum).volFlowSched->getCurrentVal();
2468 : } else {
2469 221732 : CurrentFlowSchedule = 1.0; // Allow user to avoid putting in a schedule (defaults to constant flow at all times)
2470 : }
2471 221732 : if (CurrentFlowSchedule > 1.0) {
2472 0 : CurrentFlowSchedule = 1.0; // Do not allow more flow than design maximum
2473 : }
2474 221732 : if (CurrentFlowSchedule < 0.0) {
2475 0 : CurrentFlowSchedule = 0.0; // Do not allow negative flow
2476 : }
2477 :
2478 221732 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).HotWaterMassFlowRate =
2479 221732 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).HotDesignWaterMassFlowRate * CurrentFlowSchedule;
2480 :
2481 221732 : if (state.dataLowTempRadSys->CFloRadSys(RadSysNum).EMSOverrideOnWaterMdot) {
2482 0 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).HotWaterMassFlowRate =
2483 0 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).EMSWaterMdotOverrideValue;
2484 : }
2485 :
2486 221732 : if (state.dataLowTempRadSys->CFloRadSys(RadSysNum).HotWaterInNode > 0) {
2487 665196 : SetComponentFlowRate(state,
2488 221732 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).HotWaterMassFlowRate,
2489 221732 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).HotWaterInNode,
2490 221732 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).HotWaterOutNode,
2491 221732 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).HWPlantLoc);
2492 : }
2493 : }
2494 221733 : if (state.dataLowTempRadSys->CFloRadSys(RadSysNum).CoolingSystem) {
2495 208097 : if (state.dataLowTempRadSys->CFloRadSys(RadSysNum).volFlowSched != nullptr) {
2496 0 : CurrentFlowSchedule = state.dataLowTempRadSys->CFloRadSys(RadSysNum).volFlowSched->getCurrentVal();
2497 : } else {
2498 208097 : CurrentFlowSchedule = 1.0; // Allow user to avoid putting in a schedule (defaults to constant flow at all times)
2499 : }
2500 208097 : if (CurrentFlowSchedule > 1.0) {
2501 0 : CurrentFlowSchedule = 1.0; // Do not allow more flow than design maximum
2502 : }
2503 208097 : if (CurrentFlowSchedule < 0.0) {
2504 0 : CurrentFlowSchedule = 0.0; // Do not allow negative flow
2505 : }
2506 208097 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).ChWaterMassFlowRate =
2507 208097 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).ColdDesignWaterMassFlowRate * CurrentFlowSchedule;
2508 :
2509 208097 : if (state.dataLowTempRadSys->CFloRadSys(RadSysNum).EMSOverrideOnWaterMdot) {
2510 0 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).ChWaterMassFlowRate =
2511 0 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).EMSWaterMdotOverrideValue;
2512 : }
2513 :
2514 208097 : if (state.dataLowTempRadSys->CFloRadSys(RadSysNum).ColdWaterInNode > 0) {
2515 624291 : SetComponentFlowRate(state,
2516 208097 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).ChWaterMassFlowRate,
2517 208097 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).ColdWaterInNode,
2518 208097 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).ColdWaterOutNode,
2519 208097 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).CWPlantLoc);
2520 : }
2521 : }
2522 221733 : if (state.dataLowTempRadSys->CFloRadSys(RadSysNum).opMode != OpMode::None && FirstHVACIteration) {
2523 82756 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).updateOperatingModeHistory(state);
2524 : }
2525 :
2526 221733 : } break;
2527 79059 : case SystemType::Electric: {
2528 79059 : state.dataLowTempRadSys->ElecRadSys(RadSysNum).opMode = OpMode::None;
2529 79059 : } break;
2530 0 : default:
2531 0 : break;
2532 : }
2533 666848 : }
2534 :
2535 207755 : void HydronicSystemBaseData::updateOperatingModeHistory(EnergyPlusData &state)
2536 : {
2537 : // Since this is only called when the operating mode is something other than "not operating",
2538 : // the status from the previous system time step is what it did in the last or previous time step.
2539 : // So, we can update the last status of the system using this information before resetting things
2540 : // to "not operating".
2541 207755 : this->lastOpMode = this->opMode;
2542 :
2543 207755 : if (state.dataGlobal->BeginDayFlag) {
2544 : // The begin day flag is set which mean this is the first time step of the day.
2545 : // This also means that the previous time step was the last time step of yesterday.
2546 : // So, the day should be the previous day, the hour should be the last hour of the
2547 : // day, and the time step should be the last time step.
2548 1328 : this->lastDayOfSim = state.dataGlobal->DayOfSim - 1;
2549 1328 : this->lastHourOfDay = Constant::iHoursInDay;
2550 1328 : this->lastTimeStep = state.dataGlobal->TimeStepsInHour;
2551 206427 : } else if (state.dataGlobal->BeginHourFlag) {
2552 : // It's not the beginning of the day but it is the beginning of an hour other than
2553 : // the first hour. This means that the previous time step was the previous hour of
2554 : // today in the last time step. So, the day should be the current day, the hour should
2555 : // be the previous hour, and the time step should be the last time step.
2556 36217 : this->lastDayOfSim = state.dataGlobal->DayOfSim;
2557 36217 : this->lastHourOfDay = state.dataGlobal->HourOfDay - 1;
2558 36217 : this->lastTimeStep = state.dataGlobal->TimeStepsInHour;
2559 170210 : } else if (state.dataGlobal->BeginTimeStepFlag) {
2560 : // It's neither the beginning of the day nor the beginning of an hour but it is the start
2561 : // of a time step other than the first time step in the hour. So, the day should be the
2562 : // current day, the hour should be the current hour, and the time step should be the
2563 : // previous time step.
2564 142397 : this->lastDayOfSim = state.dataGlobal->DayOfSim;
2565 142397 : this->lastHourOfDay = state.dataGlobal->HourOfDay;
2566 142397 : this->lastTimeStep = state.dataGlobal->TimeStep - 1;
2567 : } else {
2568 : // It's not the beginning of the day, hour, or time step so the "last" value is simply the
2569 : // same as the current value. Note that these parameters only track down to the zone time
2570 : // step level and will make decisions based on that.
2571 27813 : this->lastDayOfSim = state.dataGlobal->DayOfSim;
2572 27813 : this->lastHourOfDay = state.dataGlobal->HourOfDay;
2573 27813 : this->lastTimeStep = state.dataGlobal->TimeStep;
2574 : }
2575 :
2576 : // Now go ahead and reset the operating mode (this will be set to something else if the system is running)
2577 207755 : this->opMode = OpMode::None;
2578 207755 : }
2579 :
2580 572468 : void HydronicSystemBaseData::setOperatingModeBasedOnChangeoverDelay(EnergyPlusData &state)
2581 : {
2582 572468 : if (this->lastOpMode == OpMode::None) {
2583 19883 : return; // this should only happen at the beginning of a simulation (at the start of warmup and the actual simulation)
2584 : }
2585 : // so let things proceed with whatever the system wants to do
2586 :
2587 552585 : if (this->opMode == OpMode::None) {
2588 76387 : return; // always let it turn off
2589 : }
2590 :
2591 476198 : if (this->opMode == this->lastOpMode) {
2592 467504 : return; // always let it continue to operating in the same mode
2593 : }
2594 :
2595 8694 : if (this->changeoverDelaySched == nullptr) {
2596 1278 : return; // user not requesting any delays (no schedule entered) so let it do whatever is requested
2597 : }
2598 :
2599 7416 : Real64 currentChangeoverDelay = this->changeoverDelaySched->getCurrentVal();
2600 7416 : if (currentChangeoverDelay <= 0.0) {
2601 0 : return; // delay is zero so let it do whatever it requested
2602 : }
2603 :
2604 : // At this point, the radiant system is trying to switch modes from the previous time step, the user is requesting a delay in the changeover,
2605 : // and the requested delay is greater than zero. Calculate what the current time is in hours from the start of the simulation
2606 7416 : Real64 timeCurrent = 24.0 * float(state.dataGlobal->DayOfSim - 1) + float(state.dataGlobal->HourOfDay - 1) +
2607 7416 : float(state.dataGlobal->TimeStep - 1) / float(state.dataGlobal->TimeStepsInHour);
2608 7416 : Real64 timeLast = 24.0 * float(this->lastDayOfSim - 1) + float(this->lastHourOfDay - 1) +
2609 7416 : float(this->lastTimeStep - 1) / float(state.dataGlobal->TimeStepsInHour);
2610 7416 : Real64 actualTimeDifference = timeCurrent - timeLast;
2611 :
2612 : // If the time difference is not longer than the user delay, then the system should not switch modes and needs to be turned off.
2613 7416 : if (actualTimeDifference <= currentChangeoverDelay) {
2614 7416 : this->opMode = OpMode::None;
2615 : }
2616 :
2617 : // Note: if the time difference is greater than the user delay request, then go ahead and keep the operating mode needed (don't do anything).
2618 : }
2619 :
2620 82 : void SizeLowTempRadiantSystem(EnergyPlusData &state,
2621 : int const RadSysNum, // Index for the low temperature radiant system under consideration within the derived types
2622 : SystemType const systemType // Type of radiant system: hydronic, constant flow, or electric
2623 : )
2624 : {
2625 :
2626 : // SUBROUTINE INFORMATION:
2627 : // AUTHOR Fred Buhl
2628 : // DATE WRITTEN February 2002
2629 : // MODIFIED August 2013 Daeho Kang, add component sizing table entries
2630 : // August 2014 Bereket Nigusse, added scalable sizing
2631 : // March 2014 Daeho Kang, add constant flow system autosizing
2632 :
2633 : // PURPOSE OF THIS SUBROUTINE:
2634 : // This subroutine is for sizing low temperature radiant components for which flow rates
2635 : // and tube length or max electric power have not been specified in the input
2636 :
2637 : // METHODOLOGY EMPLOYED:
2638 : // Obtains flow rates from the zone sizing arrays and plant sizing data. Maximum electric
2639 : // power is set to the design heat load. Tube length is calculated by rule-of-thumb from
2640 : // the surface area.
2641 :
2642 : // Using/Aliasing
2643 : using namespace DataSizing;
2644 : using HVAC::AutoCalculateSizing;
2645 : using HVAC::CoolingCapacitySizing;
2646 : using HVAC::HeatingCapacitySizing;
2647 :
2648 : using PlantUtilities::MyPlantSizingIndex;
2649 : using PlantUtilities::RegisterPlantCompDesignFlow;
2650 :
2651 : // SUBROUTINE PARAMETER DEFINITIONS:
2652 82 : constexpr std::string_view RoutineName("SizeLowTempRadiantSystem");
2653 :
2654 : enum class OperatingMode
2655 : {
2656 : Invalid = -1,
2657 : OFF,
2658 : ClgHtg,
2659 : ClgOnly,
2660 : HtgOnly,
2661 : Num
2662 : };
2663 :
2664 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2665 82 : int PltSizHeatNum(0); // index of plant sizing object for 1st heating loop
2666 82 : int PltSizCoolNum(0); // index of plant sizing object for 1st cooling loop
2667 : int SurfNum; // surface index in radiant system data structure
2668 82 : bool ErrorsFound(false); // If errors detected in input
2669 : Real64 rho;
2670 : Real64 Cp;
2671 82 : bool IsAutoSize(false); // Indicator to autosize
2672 82 : Real64 WaterVolFlowMaxHeatDes(0.0); // Design hot water flow for reporting
2673 82 : Real64 WaterVolFlowMaxHeatUser(0.0); // User hard-sized hot water flow for
2674 82 : Real64 WaterVolFlowMaxCoolDes(0.0); // Design chilled water flow for reporting
2675 82 : Real64 WaterVolFlowMaxCoolUser(0.0); // User hard-sized chilled water flow for reporting
2676 82 : Real64 TubeLengthDes(0.0); // Design tube length for reporting
2677 82 : Real64 TubeLengthUser(0.0); // User hard-sized tube length for reporting
2678 82 : std::string CompName; // component name
2679 82 : std::string CompType; // component type
2680 82 : std::string SizingString; // input field sizing description (e.g., Nominal Capacity)
2681 : Real64 TempSize; // autosized value of coil input field
2682 : int FieldNum; // IDD numeric field number where input field description is found
2683 : bool PrintFlag; // TRUE when sizing information is reported in the eio file
2684 : int CapSizingMethod; // capacity sizing methods (HeatingDesignCapacity, CapacityPerFloorArea, FractionOfAutosizedCoolingCapacity, and
2685 : // FractionOfAutosizedHeatingCapacity )
2686 : Real64 DesCoilLoad; // design autosized or user specified capacity
2687 : Real64 WaterVolFlowMaxDes; // Design water volume flow rate for reporting
2688 : Real64 WaterVolFlowMaxUser; // User hard-sized water volume flow rate for reporting
2689 :
2690 82 : DesCoilLoad = 0.0;
2691 82 : state.dataSize->DataScalableCapSizingON = false;
2692 82 : state.dataSize->DataFracOfAutosizedHeatingCapacity = 1.0;
2693 :
2694 82 : auto const &Zone = state.dataHeatBal->Zone;
2695 :
2696 82 : if (systemType == SystemType::Electric) {
2697 :
2698 9 : if (state.dataLowTempRadSys->ElecRadSys(RadSysNum).MaxElecPower == AutoSize) {
2699 2 : IsAutoSize = true;
2700 : }
2701 :
2702 9 : if (state.dataSize->CurZoneEqNum > 0) {
2703 9 : auto &zoneEqSizing = state.dataSize->ZoneEqSizing(state.dataSize->CurZoneEqNum);
2704 :
2705 9 : CompType = "ZoneHVAC:LowTemperatureRadiant:Electric";
2706 9 : CompName = state.dataLowTempRadSys->ElecRadSys(RadSysNum).Name;
2707 9 : int SizingMethod = HeatingCapacitySizing;
2708 9 : FieldNum = 1;
2709 9 : PrintFlag = true;
2710 9 : SizingString = state.dataLowTempRadSys->ElecRadSysNumericFields(RadSysNum).FieldNames(FieldNum) + " [W]";
2711 9 : CapSizingMethod = state.dataLowTempRadSys->ElecRadSys(RadSysNum).HeatingCapMethod;
2712 9 : zoneEqSizing.SizingMethod(SizingMethod) = CapSizingMethod;
2713 :
2714 9 : if (!IsAutoSize && !state.dataSize->ZoneSizingRunDone) { // simulation continue
2715 3 : if (CapSizingMethod == HeatingDesignCapacity && state.dataLowTempRadSys->ElecRadSys(RadSysNum).ScaledHeatingCapacity > 0.0) {
2716 3 : TempSize = state.dataLowTempRadSys->ElecRadSys(RadSysNum).ScaledHeatingCapacity;
2717 3 : bool errorsFound = false;
2718 3 : HeatingCapacitySizer sizerHeatingCapacity;
2719 3 : sizerHeatingCapacity.overrideSizingString(SizingString);
2720 3 : sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
2721 3 : DesCoilLoad = sizerHeatingCapacity.size(state, TempSize, errorsFound);
2722 3 : } else if (CapSizingMethod == CapacityPerFloorArea) {
2723 0 : state.dataSize->DataScalableCapSizingON = true;
2724 0 : TempSize = state.dataLowTempRadSys->ElecRadSys(RadSysNum).ScaledHeatingCapacity *
2725 0 : Zone(state.dataLowTempRadSys->ElecRadSys(RadSysNum).ZonePtr).FloorArea;
2726 0 : bool errorsFound = false;
2727 0 : HeatingCapacitySizer sizerHeatingCapacity;
2728 0 : sizerHeatingCapacity.overrideSizingString(SizingString);
2729 0 : sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
2730 0 : DesCoilLoad = sizerHeatingCapacity.size(state, TempSize, errorsFound);
2731 0 : state.dataSize->DataScalableCapSizingON = false;
2732 0 : state.dataLowTempRadSys->ElecRadSys(RadSysNum).MaxElecPower = TempSize;
2733 0 : } else if (CapSizingMethod == FractionOfAutosizedHeatingCapacity) {
2734 0 : ShowSevereError(state,
2735 0 : format("{}: auto-sizing cannot be done for {} = {}\".",
2736 : RoutineName,
2737 : CompType,
2738 0 : state.dataLowTempRadSys->ElecRadSys(RadSysNum).Name));
2739 0 : ShowContinueError(state,
2740 : "The \"SimulationControl\" object must have the field \"Do Zone Sizing Calculation\" set to Yes when the "
2741 : "Heating Design Capacity Method = \"FractionOfAutosizedHeatingCapacity\".");
2742 0 : ErrorsFound = true;
2743 : }
2744 : } else {
2745 6 : if (CapSizingMethod == HeatingDesignCapacity || CapSizingMethod == CapacityPerFloorArea ||
2746 : CapSizingMethod == FractionOfAutosizedHeatingCapacity) {
2747 6 : if (CapSizingMethod == HeatingDesignCapacity) {
2748 2 : if (state.dataSize->ZoneSizingRunDone) {
2749 2 : CheckZoneSizing(state, CompType, CompName);
2750 4 : state.dataSize->DataConstantUsedForSizing =
2751 2 : state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).NonAirSysDesHeatLoad;
2752 2 : state.dataSize->DataFractionUsedForSizing = 1.0;
2753 : }
2754 2 : if (state.dataLowTempRadSys->ElecRadSys(RadSysNum).ScaledHeatingCapacity == AutoSize) {
2755 2 : TempSize = AutoSize;
2756 : } else {
2757 0 : TempSize = state.dataLowTempRadSys->ElecRadSys(RadSysNum).ScaledHeatingCapacity;
2758 : }
2759 4 : } else if (CapSizingMethod == CapacityPerFloorArea) {
2760 2 : if (state.dataSize->ZoneSizingRunDone) {
2761 2 : CheckZoneSizing(state, CompType, CompName);
2762 2 : zoneEqSizing.HeatingCapacity = true;
2763 2 : zoneEqSizing.DesHeatingLoad = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).NonAirSysDesHeatLoad;
2764 : }
2765 2 : TempSize = state.dataLowTempRadSys->ElecRadSys(RadSysNum).ScaledHeatingCapacity *
2766 2 : Zone(state.dataLowTempRadSys->ElecRadSys(RadSysNum).ZonePtr).FloorArea;
2767 2 : state.dataSize->DataScalableCapSizingON = true;
2768 :
2769 2 : } else if (CapSizingMethod == FractionOfAutosizedHeatingCapacity) {
2770 2 : CheckZoneSizing(state, CompType, CompName);
2771 2 : zoneEqSizing.HeatingCapacity = true;
2772 2 : zoneEqSizing.DesHeatingLoad = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).NonAirSysDesHeatLoad;
2773 2 : TempSize = zoneEqSizing.DesHeatingLoad * state.dataLowTempRadSys->ElecRadSys(RadSysNum).ScaledHeatingCapacity;
2774 2 : state.dataSize->DataScalableCapSizingON = true;
2775 : } else {
2776 0 : TempSize = state.dataLowTempRadSys->ElecRadSys(RadSysNum).ScaledHeatingCapacity;
2777 : }
2778 6 : HeatingCapacitySizer sizerHeatingCapacity;
2779 6 : sizerHeatingCapacity.overrideSizingString(SizingString);
2780 6 : sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
2781 6 : state.dataLowTempRadSys->ElecRadSys(RadSysNum).MaxElecPower = sizerHeatingCapacity.size(state, TempSize, ErrorsFound);
2782 6 : state.dataSize->DataConstantUsedForSizing = 0.0;
2783 6 : state.dataSize->DataFractionUsedForSizing = 0.0;
2784 6 : state.dataSize->DataScalableCapSizingON = false;
2785 6 : }
2786 : }
2787 : }
2788 :
2789 73 : } else if (systemType == SystemType::Hydronic) {
2790 :
2791 46 : CompType = "ZoneHVAC:LowTemperatureRadiant:VariableFlow";
2792 46 : CompName = state.dataLowTempRadSys->HydrRadSys(RadSysNum).Name;
2793 :
2794 46 : IsAutoSize = false;
2795 46 : if (state.dataLowTempRadSys->HydrRadSys(RadSysNum).ScaledHeatingCapacity == AutoSize) {
2796 44 : IsAutoSize = true;
2797 : }
2798 :
2799 46 : if (state.dataSize->CurZoneEqNum > 0) {
2800 46 : auto &zoneEqSizing = state.dataSize->ZoneEqSizing(state.dataSize->CurZoneEqNum);
2801 :
2802 46 : int SizingMethod = HeatingCapacitySizing;
2803 46 : FieldNum = 2;
2804 46 : PrintFlag = true;
2805 46 : SizingString = state.dataLowTempRadSys->HydronicRadiantSysNumericFields(RadSysNum).FieldNames(FieldNum) + " [W]";
2806 46 : CapSizingMethod = state.dataLowTempRadSys->HydrRadSys(RadSysNum).HeatingCapMethod;
2807 46 : zoneEqSizing.SizingMethod(SizingMethod) = CapSizingMethod;
2808 :
2809 46 : if (!IsAutoSize && !state.dataSize->ZoneSizingRunDone) { // simulation continue
2810 0 : if (CapSizingMethod == HeatingDesignCapacity && state.dataLowTempRadSys->HydrRadSys(RadSysNum).ScaledHeatingCapacity > 0.0) {
2811 0 : TempSize = state.dataLowTempRadSys->HydrRadSys(RadSysNum).ScaledHeatingCapacity;
2812 0 : bool errorsFound = false;
2813 0 : HeatingCapacitySizer sizerHeatingCapacity;
2814 0 : sizerHeatingCapacity.overrideSizingString(SizingString);
2815 0 : sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
2816 0 : DesCoilLoad = sizerHeatingCapacity.size(state, TempSize, errorsFound);
2817 0 : } else if (CapSizingMethod == CapacityPerFloorArea) {
2818 0 : state.dataSize->DataScalableCapSizingON = true;
2819 0 : TempSize = state.dataLowTempRadSys->HydrRadSys(RadSysNum).ScaledHeatingCapacity *
2820 0 : Zone(state.dataLowTempRadSys->HydrRadSys(RadSysNum).ZonePtr).FloorArea;
2821 0 : HeatingCapacitySizer sizerHeatingCapacity;
2822 0 : sizerHeatingCapacity.overrideSizingString(SizingString);
2823 0 : sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
2824 0 : DesCoilLoad = sizerHeatingCapacity.size(state, TempSize, ErrorsFound);
2825 0 : state.dataSize->DataScalableCapSizingON = false;
2826 0 : } else if (CapSizingMethod == FractionOfAutosizedHeatingCapacity) {
2827 0 : if (state.dataLowTempRadSys->HydrRadSys(RadSysNum).WaterVolFlowMaxHeat == AutoSize) {
2828 0 : ShowSevereError(state,
2829 0 : format("{}: auto-sizing cannot be done for {} = {}\".",
2830 : RoutineName,
2831 : CompType,
2832 0 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).Name));
2833 0 : ShowContinueError(state,
2834 : "The \"SimulationControl\" object must have the field \"Do Zone Sizing Calculation\" set to Yes when "
2835 : "the Heating Design Capacity Method = \"FractionOfAutosizedHeatingCapacity\".");
2836 0 : ErrorsFound = true;
2837 : }
2838 : }
2839 : } else { // Autosize or hard-size with sizing run
2840 46 : if (CapSizingMethod == HeatingDesignCapacity || CapSizingMethod == CapacityPerFloorArea ||
2841 : CapSizingMethod == FractionOfAutosizedHeatingCapacity) {
2842 46 : if (CapSizingMethod == HeatingDesignCapacity) {
2843 44 : if (state.dataSize->ZoneSizingRunDone) {
2844 44 : CheckZoneSizing(state, CompType, CompName);
2845 88 : state.dataSize->DataConstantUsedForSizing =
2846 44 : state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).NonAirSysDesHeatLoad;
2847 44 : state.dataSize->DataFractionUsedForSizing = 1.0;
2848 : }
2849 44 : if (state.dataLowTempRadSys->HydrRadSys(RadSysNum).ScaledHeatingCapacity == AutoSize) {
2850 44 : TempSize = AutoSize;
2851 : } else {
2852 0 : TempSize = state.dataLowTempRadSys->HydrRadSys(RadSysNum).ScaledHeatingCapacity;
2853 : }
2854 2 : } else if (CapSizingMethod == CapacityPerFloorArea) {
2855 1 : if (state.dataSize->ZoneSizingRunDone) {
2856 1 : CheckZoneSizing(state, CompType, CompName);
2857 1 : zoneEqSizing.HeatingCapacity = true;
2858 1 : zoneEqSizing.DesHeatingLoad = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).NonAirSysDesHeatLoad;
2859 : }
2860 1 : TempSize = state.dataLowTempRadSys->HydrRadSys(RadSysNum).ScaledHeatingCapacity *
2861 1 : Zone(state.dataLowTempRadSys->HydrRadSys(RadSysNum).ZonePtr).FloorArea;
2862 1 : state.dataSize->DataScalableCapSizingON = true;
2863 1 : } else if (CapSizingMethod == FractionOfAutosizedHeatingCapacity) {
2864 1 : CheckZoneSizing(state, CompType, CompName);
2865 1 : zoneEqSizing.HeatingCapacity = true;
2866 1 : zoneEqSizing.DesHeatingLoad = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).NonAirSysDesHeatLoad;
2867 1 : TempSize = zoneEqSizing.DesHeatingLoad * state.dataLowTempRadSys->HydrRadSys(RadSysNum).ScaledHeatingCapacity;
2868 1 : state.dataSize->DataScalableCapSizingON = true;
2869 : } else {
2870 0 : TempSize = state.dataLowTempRadSys->HydrRadSys(RadSysNum).ScaledHeatingCapacity;
2871 : }
2872 46 : HeatingCapacitySizer sizerHeatingCapacity;
2873 46 : sizerHeatingCapacity.overrideSizingString(SizingString);
2874 46 : sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
2875 46 : DesCoilLoad = sizerHeatingCapacity.size(state, TempSize, ErrorsFound);
2876 46 : state.dataSize->DataConstantUsedForSizing = 0.0;
2877 46 : state.dataSize->DataFractionUsedForSizing = 0.0;
2878 46 : state.dataSize->DataScalableCapSizingON = false;
2879 46 : } else {
2880 0 : DesCoilLoad = 0.0;
2881 : }
2882 : }
2883 : // finally heating capacity is saved in this variable
2884 46 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).ScaledHeatingCapacity = DesCoilLoad;
2885 : }
2886 :
2887 46 : IsAutoSize = false;
2888 46 : if (state.dataLowTempRadSys->HydrRadSys(RadSysNum).WaterVolFlowMaxHeat == AutoSize) {
2889 6 : IsAutoSize = true;
2890 : }
2891 :
2892 46 : if (state.dataSize->CurZoneEqNum > 0) {
2893 46 : if (!IsAutoSize && !state.dataSize->ZoneSizingRunDone) { // simulation continue
2894 0 : if (state.dataLowTempRadSys->HydrRadSys(RadSysNum).WaterVolFlowMaxHeat > 0.0) {
2895 0 : BaseSizer::reportSizerOutput(state,
2896 : CompType,
2897 0 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).Name,
2898 : "User-Specified Maximum Hot Water Flow [m3/s]",
2899 0 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).WaterVolFlowMaxHeat);
2900 : }
2901 : } else { // Autosize or hard-size with sizing run
2902 92 : if (state.dataLowTempRadSys->HydrRadSys(RadSysNum).HotWaterInNode > 0 &&
2903 46 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).HotWaterOutNode > 0) {
2904 46 : PltSizHeatNum = MyPlantSizingIndex(state,
2905 : CompType,
2906 46 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).Name,
2907 46 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).HotWaterInNode,
2908 46 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).HotWaterOutNode,
2909 : ErrorsFound);
2910 46 : if (PltSizHeatNum > 0) {
2911 46 : if (DesCoilLoad >= SmallLoad) {
2912 43 : rho = state.dataPlnt->PlantLoop(state.dataLowTempRadSys->HydrRadSys(RadSysNum).HWPlantLoc.loopNum)
2913 43 : .glycol->getDensity(state, Constant::HWInitConvTemp, RoutineName);
2914 43 : Cp = state.dataPlnt->PlantLoop(state.dataLowTempRadSys->HydrRadSys(RadSysNum).HWPlantLoc.loopNum)
2915 43 : .glycol->getSpecificHeat(state, Constant::HWInitConvTemp, RoutineName);
2916 43 : WaterVolFlowMaxHeatDes = DesCoilLoad / (state.dataSize->PlantSizData(PltSizHeatNum).DeltaT * Cp * rho);
2917 : } else {
2918 3 : WaterVolFlowMaxHeatDes = 0.0;
2919 : }
2920 : } else {
2921 0 : ShowSevereError(state, "Autosizing of water flow requires a heating loop Sizing:Plant object");
2922 0 : ShowContinueError(state,
2923 0 : format("Occurs in ZoneHVAC:LowTemperatureRadiant:VariableFlow Object={}",
2924 0 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).Name));
2925 0 : ErrorsFound = true;
2926 : }
2927 : }
2928 :
2929 46 : if (IsAutoSize) {
2930 6 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).WaterVolFlowMaxHeat = WaterVolFlowMaxHeatDes;
2931 12 : BaseSizer::reportSizerOutput(state,
2932 : CompType,
2933 6 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).Name,
2934 : "Design Size Maximum Hot Water Flow [m3/s]",
2935 : WaterVolFlowMaxHeatDes);
2936 : } else { // hard-size with sizing data
2937 40 : if (state.dataLowTempRadSys->HydrRadSys(RadSysNum).WaterVolFlowMaxHeat > 0.0 && WaterVolFlowMaxHeatDes > 0.0) {
2938 37 : WaterVolFlowMaxHeatUser = state.dataLowTempRadSys->HydrRadSys(RadSysNum).WaterVolFlowMaxHeat;
2939 74 : BaseSizer::reportSizerOutput(state,
2940 : CompType,
2941 37 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).Name,
2942 : "Design Size Maximum Hot Water Flow [m3/s]",
2943 : WaterVolFlowMaxHeatDes,
2944 : "User-Specified Maximum Hot Water Flow [m3/s]",
2945 : WaterVolFlowMaxHeatUser);
2946 37 : if (state.dataGlobal->DisplayExtraWarnings) {
2947 0 : if ((std::abs(WaterVolFlowMaxHeatDes - WaterVolFlowMaxHeatUser) / WaterVolFlowMaxHeatUser) >
2948 0 : state.dataSize->AutoVsHardSizingThreshold) {
2949 0 : ShowMessage(state,
2950 0 : format("SizeLowTempRadiantSystem: Potential issue with equipment sizing for "
2951 : "ZoneHVAC:LowTemperatureRadiant:VariableFlow = \"{}\".",
2952 0 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).Name));
2953 0 : ShowContinueError(state,
2954 0 : format("User-Specified Maximum Hot Water Flow of {:.5R} [m3/s]", WaterVolFlowMaxHeatUser));
2955 0 : ShowContinueError(
2956 0 : state, format("differs from Design Size Maximum Hot Water Flow of {:.5R} [m3/s]", WaterVolFlowMaxHeatDes));
2957 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
2958 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
2959 : }
2960 : }
2961 : }
2962 : }
2963 : }
2964 : }
2965 :
2966 46 : IsAutoSize = false;
2967 46 : if (state.dataLowTempRadSys->HydrRadSys(RadSysNum).ScaledCoolingCapacity == AutoSize) {
2968 44 : IsAutoSize = true;
2969 : }
2970 :
2971 46 : if (state.dataSize->CurZoneEqNum > 0) {
2972 46 : auto &zoneEqSizing = state.dataSize->ZoneEqSizing(state.dataSize->CurZoneEqNum);
2973 :
2974 46 : int SizingMethod = CoolingCapacitySizing;
2975 46 : FieldNum = 4;
2976 46 : PrintFlag = true;
2977 46 : SizingString = state.dataLowTempRadSys->HydronicRadiantSysNumericFields(RadSysNum).FieldNames(FieldNum) + " [W]";
2978 46 : CapSizingMethod = state.dataLowTempRadSys->HydrRadSys(RadSysNum).CoolingCapMethod;
2979 46 : zoneEqSizing.SizingMethod(SizingMethod) = CapSizingMethod;
2980 :
2981 46 : if (!IsAutoSize && !state.dataSize->ZoneSizingRunDone) { // simulation continue
2982 0 : if (CapSizingMethod == CoolingDesignCapacity && state.dataLowTempRadSys->HydrRadSys(RadSysNum).ScaledCoolingCapacity > 0.0) {
2983 0 : TempSize = state.dataLowTempRadSys->HydrRadSys(RadSysNum).ScaledCoolingCapacity;
2984 0 : CoolingCapacitySizer sizerCoolingCapacity;
2985 0 : sizerCoolingCapacity.overrideSizingString(SizingString);
2986 0 : sizerCoolingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
2987 0 : DesCoilLoad = sizerCoolingCapacity.size(state, TempSize, ErrorsFound);
2988 0 : } else if (CapSizingMethod == CapacityPerFloorArea) {
2989 0 : state.dataSize->DataScalableCapSizingON = true;
2990 0 : TempSize = state.dataLowTempRadSys->HydrRadSys(RadSysNum).ScaledCoolingCapacity *
2991 0 : Zone(state.dataLowTempRadSys->HydrRadSys(RadSysNum).ZonePtr).FloorArea;
2992 0 : CoolingCapacitySizer sizerCoolingCapacity;
2993 0 : sizerCoolingCapacity.overrideSizingString(SizingString);
2994 0 : sizerCoolingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
2995 0 : DesCoilLoad = sizerCoolingCapacity.size(state, TempSize, ErrorsFound);
2996 0 : state.dataSize->DataScalableCapSizingON = false;
2997 0 : } else if (CapSizingMethod == FractionOfAutosizedCoolingCapacity) {
2998 0 : if (state.dataLowTempRadSys->HydrRadSys(RadSysNum).WaterVolFlowMaxCool == AutoSize) {
2999 0 : ShowSevereError(state,
3000 0 : format("{}: auto-sizing cannot be done for {} = {}\".",
3001 : RoutineName,
3002 : CompType,
3003 0 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).Name));
3004 0 : ShowContinueError(state,
3005 : "The \"SimulationControl\" object must have the field \"Do Zone Sizing Calculation\" set to Yes when "
3006 : "the Cooling Design Capacity Method = \"FractionOfAutosizedCoolingCapacity\".");
3007 0 : ErrorsFound = true;
3008 : }
3009 : }
3010 : } else { // Autosize or hard-size with sizing run
3011 46 : if (CapSizingMethod == CoolingDesignCapacity || CapSizingMethod == CapacityPerFloorArea ||
3012 : CapSizingMethod == FractionOfAutosizedCoolingCapacity) {
3013 46 : if (CapSizingMethod == CoolingDesignCapacity) {
3014 44 : if (state.dataSize->ZoneSizingRunDone) {
3015 44 : CheckZoneSizing(state, CompType, CompName);
3016 88 : state.dataSize->DataConstantUsedForSizing =
3017 44 : state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).NonAirSysDesCoolLoad;
3018 44 : state.dataSize->DataFractionUsedForSizing = 1.0;
3019 : }
3020 44 : if (state.dataLowTempRadSys->HydrRadSys(RadSysNum).ScaledCoolingCapacity == AutoSize) {
3021 44 : TempSize = AutoSize;
3022 : } else {
3023 0 : TempSize = state.dataLowTempRadSys->HydrRadSys(RadSysNum).ScaledCoolingCapacity;
3024 : }
3025 2 : } else if (CapSizingMethod == CapacityPerFloorArea) {
3026 1 : if (state.dataSize->ZoneSizingRunDone) {
3027 1 : CheckZoneSizing(state, CompType, CompName);
3028 1 : zoneEqSizing.CoolingCapacity = true;
3029 1 : zoneEqSizing.DesCoolingLoad = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).NonAirSysDesCoolLoad;
3030 : }
3031 1 : TempSize = state.dataLowTempRadSys->HydrRadSys(RadSysNum).ScaledCoolingCapacity *
3032 1 : Zone(state.dataLowTempRadSys->HydrRadSys(RadSysNum).ZonePtr).FloorArea;
3033 1 : state.dataSize->DataScalableCapSizingON = true;
3034 1 : } else if (CapSizingMethod == FractionOfAutosizedCoolingCapacity) {
3035 1 : CheckZoneSizing(state, CompType, CompName);
3036 1 : zoneEqSizing.CoolingCapacity = true;
3037 1 : zoneEqSizing.DesCoolingLoad = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).NonAirSysDesCoolLoad;
3038 1 : TempSize = zoneEqSizing.DesCoolingLoad * state.dataLowTempRadSys->HydrRadSys(RadSysNum).ScaledCoolingCapacity;
3039 1 : state.dataSize->DataScalableCapSizingON = true;
3040 :
3041 : } else {
3042 0 : TempSize = state.dataLowTempRadSys->HydrRadSys(RadSysNum).ScaledCoolingCapacity;
3043 : }
3044 46 : CoolingCapacitySizer sizerCoolingCapacity;
3045 46 : sizerCoolingCapacity.overrideSizingString(SizingString);
3046 46 : sizerCoolingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
3047 46 : DesCoilLoad = sizerCoolingCapacity.size(state, TempSize, ErrorsFound);
3048 46 : state.dataSize->DataConstantUsedForSizing = 0.0;
3049 46 : state.dataSize->DataFractionUsedForSizing = 0.0;
3050 46 : state.dataSize->DataScalableCapSizingON = false;
3051 46 : } else {
3052 0 : DesCoilLoad = 0.0;
3053 : }
3054 : }
3055 : // finally cooling capacity is saved in this variable
3056 46 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).ScaledCoolingCapacity = DesCoilLoad;
3057 : }
3058 :
3059 46 : IsAutoSize = false;
3060 46 : if (state.dataLowTempRadSys->HydrRadSys(RadSysNum).WaterVolFlowMaxCool == AutoSize) {
3061 6 : IsAutoSize = true;
3062 : }
3063 46 : if (state.dataSize->CurZoneEqNum > 0) {
3064 46 : if (!IsAutoSize && !state.dataSize->ZoneSizingRunDone) { // simulation continue
3065 0 : if (state.dataLowTempRadSys->HydrRadSys(RadSysNum).WaterVolFlowMaxCool > 0.0) {
3066 0 : BaseSizer::reportSizerOutput(state,
3067 : CompType,
3068 0 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).Name,
3069 : "User-Specified Maximum Cold Water Flow [m3/s]",
3070 0 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).WaterVolFlowMaxCool);
3071 : }
3072 : } else { // Autosize or hard-size with sizing run
3073 89 : if (state.dataLowTempRadSys->HydrRadSys(RadSysNum).ColdWaterInNode > 0 &&
3074 43 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).ColdWaterOutNode > 0) {
3075 43 : PltSizCoolNum = MyPlantSizingIndex(state,
3076 : CompType,
3077 43 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).Name,
3078 43 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).ColdWaterInNode,
3079 43 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).ColdWaterOutNode,
3080 : ErrorsFound);
3081 43 : if (PltSizCoolNum > 0) {
3082 43 : if (DesCoilLoad >= SmallLoad) {
3083 40 : rho = state.dataPlnt->PlantLoop(state.dataLowTempRadSys->HydrRadSys(RadSysNum).CWPlantLoc.loopNum)
3084 40 : .glycol->getDensity(state, Constant::CWInitConvTemp, RoutineName);
3085 40 : Cp = state.dataPlnt->PlantLoop(state.dataLowTempRadSys->HydrRadSys(RadSysNum).CWPlantLoc.loopNum)
3086 40 : .glycol->getSpecificHeat(state, Constant::CWInitConvTemp, RoutineName);
3087 40 : WaterVolFlowMaxCoolDes = DesCoilLoad / (state.dataSize->PlantSizData(PltSizCoolNum).DeltaT * Cp * rho);
3088 : } else {
3089 3 : WaterVolFlowMaxCoolDes = 0.0;
3090 : }
3091 : } else {
3092 0 : ShowSevereError(state, "Autosizing of water flow requires a cooling loop Sizing:Plant object");
3093 0 : ShowContinueError(state,
3094 0 : format("Occurs in ZoneHVAC:LowTemperatureRadiant:VariableFlow Object={}",
3095 0 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).Name));
3096 0 : ErrorsFound = true;
3097 : }
3098 : }
3099 :
3100 46 : if (IsAutoSize) {
3101 6 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).WaterVolFlowMaxCool = WaterVolFlowMaxCoolDes;
3102 12 : BaseSizer::reportSizerOutput(state,
3103 : CompType,
3104 6 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).Name,
3105 : "Design Size Maximum Cold Water Flow [m3/s]",
3106 : WaterVolFlowMaxCoolDes);
3107 : } else { // hard-size with sizing data
3108 40 : if (state.dataLowTempRadSys->HydrRadSys(RadSysNum).WaterVolFlowMaxCool > 0.0 && WaterVolFlowMaxCoolDes > 0.0) {
3109 34 : WaterVolFlowMaxCoolUser = state.dataLowTempRadSys->HydrRadSys(RadSysNum).WaterVolFlowMaxCool;
3110 68 : BaseSizer::reportSizerOutput(state,
3111 : CompType,
3112 34 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).Name,
3113 : "Design Size Maximum Cold Water Flow [m3/s]",
3114 : WaterVolFlowMaxCoolDes,
3115 : "User-Specified Maximum Cold Water Flow [m3/s]",
3116 : WaterVolFlowMaxCoolUser);
3117 34 : if (state.dataGlobal->DisplayExtraWarnings) {
3118 0 : if ((std::abs(WaterVolFlowMaxCoolDes - WaterVolFlowMaxCoolUser) / WaterVolFlowMaxCoolUser) >
3119 0 : state.dataSize->AutoVsHardSizingThreshold) {
3120 0 : ShowMessage(state,
3121 0 : format("SizeLowTempRadiantSystem: Potential issue with equipment sizing for "
3122 : "ZoneHVAC:LowTemperatureRadiant:VariableFlow = \"{}\".",
3123 0 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).Name));
3124 0 : ShowContinueError(state,
3125 0 : format("User-Specified Maximum Cool Water Flow of {:.5R} [m3/s]", WaterVolFlowMaxCoolUser));
3126 0 : ShowContinueError(
3127 0 : state, format("differs from Design Size Maximum Cool Water Flow of {:.5R} [m3/s]", WaterVolFlowMaxCoolDes));
3128 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
3129 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
3130 : }
3131 : }
3132 : }
3133 : }
3134 : }
3135 : }
3136 :
3137 46 : IsAutoSize = false;
3138 46 : if (state.dataLowTempRadSys->HydrRadSys(RadSysNum).TubeLength == AutoSize) {
3139 6 : IsAutoSize = true;
3140 : }
3141 46 : if (state.dataSize->CurZoneEqNum > 0) {
3142 46 : if (!IsAutoSize && !state.dataSize->ZoneSizingRunDone) { // simulation continue
3143 0 : if (state.dataLowTempRadSys->HydrRadSys(RadSysNum).TubeLength > 0.0) {
3144 0 : BaseSizer::reportSizerOutput(state,
3145 : CompType,
3146 0 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).Name,
3147 : "User-Specified Hydronic Tubing Length [m]",
3148 0 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).TubeLength);
3149 : }
3150 : } else { // Autosize or hard-size with sizing run
3151 : // CheckZoneSizing is not required here because the tube length calculation is not dependent on zone sizing calculation results
3152 46 : TubeLengthDes = state.dataLowTempRadSys->HydrRadSys(RadSysNum).sizeRadiantSystemTubeLength(state);
3153 46 : if (IsAutoSize) {
3154 6 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).TubeLength = TubeLengthDes;
3155 12 : BaseSizer::reportSizerOutput(state,
3156 : CompType,
3157 6 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).Name,
3158 : "Design Size Hydronic Tubing Length [m]",
3159 : TubeLengthDes);
3160 : } else { // hard-size with sizing data
3161 40 : if (state.dataLowTempRadSys->HydrRadSys(RadSysNum).TubeLength > 0.0 && TubeLengthDes > 0.0) {
3162 40 : TubeLengthUser = state.dataLowTempRadSys->HydrRadSys(RadSysNum).TubeLength;
3163 80 : BaseSizer::reportSizerOutput(state,
3164 : CompType,
3165 40 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).Name,
3166 : "Design Size Hydronic Tubing Length [m]",
3167 : TubeLengthDes,
3168 : "User-Specified Hydronic Tubing Length [m]",
3169 : TubeLengthUser);
3170 40 : if (state.dataGlobal->DisplayExtraWarnings) {
3171 0 : if ((std::abs(TubeLengthDes - TubeLengthUser) / TubeLengthUser) > state.dataSize->AutoVsHardSizingThreshold) {
3172 0 : ShowMessage(state,
3173 0 : format("SizeLowTempRadiantSystem: Potential issue with equipment sizing for "
3174 : "ZoneHVAC:LowTemperatureRadiant:VariableFlow = \"{}\".",
3175 0 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).Name));
3176 0 : ShowContinueError(state, format("User-Specified Hydronic Tubing Length of {:.5R} [m]", TubeLengthUser));
3177 0 : ShowContinueError(state, format("differs from Design Size Hydronic Tubing Length of {:.5R} [m]", TubeLengthDes));
3178 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
3179 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
3180 : }
3181 : }
3182 : }
3183 : }
3184 : }
3185 : }
3186 :
3187 104 : for (SurfNum = 1; SurfNum <= state.dataLowTempRadSys->HydrRadSys(RadSysNum).NumOfSurfaces; ++SurfNum) {
3188 58 : if (state.dataLowTempRadSys->HydrRadSys(RadSysNum).NumCircCalcMethod == CircuitCalc::CalculateFromLength) {
3189 0 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).NumCircuits(SurfNum) =
3190 0 : (state.dataLowTempRadSys->HydrRadSys(RadSysNum).SurfaceFrac(SurfNum) *
3191 0 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).TubeLength) /
3192 0 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).CircLength;
3193 0 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).NumCircuits(SurfNum) =
3194 0 : max(state.dataLowTempRadSys->HydrRadSys(RadSysNum).NumCircuits(SurfNum), 1.0);
3195 : } else {
3196 58 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).NumCircuits(SurfNum) = 1.0;
3197 : }
3198 : }
3199 :
3200 92 : RegisterPlantCompDesignFlow(state,
3201 46 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).HotWaterInNode,
3202 46 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).WaterVolFlowMaxHeat);
3203 92 : RegisterPlantCompDesignFlow(state,
3204 46 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).ColdWaterInNode,
3205 46 : state.dataLowTempRadSys->HydrRadSys(RadSysNum).WaterVolFlowMaxCool);
3206 :
3207 27 : } else if (systemType == SystemType::ConstantFlow) {
3208 :
3209 27 : CompType = "ZoneHVAC:LowTemperatureRadiant:ConstantFlow";
3210 27 : CompName = state.dataLowTempRadSys->CFloRadSys(RadSysNum).Name;
3211 :
3212 : // Why is this not the same thing as the other OpMode enumeration? In the .hh file?
3213 : OperatingMode OpMode; // System operating mode
3214 :
3215 : // Check which operating system it is
3216 27 : int HeatNode = state.dataLowTempRadSys->CFloRadSys(RadSysNum).HotWaterInNode;
3217 27 : int CoolNode = state.dataLowTempRadSys->CFloRadSys(RadSysNum).ColdWaterInNode;
3218 27 : if (HeatNode > 0 && CoolNode > 0) {
3219 24 : OpMode = OperatingMode::ClgHtg;
3220 3 : } else if (HeatNode > 0 && CoolNode <= 0) {
3221 3 : OpMode = OperatingMode::HtgOnly;
3222 0 : } else if (CoolNode > 0 && HeatNode <= 0) {
3223 0 : OpMode = OperatingMode::ClgOnly;
3224 : } else {
3225 0 : OpMode = OperatingMode::OFF; // It shouldn't happen here
3226 : }
3227 :
3228 27 : if (state.dataLowTempRadSys->CFloRadSys(RadSysNum).WaterVolFlowMax == AutoSize) {
3229 1 : IsAutoSize = true;
3230 : }
3231 :
3232 27 : if (state.dataSize->CurZoneEqNum > 0) {
3233 27 : if (!IsAutoSize && !state.dataSize->ZoneSizingRunDone) { // simulation continue
3234 24 : if (state.dataLowTempRadSys->CFloRadSys(RadSysNum).WaterVolFlowMax > 0.0) {
3235 48 : BaseSizer::reportSizerOutput(state,
3236 : CompType,
3237 24 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).Name,
3238 : "User-Specified Maximum Water Flow [m3/s]",
3239 24 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).WaterVolFlowMax);
3240 : }
3241 : } else { // Autosize or hard-size with sizing run
3242 3 : CheckZoneSizing(state, CompType, state.dataLowTempRadSys->CFloRadSys(RadSysNum).Name);
3243 : // Estimate hot water and chilled water flows
3244 : // Index only if it provides heating to avoid severe error
3245 3 : if (OpMode == OperatingMode::ClgHtg || OpMode == OperatingMode::HtgOnly) {
3246 3 : PltSizHeatNum = MyPlantSizingIndex(state,
3247 : CompType,
3248 3 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).Name,
3249 3 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).HotWaterInNode,
3250 3 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).HotWaterOutNode,
3251 : ErrorsFound);
3252 : }
3253 3 : if (PltSizHeatNum > 0) {
3254 3 : if (state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).NonAirSysDesHeatLoad >= SmallLoad) {
3255 3 : rho = state.dataPlnt->PlantLoop(state.dataLowTempRadSys->CFloRadSys(RadSysNum).HWPlantLoc.loopNum)
3256 3 : .glycol->getDensity(state, Constant::HWInitConvTemp, "SizeLowTempRadiantSystem");
3257 3 : Cp = state.dataPlnt->PlantLoop(state.dataLowTempRadSys->CFloRadSys(RadSysNum).HWPlantLoc.loopNum)
3258 3 : .glycol->getSpecificHeat(state, Constant::HWInitConvTemp, "SizeLowTempRadiantSystem");
3259 3 : WaterVolFlowMaxHeatDes = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).NonAirSysDesHeatLoad /
3260 3 : (state.dataSize->PlantSizData(PltSizHeatNum).DeltaT * Cp * rho);
3261 : } else {
3262 0 : WaterVolFlowMaxHeatDes = 0.0;
3263 : }
3264 : } else {
3265 0 : if (OpMode == OperatingMode::ClgHtg || OpMode == OperatingMode::HtgOnly) {
3266 0 : ShowSevereError(state, "Autosizing of water flow requires a heating loop Sizing:Plant object");
3267 0 : ShowContinueError(state,
3268 0 : format("Occurs in ZoneHVAC:LowTemperatureRadiant:ConstantFlow Object={}",
3269 0 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).Name));
3270 0 : ErrorsFound = true;
3271 : }
3272 : }
3273 :
3274 : // Index only if it provides cooling system to avoid severe error
3275 3 : if (OpMode == OperatingMode::ClgHtg || OpMode == OperatingMode::ClgOnly) {
3276 3 : PltSizCoolNum = MyPlantSizingIndex(state,
3277 : CompType,
3278 3 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).Name,
3279 3 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).ColdWaterInNode,
3280 3 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).ColdWaterOutNode,
3281 : ErrorsFound);
3282 : }
3283 3 : if (PltSizCoolNum > 0) {
3284 3 : if (state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).NonAirSysDesCoolLoad >= SmallLoad) {
3285 3 : rho = state.dataPlnt->PlantLoop(state.dataLowTempRadSys->CFloRadSys(RadSysNum).CWPlantLoc.loopNum)
3286 3 : .glycol->getDensity(state, Constant::CWInitConvTemp, "SizeLowTempRadiantSystem");
3287 3 : Cp = state.dataPlnt->PlantLoop(state.dataLowTempRadSys->CFloRadSys(RadSysNum).CWPlantLoc.loopNum)
3288 3 : .glycol->getSpecificHeat(state, Constant::CWInitConvTemp, "SizeLowTempRadiantSystem");
3289 3 : WaterVolFlowMaxCoolDes = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).NonAirSysDesCoolLoad /
3290 3 : (state.dataSize->PlantSizData(PltSizCoolNum).DeltaT * Cp * rho);
3291 : } else {
3292 0 : WaterVolFlowMaxCoolDes = 0.0;
3293 : }
3294 : } else {
3295 0 : if (OpMode == OperatingMode::ClgHtg || OpMode == OperatingMode::ClgOnly) {
3296 0 : ShowSevereError(state, "Autosizing of water flow requires a cooling loop Sizing:Plant object");
3297 0 : ShowContinueError(state,
3298 0 : format("Occurs in ZoneHVAC:LowTemperatureRadiant:ConstantFlow Object={}",
3299 0 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).Name));
3300 0 : ErrorsFound = true;
3301 : }
3302 : }
3303 :
3304 : // Determine maximum water flow rate depending upon system type
3305 3 : if (OpMode == OperatingMode::ClgHtg) {
3306 3 : WaterVolFlowMaxDes = std::max(WaterVolFlowMaxHeatDes, WaterVolFlowMaxCoolDes);
3307 0 : } else if (OpMode == OperatingMode::ClgOnly) {
3308 0 : WaterVolFlowMaxDes = WaterVolFlowMaxCoolDes;
3309 0 : } else if (OpMode == OperatingMode::HtgOnly) {
3310 0 : WaterVolFlowMaxDes = WaterVolFlowMaxHeatDes;
3311 : } else {
3312 0 : WaterVolFlowMaxDes = 0.0;
3313 : }
3314 :
3315 3 : if (IsAutoSize) {
3316 1 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).WaterVolFlowMax = WaterVolFlowMaxDes;
3317 2 : BaseSizer::reportSizerOutput(state,
3318 : CompType,
3319 1 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).Name,
3320 : "Design Size Maximum Water Flow [m3/s]",
3321 : WaterVolFlowMaxDes);
3322 : } else { // hard-size with sizing data
3323 2 : if (state.dataLowTempRadSys->CFloRadSys(RadSysNum).WaterVolFlowMax > 0.0 && WaterVolFlowMaxDes > 0.0) {
3324 2 : WaterVolFlowMaxUser = state.dataLowTempRadSys->CFloRadSys(RadSysNum).WaterVolFlowMax;
3325 4 : BaseSizer::reportSizerOutput(state,
3326 : CompType,
3327 2 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).Name,
3328 : "Design Size Maximum Water Flow [m3/s]",
3329 : WaterVolFlowMaxDes,
3330 : "User-Specified Maximum Water Flow [m3/s]",
3331 : WaterVolFlowMaxUser);
3332 2 : if (state.dataGlobal->DisplayExtraWarnings) {
3333 0 : if ((std::abs(WaterVolFlowMaxDes - WaterVolFlowMaxUser) / WaterVolFlowMaxUser) >
3334 0 : state.dataSize->AutoVsHardSizingThreshold) {
3335 0 : ShowMessage(state,
3336 0 : format("SizeLowTempRadiantSystem: Potential issue with equipment sizing for "
3337 : "ZoneHVAC:LowTemperatureRadiant:ConstantFlow = \" {}\".",
3338 0 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).Name));
3339 0 : ShowContinueError(state, format("User-Specified Maximum Water Flow of {:.5R} [m3/s]", WaterVolFlowMaxUser));
3340 0 : ShowContinueError(state,
3341 0 : format("differs from Design Size Maximum Water Flow of {:.5R} [m3/s]", WaterVolFlowMaxDes));
3342 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
3343 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
3344 : }
3345 : }
3346 : }
3347 : }
3348 : }
3349 : }
3350 :
3351 27 : IsAutoSize = false;
3352 27 : if (state.dataLowTempRadSys->CFloRadSys(RadSysNum).TubeLength == AutoSize) {
3353 1 : IsAutoSize = true;
3354 : }
3355 :
3356 27 : if (state.dataSize->CurZoneEqNum > 0) {
3357 27 : if (!IsAutoSize && !state.dataSize->ZoneSizingRunDone) { // simulation continue
3358 24 : if (state.dataLowTempRadSys->CFloRadSys(RadSysNum).TubeLength > 0.0) {
3359 48 : BaseSizer::reportSizerOutput(state,
3360 : "ZoneHVAC:LowTemperatureRadiant:ConstantFlow",
3361 24 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).Name,
3362 : "User-Specified Hydronic Tubing Length [m]",
3363 24 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).TubeLength);
3364 : }
3365 : } else { // Autosize or hard-size with sizing run
3366 : // CheckZoneSizing is not required here because the tube length calculation is not dependent on zone sizing calculation results
3367 3 : TubeLengthDes = state.dataLowTempRadSys->CFloRadSys(RadSysNum).sizeRadiantSystemTubeLength(state);
3368 3 : if (IsAutoSize) {
3369 1 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).TubeLength = TubeLengthDes;
3370 2 : BaseSizer::reportSizerOutput(state,
3371 : "ZoneHVAC:LowTemperatureRadiant:ConstantFlow",
3372 1 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).Name,
3373 : "Design Size Hydronic Tubing Length [m]",
3374 : TubeLengthDes);
3375 : } else { // hard-size with sizing data
3376 2 : if (state.dataLowTempRadSys->CFloRadSys(RadSysNum).TubeLength > 0.0 && TubeLengthDes > 0.0) {
3377 2 : TubeLengthUser = state.dataLowTempRadSys->CFloRadSys(RadSysNum).TubeLength;
3378 4 : BaseSizer::reportSizerOutput(state,
3379 : "ZoneHVAC:LowTemperatureRadiant:ConstantFlow",
3380 2 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).Name,
3381 : "Design Size Hydronic Tubing Length [m]",
3382 : TubeLengthDes,
3383 : "User-Specified Hydronic Tubing Length [m]",
3384 : TubeLengthUser);
3385 2 : if (state.dataGlobal->DisplayExtraWarnings) {
3386 0 : if ((std::abs(TubeLengthDes - TubeLengthUser) / TubeLengthUser) > state.dataSize->AutoVsHardSizingThreshold) {
3387 0 : ShowMessage(state,
3388 0 : format("SizeLowTempRadiantSystem: Potential issue with equipment sizing for "
3389 : "ZoneHVAC:LowTemperatureRadiant:ConstantFlow = \" {}\".",
3390 0 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).Name));
3391 0 : ShowContinueError(state, format("User-Specified Hydronic Tubing Length of {:.5R} [m]", TubeLengthUser));
3392 0 : ShowContinueError(state, format("differs from Design Size Hydronic Tubing Length of {:.5R} [m]", TubeLengthDes));
3393 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
3394 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
3395 : }
3396 : }
3397 : }
3398 : }
3399 : }
3400 : }
3401 :
3402 54 : for (SurfNum = 1; SurfNum <= state.dataLowTempRadSys->CFloRadSys(RadSysNum).NumOfSurfaces; ++SurfNum) {
3403 27 : if (state.dataLowTempRadSys->CFloRadSys(RadSysNum).NumCircCalcMethod == CircuitCalc::CalculateFromLength) {
3404 0 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).NumCircuits(SurfNum) =
3405 0 : (state.dataLowTempRadSys->CFloRadSys(RadSysNum).SurfaceFrac(SurfNum) *
3406 0 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).TubeLength) /
3407 0 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).CircLength;
3408 0 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).NumCircuits(SurfNum) =
3409 0 : max(state.dataLowTempRadSys->CFloRadSys(RadSysNum).NumCircuits(SurfNum), 1.0);
3410 : } else {
3411 27 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).NumCircuits(SurfNum) = 1.0;
3412 : }
3413 : }
3414 27 : if (state.dataLowTempRadSys->CFloRadSys(RadSysNum).HotWaterInNode > 0) {
3415 54 : RegisterPlantCompDesignFlow(state,
3416 27 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).HotWaterInNode,
3417 27 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).WaterVolFlowMax);
3418 : }
3419 27 : if (state.dataLowTempRadSys->CFloRadSys(RadSysNum).ColdWaterInNode > 0) {
3420 48 : RegisterPlantCompDesignFlow(state,
3421 24 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).ColdWaterInNode,
3422 24 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).WaterVolFlowMax);
3423 : }
3424 : }
3425 :
3426 82 : if (ErrorsFound) {
3427 0 : ShowFatalError(state, "Preceding sizing errors cause program termination");
3428 : }
3429 82 : }
3430 :
3431 49 : Real64 HydronicSystemBaseData::sizeRadiantSystemTubeLength(EnergyPlusData &state)
3432 : {
3433 :
3434 : // SUBROUTINE INFORMATION:
3435 : // AUTHOR Rick Strand
3436 : // DATE WRITTEN August 2017
3437 :
3438 : // PURPOSE OF THIS SUBROUTINE:
3439 : // This subroutine figures out the tube length based on the spacing of tubes.
3440 : // For single surface systems, this is fairly easy as there is only one spacing
3441 : // to deal with. For multi-surface systems, more work is necessary because each
3442 : // surface could use a different spacing.
3443 :
3444 : // Return value
3445 : Real64 sizeRadiantSystemTubeLength;
3446 :
3447 49 : Real64 tubeLength(0.0); // temporary holding place for the function calculation
3448 :
3449 110 : for (int surfNum = 1; surfNum <= this->NumOfSurfaces; ++surfNum) {
3450 61 : auto &thisHydrSysSurf = state.dataSurface->Surface(this->SurfacePtr(surfNum));
3451 61 : auto const &thisHydrSpacing = state.dataConstruction->Construct(thisHydrSysSurf.Construction).ThicknessPerpend;
3452 61 : if ((thisHydrSpacing > 0.005) && (thisHydrSpacing < 0.5)) { // limit allowable spacing to between 1cm and 1m
3453 61 : tubeLength += thisHydrSysSurf.Area / (2.0 * thisHydrSpacing);
3454 : } else { // if not in allowable limit, default back to 0.15m (15cm or 6 inches)
3455 0 : tubeLength += thisHydrSysSurf.Area / 0.15;
3456 : }
3457 : }
3458 :
3459 49 : sizeRadiantSystemTubeLength = tubeLength;
3460 49 : return sizeRadiantSystemTubeLength;
3461 : }
3462 :
3463 366056 : void VariableFlowRadiantSystemData::calculateLowTemperatureRadiantSystem(EnergyPlusData &state,
3464 : Real64 &LoadMet) // load met by the radiant system, in Watts
3465 : {
3466 :
3467 : // SUBROUTINE INFORMATION:
3468 : // AUTHOR Rick Strand
3469 : // DATE WRITTEN November 2000
3470 :
3471 : // PURPOSE OF THIS SUBROUTINE:
3472 : // This subroutine does all of the stuff that is necessary to simulate
3473 : // a low temperature hydronic radiant heating/cooling system. Calls are
3474 : // made to appropriate subroutines either in this module or outside of it.
3475 :
3476 : // METHODOLOGY EMPLOYED:
3477 : // Follows the methods used by many other pieces of zone equipment.
3478 : // Much like a water coil, a hydronic system will use the ControlCompOutput
3479 : // routine to determine what fraction of capacity the unit should be
3480 : // functioning at by controlling the flow rate of water to the element.
3481 :
3482 : // REFERENCES:
3483 : // Other EnergyPlus modules
3484 : // IBLAST-QTF research program, completed in January 1995 (unreleased)
3485 : // Strand, R.K. 1995. "Heat Source Transfer Functions and Their Application to
3486 : // Low Temperature Radiant Heating Systems", Ph.D. dissertation, University
3487 : // of Illinois at Urbana-Champaign, Department of Mechanical and Industrial
3488 : // Engineering.
3489 : // Seem, J.E. 1986. "Heat Transfer in Buildings", Ph.D. dissertation, University
3490 : // of Wisconsin-Madison.
3491 :
3492 : // Using/Aliasing
3493 : using DataHeatBalance::ZoneData;
3494 : using HVAC::SmallLoad;
3495 : using PlantUtilities::SetComponentFlowRate;
3496 :
3497 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
3498 : Real64 ActWaterFlow; // actual water flow for heating or cooling [kg/sec]
3499 : Real64 ControlTemp; // temperature of whatever is controlling the radiant system
3500 : Real64 MassFlowFrac; // fraction of the maximum water flow rate as determined by the control algorithm
3501 : Real64 MaxWaterFlow; // maximum water flow for heating or cooling [kg/sec]
3502 : Real64 OffTempCool; // temperature at which the flow rate throttles back to zero for cooling
3503 : Real64 OffTempHeat; // temperature at which the flow rate throttles back to zero for heating
3504 : Real64 mdot; // local temporary for fluid mass flow rate
3505 : bool SysRunning; // True when system is running
3506 :
3507 : VarFlowRadDesignData variableFlowDesignDataObject = // Is this intended to be a copy?
3508 366056 : state.dataLowTempRadSys->HydronicRadiantSysDesign(this->DesignObjectPtr); // Contains the data for variable flow hydronic systems
3509 :
3510 366056 : MaxWaterFlow = 0.0;
3511 366056 : ActWaterFlow = 0.0;
3512 366056 : this->opMode = OpMode::None;
3513 366056 : SysRunning = true;
3514 :
3515 366056 : if (this->availSched->getCurrentVal() <= 0) {
3516 :
3517 : // Unit is off or has no load upon it; set the flow rates to zero and then
3518 : // simulate the components with the no flow conditions
3519 15426 : for (int SurfNum = 1; SurfNum <= this->NumOfSurfaces; ++SurfNum) {
3520 7713 : int SurfNum2 = this->SurfacePtr(SurfNum);
3521 7713 : auto &surface = state.dataSurface->Surface(SurfNum2);
3522 7713 : state.dataHeatBalFanSys->QRadSysSource(SurfNum2) = 0.0;
3523 7713 : if (surface.ExtBoundCond > 0 && surface.ExtBoundCond != SurfNum2) {
3524 0 : state.dataHeatBalFanSys->QRadSysSource(surface.ExtBoundCond) = 0.0; // Also zero the other side of an interzone
3525 : }
3526 : }
3527 7713 : if (this->HeatingSystem) {
3528 7710 : mdot = 0.0;
3529 7710 : SetComponentFlowRate(state, mdot, this->HotWaterInNode, this->HotWaterOutNode, this->HWPlantLoc);
3530 : }
3531 7713 : if (this->CoolingSystem) {
3532 0 : mdot = 0.0;
3533 0 : SetComponentFlowRate(state, mdot, this->ColdWaterInNode, this->ColdWaterOutNode, this->CWPlantLoc);
3534 : }
3535 : } else { // Unit might be on-->this section is intended to control the water mass flow rate being
3536 : // sent to the radiant system
3537 :
3538 358343 : ControlTemp = this->setRadiantSystemControlTemperature(state, variableFlowDesignDataObject.VarFlowControlType);
3539 :
3540 358343 : if (variableFlowDesignDataObject.heatSetptSched != nullptr) {
3541 : // OffTempHeat = this->setOffTemperatureLowTemperatureRadiantSystem(state, this->HotSetptSchedPtr,
3542 : // this->HotThrottlRange);
3543 : Real64 a;
3544 358343 : a = variableFlowDesignDataObject.HotThrottlRange; // Why are we doing this?
3545 358343 : OffTempHeat = this->setOffTemperatureLowTemperatureRadiantSystem(state,
3546 358343 : variableFlowDesignDataObject.heatSetptSched,
3547 : variableFlowDesignDataObject.HotThrottlRange,
3548 : variableFlowDesignDataObject.VarFlowSetpointType);
3549 : } else { // This system is not capable of heating, set OffTempHeat to something really low
3550 0 : OffTempHeat = state.dataLowTempRadSys->LowTempHeating;
3551 : }
3552 358343 : if (variableFlowDesignDataObject.coolSetptSched != nullptr) {
3553 351248 : OffTempCool = this->setOffTemperatureLowTemperatureRadiantSystem(state,
3554 351248 : variableFlowDesignDataObject.coolSetptSched,
3555 351248 : -variableFlowDesignDataObject.ColdThrottlRange,
3556 : variableFlowDesignDataObject.VarFlowSetpointType);
3557 : } else { // This system is not capable of cooling, set OffTempCool to something really high
3558 7095 : OffTempCool = state.dataLowTempRadSys->HighTempCooling;
3559 : }
3560 :
3561 : // Check for an illogical condition where a user enters controls that could
3562 : // potentially be heating or cooling at a particular control temperature
3563 358343 : if (OffTempHeat > OffTempCool) {
3564 0 : MassFlowFrac = 0.0;
3565 0 : ShowSevereError(state, format("Overlapping heating and cooling control temps in radiant system: {}", this->Name));
3566 0 : ShowFatalError(state, "Preceding condition causes termination.");
3567 :
3568 : } else { // Temperatures for heating and cooling do not overlap--calculate the mass flow fraction
3569 :
3570 358343 : if (ControlTemp < OffTempHeat && this->HeatingSystem) { // Heating mode
3571 154356 : this->opMode = OpMode::Heat;
3572 203987 : } else if (ControlTemp > OffTempCool && this->CoolingSystem) { // Cooling mode
3573 140407 : this->opMode = OpMode::Cool;
3574 : }
3575 :
3576 358343 : this->setOperatingModeBasedOnChangeoverDelay(state);
3577 :
3578 358343 : if (this->opMode == OpMode::Heat) {
3579 151202 : MaxWaterFlow = this->WaterFlowMaxHeat;
3580 151202 : MassFlowFrac = this->calculateOperationalFraction(OffTempHeat, ControlTemp, variableFlowDesignDataObject.HotThrottlRange);
3581 207141 : } else if (this->opMode == OpMode::Cool) {
3582 139753 : MaxWaterFlow = this->WaterFlowMaxCool;
3583 139753 : MassFlowFrac = this->calculateOperationalFraction(OffTempCool, ControlTemp, variableFlowDesignDataObject.ColdThrottlRange);
3584 : } else {
3585 67388 : MassFlowFrac = 0.0;
3586 : }
3587 : }
3588 :
3589 : // Calculate and limit the water flow rate
3590 358343 : ActWaterFlow = MassFlowFrac * MaxWaterFlow;
3591 358343 : if (ActWaterFlow < DataBranchAirLoopPlant::MassFlowTolerance) {
3592 67388 : ActWaterFlow = 0.0;
3593 : }
3594 358343 : if (this->EMSOverrideOnWaterMdot) {
3595 0 : ActWaterFlow = this->EMSWaterMdotOverrideValue;
3596 : }
3597 :
3598 358343 : if (this->opMode == OpMode::Heat) {
3599 151202 : if (this->HeatingSystem) {
3600 151202 : SetComponentFlowRate(state, ActWaterFlow, this->HotWaterInNode, this->HotWaterOutNode, this->HWPlantLoc);
3601 : } else { // not heating system
3602 0 : SysRunning = false;
3603 : }
3604 207141 : } else if (this->opMode == OpMode::Cool) {
3605 139753 : if (this->CoolingSystem) {
3606 139753 : SetComponentFlowRate(state, ActWaterFlow, this->ColdWaterInNode, this->ColdWaterOutNode, this->CWPlantLoc);
3607 : } else { // not cooling system
3608 0 : SysRunning = false;
3609 : }
3610 : }
3611 :
3612 : // Now simulate the system...
3613 358343 : if (((this->opMode == OpMode::Heat) || (this->opMode == OpMode::Cool)) && SysRunning) {
3614 290955 : this->calculateLowTemperatureRadiantSystemComponents(state, LoadMet, SystemType::Hydronic);
3615 : }
3616 : }
3617 366056 : }
3618 :
3619 290955 : void VariableFlowRadiantSystemData::calculateLowTemperatureRadiantSystemComponents(
3620 : EnergyPlusData &state,
3621 : Real64 &LoadMet,
3622 : SystemType const typeOfRadiantSystem) // Load met by the low temperature radiant system, in Watts
3623 : {
3624 :
3625 : // SUBROUTINE INFORMATION:
3626 : // AUTHOR Rick Strand
3627 : // DATE WRITTEN November 2000
3628 : // MODIFIED Sep 2011 LKL/BG - resimulate only zones needing it for Radiant systems
3629 :
3630 : // PURPOSE OF THIS SUBROUTINE:
3631 : // This subroutine solves the radiant system based on how much water is (and
3632 : // the conditions of the water) supplied to the radiant system.
3633 :
3634 : // METHODOLOGY EMPLOYED:
3635 : // Use heat exchanger formulas to obtain the heat source/sink for the radiant
3636 : // system based on the inlet conditions and flow rate of water. Once that is
3637 : // determined, recalculate the surface heat balances to reflect this heat
3638 : // addition/subtraction. The load met by the system is determined by the
3639 : // difference between the convection from all surfaces in the zone when
3640 : // there was no radiant system output and with a source/sink added.
3641 :
3642 : // REFERENCES:
3643 : // IBLAST-QTF research program, completed in January 1995 (unreleased)
3644 : // Strand, R.K. 1995. "Heat Source Transfer Functions and Their Application to
3645 : // Low Temperature Radiant Heating Systems", Ph.D. dissertation, University
3646 : // of Illinois at Urbana-Champaign, Department of Mechanical and Industrial
3647 : // Engineering.
3648 :
3649 290955 : auto &Zone = state.dataHeatBal->Zone;
3650 :
3651 : // Using/Aliasing
3652 : using PlantUtilities::SetComponentFlowRate;
3653 :
3654 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
3655 : Real64 DewPointTemp; // Dew-point temperature based on the zone air conditions
3656 : Real64 EpsMdotCp; // Epsilon (heat exchanger terminology) times water mass flow rate times water specific heat
3657 : Real64 FullWaterMassFlow; // Original water mass flow rate before reducing the flow for condensation concerns
3658 : Real64 LowestRadSurfTemp; // Lowest surface temperature of a radiant system (when condensation is a concern)
3659 : Real64 PredictedCondTemp; // Temperature at which condensation is predicted (includes user parameter)
3660 : Real64 ReductionFrac; // Fraction that the flow should be reduced to avoid condensation
3661 : Real64 SysWaterMassFlow; // System level water mass flow rate (includes effect of zone multiplier)
3662 : Real64 WaterMassFlow; // Water mass flow rate in the radiant system, kg/s
3663 : int WaterNodeIn; // Node number of the water entering the radiant system
3664 : Real64 WaterTempIn; // Temperature of the water entering the radiant system, in C
3665 : Real64 ZeroFlowSurfTemp; // Temperature of radiant surface when flow is zero
3666 : int ZoneNum; // Zone pointer for this radiant system
3667 :
3668 : VarFlowRadDesignData variableFlowDesignDataObject = // Is this intended to be a deep copy?
3669 290955 : state.dataLowTempRadSys->HydronicRadiantSysDesign(this->DesignObjectPtr); // Contains the data for variable flow hydronic systems
3670 :
3671 290955 : auto &Surface = state.dataSurface->Surface;
3672 :
3673 : Real64 Ca; // Coefficients to relate the inlet water temperature to the heat source
3674 : Real64 Cb;
3675 : Real64 Cc;
3676 : Real64 Cd;
3677 : Real64 Ce;
3678 : Real64 Cf;
3679 : Real64 Cg;
3680 : Real64 Ch;
3681 : Real64 Ci;
3682 : Real64 Cj;
3683 : Real64 Ck;
3684 : Real64 Cl;
3685 : // For more info on Ca through Cl, see comments below
3686 :
3687 : // First, apply heat exchanger logic to find the heat source/sink to the system.
3688 : // This involves finding out the heat transfer characteristics of the hydronic
3689 : // loop and then applying the equations derived on pp. 113-118 of the dissertation.
3690 :
3691 : // Set the conditions on the water side inlet
3692 290955 : switch (this->opMode) {
3693 151202 : case OpMode::Heat: {
3694 151202 : WaterNodeIn = this->HotWaterInNode;
3695 151202 : } break;
3696 139753 : case OpMode::Cool: {
3697 139753 : WaterNodeIn = this->ColdWaterInNode;
3698 139753 : } break;
3699 0 : default: {
3700 0 : WaterNodeIn = 0; // Suppress uninitialized warning
3701 0 : ShowSevereError(state, "Illegal low temperature radiant system operating mode");
3702 0 : ShowContinueError(state, format("Occurs in Radiant System={}", this->Name));
3703 0 : ShowFatalError(state, "Preceding condition causes termination.");
3704 0 : } break;
3705 : }
3706 290955 : ZoneNum = this->ZonePtr;
3707 290955 : SysWaterMassFlow = state.dataLoopNodes->Node(WaterNodeIn).MassFlowRate;
3708 290955 : WaterMassFlow = state.dataLoopNodes->Node(WaterNodeIn).MassFlowRate / double(Zone(ZoneNum).Multiplier * Zone(ZoneNum).ListMultiplier);
3709 290955 : WaterTempIn = state.dataLoopNodes->Node(WaterNodeIn).Temp;
3710 :
3711 290955 : if (WaterMassFlow <= 0.0) {
3712 : // No flow or below minimum allowed so there is no heat source/sink
3713 : // This is possible with a mismatch between system and plant operation
3714 : // or a slight mismatch between zone and system controls. This is not
3715 : // necessarily a "problem" so this exception is necessary in the code.
3716 72 : for (int RadSurfNum = 1; RadSurfNum <= this->NumOfSurfaces; ++RadSurfNum) {
3717 36 : int SurfNum = this->SurfacePtr(RadSurfNum);
3718 36 : state.dataHeatBalFanSys->QRadSysSource(SurfNum) = 0.0;
3719 36 : if (Surface(SurfNum).ExtBoundCond > 0 && Surface(SurfNum).ExtBoundCond != SurfNum) {
3720 0 : state.dataHeatBalFanSys->QRadSysSource(Surface(SurfNum).ExtBoundCond) = 0.0; // Also zero the other side of an interzone
3721 : }
3722 : }
3723 :
3724 : } else {
3725 :
3726 607630 : for (int RadSurfNum = 1; RadSurfNum <= this->NumOfSurfaces; ++RadSurfNum) {
3727 :
3728 316711 : int SurfNum = this->SurfacePtr(RadSurfNum);
3729 : // Determine the heat exchanger "effectiveness" term
3730 :
3731 1266844 : EpsMdotCp = calculateHXEffectivenessTerm(state,
3732 : SurfNum,
3733 : WaterTempIn,
3734 : WaterMassFlow,
3735 316711 : this->SurfaceFrac(RadSurfNum),
3736 316711 : this->NumCircuits(RadSurfNum),
3737 : this->DesignObjectPtr,
3738 : typeOfRadiantSystem);
3739 :
3740 : // Obtain the heat balance coefficients and calculate the intermediate coefficients
3741 : // linking the inlet water temperature to the heat source/sink to the radiant system.
3742 : // The coefficients are based on the following development...
3743 : // The heat balance equations at the outside and inside surfaces are of the form:
3744 : // Tinside = Ca + Cb*Toutside + Cc*q"
3745 : // Toutside = Cd + Ce*Tinside + Cf*q"
3746 : // Tsource = Cg + Ch*q" + Ci*Tinside + Cj*Toutside
3747 : // where:
3748 : // Tinside is the temperature at the inside surface
3749 : // Toutside is the temperature at the outside surface
3750 : // Tsource is the temperature within the radiant system at the location of the source/sink
3751 : // Ca is all of the other terms in the inside heat balance (solar, LW exchange, conduction history terms, etc.)
3752 : // Cb is the current cross CTF term
3753 : // Cc is the QTF inside term for the current heat source/sink
3754 : // Cd is all of the other terms in the outside heat balance (solar, LW exchange, conduction history terms, etc.)
3755 : // Ce is the current cross CTF term (should be equal to Cb)
3756 : // Cf is the QTF outside term for the current heat source/sink
3757 : // Cg is the summation of all temperature and source history terms at the source/sink location
3758 : // Ch is the QTF term at the source/sink location for the current heat source/sink
3759 : // Ci is the CTF inside term for the current inside surface temperature
3760 : // Cj is the CTF outside term for the current outside surface temperature
3761 : // Note that it is necessary to not use "slow conduction" assumptions because the
3762 : // source/sink has an impact on BOTH the inside and outside surface heat balances.
3763 : // Hence the more general formulation.
3764 : // The first two T equations above can be solved to remove the other surface temperature.
3765 : // This results in the following equations:
3766 : // Tinside = Ca + Cb*(Cd + Ce*Tinside + Cf*q") + Cc*q" or...
3767 : // Tinside = (Ca + Cb*Cd + (Cc+Cb*Cf)*q") / (1 - Ce*Cb)
3768 : // Toutside = Cd + Ce*(Ca + Cb*Toutside + Cc*q") + Cf*q" or...
3769 : // Toutside = (Cd + Ce*Ca + (Cf+Ce*Cc)*q") / (1 - Ce*Cb)
3770 : // Substituting the new equations for Tinside and Toutside as a function of C and q"
3771 : // into the equation for Tsource...
3772 : // Tsource = Cg + Ch*q" + Ci*((Ca + Cb*Cd + (Cc+Cb*Cf)*q") / (1 - Ce*Cb)) &
3773 : // + Cj*((Cd + Ce*Ca + (Cf+Ce*Cc)*q") / (1 - Ce*Cb))
3774 : // Or rearranging this to get Tsource as a function of q", we get...
3775 : // Tsource = Cg + ((Ci*(Ca + Cb*Cd) + Cj*(Cd + Ce*Ca))/(1-Ce*Cb)) &
3776 : // +(Ch + ((Ci*(Cc + Cb*Cf) + Cj*(Cf + Ce*Cc))/(1-Ce*Cb)))*q"
3777 : // Or in a slightly simpler form...
3778 : // Tsource = Ck + Cl*q"
3779 : // where:
3780 : // Ck = Cg + ((Ci*(Ca + Cb*Cd) + Cj*(Cd + Ce*Ca))/(1-Ce*Cb))
3781 : // Cl = Ch + ((Ci*(Cc + Cb*Cf) + Cj*(Cf + Ce*Cc))/(1-Ce*Cb))
3782 : // Note also that from heat exchanger "algebra", we have:
3783 : // q = epsilon*qmax and qmax = Mdot*Cp*(Twaterin-Tsource)
3784 : // So...
3785 : // q" = q/Area = (epsilon*Mdot*Cp/Area)*(Twaterin-Tsource)
3786 : // Or rearranging this equation:
3787 : // Tsource = -(q"*A/(epsilon*Mdot*Cp)) + Twaterin
3788 : // Setting this equation equal to the other equation for Tsource a couple lines up
3789 : // and rearranging to solve for q"...
3790 : // q" = (Twaterin - Ck) / (Cl + (A/(epsilon*Mdot*Cp))
3791 : // or
3792 : // q = (Twaterin - Ck) / ((Cl/A) + (1/epsilon*Mdot*Cp))
3793 : // or
3794 : // q = epsilon*Mdot*Cp*(Twaterin - Ck) / (1+(epsilon*Mdot*Cp*Cl/A))
3795 : // which is the desired result, that is the heat source or sink to the radiant
3796 : // system as a function of the water inlet temperature (flow rate is also in there
3797 : // as well as all of the heat balance terms "hidden" in Ck and Cl).
3798 316711 : int ConstrNum = Surface(SurfNum).Construction;
3799 316711 : auto const &thisConstruct = state.dataConstruction->Construct(ConstrNum);
3800 :
3801 316711 : if (Surface(SurfNum).HeatTransferAlgorithm == DataSurfaces::HeatTransferModel::CTF) {
3802 :
3803 202723 : Ca = state.dataHeatBalFanSys->RadSysTiHBConstCoef(SurfNum);
3804 202723 : Cb = state.dataHeatBalFanSys->RadSysTiHBToutCoef(SurfNum);
3805 202723 : Cc = state.dataHeatBalFanSys->RadSysTiHBQsrcCoef(SurfNum);
3806 :
3807 202723 : Cd = state.dataHeatBalFanSys->RadSysToHBConstCoef(SurfNum);
3808 202723 : Ce = state.dataHeatBalFanSys->RadSysToHBTinCoef(SurfNum);
3809 202723 : Cf = state.dataHeatBalFanSys->RadSysToHBQsrcCoef(SurfNum);
3810 :
3811 202723 : Cg = state.dataHeatBalFanSys->CTFTsrcConstPart(SurfNum);
3812 202723 : Ch = thisConstruct.CTFTSourceQ[0];
3813 202723 : Ci = thisConstruct.CTFTSourceIn[0];
3814 202723 : Cj = thisConstruct.CTFTSourceOut[0];
3815 :
3816 202723 : Ck = Cg + ((Ci * (Ca + Cb * Cd) + Cj * (Cd + Ce * Ca)) / (1.0 - Ce * Cb));
3817 202723 : Cl = Ch + ((Ci * (Cc + Cb * Cf) + Cj * (Cf + Ce * Cc)) / (1.0 - Ce * Cb));
3818 :
3819 202723 : state.dataHeatBalFanSys->QRadSysSource(SurfNum) =
3820 202723 : EpsMdotCp * (WaterTempIn - Ck) / (1.0 + (EpsMdotCp * Cl / Surface(SurfNum).Area));
3821 :
3822 113988 : } else if (Surface(SurfNum).HeatTransferAlgorithm == DataSurfaces::HeatTransferModel::CondFD) {
3823 :
3824 113988 : state.dataHeatBalFanSys->QRadSysSource(SurfNum) = EpsMdotCp * (WaterTempIn - state.dataHeatBalFanSys->TCondFDSourceNode(SurfNum));
3825 : }
3826 :
3827 316711 : if (Surface(SurfNum).ExtBoundCond > 0 && Surface(SurfNum).ExtBoundCond != SurfNum) {
3828 4708 : state.dataHeatBalFanSys->QRadSysSource(Surface(SurfNum).ExtBoundCond) =
3829 4708 : state.dataHeatBalFanSys->QRadSysSource(SurfNum); // Also set the other side of an interzone
3830 : }
3831 : }
3832 :
3833 : // "Temperature Comparison" Cut-off:
3834 595782 : for (int RadSurfNum = 1; RadSurfNum <= this->NumOfSurfaces; ++RadSurfNum) {
3835 : // Check to see whether or not the system should really be running. If
3836 : // QRadSysSource is negative when we are in heating mode or QRadSysSource
3837 : // is positive when we are in cooling mode, then the radiant system will
3838 : // be doing the opposite of its intention. In this case, the flow rate
3839 : // is set to zero to avoid heating in cooling mode or cooling in heating
3840 : // mode.
3841 316711 : int SurfNum = this->SurfacePtr(RadSurfNum);
3842 :
3843 633422 : if (((this->opMode == OpMode::Heat) && (state.dataHeatBalFanSys->QRadSysSource(SurfNum) <= 0.0)) ||
3844 316711 : ((this->opMode == OpMode::Cool) && (state.dataHeatBalFanSys->QRadSysSource(SurfNum) >= 0.0))) {
3845 11848 : WaterMassFlow = 0.0;
3846 11848 : if (this->opMode == OpMode::Heat) {
3847 0 : SetComponentFlowRate(state, WaterMassFlow, this->HotWaterInNode, this->HotWaterOutNode, this->HWPlantLoc);
3848 :
3849 11848 : } else if (this->opMode == OpMode::Cool) {
3850 11848 : SetComponentFlowRate(state, WaterMassFlow, this->ColdWaterInNode, this->ColdWaterOutNode, this->CWPlantLoc);
3851 : }
3852 11848 : this->WaterMassFlowRate = WaterMassFlow;
3853 11848 : this->opMode = OpMode::None;
3854 :
3855 23696 : for (int RadSurfNum2 = 1; RadSurfNum2 <= this->NumOfSurfaces; ++RadSurfNum2) {
3856 11848 : int SurfNum2 = this->SurfacePtr(RadSurfNum2);
3857 11848 : state.dataHeatBalFanSys->QRadSysSource(SurfNum2) = 0.0;
3858 11848 : if (Surface(SurfNum2).ExtBoundCond > 0 && Surface(SurfNum2).ExtBoundCond != SurfNum2) {
3859 0 : state.dataHeatBalFanSys->QRadSysSource(Surface(SurfNum2).ExtBoundCond) = 0.0; // Also zero the other side of an interzone
3860 : }
3861 : }
3862 11848 : break; // outer do loop
3863 : }
3864 : }
3865 :
3866 : // Condensation Cut-off:
3867 : // Check to see whether there are any surface temperatures within the radiant system that have
3868 : // dropped below the dew-point temperature. If so, we need to shut off this radiant system.
3869 : // A safety parameter is added (hardwired parameter) to avoid getting too close to condensation
3870 : // conditions.
3871 290919 : this->CondCausedShutDown = false;
3872 290919 : DewPointTemp =
3873 290919 : PsyTdpFnWPb(state, state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum).airHumRat, state.dataEnvrn->OutBaroPress);
3874 :
3875 290919 : if ((this->opMode == OpMode::Cool) && (variableFlowDesignDataObject.condCtrlType == CondCtrlType::SimpleOff)) {
3876 :
3877 151519 : for (int RadSurfNum2 = 1; RadSurfNum2 <= this->NumOfSurfaces; ++RadSurfNum2) {
3878 81528 : if (state.dataHeatBalSurf->SurfInsideTempHist(1)(this->SurfacePtr(RadSurfNum2)) <
3879 81528 : (DewPointTemp + variableFlowDesignDataObject.CondDewPtDeltaT)) {
3880 : // Condensation warning--must shut off radiant system
3881 4925 : this->CondCausedShutDown = true;
3882 4925 : WaterMassFlow = 0.0;
3883 4925 : this->opMode = OpMode::None;
3884 4925 : SetComponentFlowRate(state, WaterMassFlow, this->ColdWaterInNode, this->ColdWaterOutNode, this->CWPlantLoc);
3885 4925 : this->WaterMassFlowRate = WaterMassFlow;
3886 9850 : for (int RadSurfNum3 = 1; RadSurfNum3 <= this->NumOfSurfaces; ++RadSurfNum3) {
3887 4925 : int SurfNum2 = this->SurfacePtr(RadSurfNum3);
3888 4925 : state.dataHeatBalFanSys->QRadSysSource(SurfNum2) = 0.0;
3889 4925 : if (Surface(SurfNum2).ExtBoundCond > 0 && Surface(SurfNum2).ExtBoundCond != SurfNum2) {
3890 0 : state.dataHeatBalFanSys->QRadSysSource(Surface(SurfNum2).ExtBoundCond) =
3891 : 0.0; // Also zero the other side of an interzone
3892 : }
3893 : }
3894 : // Produce a warning message so that user knows the system was shut-off due to potential for condensation
3895 4925 : if (!state.dataGlobal->WarmupFlag) {
3896 727 : if (this->CondErrIndex == 0) { // allow errors up to number of radiant systems
3897 10 : ShowWarningMessage(state, format("{} [{}]", cHydronicSystem, this->Name));
3898 20 : ShowContinueError(state,
3899 20 : format("Surface [{}] temperature below dew-point temperature--potential for condensation exists",
3900 10 : Surface(this->SurfacePtr(RadSurfNum2)).Name));
3901 20 : ShowContinueError(state, "Flow to the radiant system will be shut-off to avoid condensation");
3902 20 : ShowContinueError(state,
3903 20 : format("Predicted radiant system surface temperature = {:.2R}",
3904 10 : state.dataHeatBalSurf->SurfInsideTempHist(1)(this->SurfacePtr(RadSurfNum2))));
3905 20 : ShowContinueError(state,
3906 20 : format("Zone dew-point temperature + safety delta T= {:.2R}",
3907 10 : DewPointTemp + variableFlowDesignDataObject.CondDewPtDeltaT));
3908 20 : ShowContinueErrorTimeStamp(state, "");
3909 20 : ShowContinueError(state,
3910 20 : format("Note that a {:.4R} C safety was chosen in the input for the shut-off criteria",
3911 : variableFlowDesignDataObject.CondDewPtDeltaT));
3912 30 : ShowContinueError(state, "Note also that this affects all surfaces that are part of this radiant system");
3913 : }
3914 5816 : ShowRecurringWarningErrorAtEnd(state,
3915 1454 : format("{} [{}] condensation shut-off occurrence continues.", cHydronicSystem, this->Name),
3916 727 : this->CondErrIndex,
3917 : DewPointTemp,
3918 : DewPointTemp,
3919 : _,
3920 : "C",
3921 : "C");
3922 : }
3923 4925 : break; // outer do loop
3924 : }
3925 : }
3926 :
3927 290919 : } else if ((this->opMode == OpMode::Cool) && (variableFlowDesignDataObject.condCtrlType == CondCtrlType::None)) {
3928 :
3929 91090 : for (int RadSurfNum2 = 1; RadSurfNum2 <= this->NumOfSurfaces; ++RadSurfNum2) {
3930 46477 : if (state.dataHeatBalSurf->SurfInsideTempHist(1)(this->SurfacePtr(RadSurfNum2)) < DewPointTemp) {
3931 : // Condensation occurring but user does not want to shut radiant system off ever
3932 19131 : this->CondCausedShutDown = true;
3933 : }
3934 : }
3935 :
3936 216003 : } else if ((this->opMode == OpMode::Cool) && (variableFlowDesignDataObject.condCtrlType == CondCtrlType::VariedOff)) {
3937 :
3938 8346 : LowestRadSurfTemp = 999.9;
3939 8346 : int CondSurfNum = 0;
3940 16692 : for (int RadSurfNum2 = 1; RadSurfNum2 <= this->NumOfSurfaces; ++RadSurfNum2) {
3941 8346 : if (state.dataHeatBalSurf->SurfInsideTempHist(1)(this->SurfacePtr(RadSurfNum2)) <
3942 8346 : (DewPointTemp + variableFlowDesignDataObject.CondDewPtDeltaT)) {
3943 4015 : if (state.dataHeatBalSurf->SurfInsideTempHist(1)(this->SurfacePtr(RadSurfNum2)) < LowestRadSurfTemp) {
3944 4015 : LowestRadSurfTemp = state.dataHeatBalSurf->SurfInsideTempHist(1)(this->SurfacePtr(RadSurfNum2));
3945 4015 : CondSurfNum = RadSurfNum2;
3946 : }
3947 : }
3948 : }
3949 :
3950 8346 : if (CondSurfNum > 0) { // Condensation predicted so let's deal with it
3951 : // Process here is: turn everything off and see what the resulting surface temperature is for
3952 : // the surface that was causing the lowest temperature. Then, interpolate to find the flow that
3953 : // would still allow the system to operate without producing condensation. Rerun the heat balance
3954 : // and recheck for condensation. If condensation still exists, shut everything down. This avoids
3955 : // excessive iteration and still makes an attempt to vary the flow rate.
3956 : // First, shut everything off...
3957 4015 : FullWaterMassFlow = WaterMassFlow;
3958 4015 : WaterMassFlow = 0.0;
3959 4015 : SetComponentFlowRate(state, WaterMassFlow, this->ColdWaterInNode, this->ColdWaterOutNode, this->CWPlantLoc);
3960 4015 : this->WaterMassFlowRate = WaterMassFlow;
3961 8030 : for (int RadSurfNum3 = 1; RadSurfNum3 <= this->NumOfSurfaces; ++RadSurfNum3) {
3962 4015 : int SurfNum2 = this->SurfacePtr(RadSurfNum3);
3963 4015 : state.dataHeatBalFanSys->QRadSysSource(SurfNum2) = 0.0;
3964 4015 : if (Surface(SurfNum2).ExtBoundCond > 0 && Surface(SurfNum2).ExtBoundCond != SurfNum2) {
3965 0 : state.dataHeatBalFanSys->QRadSysSource(Surface(SurfNum2).ExtBoundCond) = 0.0; // Also zero the other side of an interzone
3966 : }
3967 : }
3968 : // Redo the heat balances since we have changed the heat source (set it to zero)
3969 4015 : HeatBalanceSurfaceManager::CalcHeatBalanceOutsideSurf(state, ZoneNum);
3970 4015 : HeatBalanceSurfaceManager::CalcHeatBalanceInsideSurf(state, ZoneNum);
3971 : // Now check all of the surface temperatures. If any potentially have condensation, leave the system off.
3972 8030 : for (int RadSurfNum2 = 1; RadSurfNum2 <= this->NumOfSurfaces; ++RadSurfNum2) {
3973 4015 : if (state.dataHeatBalSurf->SurfInsideTempHist(1)(this->SurfacePtr(RadSurfNum2)) <
3974 4015 : (DewPointTemp + variableFlowDesignDataObject.CondDewPtDeltaT)) {
3975 0 : this->CondCausedShutDown = true;
3976 : }
3977 : }
3978 : // If the system does not need to be shut down, then let's see if we can vary the flow based
3979 : // on the lowest temperature surface from before. This will use interpolation to try a new
3980 : // flow rate.
3981 4015 : if (!this->CondCausedShutDown) {
3982 4015 : PredictedCondTemp = DewPointTemp + variableFlowDesignDataObject.CondDewPtDeltaT;
3983 4015 : ZeroFlowSurfTemp = state.dataHeatBalSurf->SurfInsideTempHist(1)(this->SurfacePtr(CondSurfNum));
3984 4015 : ReductionFrac = (ZeroFlowSurfTemp - PredictedCondTemp) / std::abs(ZeroFlowSurfTemp - LowestRadSurfTemp);
3985 4015 : if (ReductionFrac < 0.0) {
3986 0 : ReductionFrac = 0.0; // Shouldn't happen as the above check should have screened this out
3987 : }
3988 4015 : if (ReductionFrac > 1.0) {
3989 0 : ReductionFrac = 1.0; // Shouldn't happen either because condensation doesn't exist then
3990 : }
3991 4015 : WaterMassFlow = ReductionFrac * FullWaterMassFlow;
3992 4015 : SysWaterMassFlow = double(Zone(ZoneNum).Multiplier * Zone(ZoneNum).ListMultiplier) * WaterMassFlow;
3993 : // Got a new reduced flow rate that should work...reset loop variable and resimulate the system
3994 4015 : SetComponentFlowRate(state, SysWaterMassFlow, this->ColdWaterInNode, this->ColdWaterOutNode, this->CWPlantLoc);
3995 4015 : this->WaterMassFlowRate = SysWaterMassFlow;
3996 :
3997 : // Go through all of the surfaces again with the new flow rate...
3998 8030 : for (int RadSurfNum3 = 1; RadSurfNum3 <= this->NumOfSurfaces; ++RadSurfNum3) {
3999 4015 : int SurfNum = this->SurfacePtr(RadSurfNum3);
4000 : // Determine the heat exchanger "effectiveness" term
4001 :
4002 16060 : EpsMdotCp = calculateHXEffectivenessTerm(state,
4003 : SurfNum,
4004 : WaterTempIn,
4005 : WaterMassFlow,
4006 4015 : this->SurfaceFrac(RadSurfNum3),
4007 4015 : this->NumCircuits(RadSurfNum3),
4008 : this->DesignObjectPtr,
4009 : typeOfRadiantSystem);
4010 :
4011 4015 : int ConstrNum = Surface(SurfNum).Construction;
4012 4015 : auto const &thisConstruct = state.dataConstruction->Construct(ConstrNum);
4013 4015 : if (Surface(SurfNum).HeatTransferAlgorithm == DataSurfaces::HeatTransferModel::CTF) {
4014 : // For documentation on coefficients, see code earlier in this subroutine
4015 4015 : Ca = state.dataHeatBalFanSys->RadSysTiHBConstCoef(SurfNum);
4016 4015 : Cb = state.dataHeatBalFanSys->RadSysTiHBToutCoef(SurfNum);
4017 4015 : Cc = state.dataHeatBalFanSys->RadSysTiHBQsrcCoef(SurfNum);
4018 4015 : Cd = state.dataHeatBalFanSys->RadSysToHBConstCoef(SurfNum);
4019 4015 : Ce = state.dataHeatBalFanSys->RadSysToHBTinCoef(SurfNum);
4020 4015 : Cf = state.dataHeatBalFanSys->RadSysToHBQsrcCoef(SurfNum);
4021 4015 : Cg = state.dataHeatBalFanSys->CTFTsrcConstPart(SurfNum);
4022 4015 : Ch = thisConstruct.CTFTSourceQ[0];
4023 4015 : Ci = thisConstruct.CTFTSourceIn[0];
4024 4015 : Cj = thisConstruct.CTFTSourceOut[0];
4025 4015 : Ck = Cg + ((Ci * (Ca + Cb * Cd) + Cj * (Cd + Ce * Ca)) / (1.0 - Ce * Cb));
4026 4015 : Cl = Ch + ((Ci * (Cc + Cb * Cf) + Cj * (Cf + Ce * Cc)) / (1.0 - Ce * Cb));
4027 4015 : state.dataHeatBalFanSys->QRadSysSource(SurfNum) =
4028 4015 : EpsMdotCp * (WaterTempIn - Ck) / (1.0 + (EpsMdotCp * Cl / Surface(SurfNum).Area));
4029 0 : } else if (Surface(SurfNum).HeatTransferAlgorithm == DataSurfaces::HeatTransferModel::CondFD) {
4030 0 : state.dataHeatBalFanSys->QRadSysSource(SurfNum) =
4031 0 : EpsMdotCp * (WaterTempIn - state.dataHeatBalFanSys->TCondFDSourceNode(SurfNum));
4032 : }
4033 4015 : if (Surface(SurfNum).ExtBoundCond > 0 && Surface(SurfNum).ExtBoundCond != SurfNum) {
4034 0 : state.dataHeatBalFanSys->QRadSysSource(Surface(SurfNum).ExtBoundCond) =
4035 0 : state.dataHeatBalFanSys->QRadSysSource(SurfNum); // Also set the other side of an interzone
4036 : }
4037 : }
4038 :
4039 : // Redo the heat balances since we have changed the heat source
4040 4015 : HeatBalanceSurfaceManager::CalcHeatBalanceOutsideSurf(state, ZoneNum);
4041 4015 : HeatBalanceSurfaceManager::CalcHeatBalanceInsideSurf(state, ZoneNum);
4042 :
4043 : // Check for condensation one more time. If no condensation, we are done. If there is
4044 : // condensation, shut things down and be done.
4045 8030 : for (int RadSurfNum2 = 1; RadSurfNum2 <= this->NumOfSurfaces; ++RadSurfNum2) {
4046 4015 : if (this->CondCausedShutDown) {
4047 0 : break;
4048 : }
4049 4015 : if (state.dataHeatBalSurf->SurfInsideTempHist(1)(this->SurfacePtr(RadSurfNum2)) < (PredictedCondTemp)) {
4050 : // Condensation still present--must shut off radiant system
4051 3868 : this->CondCausedShutDown = true;
4052 3868 : WaterMassFlow = 0.0;
4053 3868 : this->opMode = OpMode::None;
4054 3868 : SetComponentFlowRate(state, WaterMassFlow, this->ColdWaterInNode, this->ColdWaterOutNode, this->CWPlantLoc);
4055 3868 : this->WaterMassFlowRate = WaterMassFlow;
4056 7736 : for (int RadSurfNum3 = 1; RadSurfNum3 <= this->NumOfSurfaces; ++RadSurfNum3) {
4057 3868 : int SurfNum2 = this->SurfacePtr(RadSurfNum3);
4058 3868 : state.dataHeatBalFanSys->QRadSysSource(SurfNum2) = 0.0;
4059 3868 : if (Surface(SurfNum2).ExtBoundCond > 0 && Surface(SurfNum2).ExtBoundCond != SurfNum2) {
4060 0 : state.dataHeatBalFanSys->QRadSysSource(Surface(SurfNum2).ExtBoundCond) =
4061 : 0.0; // Also zero the other side of an interzone
4062 : }
4063 : }
4064 : }
4065 : }
4066 : }
4067 :
4068 4015 : if (this->CondCausedShutDown) {
4069 : // Produce a warning message so that user knows the system was shut-off due to potential for condensation
4070 3868 : if (!state.dataGlobal->WarmupFlag) {
4071 571 : if (this->CondErrIndex == 0) { // allow errors up to number of radiant systems
4072 2 : ShowWarningMessage(state, format("{} [{}]", cHydronicSystem, this->Name));
4073 4 : ShowContinueError(state,
4074 4 : format("Surface [{}] temperature below dew-point temperature--potential for condensation exists",
4075 2 : Surface(this->SurfacePtr(CondSurfNum)).Name));
4076 4 : ShowContinueError(state, "Flow to the radiant system will be shut-off to avoid condensation");
4077 4 : ShowContinueError(state,
4078 4 : format("Predicted radiant system surface temperature = {:.2R}",
4079 2 : state.dataHeatBalSurf->SurfInsideTempHist(1)(this->SurfacePtr(CondSurfNum))));
4080 4 : ShowContinueError(state,
4081 4 : format("Zone dew-point temperature + safety delta T= {:.2R}",
4082 2 : DewPointTemp + variableFlowDesignDataObject.CondDewPtDeltaT));
4083 4 : ShowContinueErrorTimeStamp(state, "");
4084 4 : ShowContinueError(state,
4085 4 : format("Note that a {:.4R} C safety was chosen in the input for the shut-off criteria",
4086 : variableFlowDesignDataObject.CondDewPtDeltaT));
4087 6 : ShowContinueError(state, "Note also that this affects all surfaces that are part of this radiant system");
4088 : }
4089 4568 : ShowRecurringWarningErrorAtEnd(state,
4090 1142 : format("{} [{}] condensation shut-off occurrence continues.", cHydronicSystem, this->Name),
4091 571 : this->CondErrIndex,
4092 : DewPointTemp,
4093 : DewPointTemp,
4094 : _,
4095 : "C",
4096 : "C");
4097 : }
4098 : }
4099 : } // Condensation Predicted in Variable Shut-Off Control Type
4100 : } // In cooling mode and one of the condensation control types
4101 : } // There was a non-zero flow
4102 :
4103 : // Now that we have the source/sink term, we must redo the heat balances to obtain
4104 : // the new SumHATsurf value for the zone. Note that the difference between the new
4105 : // SumHATsurf and the value originally calculated by the heat balance with a zero
4106 : // source for all radiant systems in the zone is the load met by the system (approximately).
4107 290955 : HeatBalanceSurfaceManager::CalcHeatBalanceOutsideSurf(state, ZoneNum);
4108 290955 : HeatBalanceSurfaceManager::CalcHeatBalanceInsideSurf(state, ZoneNum);
4109 :
4110 290955 : LoadMet = state.dataHeatBal->Zone(ZoneNum).sumHATsurf(state) - this->ZeroLTRSourceSumHATsurf;
4111 290955 : }
4112 :
4113 221733 : void ConstantFlowRadiantSystemData::calculateLowTemperatureRadiantSystem(EnergyPlusData &state,
4114 : Real64 &LoadMet) // load met by the radiant system, in Watts
4115 : {
4116 :
4117 : // SUBROUTINE INFORMATION:
4118 : // AUTHOR Rick Strand
4119 : // DATE WRITTEN August 2003
4120 :
4121 : // PURPOSE OF THIS SUBROUTINE:
4122 : // This subroutine does all of the stuff that is necessary to simulate
4123 : // a constant flow low temperature hydronic radiant heating/cooling system.
4124 : // Calls are made to appropriate subroutines either in this module or
4125 : // outside of it.
4126 :
4127 : // METHODOLOGY EMPLOYED:
4128 : // Similar in many aspects to the hydronic (variable flow) radiant system
4129 : // except that flow rate through the radiant system is constant (based on
4130 : // the user schedule) and the inlet temperature is varied by injecting
4131 : // more or less fluid from the main loop to achieve the desired inlet
4132 : // temperature.
4133 :
4134 : // REFERENCES:
4135 : // Other EnergyPlus modules
4136 : // IBLAST-QTF research program, completed in January 1995 (unreleased)
4137 : // Strand, R.K. 1995. "Heat Source Transfer Functions and Their Application to
4138 : // Low Temperature Radiant Heating Systems", Ph.D. dissertation, University
4139 : // of Illinois at Urbana-Champaign, Department of Mechanical and Industrial
4140 : // Engineering.
4141 : // Seem, J.E. 1986. "Heat Transfer in Buildings", Ph.D. dissertation, University
4142 : // of Wisconsin-Madison.
4143 :
4144 : // Using/Aliasing
4145 : using DataHeatBalance::ZoneData;
4146 : using HVAC::SmallLoad;
4147 : using PlantUtilities::SetComponentFlowRate;
4148 :
4149 : // SUBROUTINE PARAMETER DEFINITIONS:
4150 221733 : Real64 constexpr LowCpFluidValue(100.0); // lowest allowed Cp fluid value (to avoid dividing by zero) [J/kg-K]
4151 221733 : constexpr std::string_view RoutineName("CalcLowTempCFloRadiantSystem");
4152 :
4153 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
4154 : Real64 CpFluid; // Specific heat of the fluid in the radiant system
4155 : Real64 InjectFlowRate; // Calculated injection flow rate that will meet the inlet temperature requirement
4156 : Real64 OffTempCool; // temperature at which the cooling shuts down
4157 : Real64 OffTempHeat; // temperature at which the heating shuts down
4158 : Real64 PumpPartLoadRat; // Pump part load ratio (based on user schedule, or 1.0 for no schedule)
4159 : Real64 PumpTempRise; // Temperature rise of the fluid as it passes through the pump
4160 : Real64 RadInTemp; // "Desired" radiant system water inlet temperature [Celsius]
4161 : Real64 SetPointTemp; // temperature that will be used to control the radiant system [Celsius]
4162 : Real64 SetPointTempHi; // Current high point in setpoint temperature range
4163 : Real64 SetPointTempLo; // Current low point in setpoint temperature range
4164 : Real64 ShaftPower; // Amount of power expended at the pump shaft
4165 : bool SysRunning; // TRUE when the system is running
4166 : Real64 SysWaterInTemp; // Fluid temperature supplied from the loop
4167 : Real64 WaterTempHi; // Current high point in water temperature range
4168 : Real64 WaterTempLo; // Current low point in water temperature range
4169 : Real64 mdot; // local temporary for water mass flow rate kg/s
4170 :
4171 : ConstantFlowRadDesignData ConstantFlowDesignDataObject = // Once again, is this supposed to be a deep copy?
4172 221733 : state.dataLowTempRadSys->CflowRadiantSysDesign(this->DesignObjectPtr); // Contains the data for variable flow hydronic systems
4173 :
4174 : // initialize local variables
4175 221733 : SysRunning = true; // default to running and turn off only if not running
4176 221733 : state.dataLowTempRadSys->VarOffCond = false;
4177 :
4178 221733 : if (this->availSched->getCurrentVal() <= 0) {
4179 7608 : SysRunning = false;
4180 : }
4181 :
4182 221733 : if (SysRunning) { // Unit is probably on-->this section is intended to control the water
4183 : // mass flow rate being sent to the radiant system
4184 :
4185 : // Set the current setpoint temperature (same procedure for either heating or cooling)
4186 :
4187 214125 : SetPointTemp = this->setRadiantSystemControlTemperature(state, ConstantFlowDesignDataObject.ConstFlowControlType);
4188 :
4189 : // Avoid problems when there is no heating or cooling control because the system only cools or heats
4190 214125 : if (this->hotCtrlHiTempSched != nullptr) {
4191 214125 : OffTempHeat = this->hotCtrlHiTempSched->getCurrentVal();
4192 : } else {
4193 0 : OffTempHeat = state.dataLowTempRadSys->LowTempHeating;
4194 : }
4195 214125 : if (this->coldCtrlLoTempSched != nullptr) {
4196 208098 : OffTempCool = this->coldCtrlLoTempSched->getCurrentVal();
4197 : } else {
4198 6027 : OffTempCool = state.dataLowTempRadSys->HighTempCooling;
4199 : }
4200 :
4201 214125 : if (SetPointTemp < OffTempHeat && this->HeatingSystem) { // Heating mode
4202 72716 : this->opMode = OpMode::Heat;
4203 141409 : } else if (SetPointTemp > OffTempCool && this->CoolingSystem) { // Cooling mode
4204 113868 : this->opMode = OpMode::Cool;
4205 : }
4206 :
4207 214125 : this->setOperatingModeBasedOnChangeoverDelay(state);
4208 :
4209 : // Now actually decide what to do based on the setpoint temperature in relation to the control temperatures
4210 214125 : if (this->opMode == OpMode::Heat) { // HEATING MODE
4211 :
4212 69897 : this->WaterMassFlowRate = this->HotWaterMassFlowRate;
4213 :
4214 69897 : if (!this->HeatingSystem) {
4215 :
4216 0 : SysRunning = false; // Can't heat unless it's a heating system
4217 :
4218 : } else { // It is a heating system so set all of the values for controls
4219 :
4220 69897 : SetPointTempHi = this->hotCtrlHiTempSched->getCurrentVal();
4221 69897 : SetPointTempLo = this->hotCtrlLoTempSched->getCurrentVal();
4222 69897 : if (SetPointTempHi < SetPointTempLo) {
4223 0 : ShowSevereError(state, format("Heating setpoint temperature mismatch in{}", this->Name));
4224 0 : ShowContinueError(state, "High setpoint temperature is less than low setpoint temperature--check your schedule input");
4225 0 : ShowFatalError(state, "Preceding condition causes termination.");
4226 : }
4227 :
4228 69897 : WaterTempHi = this->hotWaterHiTempSched->getCurrentVal();
4229 69897 : WaterTempLo = this->hotWaterLoTempSched->getCurrentVal();
4230 69897 : if (WaterTempHi < WaterTempLo) {
4231 0 : ShowSevereError(state, format("Heating water temperature mismatch in{}", this->Name));
4232 0 : ShowContinueError(state, "High water temperature is less than low water temperature--check your schedule input");
4233 0 : ShowFatalError(state, "Preceding condition causes termination.");
4234 : }
4235 :
4236 69897 : if (SetPointTemp >= SetPointTempHi) {
4237 : // System is above high heating setpoint so we should be able to turn the system off
4238 137 : RadInTemp = WaterTempLo;
4239 137 : SysRunning = false;
4240 69760 : } else if (SetPointTemp <= SetPointTempLo) {
4241 : // System is running with its highest inlet temperature
4242 12651 : RadInTemp = WaterTempHi;
4243 : } else {
4244 : // Interpolate to obtain the current radiant system inlet temperature
4245 57109 : RadInTemp = WaterTempHi - (WaterTempHi - WaterTempLo) * (SetPointTemp - SetPointTempLo) / (SetPointTempHi - SetPointTempLo);
4246 : }
4247 : }
4248 :
4249 144228 : } else if (this->opMode == OpMode::Cool) { // COOLING MODE
4250 :
4251 113849 : this->WaterMassFlowRate = this->ChWaterMassFlowRate;
4252 :
4253 113849 : if (!this->CoolingSystem) {
4254 :
4255 0 : SysRunning = false; // Can't cool unless it's a cooling system
4256 :
4257 : } else { // It is a cooling system so set all of the values for controls
4258 :
4259 113849 : SetPointTempHi = this->coldCtrlHiTempSched->getCurrentVal();
4260 113849 : SetPointTempLo = this->coldCtrlLoTempSched->getCurrentVal();
4261 113849 : if (SetPointTempHi < SetPointTempLo) {
4262 0 : ShowSevereError(state, format("Cooling setpoint temperature mismatch in{}", this->Name));
4263 0 : ShowContinueError(state, "High setpoint temperature is less than low setpoint temperature--check your schedule input");
4264 0 : ShowFatalError(state, "Preceding condition causes termination.");
4265 : }
4266 :
4267 113849 : WaterTempHi = this->coldWaterHiTempSched->getCurrentVal();
4268 113849 : WaterTempLo = this->coldWaterLoTempSched->getCurrentVal();
4269 113849 : if (WaterTempHi < WaterTempLo) {
4270 0 : ShowSevereError(state, format("Cooling water temperature mismatch in{}", this->Name));
4271 0 : ShowContinueError(state, "High water temperature is less than low water temperature--check your schedule input");
4272 0 : ShowFatalError(state, "Preceding condition causes termination.");
4273 : }
4274 :
4275 113849 : if (SetPointTemp <= SetPointTempLo) {
4276 : // System is below low cooling setpoint so we should be able to turn the system off
4277 633 : RadInTemp = WaterTempHi;
4278 633 : SysRunning = false;
4279 113216 : } else if (SetPointTemp >= SetPointTempHi) {
4280 : // System is running with its lowest inlet temperature
4281 53811 : RadInTemp = WaterTempLo;
4282 : } else {
4283 : // Interpolate to obtain the current radiant system inlet temperature
4284 59405 : RadInTemp = WaterTempHi - (WaterTempHi - WaterTempLo) * (SetPointTemp - SetPointTempLo) / (SetPointTempHi - SetPointTempLo);
4285 : }
4286 : }
4287 :
4288 : } else { // System is not running because the setpoint temperature is in the "deadband"
4289 :
4290 30379 : RadInTemp = SetPointTemp;
4291 30379 : SysRunning = false;
4292 : }
4293 : }
4294 :
4295 221733 : if (SysRunning) {
4296 182976 : CpFluid = this->water->getSpecificHeat(state, RadInTemp, RoutineName);
4297 : }
4298 :
4299 221733 : if ((!SysRunning) || (CpFluid < LowCpFluidValue)) {
4300 : // Unit is off or has no load upon it OR CpFluid value is "zero" so
4301 : // set the flow rates to zero and then simulate the components with
4302 : // the no flow conditions
4303 38757 : this->opMode = OpMode::None;
4304 38757 : this->WaterMassFlowRate = 0.0;
4305 38757 : this->WaterInjectionRate = 0.0;
4306 38757 : this->WaterRecircRate = 0.0;
4307 38757 : this->HeatPower = 0.0;
4308 38757 : this->CoolPower = 0.0;
4309 38757 : this->PumpPower = 0.0;
4310 38757 : this->PumpMassFlowRate = 0.0;
4311 38757 : this->PumpHeattoFluid = 0.0;
4312 :
4313 77514 : for (int SurfNum = 1; SurfNum <= this->NumOfSurfaces; ++SurfNum) {
4314 38757 : int SurfNum2 = this->SurfacePtr(SurfNum);
4315 38757 : auto &surface = state.dataSurface->Surface(SurfNum2);
4316 38757 : state.dataHeatBalFanSys->QRadSysSource(SurfNum2) = 0.0;
4317 38757 : if (surface.ExtBoundCond > 0 && surface.ExtBoundCond != SurfNum2) {
4318 0 : state.dataHeatBalFanSys->QRadSysSource(surface.ExtBoundCond) = 0.0; // Also zero the other side of an interzone
4319 : }
4320 : }
4321 :
4322 : // turn off flow requests made during init because it is not actually running
4323 38757 : if (this->CWPlantLoc.loopNum > 0) {
4324 31149 : mdot = 0.0;
4325 31149 : SetComponentFlowRate(state, mdot, this->ColdWaterInNode, this->ColdWaterOutNode, this->CWPlantLoc);
4326 : }
4327 38757 : if (this->HWPlantLoc.loopNum > 0) {
4328 38757 : mdot = 0.0;
4329 38757 : SetComponentFlowRate(state, mdot, this->HotWaterInNode, this->HotWaterOutNode, this->HWPlantLoc);
4330 : }
4331 38757 : } else { // (SysRunning) so simulate the system...
4332 : bool Iteration; // FALSE when a normal solution, TRUE when it is a solution where we must also find the inlet temp
4333 : int LoopInNode; // Node on the loop that is the inlet to the constant flow radiant system
4334 :
4335 : // Determine pump flow rate and pump heat addition
4336 182976 : this->PumpMassFlowRate = this->WaterMassFlowRate; // Set in InitLowTempRadiantSystem
4337 182976 : PumpPartLoadRat = (this->volFlowSched != nullptr) ? this->volFlowSched->getCurrentVal() : 1.0;
4338 :
4339 182976 : this->PumpPower = PumpPartLoadRat * this->NomPowerUse;
4340 182976 : ShaftPower = this->PumpPower * ConstantFlowDesignDataObject.MotorEffic;
4341 : // This adds the pump heat based on User input for the pump (same as in Pump module)
4342 : // We assume that all of the heat ends up in the fluid eventually since this is a closed loop.
4343 182976 : this->PumpHeattoFluid = ShaftPower + ((this->PumpPower - ShaftPower) * ConstantFlowDesignDataObject.FracMotorLossToFluid);
4344 182976 : if (this->PumpMassFlowRate > 0.0) {
4345 182910 : PumpTempRise = this->PumpHeattoFluid / (this->PumpMassFlowRate * CpFluid);
4346 : } else {
4347 66 : PumpTempRise = 0.0;
4348 : }
4349 :
4350 365952 : state.dataLowTempRadSys->LoopReqTemp =
4351 182976 : RadInTemp - PumpTempRise; // Temperature required at the inlet of the pump to meet the temperature request
4352 :
4353 182976 : if (this->opMode == OpMode::Heat) {
4354 :
4355 : // in heating mode so shut down cold water flow request
4356 69760 : if (this->CWPlantLoc.loopNum > 0) {
4357 63733 : mdot = 0.0;
4358 63733 : SetComponentFlowRate(state, mdot, this->ColdWaterInNode, this->ColdWaterOutNode, this->CWPlantLoc);
4359 : }
4360 69760 : LoopInNode = this->HotWaterInNode;
4361 69760 : auto const &hotNode = state.dataLoopNodes->Node(LoopInNode);
4362 69760 : SysWaterInTemp = hotNode.Temp;
4363 69760 : Iteration = false;
4364 :
4365 69760 : if ((SysWaterInTemp >= state.dataLowTempRadSys->LoopReqTemp) && (hotNode.MassFlowRateMaxAvail >= this->WaterMassFlowRate)) {
4366 : // Case 1: Adequate temperature and flow
4367 : // Best condition--loop inlet temperature greater than requested and we have enough flow.
4368 : // So, proceed assuming the RadInTemp requested by the controls and then figure out the
4369 : // mixing after the outlet radiant temperature is calculated.
4370 69760 : this->WaterInletTemp = RadInTemp;
4371 69760 : this->calculateLowTemperatureRadiantSystemComponents(state, LoopInNode, Iteration, LoadMet, SystemType::ConstantFlow);
4372 :
4373 : // We now have inlet and outlet temperatures--we still need to set the flow rates
4374 69760 : if ((SysWaterInTemp - this->WaterOutletTemp) != 0.0) { // protect divide by zero
4375 69760 : this->WaterInjectionRate =
4376 69760 : (this->WaterMassFlowRate * (this->WaterInletTemp - this->WaterOutletTemp) / (SysWaterInTemp - this->WaterOutletTemp)) -
4377 69760 : (this->PumpHeattoFluid / (CpFluid * (SysWaterInTemp - this->WaterOutletTemp)));
4378 : } else {
4379 0 : this->WaterInjectionRate = this->WaterMassFlowRate;
4380 : }
4381 69760 : this->WaterRecircRate = this->WaterMassFlowRate - this->WaterInjectionRate;
4382 :
4383 0 : } else if ((SysWaterInTemp < state.dataLowTempRadSys->LoopReqTemp) && (hotNode.MassFlowRateMaxAvail >= this->WaterMassFlowRate)) {
4384 : // Case 2: Adequate flow but temperature too low
4385 : // Only thing to do is to reset the inlet temperature and assume that the loop will supply
4386 : // the entire flow to the component (no recirculation but potentially some bypass for the
4387 : // overall loop). There is no way we can meet the control temperature so don't even try.
4388 0 : this->WaterInletTemp = SysWaterInTemp + PumpTempRise;
4389 0 : this->calculateLowTemperatureRadiantSystemComponents(state, LoopInNode, Iteration, LoadMet, SystemType::ConstantFlow);
4390 :
4391 : // We now have inlet and outlet temperatures--we still need to set the flow rates
4392 0 : if ((SysWaterInTemp - this->WaterOutletTemp) != 0.0) { // protect divide by zero
4393 0 : this->WaterInjectionRate =
4394 0 : (this->WaterMassFlowRate * (this->WaterInletTemp - this->WaterOutletTemp) / (SysWaterInTemp - this->WaterOutletTemp)) -
4395 0 : (this->PumpHeattoFluid / (CpFluid * (SysWaterInTemp - this->WaterOutletTemp)));
4396 : } else {
4397 0 : this->WaterInjectionRate = this->WaterMassFlowRate;
4398 : }
4399 0 : if (this->WaterInjectionRate > this->WaterMassFlowRate) {
4400 0 : this->WaterInjectionRate = this->WaterMassFlowRate;
4401 : }
4402 0 : this->WaterRecircRate = 0.0; // by definition
4403 :
4404 0 : } else if ((SysWaterInTemp >= state.dataLowTempRadSys->LoopReqTemp) && (hotNode.MassFlowRateMaxAvail < this->WaterMassFlowRate)) {
4405 : // Case 3: Adequate temperature but loop flow is less than component flow
4406 : // This case might work out, but there is no guarantee that there is enough loop flow to
4407 : // mix with the recirculation flow and still provide a high enough temperature. First
4408 : // step is to try the inlet temperature and flow rate as in Case 1. If we can obtain
4409 : // the proper temperature inlet to the radiant system, then we are done. If not, we
4410 : // have to repeat the solution for an unknown inlet temperature and a known recirculation
4411 : // rate.
4412 0 : this->WaterInletTemp = RadInTemp;
4413 0 : this->calculateLowTemperatureRadiantSystemComponents(state, LoopInNode, Iteration, LoadMet, SystemType::ConstantFlow);
4414 :
4415 : // Now see if we can really get that desired into temperature (RadInTemp) by solving
4416 : // for the flow that is injected from the loop. A heat balance for the mixer that relates
4417 : // the important quantities is:
4418 : // Mdotradsys*Cp*Tradsysin = Mdotloop*Cp*Tloop + (Mdotradsys-Mdotloop)*Cp*Tradsysout + PumpHeat
4419 : // or rearranging to get the injection flow (Mdotloop):
4420 : // Mdotloop = Mdotcomp*(Tradsysin-Tradsysout)/(Tloop-Tradsysout) - PumpHeat/(Cp*(Tloop-Tradsysout))
4421 : // If Mdotloop from this equation is greater that the loop flow rate (Node%MassFlowRate),
4422 : // then we cannot meet the inlet temperature and we have to "iterate" through the
4423 : // alternate solution.
4424 0 : if ((SysWaterInTemp - this->WaterOutletTemp) != 0.0) { // protect divide by zero
4425 0 : InjectFlowRate =
4426 0 : (this->WaterMassFlowRate * (this->WaterInletTemp - this->WaterOutletTemp) / (SysWaterInTemp - this->WaterOutletTemp)) -
4427 0 : (this->PumpHeattoFluid / (CpFluid * (SysWaterInTemp - this->WaterOutletTemp)));
4428 : } else {
4429 0 : InjectFlowRate = this->WaterMassFlowRate;
4430 : }
4431 0 : if (InjectFlowRate > hotNode.MassFlowRateMaxAvail) {
4432 : // We didn't have enough flow from the loop to meet our inlet temperature request.
4433 : // So, set the injection rate to the loop flow and calculate the recirculation flow.
4434 : // Then, resimulate the radiant system using these values (it will obtain the actual
4435 : // inlet temperature that results from this).
4436 0 : this->WaterInjectionRate = hotNode.MassFlowRateMaxAvail;
4437 0 : this->WaterRecircRate = this->WaterMassFlowRate - this->WaterInjectionRate;
4438 0 : this->WaterInletTemp = SysWaterInTemp + PumpTempRise;
4439 0 : Iteration = true;
4440 0 : this->calculateLowTemperatureRadiantSystemComponents(state, LoopInNode, Iteration, LoadMet, SystemType::ConstantFlow);
4441 : } else {
4442 0 : this->WaterInjectionRate = InjectFlowRate;
4443 0 : this->WaterRecircRate = this->WaterMassFlowRate - this->WaterInjectionRate;
4444 : }
4445 :
4446 0 : } else if ((SysWaterInTemp < state.dataLowTempRadSys->LoopReqTemp) && (hotNode.MassFlowRateMaxAvail < this->WaterMassFlowRate)) {
4447 : // Case 4: Temperature too low and loop flow is less than component flow
4448 : // Worst condition--can't meet the temperature request at all. Only thing to do is to
4449 : // set the loop flow and recirculation rate (known) and solve for the inlet temperature
4450 : // using the "iteration" solution scheme from "Case 3B" above
4451 0 : this->WaterInjectionRate = hotNode.MassFlowRateMaxAvail;
4452 0 : this->WaterRecircRate = this->WaterMassFlowRate - this->WaterInjectionRate;
4453 0 : this->WaterInletTemp = SysWaterInTemp + PumpTempRise;
4454 0 : Iteration = true;
4455 0 : this->calculateLowTemperatureRadiantSystemComponents(state, LoopInNode, Iteration, LoadMet, SystemType::ConstantFlow);
4456 : }
4457 :
4458 113216 : } else if (this->opMode == OpMode::Cool) {
4459 :
4460 : // in cooling mode so shut down heating water flow request
4461 113216 : if (this->HWPlantLoc.loopNum > 0) {
4462 113216 : mdot = 0.0;
4463 113216 : SetComponentFlowRate(state, mdot, this->HotWaterInNode, this->HotWaterOutNode, this->HWPlantLoc);
4464 : }
4465 113216 : LoopInNode = this->ColdWaterInNode;
4466 113216 : auto const &coldNode = state.dataLoopNodes->Node(LoopInNode);
4467 113216 : SysWaterInTemp = coldNode.Temp;
4468 113216 : state.dataLowTempRadSys->CFloCondIterNum = 1;
4469 348002 : while ((state.dataLowTempRadSys->CFloCondIterNum <= 1) ||
4470 117393 : ((state.dataLowTempRadSys->CFloCondIterNum <= 2) && (ConstantFlowDesignDataObject.condCtrlType == CondCtrlType::VariedOff) &&
4471 13834 : (state.dataLowTempRadSys->VarOffCond))) {
4472 117393 : Iteration = false;
4473 :
4474 117393 : if ((SysWaterInTemp <= state.dataLowTempRadSys->LoopReqTemp) && (coldNode.MassFlowRateMaxAvail >= this->WaterMassFlowRate)) {
4475 : // Case 1: Adequate temperature and flow
4476 : // Best condition--loop inlet temperature lower than requested and we have enough flow.
4477 : // So, proceed assuming the RadInTemp requested by the controls and then figure out the
4478 : // mixing after the outlet radiant temperature is calculated.
4479 :
4480 : // This condition can also happen when state.dataLowTempRadSys->LoopReqTemp has been reset to dewpoint for condensation
4481 : // control
4482 82724 : if (!state.dataLowTempRadSys->VarOffCond) {
4483 78547 : this->WaterInletTemp = RadInTemp;
4484 : } else {
4485 4177 : this->WaterInletTemp = state.dataLowTempRadSys->LoopReqTemp;
4486 : }
4487 82724 : this->calculateLowTemperatureRadiantSystemComponents(state, LoopInNode, Iteration, LoadMet, SystemType::ConstantFlow);
4488 :
4489 : // We now have inlet and outlet temperatures--we still need to set the flow rates
4490 82724 : if ((SysWaterInTemp - this->WaterOutletTemp) != 0.0) { // protect div by zero
4491 82722 : this->WaterInjectionRate = (this->WaterMassFlowRate * (this->WaterInletTemp - this->WaterOutletTemp) /
4492 82722 : (SysWaterInTemp - this->WaterOutletTemp)) -
4493 82722 : (this->PumpHeattoFluid / (CpFluid * (SysWaterInTemp - this->WaterOutletTemp)));
4494 : } else {
4495 2 : this->WaterInjectionRate = this->WaterMassFlowRate;
4496 : }
4497 82724 : this->WaterRecircRate = this->WaterMassFlowRate - this->WaterInjectionRate;
4498 :
4499 69338 : } else if ((SysWaterInTemp > state.dataLowTempRadSys->LoopReqTemp) &&
4500 34669 : (coldNode.MassFlowRateMaxAvail >= this->WaterMassFlowRate)) {
4501 : // Case 2: Adequate flow but temperature too high
4502 : // Only thing to do is to reset the inlet temperature and assume that the loop will supply
4503 : // the entire flow to the component (no recirculation but potentially some bypass for the
4504 : // overall loop). There is no way we can meet the control temperature so don't even try.
4505 34669 : this->WaterInletTemp = SysWaterInTemp + PumpTempRise;
4506 34669 : this->calculateLowTemperatureRadiantSystemComponents(state, LoopInNode, Iteration, LoadMet, SystemType::ConstantFlow);
4507 :
4508 : // We now have inlet and outlet temperatures--we still need to set the flow rates
4509 34669 : if ((SysWaterInTemp - this->WaterOutletTemp) != 0.0) { // protect div by zero
4510 34666 : this->WaterInjectionRate = (this->WaterMassFlowRate * (this->WaterInletTemp - this->WaterOutletTemp) /
4511 34666 : (SysWaterInTemp - this->WaterOutletTemp)) -
4512 34666 : (this->PumpHeattoFluid / (CpFluid * (SysWaterInTemp - this->WaterOutletTemp)));
4513 : } else { // no temp change present, set injection rate to full flow
4514 3 : this->WaterInjectionRate = this->WaterMassFlowRate;
4515 : }
4516 34669 : if (this->WaterInjectionRate > this->WaterMassFlowRate) {
4517 5322 : this->WaterInjectionRate = this->WaterMassFlowRate;
4518 : }
4519 34669 : this->WaterRecircRate = 0.0; // by definition
4520 :
4521 0 : } else if ((SysWaterInTemp <= state.dataLowTempRadSys->LoopReqTemp) &&
4522 0 : (coldNode.MassFlowRateMaxAvail < this->WaterMassFlowRate)) {
4523 : // Case 3: Adequate temperature but loop flow is less than component flow
4524 : // This case might work out, but there is no guarantee that there is enough loop flow to
4525 : // mix with the recirculation flow and still provide a high enough temperature. First
4526 : // step is to try the inlet temperature and flow rate as in Case 1. If we can obtain
4527 : // the proper temperature inlet to the radiant system, then we are done. If not, we
4528 : // have to repeat the solution for an unknown inlet temperature and a known recirculation
4529 : // rate.
4530 : // This condition might happen when state.dataLowTempRadSys->LoopReqTemp has been reset to dewpoint for condensation control
4531 0 : if (!state.dataLowTempRadSys->VarOffCond) {
4532 0 : this->WaterInletTemp = RadInTemp;
4533 : } else {
4534 0 : this->WaterInletTemp = state.dataLowTempRadSys->LoopReqTemp;
4535 : }
4536 0 : this->calculateLowTemperatureRadiantSystemComponents(state, LoopInNode, Iteration, LoadMet, SystemType::ConstantFlow);
4537 :
4538 : // Now see if we can really get that desired into temperature (RadInTemp) by solving
4539 : // for the flow that is injected from the loop. A heat balance for the mixer that relates
4540 : // the important quantities is:
4541 : // Mdotradsys*Cp*Tradsysin = Mdotloop*Cp*Tloop + (Mdotradsys-Mdotloop)*Cp*Tradsysout + PumpHeat
4542 : // or rearranging to get the injection flow (Mdotloop):
4543 : // Mdotloop = Mdotcomp*(Tradsysin-Tradsysout)/(Tloop-Tradsysout) - PumpHeat/(Cp*(Tloop-Tradsysout))
4544 : // If Mdotloop from this equation is greater that the loop flow rate (Node%MassFlowRate),
4545 : // then we cannot meet the inlet temperature and we have to "iterate" through the
4546 : // alternate solution.
4547 0 : if ((SysWaterInTemp - this->WaterOutletTemp) != 0.0) { // protect div by zero
4548 0 : InjectFlowRate = (this->WaterMassFlowRate * (this->WaterInletTemp - this->WaterOutletTemp) /
4549 0 : (SysWaterInTemp - this->WaterOutletTemp)) -
4550 0 : (this->PumpHeattoFluid / (CpFluid * (SysWaterInTemp - this->WaterOutletTemp)));
4551 : } else {
4552 0 : InjectFlowRate = this->WaterMassFlowRate;
4553 : }
4554 0 : if (InjectFlowRate > coldNode.MassFlowRateMaxAvail) {
4555 : // We didn't have enough flow from the loop to meet our inlet temperature request.
4556 : // So, set the injection rate to the loop flow and calculate the recirculation flow.
4557 : // Then, resimulate the radiant system using these values (it will obtain the actual
4558 : // inlet temperature that results from this).
4559 0 : this->WaterInjectionRate = coldNode.MassFlowRateMaxAvail;
4560 0 : this->WaterRecircRate = this->WaterMassFlowRate - this->WaterInjectionRate;
4561 0 : this->WaterInletTemp = SysWaterInTemp + PumpTempRise;
4562 0 : Iteration = true;
4563 0 : this->calculateLowTemperatureRadiantSystemComponents(state, LoopInNode, Iteration, LoadMet, SystemType::ConstantFlow);
4564 : } else {
4565 0 : this->WaterInjectionRate = InjectFlowRate;
4566 0 : this->WaterRecircRate = this->WaterMassFlowRate - this->WaterInjectionRate;
4567 : }
4568 :
4569 0 : } else if ((SysWaterInTemp > state.dataLowTempRadSys->LoopReqTemp) && (coldNode.MassFlowRateMaxAvail < this->WaterMassFlowRate)) {
4570 : // Case 4: Temperature too low and loop flow is less than component flow
4571 : // Worst condition--can't meet the temperature request at all. Only thing to do is to
4572 : // set the loop flow and recirculation rate (known) and solve for the inlet temperature
4573 : // using the "iteration" solution scheme from "Case 3B" above
4574 0 : this->WaterInjectionRate = coldNode.MassFlowRateMaxAvail;
4575 0 : this->WaterRecircRate = this->WaterMassFlowRate - this->WaterInjectionRate;
4576 0 : this->WaterInletTemp = SysWaterInTemp + PumpTempRise;
4577 0 : Iteration = true;
4578 0 : this->calculateLowTemperatureRadiantSystemComponents(state, LoopInNode, Iteration, LoadMet, SystemType::ConstantFlow);
4579 : }
4580 :
4581 117393 : ++state.dataLowTempRadSys->CFloCondIterNum;
4582 : }
4583 :
4584 : } // Operating mode (heating or cooling)
4585 :
4586 : // Case when system has been shut down because of condensation issues or other limitations:
4587 182976 : if (this->WaterMassFlowRate < DataBranchAirLoopPlant::MassFlowTolerance) {
4588 8801 : this->WaterMassFlowRate = 0.0;
4589 8801 : this->WaterInjectionRate = 0.0;
4590 8801 : this->WaterRecircRate = 0.0;
4591 8801 : this->PumpMassFlowRate = 0.0;
4592 8801 : this->opMode = OpMode::None;
4593 : }
4594 :
4595 : // There are some cases when the pump heat is actually enough to provide all the heating that the system needs.
4596 : // In this case, the water injection flow rate will come back as a slightly negative number. Reset it to zero
4597 : // and just recirculate all the flow through the local loop.
4598 182976 : if (this->WaterInjectionRate < 0.0) {
4599 33 : this->WaterInjectionRate = 0.0;
4600 33 : this->WaterRecircRate = this->WaterMassFlowRate;
4601 : }
4602 :
4603 : // Error check, just in case
4604 182976 : if (this->WaterRecircRate < 0.0) {
4605 0 : ShowWarningError(state, "Flow mismatch in radiant system--result will be an energy imbalance--should not get this error");
4606 0 : ShowContinueErrorTimeStamp(state, format("WaterRecircRate={:.2T}, in Radiant System={},", this->WaterRecircRate, this->Name));
4607 0 : this->WaterRecircRate = 0.0;
4608 0 : this->WaterInjectionRate = this->WaterMassFlowRate;
4609 : }
4610 :
4611 : } // System running mode (yes or no)
4612 221733 : }
4613 :
4614 187153 : void ConstantFlowRadiantSystemData::calculateLowTemperatureRadiantSystemComponents(
4615 : EnergyPlusData &state,
4616 : int const MainLoopNodeIn, // Node number on main loop of the inlet node to the radiant system
4617 : bool const Iteration, // FALSE for the regular solution, TRUE when we had to loop back
4618 : Real64 &LoadMet, // Load met by the low temperature radiant system, in Watts
4619 : SystemType const typeOfRadiantSystem)
4620 : {
4621 :
4622 : // SUBROUTINE INFORMATION:
4623 : // AUTHOR Rick Strand
4624 : // DATE WRITTEN August 2003
4625 : // MODIFIED Sep 2011 LKL/BG - resimulate only zones needing it for Radiant systems
4626 :
4627 : // PURPOSE OF THIS SUBROUTINE:
4628 : // This subroutine solves the radiant system based on how much water is (and
4629 : // the conditions of the water) supplied to the radiant system. The purpose
4630 : // of this subroutine is similar to CalcLowTempHydrRadSysComps except that
4631 : // it solves this for a constant flow hydronic radiant system.
4632 :
4633 : // METHODOLOGY EMPLOYED:
4634 : // Use heat exchanger formulas to obtain the heat source/sink for the radiant
4635 : // system based on the inlet conditions and flow rate of water. Once that is
4636 : // determined, recalculate the surface heat balances to reflect this heat
4637 : // addition/subtraction. The load met by the system is determined by the
4638 : // difference between the convection from all surfaces in the zone when
4639 : // there was no radiant system output and with a source/sink added.
4640 :
4641 : // REFERENCES:
4642 : // IBLAST-QTF research program, completed in January 1995 (unreleased)
4643 : // Strand, R.K. 1995. "Heat Source Transfer Functions and Their Application to
4644 : // Low Temperature Radiant Heating Systems", Ph.D. dissertation, University
4645 : // of Illinois at Urbana-Champaign, Department of Mechanical and Industrial
4646 : // Engineering.
4647 :
4648 187153 : auto &Zone = state.dataHeatBal->Zone;
4649 :
4650 : // Using/Aliasing
4651 : using PlantUtilities::SetComponentFlowRate;
4652 :
4653 : // SUBROUTINE PARAMETER DEFINITIONS:
4654 187153 : Real64 constexpr TempCheckLimit(0.1); // Maximum allowed temperature difference between outlet temperature calculations
4655 187153 : Real64 constexpr ZeroSystemResp(0.1); // Response below which the system response is really zero
4656 187153 : constexpr std::string_view RoutineName("CalcLowTempCFloRadSysComps");
4657 :
4658 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
4659 : Real64 Cp; // Intermediate calculational variable for specific heat of water
4660 : Real64 DewPointTemp; // Dew-point temperature based on the zone air conditions
4661 : Real64 EpsMdotCp; // Epsilon (heat exchanger terminology) times water mass flow rate times water specific heat
4662 : Real64 LoopTerm; // Intermeidate calculation variable for determining the water inlet temperature
4663 : Real64 Mdot; // Intermediate calculation variable for mass flow rate in a surface within the radiant system
4664 : Real64 RecircTerm; // Intermeidate calculation variable for determining the water inlet temperature
4665 : Real64 SumFlowFracCkCm; // Summation of surface flow fraction, Ck, and Cm product for each surface in the system
4666 : Real64 SumFlowFracOneMinusCm; // Summation of surface flow fraction times (1-Cm) for each surface in the radiant system
4667 : Real64 TotalRadSysPower; // Total heat source/sink to radiant system
4668 : Real64 TwiCoeff; // Intermeidate calculation variable for determining the water inlet temperature
4669 : Real64 WaterMassFlow; // Water mass flow rate in the radiant system, kg/s
4670 : Real64 WaterOutletTempCheck; // Radiant system water outlet temperature (calculated from mixing all outlet streams together)
4671 : Real64 WaterTempIn; // Temperature of the water entering the radiant system, in C
4672 : int ZoneNum; // number of zone being served
4673 : Real64 ZoneMult; // Zone multiplier for this system
4674 :
4675 : ConstantFlowRadDesignData ConstantFlowDesignDataObject = // I repeat myself
4676 187153 : state.dataLowTempRadSys->CflowRadiantSysDesign(this->DesignObjectPtr); // Contains the data for variable flow hydronic systems
4677 187153 : auto &Surface = state.dataSurface->Surface;
4678 :
4679 : Real64 Ca; // Coefficients to relate the inlet water temperature to the heat source
4680 : Real64 Cb;
4681 : Real64 Cc;
4682 : Real64 Cd;
4683 : Real64 Ce;
4684 : Real64 Cf;
4685 : Real64 Cg;
4686 : Real64 Ch;
4687 : Real64 Ci;
4688 : Real64 Cj;
4689 : Real64 Ck;
4690 : Real64 Cl;
4691 : // For more info on Ca through Cl, see comments below
4692 :
4693 : // First, apply heat exchanger logic to find the heat source/sink to the system.
4694 : // This involves finding out the heat transfer characteristics of the hydronic
4695 : // loop and then applying the equations derived on pp. 113-118 of the dissertation.
4696 187153 : if (state.dataLowTempRadSys->FirstTimeFlag) {
4697 9 : state.dataLowTempRadSys->Ckj.allocate(state.dataLowTempRadSys->MaxCloNumOfSurfaces);
4698 9 : state.dataLowTempRadSys->Cmj.allocate(state.dataLowTempRadSys->MaxCloNumOfSurfaces);
4699 9 : state.dataLowTempRadSys->WaterTempOut.allocate(state.dataLowTempRadSys->MaxCloNumOfSurfaces);
4700 9 : state.dataLowTempRadSys->FirstTimeFlag = false;
4701 : }
4702 :
4703 187153 : state.dataLowTempRadSys->Ckj = 0.0;
4704 187153 : state.dataLowTempRadSys->Cmj = 0.0;
4705 187153 : state.dataLowTempRadSys->WaterTempOut = this->WaterInletTemp;
4706 :
4707 187153 : ZoneNum = this->ZonePtr;
4708 187153 : ZoneMult = double(Zone(ZoneNum).Multiplier * Zone(ZoneNum).ListMultiplier);
4709 187153 : WaterMassFlow = this->WaterMassFlowRate / ZoneMult;
4710 187153 : WaterTempIn = this->WaterInletTemp;
4711 :
4712 187153 : if (WaterMassFlow <= 0.0) {
4713 : // No flow or below minimum allowed so there is no heat source/sink
4714 : // This is possible with a mismatch between system and plant operation
4715 : // or a slight mismatch between zone and system controls. This is not
4716 : // necessarily a "problem" so this exception is necessary in the code.
4717 132 : for (int RadSurfNum = 1; RadSurfNum <= this->NumOfSurfaces; ++RadSurfNum) {
4718 66 : int SurfNum = this->SurfacePtr(RadSurfNum);
4719 66 : state.dataHeatBalFanSys->QRadSysSource(SurfNum) = 0.0;
4720 66 : if (Surface(SurfNum).ExtBoundCond > 0 && Surface(SurfNum).ExtBoundCond != SurfNum) {
4721 0 : state.dataHeatBalFanSys->QRadSysSource(Surface(SurfNum).ExtBoundCond) = 0.0; // Also zero the other side of an interzone
4722 : }
4723 : }
4724 :
4725 66 : this->WaterOutletTemp = this->WaterInletTemp;
4726 :
4727 : } else {
4728 :
4729 374174 : for (int RadSurfNum = 1; RadSurfNum <= this->NumOfSurfaces; ++RadSurfNum) {
4730 187087 : int SurfNum = this->SurfacePtr(RadSurfNum);
4731 : // Determine the heat exchanger "effectiveness" term
4732 :
4733 748348 : EpsMdotCp = calculateHXEffectivenessTerm(state,
4734 : SurfNum,
4735 : WaterTempIn,
4736 : WaterMassFlow,
4737 187087 : this->SurfaceFrac(RadSurfNum),
4738 187087 : this->NumCircuits(RadSurfNum),
4739 : this->DesignObjectPtr,
4740 : typeOfRadiantSystem);
4741 :
4742 : // Obtain the heat balance coefficients and calculate the intermediate coefficients
4743 : // linking the inlet water temperature to the heat source/sink to the radiant system.
4744 : // The coefficients are based on the following development...
4745 : // The heat balance equations at the outside and inside surfaces are of the form:
4746 : // Tinside = Ca + Cb*Toutside + Cc*q"
4747 : // Toutside = Cd + Ce*Tinside + Cf*q"
4748 : // Tsource = Cg + Ch*q" + Ci*Tinside + Cj*Toutside
4749 : // where:
4750 : // Tinside is the temperature at the inside surface
4751 : // Toutside is the temperature at the outside surface
4752 : // Tsource is the temperature within the radiant system at the location of the source/sink
4753 : // Ca is all of the other terms in the inside heat balance (solar, LW exchange, conduction history terms, etc.)
4754 : // Cb is the current cross CTF term
4755 : // Cc is the QTF inside term for the current heat source/sink
4756 : // Cd is all of the other terms in the outside heat balance (solar, LW exchange, conduction history terms, etc.)
4757 : // Ce is the current cross CTF term (should be equal to Cb)
4758 : // Cf is the QTF outside term for the current heat source/sink
4759 : // Cg is the summation of all temperature and source history terms at the source/sink location
4760 : // Ch is the QTF term at the source/sink location for the current heat source/sink
4761 : // Ci is the CTF inside term for the current inside surface temperature
4762 : // Cj is the CTF outside term for the current outside surface temperature
4763 : // Note that it is necessary to not use "slow conduction" assumptions because the
4764 : // source/sink has an impact on BOTH the inside and outside surface heat balances.
4765 : // Hence the more general formulation.
4766 : // The first two T equations above can be solved to remove the other surface temperature.
4767 : // This results in the following equations:
4768 : // Tinside = Ca + Cb*(Cd + Ce*Tinside + Cf*q") + Cc*q" or...
4769 : // Tinside = (Ca + Cb*Cd + (Cc+Cb*Cf)*q") / (1 - Ce*Cb)
4770 : // Toutside = Cd + Ce*(Ca + Cb*Toutside + Cc*q") + Cf*q" or...
4771 : // Toutside = (Cd + Ce*Ca + (Cf+Ce*Cc)*q") / (1 - Ce*Cb)
4772 : // Substituting the new equations for Tinside and Toutside as a function of C and q"
4773 : // into the equation for Tsource...
4774 : // Tsource = Cg + Ch*q" + Ci*((Ca + Cb*Cd + (Cc+Cb*Cf)*q") / (1 - Ce*Cb)) &
4775 : // + Cj*((Cd + Ce*Ca + (Cf+Ce*Cc)*q") / (1 - Ce*Cb))
4776 : // Or rearranging this to get Tsource as a function of q", we get...
4777 : // Tsource = Cg + ((Ci*(Ca + Cb*Cd) + Cj*(Cd + Ce*Ca))/(1-Ce*Cb)) &
4778 : // +(Ch + ((Ci*(Cc + Cb*Cf) + Cj*(Cf + Ce*Cc))/(1-Ce*Cb)))*q"
4779 : // Or in a slightly simpler form...
4780 : // Tsource = Ck + Cl*q"
4781 : // where:
4782 : // Ck = Cg + ((Ci*(Ca + Cb*Cd) + Cj*(Cd + Ce*Ca))/(1-Ce*Cb))
4783 : // Cl = Ch + ((Ci*(Cc + Cb*Cf) + Cj*(Cf + Ce*Cc))/(1-Ce*Cb))
4784 : // Note also that from heat exchanger "algebra", we have:
4785 : // q = epsilon*qmax and qmax = Mdot*Cp*(Twaterin-Tsource)
4786 : // So...
4787 : // q" = q/Area = (epsilon*Mdot*Cp/Area)*(Twaterin-Tsource)
4788 : // Or rearranging this equation:
4789 : // Tsource = -(q"*A/(epsilon*Mdot*Cp)) + Twaterin
4790 : // Setting this equation equal to the other equation for Tsource a couple lines up
4791 : // and rearranging to solve for q"...
4792 : // q" = (Twaterin - Ck) / (Cl + (A/(epsilon*Mdot*Cp))
4793 : // or
4794 : // q = (Twaterin - Ck) / ((Cl/A) + (1/epsilon*Mdot*Cp))
4795 : // or
4796 : // q = epsilon*Mdot*Cp*(Twaterin - Ck) / (1+(epsilon*Mdot*Cp*Cl/A))
4797 : // which is the desired result, that is the heat source or sink to the radiant
4798 : // system as a function of the water inlet temperature (flow rate is also in there
4799 : // as well as all of the heat balance terms "hidden" in Ck and Cl).
4800 :
4801 187087 : int ConstrNum = Surface(SurfNum).Construction;
4802 187087 : auto const &thisConstruct = state.dataConstruction->Construct(ConstrNum);
4803 :
4804 187087 : Ca = state.dataHeatBalFanSys->RadSysTiHBConstCoef(SurfNum);
4805 187087 : Cb = state.dataHeatBalFanSys->RadSysTiHBToutCoef(SurfNum);
4806 187087 : Cc = state.dataHeatBalFanSys->RadSysTiHBQsrcCoef(SurfNum);
4807 :
4808 187087 : Cd = state.dataHeatBalFanSys->RadSysToHBConstCoef(SurfNum);
4809 187087 : Ce = state.dataHeatBalFanSys->RadSysToHBTinCoef(SurfNum);
4810 187087 : Cf = state.dataHeatBalFanSys->RadSysToHBQsrcCoef(SurfNum);
4811 :
4812 187087 : Cg = state.dataHeatBalFanSys->CTFTsrcConstPart(SurfNum);
4813 187087 : Ch = thisConstruct.CTFTSourceQ[0];
4814 187087 : Ci = thisConstruct.CTFTSourceIn[0];
4815 187087 : Cj = thisConstruct.CTFTSourceOut[0];
4816 :
4817 187087 : Ck = Cg + ((Ci * (Ca + Cb * Cd) + Cj * (Cd + Ce * Ca)) / (1.0 - Ce * Cb));
4818 187087 : Cl = Ch + ((Ci * (Cc + Cb * Cf) + Cj * (Cf + Ce * Cc)) / (1.0 - Ce * Cb));
4819 :
4820 187087 : Mdot = WaterMassFlow * this->SurfaceFrac(RadSurfNum);
4821 187087 : Cp = this->water->getSpecificHeat(state, WaterTempIn, RoutineName);
4822 :
4823 187087 : if (!Iteration) {
4824 :
4825 187087 : if (Surface(SurfNum).HeatTransferAlgorithm == DataSurfaces::HeatTransferModel::CTF) {
4826 150349 : state.dataHeatBalFanSys->QRadSysSource(SurfNum) =
4827 150349 : EpsMdotCp * (WaterTempIn - Ck) / (1.0 + (EpsMdotCp * Cl / Surface(SurfNum).Area));
4828 : }
4829 :
4830 187087 : if (Surface(SurfNum).HeatTransferAlgorithm == DataSurfaces::HeatTransferModel::CondFD) {
4831 36738 : state.dataHeatBalFanSys->QRadSysSource(SurfNum) =
4832 36738 : EpsMdotCp * (WaterTempIn - state.dataHeatBalFanSys->TCondFDSourceNode(SurfNum));
4833 : }
4834 :
4835 187087 : if (Surface(SurfNum).ExtBoundCond > 0 && Surface(SurfNum).ExtBoundCond != SurfNum) {
4836 0 : state.dataHeatBalFanSys->QRadSysSource(Surface(SurfNum).ExtBoundCond) =
4837 0 : state.dataHeatBalFanSys->QRadSysSource(SurfNum); // Also set the other side of an interzone
4838 : }
4839 187087 : state.dataLowTempRadSys->WaterTempOut(RadSurfNum) = WaterTempIn - (state.dataHeatBalFanSys->QRadSysSource(SurfNum) / (Mdot * Cp));
4840 : } else { // (Iteration)
4841 : // In this case, we did not know the inlet temperature directly and have
4842 : // to figure it out as part of the solution. Thus, we have to do a little
4843 : // more algebra.
4844 : // The last equation in the previous block was:
4845 : // q = epsilon*Mdot*Cp*(Twaterin - Ck) / (1+(epsilon*Mdot*Cp*Cl/A))
4846 : // which combines with:
4847 : // q = Mdot*Cp*(Twaterin - Twaterout,j)
4848 : // so that:
4849 : // (Twaterin - Twaterout.j) = epsilon*(Twaterin - Ck) / (1+(epsilon*Mdot*Cp*Cl/A))
4850 : // Let:
4851 : // Cm = epsilonj / (1+(epsilonj*Mdot,j*Cp*Cl,j/A))
4852 : // for each surface in the radiant system. This results in:
4853 : // (Twaterin - Twaterout,j) = Cm,j*(Twaterin - Ck,j)
4854 : // Or:
4855 : // Twaterout,j = (1 - Cm,j)*Twaterin + Cm,j*Ck,j
4856 : // This holds for each surface that is part of the radiant system (j). To get the
4857 : // overall outlet temperature, we have to do a mixing calculation after all of the
4858 : // surfaces have been simulated:
4859 : // Twaterout = SUM(Fractionj*Twaterout,j)
4860 : // We also have to solve an energy balance at the mixing valve and add in pump heat.
4861 : // The energy balance at the mixing valve relates the loop inlet temperature (Tloopin)
4862 : // and the overall outlet temperature (Twaterout):
4863 : // Tpumpin = (Mdotloop/Mdotradsys)*Tloopin + (Mdotrecirc/Mdotradsys)*Twaterout
4864 : // This can then be related to the inlet water temperature to the radiant system
4865 : // after pump heat has been taken into account:
4866 : // Twaterin = (Mdotloop/Mdotradsys)*Tloopin + (Mdotrecirc/Mdotradsys)*Twaterout + PumpHeat/(Mdotradsys*Cp)
4867 : // Pluggin in the definition of Twaterout (sum equation above) and then the definition
4868 : // of each individual Twaterout,j equation (which is solely a function of Twaterin
4869 : // and coefficients), we can obtain an equation for Twaterin that consists of all
4870 : // known quantities. This requires us to calculate Ck,j and Cm,j for all the radiant
4871 : // surfaces in the system first and then coming up with a calculation for Twaterin.
4872 : // After than, individual Twaterout,j can be calculated along with QRadSysSource.
4873 0 : state.dataLowTempRadSys->Ckj(RadSurfNum) = Ck;
4874 0 : state.dataLowTempRadSys->Cmj(RadSurfNum) = (EpsMdotCp / (Mdot * Cp)) / (1.0 + (EpsMdotCp * Cl / Surface(SurfNum).Area));
4875 :
4876 0 : if (RadSurfNum == this->NumOfSurfaces) { // Last one so we can now do the other calculations
4877 : // Equation for Twaterin is:
4878 : // Twaterin = (LoopTerm + RecircTerm)/(TwiCoeff)
4879 : // where:
4880 : // LoopTerm = (Mdotloop/Mdotradsys)*Tloopin + PumpHeat/(Mdotradsys*Cp)
4881 : // RecircTerm = (Mdotrecirc/Mdotradsys)*SUM(FlowFracj*Ck,j*Cm,j)
4882 : // TwiCoeff = 1 - (Mdotrecirc/Mdotradsys)*SUM(FlowFracj*(1 - Cm,j))
4883 0 : SumFlowFracCkCm = 0.0;
4884 0 : SumFlowFracOneMinusCm = 0.0;
4885 0 : for (int RadSurfNum2 = 1; RadSurfNum2 <= this->NumOfSurfaces; ++RadSurfNum2) {
4886 0 : SumFlowFracCkCm += (this->SurfaceFrac(RadSurfNum2) * state.dataLowTempRadSys->Ckj(RadSurfNum) *
4887 0 : state.dataLowTempRadSys->Cmj(RadSurfNum2));
4888 0 : SumFlowFracOneMinusCm += (this->SurfaceFrac(RadSurfNum2) * (1.0 - state.dataLowTempRadSys->Cmj(RadSurfNum2)));
4889 : }
4890 :
4891 0 : LoopTerm = (this->WaterInjectionRate / this->WaterMassFlowRate) * state.dataLoopNodes->Node(MainLoopNodeIn).Temp +
4892 0 : (this->PumpHeattoFluid / (this->WaterMassFlowRate * Cp));
4893 :
4894 0 : RecircTerm = (this->WaterRecircRate / this->WaterMassFlowRate) * SumFlowFracCkCm;
4895 :
4896 0 : TwiCoeff = 1.0 - (this->WaterRecircRate / this->WaterMassFlowRate) * SumFlowFracOneMinusCm;
4897 :
4898 0 : WaterTempIn = (LoopTerm + RecircTerm) / (TwiCoeff);
4899 :
4900 0 : this->WaterInletTemp = WaterTempIn;
4901 :
4902 0 : for (int RadSurfNum2 = 1; RadSurfNum2 <= this->NumOfSurfaces; ++RadSurfNum2) {
4903 0 : state.dataLowTempRadSys->WaterTempOut(RadSurfNum2) =
4904 0 : WaterTempIn * (1.0 - state.dataLowTempRadSys->Cmj(RadSurfNum2)) +
4905 0 : (state.dataLowTempRadSys->Ckj(RadSurfNum2) * state.dataLowTempRadSys->Cmj(RadSurfNum2));
4906 0 : Mdot = WaterMassFlow * this->SurfaceFrac(RadSurfNum2);
4907 0 : int SurfNum2 = this->SurfacePtr(RadSurfNum2);
4908 0 : state.dataHeatBalFanSys->QRadSysSource(SurfNum2) =
4909 0 : Mdot * Cp * (WaterTempIn - state.dataLowTempRadSys->WaterTempOut(RadSurfNum2));
4910 0 : if (Surface(SurfNum2).ExtBoundCond > 0 && Surface(SurfNum2).ExtBoundCond != SurfNum2) {
4911 0 : state.dataHeatBalFanSys->QRadSysSource(Surface(SurfNum2).ExtBoundCond) =
4912 0 : state.dataHeatBalFanSys->QRadSysSource(SurfNum2); // Also set the other side of an interzone
4913 : }
4914 : }
4915 : }
4916 : }
4917 : }
4918 :
4919 373721 : for (int RadSurfNum = 1; RadSurfNum <= this->NumOfSurfaces; ++RadSurfNum) {
4920 187087 : int SurfNum = this->SurfacePtr(RadSurfNum);
4921 : // "Temperature Comparison" Cut-off:
4922 : // Check to see whether or not the system should really be running. If
4923 : // QRadSysSource is negative when we are in heating mode or QRadSysSource
4924 : // is positive when we are in cooling mode, then the radiant system will
4925 : // be doing the opposite of its intention. In this case, the flow rate
4926 : // is set to zero to avoid heating in cooling mode or cooling in heating
4927 : // mode.
4928 373721 : if (((this->opMode == OpMode::Heat) && (state.dataHeatBalFanSys->QRadSysSource(SurfNum) <= 0.0)) ||
4929 186634 : ((this->opMode == OpMode::Cool) && (state.dataHeatBalFanSys->QRadSysSource(SurfNum) >= 0.0))) {
4930 453 : WaterMassFlow = 0.0;
4931 453 : if (this->opMode == OpMode::Heat) {
4932 453 : SetComponentFlowRate(state, WaterMassFlow, this->HotWaterInNode, this->HotWaterOutNode, this->HWPlantLoc);
4933 0 : } else if (this->opMode == OpMode::Cool) {
4934 0 : SetComponentFlowRate(state, WaterMassFlow, this->ColdWaterInNode, this->ColdWaterOutNode, this->CWPlantLoc);
4935 : }
4936 453 : this->WaterMassFlowRate = WaterMassFlow;
4937 453 : this->opMode = OpMode::None;
4938 906 : for (int RadSurfNum2 = 1; RadSurfNum2 <= this->NumOfSurfaces; ++RadSurfNum2) {
4939 453 : int SurfNum2 = this->SurfacePtr(RadSurfNum2);
4940 453 : state.dataHeatBalFanSys->QRadSysSource(SurfNum2) = 0.0;
4941 453 : if (Surface(SurfNum2).ExtBoundCond > 0 && Surface(SurfNum2).ExtBoundCond != SurfNum2) {
4942 0 : state.dataHeatBalFanSys->QRadSysSource(Surface(SurfNum2).ExtBoundCond) = 0.0; // Also zero the other side of an interzone
4943 : }
4944 : }
4945 453 : break; // outer do loop
4946 : }
4947 : }
4948 : // Condensation Cut-off:
4949 : // Check to see whether there are any surface temperatures within the radiant system that have
4950 : // dropped below the dew-point temperature. If so, we need to shut off this radiant system.
4951 : // A safety parameter is added (hardwired parameter) to avoid getting too close to condensation
4952 : // conditions.
4953 187087 : this->CondCausedShutDown = false;
4954 187087 : DewPointTemp =
4955 187087 : PsyTdpFnWPb(state, state.dataZoneTempPredictorCorrector->zoneHeatBalance(this->ZonePtr).airHumRat, state.dataEnvrn->OutBaroPress);
4956 :
4957 187087 : if ((this->opMode == OpMode::Cool) && (ConstantFlowDesignDataObject.condCtrlType == CondCtrlType::SimpleOff)) {
4958 :
4959 44105 : for (int RadSurfNum2 = 1; RadSurfNum2 <= this->NumOfSurfaces; ++RadSurfNum2) {
4960 24118 : if (state.dataHeatBalSurf->SurfInsideTempHist(1)(this->SurfacePtr(RadSurfNum2)) <
4961 24118 : (DewPointTemp + ConstantFlowDesignDataObject.CondDewPtDeltaT)) {
4962 : // Condensation warning--must shut off radiant system
4963 4131 : this->CondCausedShutDown = true;
4964 4131 : WaterMassFlow = 0.0;
4965 4131 : this->opMode = OpMode::None;
4966 4131 : SetComponentFlowRate(state, WaterMassFlow, this->ColdWaterInNode, this->ColdWaterOutNode, this->CWPlantLoc);
4967 4131 : this->WaterMassFlowRate = WaterMassFlow;
4968 8262 : for (int RadSurfNum3 = 1; RadSurfNum3 <= this->NumOfSurfaces; ++RadSurfNum3) {
4969 4131 : int SurfNum2 = this->SurfacePtr(RadSurfNum3);
4970 4131 : state.dataHeatBalFanSys->QRadSysSource(SurfNum2) = 0.0;
4971 4131 : if (Surface(SurfNum2).ExtBoundCond > 0 && Surface(SurfNum2).ExtBoundCond != SurfNum2) {
4972 0 : state.dataHeatBalFanSys->QRadSysSource(Surface(SurfNum2).ExtBoundCond) =
4973 : 0.0; // Also zero the other side of an interzone
4974 : }
4975 : }
4976 : // Produce a warning message so that user knows the system was shut-off due to potential for condensation
4977 4131 : if (!state.dataGlobal->WarmupFlag) {
4978 582 : if (this->CondErrIndex == 0) { // allow errors up to number of radiant systems
4979 2 : ShowWarningMessage(state, format("{} [{}]", cConstantFlowSystem, this->Name));
4980 4 : ShowContinueError(state,
4981 4 : format("Surface [{}] temperature below dew-point temperature--potential for condensation exists",
4982 2 : Surface(this->SurfacePtr(RadSurfNum2)).Name));
4983 4 : ShowContinueError(state, "Flow to the radiant system will be shut-off to avoid condensation");
4984 4 : ShowContinueError(state,
4985 4 : format("Predicted radiant system surface temperature = {:.2R}",
4986 2 : state.dataHeatBalSurf->SurfInsideTempHist(1)(this->SurfacePtr(RadSurfNum2))));
4987 4 : ShowContinueError(state,
4988 4 : format("Zone dew-point temperature + safety delta T= {:.2R}",
4989 2 : DewPointTemp + ConstantFlowDesignDataObject.CondDewPtDeltaT));
4990 4 : ShowContinueErrorTimeStamp(state, "");
4991 4 : ShowContinueError(state,
4992 4 : format("Note that a {:.4R} C safety was chosen in the input for the shut-off criteria",
4993 : ConstantFlowDesignDataObject.CondDewPtDeltaT));
4994 6 : ShowContinueError(state, "Note also that this affects all surfaces that are part of this radiant system");
4995 : }
4996 4656 : ShowRecurringWarningErrorAtEnd(
4997 : state,
4998 1164 : format("{} [{}] condensation shut-off occurrence continues.", cConstantFlowSystem, this->Name),
4999 582 : this->CondErrIndex,
5000 : DewPointTemp,
5001 : DewPointTemp,
5002 : _,
5003 : "C",
5004 : "C");
5005 : }
5006 4131 : break; // outer do loop
5007 : }
5008 : }
5009 :
5010 187087 : } else if ((this->opMode == OpMode::Cool) && (ConstantFlowDesignDataObject.condCtrlType == CondCtrlType::None)) {
5011 :
5012 150468 : for (int RadSurfNum2 = 1; RadSurfNum2 <= this->NumOfSurfaces; ++RadSurfNum2) {
5013 75234 : if (state.dataHeatBalSurf->SurfInsideTempHist(1)(this->SurfacePtr(RadSurfNum2)) < DewPointTemp) {
5014 : // Condensation occurring but user does not want to shut radiant system off ever
5015 36362 : this->CondCausedShutDown = true;
5016 : }
5017 : }
5018 :
5019 162969 : } else if ((this->opMode == OpMode::Cool) && (ConstantFlowDesignDataObject.condCtrlType == CondCtrlType::VariedOff)) {
5020 :
5021 31867 : for (int RadSurfNum2 = 1; RadSurfNum2 <= this->NumOfSurfaces; ++RadSurfNum2) {
5022 18009 : if (state.dataHeatBalSurf->SurfInsideTempHist(1)(this->SurfacePtr(RadSurfNum2)) <
5023 18009 : (DewPointTemp + ConstantFlowDesignDataObject.CondDewPtDeltaT)) {
5024 8328 : state.dataLowTempRadSys->VarOffCond = true;
5025 8328 : if (state.dataLowTempRadSys->CFloCondIterNum >= 2) {
5026 : // We have already iterated once so now we must shut off radiant system
5027 4151 : this->CondCausedShutDown = true;
5028 4151 : WaterMassFlow = 0.0;
5029 4151 : this->opMode = OpMode::None;
5030 4151 : SetComponentFlowRate(state, WaterMassFlow, this->ColdWaterInNode, this->ColdWaterOutNode, this->CWPlantLoc);
5031 4151 : this->WaterMassFlowRate = WaterMassFlow;
5032 8302 : for (int RadSurfNum3 = 1; RadSurfNum3 <= this->NumOfSurfaces; ++RadSurfNum3) {
5033 4151 : int SurfNum2 = this->SurfacePtr(RadSurfNum3);
5034 4151 : state.dataHeatBalFanSys->QRadSysSource(SurfNum2) = 0.0;
5035 4151 : if (Surface(SurfNum2).ExtBoundCond > 0 && Surface(SurfNum2).ExtBoundCond != SurfNum2) {
5036 0 : state.dataHeatBalFanSys->QRadSysSource(Surface(SurfNum2).ExtBoundCond) =
5037 : 0.0; // Also zero the other side of an interzone
5038 : }
5039 : }
5040 : // Produce a warning message so that user knows the system was shut-off due to potential for condensation
5041 4151 : if (!state.dataGlobal->WarmupFlag) {
5042 577 : if (this->CondErrIndex == 0) { // allow errors up to number of radiant systems
5043 2 : ShowWarningMessage(state, format("{} [{}]", cConstantFlowSystem, this->Name));
5044 4 : ShowContinueError(
5045 : state,
5046 4 : format("Surface [{}] temperature below dew-point temperature--potential for condensation exists",
5047 2 : Surface(this->SurfacePtr(RadSurfNum2)).Name));
5048 4 : ShowContinueError(state, "Flow to the radiant system will be shut-off to avoid condensation");
5049 4 : ShowContinueError(state,
5050 4 : format("Predicted radiant system surface temperature = {:.2R}",
5051 2 : state.dataHeatBalSurf->SurfInsideTempHist(1)(this->SurfacePtr(RadSurfNum2))));
5052 4 : ShowContinueError(state,
5053 4 : format("Zone dew-point temperature + safety delta T= {:.2R}",
5054 2 : DewPointTemp + ConstantFlowDesignDataObject.CondDewPtDeltaT));
5055 4 : ShowContinueErrorTimeStamp(state, "");
5056 4 : ShowContinueError(state,
5057 4 : format("Note that a {:.4R} C safety was chosen in the input for the shut-off criteria",
5058 : ConstantFlowDesignDataObject.CondDewPtDeltaT));
5059 6 : ShowContinueError(state, "Note also that this affects all surfaces that are part of this radiant system");
5060 : }
5061 4616 : ShowRecurringWarningErrorAtEnd(
5062 : state,
5063 1154 : format("{} [{}] condensation shut-off occurrence continues.", cConstantFlowSystem, this->Name),
5064 577 : this->CondErrIndex,
5065 : DewPointTemp,
5066 : DewPointTemp,
5067 : _,
5068 : "C",
5069 : "C");
5070 : }
5071 4151 : break; // outer do loop
5072 : } else { // (First iteration--reset loop required temperature and try again to avoid condensation)
5073 4177 : state.dataLowTempRadSys->LoopReqTemp = DewPointTemp + ConstantFlowDesignDataObject.CondDewPtDeltaT;
5074 : }
5075 : }
5076 : }
5077 : }
5078 :
5079 : // Determine radiant system outlet temperature (two ways to calculate--use as a check)
5080 187087 : WaterOutletTempCheck = 0.0;
5081 187087 : TotalRadSysPower = 0.0;
5082 374174 : for (int RadSurfNum = 1; RadSurfNum <= this->NumOfSurfaces; ++RadSurfNum) {
5083 187087 : int SurfNum = this->SurfacePtr(RadSurfNum);
5084 187087 : TotalRadSysPower += state.dataHeatBalFanSys->QRadSysSource(SurfNum);
5085 187087 : WaterOutletTempCheck += (this->SurfaceFrac(RadSurfNum) * state.dataLowTempRadSys->WaterTempOut(RadSurfNum));
5086 : }
5087 187087 : TotalRadSysPower *= ZoneMult;
5088 :
5089 187087 : if (this->WaterMassFlowRate > 0.0) {
5090 178352 : Cp = this->water->getSpecificHeat(state, WaterTempIn, RoutineName);
5091 178352 : this->WaterOutletTemp = this->WaterInletTemp - (TotalRadSysPower / (this->WaterMassFlowRate * Cp));
5092 178352 : if ((std::abs(this->WaterOutletTemp - WaterOutletTempCheck) > TempCheckLimit) && (std::abs(TotalRadSysPower) > ZeroSystemResp)) {
5093 : // If the total system power is zero, that means we have shut down and the temperatures won't match because of that
5094 0 : ShowWarningError(state, "Radiant system water outlet temperature calculation mismatch--this should not happen");
5095 : }
5096 : } else {
5097 8735 : this->WaterOutletTemp = this->WaterInletTemp;
5098 : }
5099 : }
5100 :
5101 : // Now that we have the source/sink term(s), we must redo the heat balances to obtain
5102 : // the new SumHATsurf value for the zone. Note that the difference between the new
5103 : // SumHATsurf and the value originally calculated by the heat balance with a zero
5104 : // source for all radiant systems in the zone is the load met by the system (approximately).
5105 187153 : HeatBalanceSurfaceManager::CalcHeatBalanceOutsideSurf(state, ZoneNum);
5106 187153 : HeatBalanceSurfaceManager::CalcHeatBalanceInsideSurf(state, ZoneNum);
5107 :
5108 187153 : LoadMet = state.dataHeatBal->Zone(this->ZonePtr).sumHATsurf(state) - this->ZeroLTRSourceSumHATsurf;
5109 187153 : }
5110 : // TODO Write unit tests for baseboard
5111 78 : void ConstantFlowRadiantSystemData::calculateRunningMeanAverageTemperature(EnergyPlusData &state, int RadSysNum)
5112 : {
5113 : // This routine grabs the current weather data since it is currently available at this point in the simulation. Note, however,
5114 : // that the formula that calculates the running mean average (dry-bulb) temperature uses the values from "yesterday". So, today's
5115 : // values are calculated and then shifted at the beginning of the next day to the tomorrow variables. It is these tomorrow variables
5116 : // that are then used in the formula. So, that is why some of the assignments are done in the order that they are in below.
5117 :
5118 78 : ConstantFlowRadDesignData constantFlowDesignDataObject{state.dataLowTempRadSys->CflowRadiantSysDesign(
5119 78 : state.dataLowTempRadSys->CFloRadSys(RadSysNum).DesignObjectPtr)}; // Contains the data for constant flow hydronic systems
5120 :
5121 78 : if (state.dataGlobal->DayOfSim == 1 && state.dataGlobal->WarmupFlag) {
5122 : // there is no "history" here--assume everything that came before was the same (this applies to design days also--weather is always the
5123 : // same
5124 24 : this->todayAverageOutdoorDryBulbTemperature = this->calculateCurrentDailyAverageODB(state);
5125 24 : this->yesterdayAverageOutdoorDryBulbTemperature = this->todayAverageOutdoorDryBulbTemperature;
5126 24 : this->todayRunningMeanOutdoorDryBulbTemperature = this->todayAverageOutdoorDryBulbTemperature;
5127 24 : this->yesterdayRunningMeanOutdoorDryBulbTemperature = this->todayAverageOutdoorDryBulbTemperature;
5128 54 : } else if (!state.dataGlobal->WarmupFlag && state.dataGlobal->NumOfDayInEnvrn > 1) {
5129 : // This is an environment with more than one day (non-design day) so...
5130 : // First update yesterday's information using what was previously calculated for "today"
5131 0 : this->yesterdayAverageOutdoorDryBulbTemperature = this->todayAverageOutdoorDryBulbTemperature;
5132 0 : this->yesterdayRunningMeanOutdoorDryBulbTemperature = this->todayRunningMeanOutdoorDryBulbTemperature;
5133 : // Now update the running mean and average outdoor air temperatures
5134 0 : this->todayRunningMeanOutdoorDryBulbTemperature =
5135 0 : (1.0 - constantFlowDesignDataObject.runningMeanOutdoorAirTemperatureWeightingFactor) *
5136 0 : this->yesterdayAverageOutdoorDryBulbTemperature +
5137 0 : constantFlowDesignDataObject.runningMeanOutdoorAirTemperatureWeightingFactor * this->yesterdayRunningMeanOutdoorDryBulbTemperature;
5138 0 : this->todayAverageOutdoorDryBulbTemperature = this->calculateCurrentDailyAverageODB(state);
5139 : }
5140 78 : }
5141 :
5142 24 : Real64 ConstantFlowRadiantSystemData::calculateCurrentDailyAverageODB(EnergyPlusData &state)
5143 : {
5144 24 : Real64 sum = 0.0;
5145 600 : for (int hourNumber = 1; hourNumber <= Constant::iHoursInDay; ++hourNumber) {
5146 4032 : for (int timeStepNumber = 1; timeStepNumber <= state.dataGlobal->TimeStepsInHour; ++timeStepNumber) {
5147 3456 : sum += state.dataWeather->wvarsHrTsToday(timeStepNumber, hourNumber).OutDryBulbTemp;
5148 : }
5149 : }
5150 24 : return sum / (Constant::rHoursInDay * state.dataGlobal->TimeStepsInHour);
5151 : }
5152 :
5153 79059 : void ElectricRadiantSystemData::calculateLowTemperatureRadiantSystem(EnergyPlusData &state,
5154 : Real64 &LoadMet) // load met by the radiant system, in Watts
5155 : {
5156 :
5157 : // SUBROUTINE INFORMATION:
5158 : // AUTHOR Rick Strand
5159 : // DATE WRITTEN November 2000
5160 : // MODIFIED Sep 2011 LKL/BG - resimulate only zones needing it for Radiant systems
5161 :
5162 : // PURPOSE OF THIS SUBROUTINE:
5163 : // This subroutine does all of the stuff that is necessary to simulate
5164 : // a low temperature electric radiant heating system. Calls are made to
5165 : // appropriate subroutines either in this module or outside of it.
5166 :
5167 : // METHODOLOGY EMPLOYED:
5168 : // Follows the methods used by many other pieces of zone equipment except
5169 : // that we are controlling the electrical input to the building element's
5170 : // resistance heating wires. Note that cooling is not allowed for such
5171 : // a system.
5172 :
5173 : // REFERENCES:
5174 : // Other EnergyPlus modules
5175 : // IBLAST-QTF research program, completed in January 1995 (unreleased)
5176 : // Strand, R.K. 1995. "Heat Source Transfer Functions and Their Application to
5177 : // Low Temperature Radiant Heating Systems", Ph.D. dissertation, University
5178 : // of Illinois at Urbana-Champaign, Department of Mechanical and Industrial
5179 : // Engineering.
5180 : // Seem, J.E. 1986. "Heat Transfer in Buildings", Ph.D. dissertation, University
5181 : // of Wisconsin-Madison.
5182 :
5183 : // Using/Aliasing
5184 : using DataHeatBalance::ZoneData;
5185 : using HVAC::SmallLoad;
5186 :
5187 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
5188 : Real64 ControlTemp; // Temperature of the parameter that is controlling the radiant system
5189 : Real64 HeatFrac; // fraction of maximum electrical heat input to radiant system [dimensionless]
5190 : Real64 OffTemp; // Temperature above which the radiant system should be completely off [C]
5191 : int RadSurfNum; // number of surface that is the radiant system
5192 : int SurfNum; // intermediate variable for surface number in Surface derived type
5193 : int ZoneNum; // number of zone being served
5194 :
5195 : // initialize local variables
5196 79059 : ZoneNum = this->ZonePtr;
5197 79059 : HeatFrac = 0.0;
5198 79059 : auto &Surface = state.dataSurface->Surface;
5199 :
5200 79059 : if (this->availSched->getCurrentVal() <= 0.0) {
5201 :
5202 : // Unit is off; set the heat source terms to zero
5203 82788 : for (RadSurfNum = 1; RadSurfNum <= this->NumOfSurfaces; ++RadSurfNum) {
5204 41394 : SurfNum = this->SurfacePtr(RadSurfNum);
5205 41394 : state.dataHeatBalFanSys->QRadSysSource(SurfNum) = 0.0;
5206 41394 : if (Surface(SurfNum).ExtBoundCond > 0 && Surface(SurfNum).ExtBoundCond != SurfNum) {
5207 0 : state.dataHeatBalFanSys->QRadSysSource(Surface(SurfNum).ExtBoundCond) = 0.0; // Also zero the other side of an interzone
5208 : }
5209 : }
5210 :
5211 : } else { // Unit might be on-->this section is intended to determine whether the controls say
5212 : // that the unit should be on or not
5213 :
5214 : // Determine the current setpoint temperature and the temperature at which the unit should be completely off
5215 37665 : OffTemp = this->setOffTemperatureLowTemperatureRadiantSystem(state, this->setptSched, this->ThrottlRange, this->setpointType);
5216 :
5217 : // Determine the control temperature--what the setpoint/offtemp is being compared to for unit operation
5218 :
5219 37665 : ControlTemp = this->setRadiantSystemControlTemperature(state, controlType);
5220 :
5221 37665 : if (ControlTemp < OffTemp) { // HEATING MODE
5222 :
5223 29353 : this->opMode = OpMode::Heat;
5224 :
5225 29353 : HeatFrac = this->calculateOperationalFraction(OffTemp, ControlTemp, this->ThrottlRange);
5226 :
5227 : // Set the heat source for the low temperature electric radiant system
5228 58706 : for (RadSurfNum = 1; RadSurfNum <= this->NumOfSurfaces; ++RadSurfNum) {
5229 29353 : SurfNum = this->SurfacePtr(RadSurfNum);
5230 29353 : state.dataHeatBalFanSys->QRadSysSource(SurfNum) = HeatFrac * this->MaxElecPower * this->SurfaceFrac(RadSurfNum);
5231 29353 : if (Surface(SurfNum).ExtBoundCond > 0 && Surface(SurfNum).ExtBoundCond != SurfNum) {
5232 0 : state.dataHeatBalFanSys->QRadSysSource(Surface(SurfNum).ExtBoundCond) =
5233 0 : state.dataHeatBalFanSys->QRadSysSource(SurfNum); // Also set the other side of an interzone
5234 : }
5235 : }
5236 :
5237 : // Now "simulate" the system by recalculating the heat balances
5238 29353 : HeatBalanceSurfaceManager::CalcHeatBalanceOutsideSurf(state, ZoneNum);
5239 29353 : HeatBalanceSurfaceManager::CalcHeatBalanceInsideSurf(state, ZoneNum);
5240 :
5241 29353 : LoadMet = state.dataHeatBal->Zone(ZoneNum).sumHATsurf(state) - this->ZeroLTRSourceSumHATsurf;
5242 :
5243 : } else { // OFF or COOLING MODE (not allowed for an electric low temperature radiant system), turn it off
5244 :
5245 16624 : for (RadSurfNum = 1; RadSurfNum <= this->NumOfSurfaces; ++RadSurfNum) {
5246 8312 : SurfNum = this->SurfacePtr(RadSurfNum);
5247 8312 : state.dataHeatBalFanSys->QRadSysSource(SurfNum) = 0.0;
5248 8312 : if (Surface(SurfNum).ExtBoundCond > 0 && Surface(SurfNum).ExtBoundCond != SurfNum) {
5249 0 : state.dataHeatBalFanSys->QRadSysSource(Surface(SurfNum).ExtBoundCond) = 0.0; // Also zero the other side of an interzone
5250 : }
5251 : }
5252 : }
5253 : }
5254 79059 : }
5255 :
5256 666848 : void RadiantSystemBaseData::updateLowTemperatureRadiantSystemSurfaces(EnergyPlusData &state)
5257 : {
5258 :
5259 : // The purpose of this routine is to update the average heat source/sink for a particular system over the various system time
5260 : // steps that make up the zone time step. For hydronic systems, this routine must also set the outlet water conditions.
5261 : // For the source/sink average update, if the system time step elapsed is still what it used to be, then either we are still
5262 : // iterating orwe had to go back and shorten the time step. As a result, we have to subtract out the previous value that we
5263 : // added. If the system time step elapsed is different, then we just need to add the new values to the running average.
5264 :
5265 666848 : Real64 TimeStepSys = state.dataHVACGlobal->TimeStepSys;
5266 666848 : Real64 SysTimeElapsed = state.dataHVACGlobal->SysTimeElapsed;
5267 666848 : Real64 TimeStepZone = state.dataGlobal->TimeStepZone;
5268 :
5269 1373860 : for (int radSurfNum = 1; radSurfNum <= this->NumOfSurfaces; ++radSurfNum) {
5270 :
5271 707012 : int surfNum = this->SurfacePtr(radSurfNum);
5272 :
5273 707012 : if (this->LastSysTimeElapsed == SysTimeElapsed) {
5274 : // Still iterating or reducing system time step, so subtract old values which were
5275 : // not valid
5276 649209 : this->QRadSysSrcAvg(radSurfNum) -= this->LastQRadSysSrc(radSurfNum) * this->LastTimeStepSys / TimeStepZone;
5277 : }
5278 :
5279 : // Update the running average and the "last" values with the current values of the appropriate variables
5280 707012 : this->QRadSysSrcAvg(radSurfNum) += state.dataHeatBalFanSys->QRadSysSource(surfNum) * TimeStepSys / TimeStepZone;
5281 707012 : this->LastQRadSysSrc(radSurfNum) = state.dataHeatBalFanSys->QRadSysSource(surfNum);
5282 : }
5283 666848 : this->LastSysTimeElapsed = SysTimeElapsed;
5284 666848 : this->LastTimeStepSys = TimeStepSys;
5285 666848 : }
5286 :
5287 366056 : void VariableFlowRadiantSystemData::updateLowTemperatureRadiantSystem(EnergyPlusData &state)
5288 : {
5289 :
5290 : // Using/Aliasing
5291 : using PlantUtilities::SafeCopyPlantNode;
5292 : using PlantUtilities::SetComponentFlowRate;
5293 :
5294 : // SUBROUTINE PARAMETER DEFINITIONS:
5295 366056 : constexpr std::string_view RoutineName("UpdateVariableFlowSystem");
5296 :
5297 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
5298 : Real64 cpWater; // Specific heat of water
5299 : int waterInletNode; // Node number for the water side inlet of the radiant system
5300 : Real64 waterMassFlow; // Flow rate of water in the radiant system
5301 : int waterOutletNode; // Node number for the water side outlet of the radiant system
5302 :
5303 366056 : auto &Zone = state.dataHeatBal->Zone;
5304 366056 : auto &Node = state.dataLoopNodes->Node;
5305 :
5306 : // For a hydronic system, calculate the water side outlet conditions and set the
5307 : // appropriate conditions on the correct HVAC node.
5308 :
5309 : // First sum up all of the heat sources/sinks associated with this system
5310 366056 : Real64 TotalHeatSource(0.0); // Total heat source or sink for a particular radiant system (sum of all surface source/sinks)
5311 772276 : for (int radSurfNum = 1; radSurfNum <= this->NumOfSurfaces; ++radSurfNum) {
5312 406220 : TotalHeatSource += state.dataHeatBalFanSys->QRadSysSource(this->SurfacePtr(radSurfNum));
5313 : }
5314 366056 : TotalHeatSource *= double(Zone(this->ZonePtr).Multiplier * Zone(this->ZonePtr).ListMultiplier);
5315 :
5316 : // Update the heating side of things
5317 366056 : if (this->HeatingSystem) {
5318 :
5319 366010 : waterInletNode = this->HotWaterInNode;
5320 366010 : waterOutletNode = this->HotWaterOutNode;
5321 366010 : waterMassFlow = Node(waterInletNode).MassFlowRate;
5322 :
5323 366010 : cpWater = state.dataPlnt->PlantLoop(this->HWPlantLoc.loopNum).glycol->getSpecificHeat(state, Node(waterInletNode).Temp, RoutineName);
5324 :
5325 366010 : if (this->opMode == OpMode::Heat) {
5326 151202 : if ((cpWater > 0.0) && (waterMassFlow > 0.0)) {
5327 151196 : SafeCopyPlantNode(state, waterInletNode, waterOutletNode);
5328 151196 : Node(waterOutletNode).Temp = Node(waterInletNode).Temp - TotalHeatSource / waterMassFlow / cpWater;
5329 : } else {
5330 6 : SafeCopyPlantNode(state, waterInletNode, waterOutletNode);
5331 : }
5332 :
5333 : } else { // OpMode::Cool or not on
5334 214808 : SafeCopyPlantNode(state, waterInletNode, waterOutletNode);
5335 : }
5336 :
5337 366010 : this->checkForOutOfRangeTemperatureResult(state, Node(waterOutletNode).Temp, Node(waterInletNode).Temp);
5338 : }
5339 :
5340 366056 : if (this->CoolingSystem) {
5341 :
5342 351205 : waterInletNode = this->ColdWaterInNode;
5343 351205 : waterOutletNode = this->ColdWaterOutNode;
5344 351205 : waterMassFlow = Node(waterInletNode).MassFlowRate;
5345 :
5346 351205 : cpWater = state.dataPlnt->PlantLoop(this->CWPlantLoc.loopNum).glycol->getSpecificHeat(state, Node(waterInletNode).Temp, RoutineName);
5347 :
5348 351205 : if (this->opMode == OpMode::Cool) {
5349 119112 : if ((cpWater > 0.0) && (waterMassFlow > 0.0)) {
5350 119082 : SafeCopyPlantNode(state, waterInletNode, waterOutletNode);
5351 119082 : Node(waterOutletNode).Temp = Node(waterInletNode).Temp - TotalHeatSource / waterMassFlow / cpWater;
5352 : } else {
5353 30 : SafeCopyPlantNode(state, waterInletNode, waterOutletNode);
5354 : }
5355 :
5356 : } else { // OpMode::Heat or not on
5357 232093 : SafeCopyPlantNode(state, waterInletNode, waterOutletNode);
5358 : }
5359 :
5360 351205 : this->checkForOutOfRangeTemperatureResult(state, Node(waterOutletNode).Temp, Node(waterInletNode).Temp);
5361 : }
5362 366056 : }
5363 :
5364 221733 : void ConstantFlowRadiantSystemData::updateLowTemperatureRadiantSystem(EnergyPlusData &state)
5365 : {
5366 :
5367 : // Using/Aliasing
5368 : using PlantUtilities::SafeCopyPlantNode;
5369 : using PlantUtilities::SetComponentFlowRate;
5370 :
5371 : Real64 bypassMassFlow; // Local bypass for a constant flow radiant system (could have recirculation and/or bypass)
5372 : int waterInletNode; // Node number for the water side inlet of the radiant system
5373 : int waterOutletNode; // Node number for the water side outlet of the radiant system
5374 :
5375 : // For a constant flow system, calculate the water side outlet conditions
5376 : // and set the appropriate conditions on the correct HVAC node. This may
5377 : // require mixing if the main system does not provide all of the flow that
5378 : // the local radiant system circulates.
5379 :
5380 : // Update the heating side of things
5381 221733 : if (this->HeatingSystem) {
5382 :
5383 221732 : waterInletNode = this->HotWaterInNode;
5384 221732 : waterOutletNode = this->HotWaterOutNode;
5385 221732 : SafeCopyPlantNode(state, waterInletNode, waterOutletNode);
5386 :
5387 221732 : if (this->opMode == OpMode::Heat) {
5388 :
5389 : // Leave the inlet and outlet flow alone (if high enough) and perform a bypass if more flow than needed
5390 69273 : if (state.dataLoopNodes->Node(waterInletNode).MassFlowRate <= this->WaterInjectionRate) {
5391 : // Note that the water injection rate has already been restricted to the maximum available flow
5392 0 : state.dataLoopNodes->Node(waterOutletNode).Temp = this->WaterOutletTemp;
5393 : } else {
5394 : // Loop is providing more flow than needed so perform a local bypass and
5395 : // mix the flows to obtain the proper outlet temperature. In this case,
5396 : // the mass flow rates on the loop are left alone and the outlet temperature
5397 : // is calculated from a simple steady-steady, steady-flow energy balance.
5398 69273 : bypassMassFlow = state.dataLoopNodes->Node(waterInletNode).MassFlowRate - this->WaterInjectionRate;
5399 69273 : state.dataLoopNodes->Node(waterOutletNode).Temp =
5400 69273 : ((bypassMassFlow * state.dataLoopNodes->Node(waterInletNode).Temp) + (this->WaterInjectionRate * this->WaterOutletTemp)) /
5401 69273 : (state.dataLoopNodes->Node(waterOutletNode).MassFlowRate);
5402 : }
5403 : }
5404 665196 : this->checkForOutOfRangeTemperatureResult(
5405 221732 : state, state.dataLoopNodes->Node(waterOutletNode).Temp, state.dataLoopNodes->Node(waterInletNode).Temp);
5406 : }
5407 :
5408 221733 : if (this->CoolingSystem) {
5409 :
5410 208097 : waterInletNode = this->ColdWaterInNode;
5411 208097 : waterOutletNode = this->ColdWaterOutNode;
5412 208097 : SafeCopyPlantNode(state, waterInletNode, waterOutletNode);
5413 :
5414 208097 : if (this->opMode == OpMode::Cool) {
5415 :
5416 104902 : if (state.dataLoopNodes->Node(waterInletNode).MassFlowRate <= this->WaterInjectionRate) {
5417 : // Note that the water injection rate has already been restricted to the maximum available flow
5418 :
5419 20566 : state.dataLoopNodes->Node(waterOutletNode).Temp = this->WaterOutletTemp;
5420 : } else {
5421 : // Loop is providing more flow than needed so perform a local bypass and
5422 : // mix the flows to obtain the proper outlet temperature. In this case,
5423 : // the mass flow rates on the loop are left alone and the outlet temperature
5424 : // is calculated from a simple steady-steady, steady-flow energy balance.
5425 84336 : bypassMassFlow = state.dataLoopNodes->Node(waterInletNode).MassFlowRate - this->WaterInjectionRate;
5426 84336 : state.dataLoopNodes->Node(waterOutletNode).Temp =
5427 84336 : ((bypassMassFlow * state.dataLoopNodes->Node(waterInletNode).Temp) + (this->WaterInjectionRate * this->WaterOutletTemp)) /
5428 84336 : (state.dataLoopNodes->Node(waterOutletNode).MassFlowRate);
5429 : }
5430 :
5431 314706 : this->checkForOutOfRangeTemperatureResult(
5432 104902 : state, state.dataLoopNodes->Node(waterOutletNode).Temp, state.dataLoopNodes->Node(waterInletNode).Temp);
5433 : }
5434 : }
5435 221733 : }
5436 :
5437 79059 : void ElectricRadiantSystemData::updateLowTemperatureRadiantSystem([[maybe_unused]] EnergyPlusData &state)
5438 : { // Dummy routine: no updates are needed for electric radiant systems
5439 79059 : }
5440 :
5441 1043849 : void HydronicSystemBaseData::checkForOutOfRangeTemperatureResult(EnergyPlusData &state, Real64 const outletTemp, Real64 const inletTemp)
5442 : {
5443 :
5444 : // SUBROUTINE INFORMATION:
5445 : // AUTHOR B. Griffith
5446 : // DATE WRITTEN March 2013
5447 :
5448 : // PURPOSE OF THIS SUBROUTINE:
5449 : // check for crazy, out of range temperature results for fluid leaving radiant system
5450 :
5451 : // Using/Aliasing
5452 :
5453 1043849 : Real64 constexpr upperRangeLimit(500.0); // high error trigger limit for when model is not working
5454 1043849 : Real64 constexpr lowerRangeLimit(-300.0); // Low error trigger limit for when model is not working
5455 :
5456 1043849 : if (outletTemp < lowerRangeLimit) {
5457 0 : state.dataLowTempRadSys->warnTooLow = true;
5458 : }
5459 :
5460 1043849 : if (outletTemp > upperRangeLimit) {
5461 0 : state.dataLowTempRadSys->warnTooHigh = true;
5462 : }
5463 :
5464 1043849 : if (state.dataLowTempRadSys->warnTooLow || state.dataLowTempRadSys->warnTooHigh) {
5465 0 : if (state.dataLowTempRadSys->warnTooLow) {
5466 0 : if (this->OutRangeLoErrorCount == 0) {
5467 0 : ShowSevereMessage(state, "UpdateLowTempRadiantSystem: model result for fluid outlet temperature is not physical.");
5468 0 : ShowContinueError(state, format("Occurs for radiant system name = {}", this->Name));
5469 0 : ShowContinueError(state, format("Calculated radiant system outlet temperature = {:.3R} [C]", outletTemp));
5470 0 : ShowContinueError(state, format("Radiant system inlet temperature = {:.3R} [C]", inletTemp));
5471 0 : ShowContinueError(
5472 : state, "A possible cause is that the materials used in the internal source construction are not compatible with the model.");
5473 : }
5474 0 : ShowRecurringSevereErrorAtEnd(
5475 : state,
5476 0 : "UpdateLowTempRadiantSystem: Detected low out of range outlet temperature result for radiant system name =" + this->Name,
5477 0 : this->OutRangeLoErrorCount,
5478 : outletTemp,
5479 : outletTemp);
5480 : }
5481 :
5482 0 : if (state.dataLowTempRadSys->warnTooHigh) {
5483 0 : if (this->OutRangeHiErrorCount == 0) {
5484 0 : ShowSevereMessage(state, "UpdateLowTempRadiantSystem: model result for fluid outlet temperature is not physical.");
5485 0 : ShowContinueError(state, format("Occurs for radiant system name = {}", this->Name));
5486 0 : ShowContinueError(state, format("Calculated radiant system outlet temperature = {:.3R} [C]", outletTemp));
5487 0 : ShowContinueError(state, format("Radiant system inlet temperature = {:.3R} [C]", inletTemp));
5488 0 : ShowContinueError(
5489 : state, "A possible cause is that the materials used in the internal source construction are not compatible with the model.");
5490 : }
5491 0 : ShowRecurringSevereErrorAtEnd(
5492 : state,
5493 0 : "UpdateLowTempRadiantSystem: Detected high out of range outlet temperature result radiant system name =" + this->Name,
5494 0 : this->OutRangeHiErrorCount,
5495 : outletTemp,
5496 : outletTemp);
5497 : }
5498 : }
5499 1043849 : }
5500 :
5501 610133 : Real64 RadiantSystemBaseData::setRadiantSystemControlTemperature(EnergyPlusData &state, CtrlType TempControlType)
5502 : {
5503 610133 : auto &thisZoneHB = state.dataZoneTempPredictorCorrector->zoneHeatBalance(this->ZonePtr);
5504 610133 : switch (TempControlType) {
5505 472548 : case CtrlType::MAT:
5506 472548 : return thisZoneHB.MAT;
5507 24689 : case CtrlType::MRT:
5508 24689 : return thisZoneHB.MRT;
5509 24733 : case CtrlType::Operative:
5510 24733 : return 0.5 * (thisZoneHB.MAT + thisZoneHB.MRT);
5511 16292 : case CtrlType::ODB:
5512 16292 : return state.dataHeatBal->Zone(this->ZonePtr).OutDryBulbTemp;
5513 14123 : case CtrlType::OWB:
5514 14123 : return state.dataHeatBal->Zone(this->ZonePtr).OutWetBulbTemp;
5515 15662 : case CtrlType::SurfFaceTemp:
5516 15662 : return state.dataHeatBalSurf->SurfTempIn(this->SurfacePtr(1)); // Grabs the inside face temperature of the first surface in the list
5517 15662 : case CtrlType::SurfIntTemp:
5518 15662 : return state.dataHeatBalSurf->SurfTempUserLoc(
5519 15662 : this->SurfacePtr(1)); // Grabs the temperature inside the slab at the location specified by the user
5520 26424 : case CtrlType::RunningMeanODB:
5521 26424 : return this->todayRunningMeanOutdoorDryBulbTemperature;
5522 0 : default:
5523 0 : ShowSevereError(state, format("Illegal control type in low temperature radiant system or it's design object: {}", this->Name));
5524 0 : ShowFatalError(state, "Preceding condition causes termination.");
5525 0 : return 0.0; // hush the compiler
5526 : }
5527 : }
5528 :
5529 : Real64
5530 320308 : RadiantSystemBaseData::calculateOperationalFraction(Real64 const offTemperature, Real64 const controlTemperature, Real64 const throttlingRange)
5531 : {
5532 320308 : Real64 temperatureDifference = std::abs(offTemperature - controlTemperature);
5533 320308 : if (temperatureDifference <= 0.0) {
5534 0 : return 0.0; // No temperature difference--turn things off (set to zero); technically shouldn't happen
5535 320308 : } else if (throttlingRange < 0.001) {
5536 8452 : return 1.0; // Throttling range is essentially zero and there is a temperature difference--turn it full on
5537 : } else {
5538 : // Temperature difference is non-zero and less than the throttling range--calculate the operation fraction, but limit to a maximum of 1.0
5539 311856 : return min(temperatureDifference / throttlingRange, 1.0);
5540 : }
5541 : }
5542 :
5543 747256 : Real64 RadiantSystemBaseData::setOffTemperatureLowTemperatureRadiantSystem(EnergyPlusData &state,
5544 : Sched::Schedule const *sched,
5545 : const Real64 throttlingRange,
5546 : SetpointType setpointType)
5547 : {
5548 747256 : Real64 scheduleValue = sched->getCurrentVal();
5549 747256 : switch (setpointType) {
5550 700162 : case SetpointType::HalfFlowPower:
5551 700162 : return scheduleValue + 0.5 * throttlingRange;
5552 47094 : case SetpointType::ZeroFlowPower:
5553 47094 : return scheduleValue;
5554 0 : default:
5555 0 : ShowSevereError(state, format("Illegal setpoint type in low temperature radiant system: {}", this->Name));
5556 0 : ShowFatalError(state, "Preceding condition causes termination.");
5557 0 : return scheduleValue + 0.5 * throttlingRange; // hush the compiler
5558 : }
5559 : }
5560 :
5561 : Real64
5562 507813 : HydronicSystemBaseData::calculateHXEffectivenessTerm(EnergyPlusData &state,
5563 : int const SurfNum, // Surface number for this particular part of the radiant system
5564 : Real64 const Temperature, // Temperature of water entering the radiant system, in C
5565 : Real64 const WaterMassFlow, // Mass flow rate of water in the radiant system, in kg/s
5566 : Real64 const FlowFraction, // Mass flow rate fraction for this surface in the radiant system
5567 : Real64 const NumCircs, // Number of fluid circuits in this surface
5568 : int const DesignObjPtr, // Design Object Pointer
5569 : SystemType const typeOfRadiantSystem)
5570 : {
5571 :
5572 : // SUBROUTINE INFORMATION:
5573 : // AUTHOR Rick Strand
5574 : // DATE WRITTEN December 2000
5575 :
5576 : // PURPOSE OF THIS SUBROUTINE:
5577 : // This subroutine calculates the radiant system "heat exchanger"
5578 : // effectiveness term. This is equal to the mass flow rate of water
5579 : // times the specific heat of water times the effectiveness of
5580 : // the heat exchanger (radiant system "coil").
5581 :
5582 : // METHODOLOGY EMPLOYED:
5583 : // Assumes that the only real heat transfer term that we have to
5584 : // deal with is the convection from the water to the tube. The
5585 : // other assumptions are that the tube inside surface temperature
5586 : // is equal to the "source location temperature" and that it is
5587 : // a CONSTANT throughout the radiant system. This is to make
5588 : // the problem more tractable and to fit with other system assumptions
5589 : // that were made elsewhere in the radiant system model.
5590 :
5591 : // REFERENCES:
5592 : // Property data for water shown below as parameters taken from
5593 : // Incropera and DeWitt, Introduction to Heat Transfer, Table A.6.
5594 : // Heat exchanger information also from Incropera and DeWitt.
5595 : // Code based loosely on code from IBLAST program (research version)
5596 :
5597 : // Return value
5598 : Real64 calculateHXEffectivenessTerm;
5599 :
5600 : // SUBROUTINE PARAMETER DEFINITIONS:
5601 507813 : Real64 constexpr MaxLaminarRe(2300.0); // Maximum Reynolds number for laminar flow
5602 507813 : int constexpr NumOfPropDivisions(13);
5603 507813 : Real64 constexpr MaxExpPower(50.0); // Maximum power after which EXP argument would be zero for DP variables
5604 : Array1D<Real64> Temps(NumOfPropDivisions,
5605 507813 : {1.85, 6.85, 11.85, 16.85, 21.85, 26.85, 31.85, 36.85, 41.85, 46.85, 51.85, 56.85, 61.85}); // Temperature, in C
5606 : Array1D<Real64> Mu(NumOfPropDivisions,
5607 : {0.001652,
5608 : 0.001422,
5609 : 0.001225,
5610 : 0.00108,
5611 : 0.000959,
5612 : 0.000855,
5613 : 0.000769,
5614 : 0.000695,
5615 : 0.000631,
5616 : 0.000577,
5617 : 0.000528,
5618 : 0.000489,
5619 507813 : 0.000453}); // Viscosity, in Ns/m2
5620 : Array1D<Real64> Conductivity(
5621 507813 : NumOfPropDivisions, {0.574, 0.582, 0.590, 0.598, 0.606, 0.613, 0.620, 0.628, 0.634, 0.640, 0.645, 0.650, 0.656}); // Conductivity, in W/mK
5622 : Array1D<Real64> Pr(NumOfPropDivisions,
5623 507813 : {12.22, 10.26, 8.81, 7.56, 6.62, 5.83, 5.20, 4.62, 4.16, 3.77, 3.42, 3.15, 2.88}); // Prandtl number (dimensionless)
5624 507813 : constexpr std::string_view RoutineName("calculateHXEffectivenessTerm");
5625 :
5626 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
5627 : int Index;
5628 : Real64 InterpFrac;
5629 : Real64 NuD;
5630 : Real64 ReD;
5631 : Real64 NTU;
5632 507813 : Real64 CpWater(0.0);
5633 : Real64 Kactual;
5634 : Real64 MUactual;
5635 : Real64 PRactual;
5636 : Real64 Eff; // HX effectiveness
5637 :
5638 507813 : FluidToSlabHeatTransferType FluidToSlabHeatTransfer(FluidToSlabHeatTransferType::ConvectionOnly);
5639 507813 : Real64 TubeDiameterInner(0.0); // inside tube diameter for embedded tubing (meters)
5640 507813 : Real64 TubeDiameterOuter(0.0); // outside tube diameter for embedded tubing (meters)
5641 :
5642 507813 : if (typeOfRadiantSystem == SystemType::Hydronic) {
5643 : VarFlowRadDesignData variableFlowDesignDataObject{
5644 320726 : state.dataLowTempRadSys->HydronicRadiantSysDesign(DesignObjPtr)}; // Contains the data for variable flow hydronic systems
5645 320726 : FluidToSlabHeatTransfer = variableFlowDesignDataObject.FluidToSlabHeatTransfer;
5646 320726 : TubeDiameterInner = variableFlowDesignDataObject.TubeDiameterInner;
5647 320726 : TubeDiameterOuter = variableFlowDesignDataObject.TubeDiameterOuter;
5648 320726 : }
5649 507813 : if (typeOfRadiantSystem == SystemType::ConstantFlow) {
5650 : ConstantFlowRadDesignData constantFlowDesignDataObject{
5651 187087 : state.dataLowTempRadSys->CflowRadiantSysDesign(DesignObjPtr)}; // Contains the data for constant flow hydronic systems
5652 187087 : FluidToSlabHeatTransfer = constantFlowDesignDataObject.FluidToSlabHeatTransfer;
5653 187087 : TubeDiameterInner = constantFlowDesignDataObject.TubeDiameterInner;
5654 187087 : TubeDiameterOuter = constantFlowDesignDataObject.TubeDiameterOuter;
5655 187087 : }
5656 :
5657 : // First find out where we are in the range of temperatures
5658 507813 : Index = 1;
5659 3642347 : while (Index <= NumOfPropDivisions) {
5660 3642347 : if (Temperature < Temps(Index)) {
5661 507813 : break; // DO loop
5662 : }
5663 3134534 : ++Index;
5664 : }
5665 :
5666 : // Initialize thermal properties of water
5667 507813 : if (Index == 1) {
5668 0 : MUactual = Mu(Index);
5669 0 : Kactual = Conductivity(Index);
5670 0 : PRactual = Pr(Index);
5671 507813 : } else if (Index > NumOfPropDivisions) {
5672 0 : Index = NumOfPropDivisions;
5673 0 : MUactual = Mu(Index);
5674 0 : Kactual = Conductivity(Index);
5675 0 : PRactual = Pr(Index);
5676 : } else {
5677 507813 : InterpFrac = (Temperature - Temps(Index - 1)) / (Temps(Index) - Temps(Index - 1));
5678 507813 : MUactual = Mu(Index - 1) + InterpFrac * (Mu(Index) - Mu(Index - 1));
5679 507813 : Kactual = Conductivity(Index - 1) + InterpFrac * (Conductivity(Index) - Conductivity(Index - 1));
5680 507813 : PRactual = Pr(Index - 1) + InterpFrac * (Pr(Index) - Pr(Index - 1));
5681 : }
5682 : // arguments are glycol name, temperature, and concentration
5683 507813 : switch (this->opMode) {
5684 238238 : case OpMode::Heat: {
5685 238238 : CpWater = state.dataPlnt->PlantLoop(this->HWPlantLoc.loopNum).glycol->getSpecificHeat(state, Temperature, RoutineName);
5686 238238 : } break;
5687 269575 : case OpMode::Cool: {
5688 269575 : CpWater = state.dataPlnt->PlantLoop(this->CWPlantLoc.loopNum).glycol->getSpecificHeat(state, Temperature, RoutineName);
5689 269575 : } break;
5690 0 : default: {
5691 0 : assert(false);
5692 : } break;
5693 : }
5694 :
5695 : // Calculate NTU based on the heat transfer model
5696 :
5697 507813 : if (FluidToSlabHeatTransfer == FluidToSlabHeatTransferType::ISOStandard) {
5698 :
5699 52342 : Real64 U = this->calculateUFromISOStandard(state, SurfNum, WaterMassFlow * FlowFraction, typeOfRadiantSystem, DesignObjPtr);
5700 :
5701 : // Calculate the NTU parameter
5702 : // NTU = UA/[(Mdot*Cp)min]
5703 : // where: U = h (convection coefficient) and h = (k)(Nu)/D
5704 : // A = Constant::Pi()*D*TubeLength
5705 52342 : NTU = U * Constant::Pi * TubeDiameterOuter * this->TubeLength / (WaterMassFlow * CpWater); // FlowFraction cancels out here
5706 : } else { // (this->FluidToSlabHeatTransfer == FluidToSlabHeatTransferTypes::ConvectionOnly)
5707 :
5708 : // Calculate the Reynold's number from RE=(4*Mdot)/(Pi*Mu*Diameter)
5709 455471 : ReD = 4.0 * WaterMassFlow * FlowFraction / (Constant::Pi * MUactual * TubeDiameterInner * NumCircs);
5710 :
5711 : // Calculate the Nusselt number based on what flow regime one is in
5712 455471 : if (ReD >= MaxLaminarRe) { // Turbulent flow --> use Colburn equation
5713 :
5714 432239 : NuD = 0.023 * std::pow(ReD, 0.8) * std::pow(PRactual, 1.0 / 3.0);
5715 :
5716 : } else { // Laminar flow --> use constant surface temperature relation
5717 :
5718 23232 : NuD = 3.66;
5719 : }
5720 :
5721 : // Calculate the NTU parameter
5722 : // NTU = UA/[(Mdot*Cp)min]
5723 : // where: U = h (convection coefficient) and h = (k)(Nu)/D
5724 : // A = Pi*D*TubeLength
5725 455471 : NTU = Constant::Pi * Kactual * NuD * this->TubeLength / (WaterMassFlow * CpWater); // FlowFraction cancels out here
5726 : }
5727 :
5728 : // Calculate Epsilon*MassFlowRate*Cp
5729 507813 : if (NTU > MaxExpPower) {
5730 412748 : Eff = 1.0;
5731 412748 : calculateHXEffectivenessTerm = FlowFraction * WaterMassFlow * CpWater;
5732 : } else {
5733 95065 : Eff = 1.0 - std::exp(-NTU);
5734 95065 : calculateHXEffectivenessTerm = Eff * FlowFraction * WaterMassFlow * CpWater;
5735 : }
5736 :
5737 507813 : return calculateHXEffectivenessTerm;
5738 507813 : }
5739 :
5740 52342 : Real64 HydronicSystemBaseData::calculateUFromISOStandard(EnergyPlusData &state,
5741 : int const SurfNum,
5742 : Real64 const WaterMassFlow,
5743 : SystemType typeOfRadiantSystem,
5744 : int const DesignObjPtr // Design Object Pointer
5745 : )
5746 : {
5747 : // Calculates the U-value for a pipe embedded in a radiant system using the information
5748 : // from ISO Standard 11855, Part 2 (2012): "Building environment design — Design, dimensioning,
5749 : // installation and control of embedded radiant heating and cooling systems — Part 2:
5750 : // Determination of the design heating and cooling capacity." This looks exclusively at the heat transfer
5751 : // between the fluid and the inner side of the pipe and heat conduction through the pipe. The remainder
5752 : // of the ISO calculation relates to the slab itself which is modeled using transient heat conduction here
5753 : // in EnergyPlus.
5754 :
5755 : // Return value
5756 : Real64 calculateUFromISOStandard;
5757 :
5758 52342 : int constructionNumber = state.dataSurface->Surface(SurfNum).Construction;
5759 :
5760 52342 : Real64 TubeDiameterOuter(0.0);
5761 52342 : Real64 TubeDiameterInner(0.0);
5762 52342 : Real64 TubeConductivity(0.0);
5763 :
5764 52342 : if (typeOfRadiantSystem == SystemType::Hydronic) {
5765 : VarFlowRadDesignData variableFlowDesignDataObject{
5766 23077 : state.dataLowTempRadSys->HydronicRadiantSysDesign(DesignObjPtr)}; // Contains the data for variable flow hydronic systems
5767 23077 : TubeDiameterOuter = variableFlowDesignDataObject.TubeDiameterOuter;
5768 23077 : TubeDiameterInner = variableFlowDesignDataObject.TubeDiameterInner;
5769 23077 : TubeConductivity = variableFlowDesignDataObject.VarFlowTubeConductivity;
5770 23077 : }
5771 52342 : if (typeOfRadiantSystem == SystemType::ConstantFlow) {
5772 : ConstantFlowRadDesignData constantFlowDesignDataObject{
5773 29265 : state.dataLowTempRadSys->CflowRadiantSysDesign(DesignObjPtr)}; // Contains the data for constant flow hydronic systems
5774 29265 : TubeDiameterOuter = constantFlowDesignDataObject.TubeDiameterOuter;
5775 29265 : TubeDiameterInner = constantFlowDesignDataObject.TubeDiameterInner;
5776 29265 : TubeConductivity = constantFlowDesignDataObject.ConstFlowTubeConductivity;
5777 29265 : }
5778 :
5779 : // Fluid resistance to heat transfer, assumes turbulent flow (Equation B5, p. 38 of ISO Standard 11855-2)
5780 52342 : Real64 distanceBetweenPipes = 2.0 * state.dataConstruction->Construct(constructionNumber).ThicknessPerpend;
5781 52342 : Real64 ratioDiameterToMassFlowLength = TubeDiameterInner / WaterMassFlow / this->TubeLength;
5782 52342 : Real64 rFluid = 0.125 / Constant::Pi * std::pow(distanceBetweenPipes, 0.13) * std::pow(ratioDiameterToMassFlowLength, 0.87);
5783 :
5784 : // Resistance to heat transfer (conduction through the piping material, Equation B6, p. 38 of ISO Standard 11855-2)
5785 52342 : Real64 rTube = 0.5 * distanceBetweenPipes * std::log(TubeDiameterOuter / TubeDiameterInner) / Constant::Pi / TubeConductivity;
5786 :
5787 52342 : calculateUFromISOStandard = 1.0 / (rFluid + rTube);
5788 :
5789 52342 : return calculateUFromISOStandard;
5790 : }
5791 :
5792 2799877 : void UpdateRadSysSourceValAvg(EnergyPlusData &state,
5793 : bool &LowTempRadSysOn) // .TRUE. if the radiant system has run this zone time step
5794 : {
5795 :
5796 : // SUBROUTINE INFORMATION:
5797 : // AUTHOR Rick Strand
5798 : // DATE WRITTEN November 2000
5799 :
5800 : // PURPOSE OF THIS SUBROUTINE:
5801 : // To transfer the average value of the heat source/sink over the entire
5802 : // zone time step back to the heat balance routines so that the heat
5803 : // balance algorithms can simulate one last time with the average source
5804 : // to maintain some reasonable amount of continuity and energy balance
5805 : // in the temperature and flux histories.
5806 :
5807 : // METHODOLOGY EMPLOYED:
5808 : // All of the record keeping for the average term is done in the Update
5809 : // routine so the only other thing that this subroutine does is check to
5810 : // see if the system was even on. If any average term is non-zero, then
5811 : // one or more of the radiant systems was running.
5812 :
5813 : // SUBROUTINE PARAMETER DEFINITIONS:
5814 2799877 : Real64 constexpr CloseEnough(0.01); // Some arbitrarily small value to avoid zeros and numbers that are almost the same
5815 :
5816 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
5817 : int SurfNum; // DO loop counter for surface index
5818 :
5819 2799877 : LowTempRadSysOn = false;
5820 :
5821 : // If there are no radiant systems in this input file, just RETURN
5822 2799877 : if (state.dataLowTempRadSys->TotalNumOfRadSystems == 0) {
5823 2712229 : return;
5824 : }
5825 :
5826 : // Now check to see if anything is running and transfer information from the "average" variables to
5827 : // the array that will be used within the heat balance.
5828 87648 : state.dataHeatBalFanSys->QRadSysSource = 0.0; // Zero this out first
5829 228201 : for (int numRadSys = 1; numRadSys <= state.dataLowTempRadSys->NumOfHydrLowTempRadSys; ++numRadSys) {
5830 140553 : auto &thisLTR = state.dataLowTempRadSys->HydrRadSys(numRadSys);
5831 298686 : for (int numRadSurf = 1; numRadSurf <= thisLTR.NumOfSurfaces; ++numRadSurf) {
5832 158133 : if (thisLTR.QRadSysSrcAvg(numRadSurf) != 0.0) {
5833 113420 : LowTempRadSysOn = true;
5834 : }
5835 158133 : SurfNum = thisLTR.SurfacePtr(numRadSurf);
5836 158133 : state.dataHeatBalFanSys->QRadSysSource(SurfNum) = thisLTR.QRadSysSrcAvg(numRadSurf);
5837 : }
5838 : }
5839 169593 : for (int numRadSys = 1; numRadSys <= state.dataLowTempRadSys->NumOfCFloLowTempRadSys; ++numRadSys) {
5840 81945 : auto &thisLTR = state.dataLowTempRadSys->CFloRadSys(numRadSys);
5841 163890 : for (int numRadSurf = 1; numRadSurf <= thisLTR.NumOfSurfaces; ++numRadSurf) {
5842 81945 : if (thisLTR.QRadSysSrcAvg(numRadSurf) != 0.0) {
5843 62968 : LowTempRadSysOn = true;
5844 : }
5845 81945 : SurfNum = thisLTR.SurfacePtr(numRadSurf);
5846 81945 : state.dataHeatBalFanSys->QRadSysSource(SurfNum) = thisLTR.QRadSysSrcAvg(numRadSurf);
5847 : }
5848 : }
5849 119985 : for (int numRadSys = 1; numRadSys <= state.dataLowTempRadSys->NumOfElecLowTempRadSys; ++numRadSys) {
5850 32337 : auto &thisLTR = state.dataLowTempRadSys->ElecRadSys(numRadSys);
5851 64674 : for (int numRadSurf = 1; numRadSurf <= thisLTR.NumOfSurfaces; ++numRadSurf) {
5852 32337 : if (thisLTR.QRadSysSrcAvg(numRadSurf) != 0.0) {
5853 13256 : LowTempRadSysOn = true;
5854 : }
5855 32337 : SurfNum = thisLTR.SurfacePtr(numRadSurf);
5856 32337 : state.dataHeatBalFanSys->QRadSysSource(SurfNum) = thisLTR.QRadSysSrcAvg(numRadSurf);
5857 : }
5858 : }
5859 :
5860 87648 : auto const &Surface = state.dataSurface->Surface;
5861 :
5862 : // For interzone surfaces, QRadSysSource was only updated for the "active" side. The
5863 : // active side would have a non-zero value at this point. If the numbers differ, then we have to manually update.
5864 1929609 : for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
5865 1841961 : if (Surface(SurfNum).ExtBoundCond > 0 && Surface(SurfNum).ExtBoundCond != SurfNum) {
5866 511686 : if (std::abs(state.dataHeatBalFanSys->QRadSysSource(SurfNum) -
5867 511686 : state.dataHeatBalFanSys->QRadSysSource(Surface(SurfNum).ExtBoundCond)) > CloseEnough) { // numbers differ
5868 2610 : if (std::abs(state.dataHeatBalFanSys->QRadSysSource(SurfNum)) >
5869 1305 : std::abs(state.dataHeatBalFanSys->QRadSysSource(Surface(SurfNum).ExtBoundCond))) {
5870 1305 : state.dataHeatBalFanSys->QRadSysSource(Surface(SurfNum).ExtBoundCond) = state.dataHeatBalFanSys->QRadSysSource(SurfNum);
5871 : } else {
5872 0 : state.dataHeatBalFanSys->QRadSysSource(SurfNum) = state.dataHeatBalFanSys->QRadSysSource(Surface(SurfNum).ExtBoundCond);
5873 : }
5874 : }
5875 : }
5876 : }
5877 : }
5878 :
5879 366056 : void VariableFlowRadiantSystemData::reportLowTemperatureRadiantSystem([[maybe_unused]] EnergyPlusData &state)
5880 : {
5881 :
5882 366056 : auto &Zone = state.dataHeatBal->Zone;
5883 :
5884 : // Using/Aliasing
5885 366056 : Real64 TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
5886 :
5887 366056 : Real64 totalRadSysPower(0.0); // Total source/sink power for the radiant system (sum of all surfaces of the system)
5888 :
5889 772276 : for (int radSurfNum = 1; radSurfNum <= this->NumOfSurfaces; ++radSurfNum) {
5890 406220 : totalRadSysPower += state.dataHeatBalFanSys->QRadSysSource(this->SurfacePtr(radSurfNum));
5891 : }
5892 :
5893 366056 : totalRadSysPower *= double(Zone(this->ZonePtr).Multiplier * Zone(this->ZonePtr).ListMultiplier);
5894 :
5895 366056 : this->HeatPower = 0.0;
5896 366056 : this->CoolPower = 0.0;
5897 :
5898 366056 : if (this->opMode == OpMode::Heat) {
5899 151202 : this->WaterInletTemp = state.dataLoopNodes->Node(this->HotWaterInNode).Temp;
5900 151202 : this->WaterOutletTemp = state.dataLoopNodes->Node(this->HotWaterOutNode).Temp;
5901 151202 : this->WaterMassFlowRate = state.dataLoopNodes->Node(this->HotWaterInNode).MassFlowRate;
5902 151202 : this->HeatPower = totalRadSysPower;
5903 :
5904 214854 : } else if (this->opMode == OpMode::Cool) {
5905 119112 : this->WaterInletTemp = state.dataLoopNodes->Node(this->ColdWaterInNode).Temp;
5906 119112 : this->WaterOutletTemp = state.dataLoopNodes->Node(this->ColdWaterOutNode).Temp;
5907 119112 : this->WaterMassFlowRate = state.dataLoopNodes->Node(this->ColdWaterInNode).MassFlowRate;
5908 119112 : this->CoolPower = -totalRadSysPower;
5909 :
5910 : } else { // Not Operating: Leave temperatures at previous values
5911 95742 : this->WaterMassFlowRate = 0.0;
5912 95742 : this->WaterOutletTemp = this->WaterInletTemp;
5913 : }
5914 :
5915 366056 : this->HeatEnergy = this->HeatPower * TimeStepSysSec;
5916 366056 : this->CoolEnergy = this->CoolPower * TimeStepSysSec;
5917 :
5918 366056 : if (this->CondCausedShutDown) {
5919 32019 : this->CondCausedTimeOff = TimeStepSysSec;
5920 : } else {
5921 334037 : this->CondCausedTimeOff = 0.0;
5922 : }
5923 366056 : }
5924 :
5925 221733 : void ConstantFlowRadiantSystemData::reportLowTemperatureRadiantSystem(EnergyPlusData &state)
5926 : {
5927 :
5928 221733 : auto &Zone = state.dataHeatBal->Zone;
5929 :
5930 : // Using/Aliasing
5931 221733 : Real64 TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
5932 :
5933 221733 : constexpr std::string_view routineName("ReportConstantFlowSystem");
5934 : Real64 cpFluid; // Specific heat of the fluid in the radiant system
5935 221733 : Real64 totalRadSysPower(0.0); // Total source/sink power for the radiant system (sum of all surfaces of the system)
5936 :
5937 443466 : for (int radSurfNum = 1; radSurfNum <= this->NumOfSurfaces; ++radSurfNum) {
5938 221733 : totalRadSysPower += state.dataHeatBalFanSys->QRadSysSource(this->SurfacePtr(radSurfNum));
5939 : }
5940 :
5941 221733 : totalRadSysPower *= double(Zone(this->ZonePtr).Multiplier * Zone(this->ZonePtr).ListMultiplier);
5942 :
5943 221733 : this->HeatPower = 0.0;
5944 221733 : this->CoolPower = 0.0;
5945 :
5946 : // Note that temperatures have already been set as part of the simulation
5947 : // step. So, they do not need to be calculated here except for the pump
5948 : // inlet temperature which was not calculated elsewhere. If the system is
5949 : // not operating, leave the temperatures with their previous values but
5950 : // zero out the flow and power quantities (should have already been done
5951 : // in another routine, but just in case...).
5952 :
5953 221733 : if (this->opMode == OpMode::Heat) {
5954 69273 : cpFluid = state.dataPlnt->PlantLoop(this->HWPlantLoc.loopNum)
5955 69273 : .glycol->getSpecificHeat(state, state.dataLoopNodes->Node(this->HotWaterInNode).Temp, routineName);
5956 :
5957 69273 : this->HeatPower = totalRadSysPower;
5958 69273 : if (this->PumpMassFlowRate > 0.0) {
5959 69273 : this->PumpInletTemp = this->WaterInletTemp - (this->PumpHeattoFluid / (this->PumpMassFlowRate * cpFluid));
5960 : } else {
5961 0 : this->PumpInletTemp = this->WaterInletTemp;
5962 : }
5963 :
5964 152460 : } else if (this->opMode == OpMode::Cool) {
5965 104902 : cpFluid = state.dataPlnt->PlantLoop(this->CWPlantLoc.loopNum)
5966 104902 : .glycol->getSpecificHeat(state, state.dataLoopNodes->Node(this->ColdWaterInNode).Temp, routineName);
5967 :
5968 104902 : this->CoolPower = -totalRadSysPower;
5969 104902 : this->PumpInletTemp = this->WaterInletTemp - (this->PumpHeattoFluid / (this->PumpMassFlowRate * cpFluid));
5970 :
5971 : } else { // Not Operating
5972 47558 : this->WaterOutletTemp = this->WaterInletTemp;
5973 47558 : this->PumpInletTemp = this->WaterInletTemp;
5974 47558 : this->WaterMassFlowRate = 0.0;
5975 47558 : this->WaterInjectionRate = 0.0;
5976 47558 : this->WaterRecircRate = 0.0;
5977 47558 : this->HeatPower = 0.0;
5978 47558 : this->CoolPower = 0.0;
5979 47558 : this->PumpPower = 0.0;
5980 47558 : this->PumpMassFlowRate = 0.0;
5981 47558 : this->PumpHeattoFluid = 0.0;
5982 : }
5983 :
5984 221733 : this->HeatEnergy = this->HeatPower * TimeStepSysSec;
5985 221733 : this->CoolEnergy = this->CoolPower * TimeStepSysSec;
5986 221733 : this->PumpEnergy = this->PumpPower * TimeStepSysSec;
5987 221733 : this->PumpHeattoFluidEnergy = this->PumpHeattoFluid * TimeStepSysSec;
5988 :
5989 221733 : if (this->CondCausedShutDown) {
5990 51257 : this->CondCausedTimeOff = TimeStepSysSec;
5991 : } else {
5992 170476 : this->CondCausedTimeOff = 0.0;
5993 : }
5994 221733 : }
5995 :
5996 79059 : void ElectricRadiantSystemData::reportLowTemperatureRadiantSystem([[maybe_unused]] EnergyPlusData &state)
5997 : {
5998 :
5999 79059 : auto &Zone = state.dataHeatBal->Zone;
6000 79059 : Real64 TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
6001 : // Using/Aliasing
6002 79059 : Real64 totalRadSysPower(0.0); // Total source/sink power for the radiant system (sum of all surfaces of the system)
6003 :
6004 158118 : for (int radSurfNum = 1; radSurfNum <= this->NumOfSurfaces; ++radSurfNum) {
6005 79059 : totalRadSysPower += state.dataHeatBalFanSys->QRadSysSource(this->SurfacePtr(radSurfNum));
6006 : }
6007 :
6008 79059 : totalRadSysPower *= double(Zone(this->ZonePtr).Multiplier * Zone(this->ZonePtr).ListMultiplier);
6009 :
6010 79059 : this->ElecPower = totalRadSysPower;
6011 79059 : this->ElecEnergy = this->ElecPower * TimeStepSysSec;
6012 79059 : this->HeatPower = this->ElecPower;
6013 79059 : this->HeatEnergy = this->ElecEnergy;
6014 79059 : }
6015 :
6016 : } // namespace LowTempRadiantSystem
6017 :
6018 : } // namespace EnergyPlus
|