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