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