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