Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2023, 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 :
55 : // EnergyPlus Headers
56 : #include <EnergyPlus/Autosizing/HeatingCapacitySizing.hh>
57 : #include <EnergyPlus/Data/EnergyPlusData.hh>
58 : #include <EnergyPlus/DataHVACGlobals.hh>
59 : #include <EnergyPlus/DataHeatBalFanSys.hh>
60 : #include <EnergyPlus/DataHeatBalSurface.hh>
61 : #include <EnergyPlus/DataHeatBalance.hh>
62 : #include <EnergyPlus/DataIPShortCuts.hh>
63 : #include <EnergyPlus/DataSizing.hh>
64 : #include <EnergyPlus/DataSurfaces.hh>
65 : #include <EnergyPlus/DataViewFactorInformation.hh>
66 : #include <EnergyPlus/DataZoneEquipment.hh>
67 : #include <EnergyPlus/General.hh>
68 : #include <EnergyPlus/GeneralRoutines.hh>
69 : #include <EnergyPlus/HeatBalanceIntRadExchange.hh>
70 : #include <EnergyPlus/HeatBalanceSurfaceManager.hh>
71 : #include <EnergyPlus/HighTempRadiantSystem.hh>
72 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
73 : #include <EnergyPlus/OutputProcessor.hh>
74 : #include <EnergyPlus/ScheduleManager.hh>
75 : #include <EnergyPlus/UtilityRoutines.hh>
76 : #include <EnergyPlus/ZoneTempPredictorCorrector.hh>
77 :
78 : namespace EnergyPlus {
79 :
80 : namespace HighTempRadiantSystem {
81 :
82 : // Module containing the routines dealing with the high temperature radiant systems
83 :
84 : // MODULE INFORMATION:
85 : // AUTHOR Rick Strand
86 : // DATE WRITTEN February 2001
87 : // MODIFIED na
88 : // RE-ENGINEERED na
89 :
90 : // PURPOSE OF THIS MODULE:
91 : // The purpose of this module is to simulate high temperature radiant systems.
92 : // It is the intention of this module to cover all types of high temperature
93 : // radiant systems (gas and electric)
94 :
95 : // METHODOLOGY EMPLOYED:
96 : // Based on work done in BLAST, the EnergyPlus low temperature radiant system
97 : // model, this model has similar inherent challenges that are similar to the
98 : // low temperature radiant system. Because it is a system that directly
99 : // effects the surface heat balances, it must be a part of both the heat
100 : // balance routines and linked in with the HVAC system.
101 : // REFERENCES:
102 : // Building Systems Laboratory, BLAST User's Guide/Reference.
103 : // Maloney, Dan. 1987. "Development of a radiant heater model and the
104 : // incorporation of thermal comfort considerations into the BLAST
105 : // energy analysis program", M.S. thesis, University of Illinois at
106 : // Urbana-Champaign (Dept. of Mechanical and Industrial Engineering).
107 :
108 : // OTHER NOTES: none
109 :
110 : // USE STATEMENTS:
111 : // Use statements for data only modules
112 : // Using/Aliasing
113 : using DataHVACGlobals::SmallLoad;
114 :
115 : // Data
116 : // MODULE PARAMETER DEFINITIONS:
117 : constexpr const char *cGas("Gas");
118 : constexpr const char *cNaturalGas("NaturalGas");
119 : constexpr const char *cElectric("Electric");
120 : constexpr const char *cElectricity("Electricity");
121 : constexpr const char *cMATControl("MeanAirTemperature"); // Control for using mean air temperature
122 : constexpr const char *cMRTControl("MeanRadiantTemperature"); // Control for using mean radiant temperature
123 : constexpr const char *cOperativeControl("OperativeTemperature"); // Control for using operative temperature
124 : constexpr const char *cMATSPControl("MeanAirTemperatureSetpoint"); // Control for to MAT setpoint
125 : constexpr const char *cMRTSPControl("MeanRadiantTemperatureSetpoint"); // Control for to MRT setpoint
126 : constexpr const char *cOperativeSPControl("OperativeTemperatureSetpoint"); // Control for operative temperature setpoint
127 :
128 : // MODULE VARIABLE DECLARATIONS:
129 :
130 : // SUBROUTINE SPECIFICATIONS FOR MODULE HighTempRadiantSystem
131 :
132 : // Functions
133 :
134 128052 : void SimHighTempRadiantSystem(EnergyPlusData &state,
135 : std::string_view CompName, // name of the low temperature radiant system
136 : bool const FirstHVACIteration, // TRUE if 1st HVAC simulation of system timestep
137 : Real64 &LoadMet, // load met by the radiant system, in Watts
138 : int &CompIndex)
139 : {
140 :
141 : // SUBROUTINE INFORMATION:
142 : // AUTHOR Rick Strand
143 : // DATE WRITTEN February 2001
144 : // MODIFIED na
145 : // RE-ENGINEERED na
146 :
147 : // PURPOSE OF THIS SUBROUTINE:
148 : // This subroutine is the "manager" for the high temperature radiant
149 : // system model. It is called from the outside and controls the
150 : // actions and subroutine calls to lower levels as appropriate.
151 :
152 : // METHODOLOGY EMPLOYED:
153 : // Standard EnergyPlus manager subroutine layout
154 :
155 : // Using/Aliasing
156 :
157 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
158 : bool ErrorsFoundInGet; // Set to true when there are severe errors during the Get routine
159 : int RadSysNum; // Radiant system number/index in local derived types
160 :
161 128052 : if (state.dataHighTempRadSys->GetInputFlag) {
162 4 : ErrorsFoundInGet = false;
163 4 : GetHighTempRadiantSystem(state, ErrorsFoundInGet);
164 4 : if (ErrorsFoundInGet)
165 0 : ShowFatalError(state, "GetHighTempRadiantSystem: Errors found in input. Preceding condition(s) cause termination.");
166 4 : state.dataHighTempRadSys->GetInputFlag = false;
167 : }
168 :
169 : // Find the correct ZoneHVAC:HighTemperatureRadiant
170 128052 : if (CompIndex == 0) {
171 10 : RadSysNum = UtilityRoutines::FindItemInList(CompName, state.dataHighTempRadSys->HighTempRadSys);
172 10 : if (RadSysNum == 0) {
173 0 : ShowFatalError(state, "SimHighTempRadiantSystem: Unit not found=" + std::string{CompName});
174 : }
175 10 : CompIndex = RadSysNum;
176 : } else {
177 128042 : RadSysNum = CompIndex;
178 128042 : if (RadSysNum > state.dataHighTempRadSys->NumOfHighTempRadSys || RadSysNum < 1) {
179 0 : ShowFatalError(state,
180 0 : format("SimHighTempRadiantSystem: Invalid CompIndex passed={}, Number of Units={}, Entered Unit name={}",
181 : RadSysNum,
182 0 : state.dataHighTempRadSys->NumOfHighTempRadSys,
183 0 : CompName));
184 : }
185 128042 : if (state.dataHighTempRadSys->CheckEquipName(RadSysNum)) {
186 10 : if (CompName != state.dataHighTempRadSys->HighTempRadSys(RadSysNum).Name) {
187 0 : ShowFatalError(state,
188 0 : format("SimHighTempRadiantSystem: Invalid CompIndex passed={}, Unit name={}, stored Unit Name for that index={}",
189 : RadSysNum,
190 : CompName,
191 0 : state.dataHighTempRadSys->HighTempRadSys(RadSysNum).Name));
192 : }
193 10 : state.dataHighTempRadSys->CheckEquipName(RadSysNum) = false;
194 : }
195 : }
196 :
197 128052 : InitHighTempRadiantSystem(state, FirstHVACIteration, RadSysNum);
198 :
199 128052 : switch (state.dataHighTempRadSys->HighTempRadSys(RadSysNum).ControlType) {
200 42969 : case RadControlType::MATControl:
201 : case RadControlType::MRTControl:
202 : case RadControlType::OperativeControl: {
203 42969 : CalcHighTempRadiantSystem(state, RadSysNum);
204 42969 : } break;
205 85083 : case RadControlType::MATSPControl:
206 : case RadControlType::MRTSPControl:
207 : case RadControlType::OperativeSPControl: {
208 85083 : CalcHighTempRadiantSystemSP(state, FirstHVACIteration, RadSysNum);
209 85083 : } break;
210 0 : default:
211 0 : break;
212 : }
213 :
214 128052 : UpdateHighTempRadiantSystem(state, RadSysNum, LoadMet);
215 :
216 128052 : ReportHighTempRadiantSystem(state, RadSysNum);
217 128052 : }
218 :
219 4 : void GetHighTempRadiantSystem(EnergyPlusData &state, bool &ErrorsFound // TRUE if errors are found on processing the input
220 : )
221 : {
222 :
223 : // SUBROUTINE INFORMATION:
224 : // AUTHOR Rick Strand
225 : // DATE WRITTEN February 2001
226 : // MODIFIED na
227 : // RE-ENGINEERED na
228 :
229 : // PURPOSE OF THIS SUBROUTINE:
230 : // This subroutine reads the input for high temperature radiant systems
231 : // from the user input file. This will contain all of the information
232 : // needed to simulate a high temperature radiant system.
233 :
234 : // METHODOLOGY EMPLOYED:
235 : // Standard EnergyPlus methodology.
236 :
237 : // Using/Aliasing
238 : using DataSizing::AutoSize;
239 : using DataSizing::CapacityPerFloorArea;
240 : using DataSizing::FractionOfAutosizedHeatingCapacity;
241 : using DataSizing::HeatingDesignCapacity;
242 :
243 : using ScheduleManager::GetScheduleIndex;
244 :
245 : // SUBROUTINE PARAMETER DEFINITIONS:
246 4 : Real64 constexpr MaxCombustionEffic(1.00); // Limit the combustion efficiency to perfection
247 4 : Real64 constexpr MaxFraction(1.0); // Limit the highest allowed fraction for heat transfer parts
248 4 : Real64 constexpr MinCombustionEffic(0.01); // Limit the minimum combustion efficiency
249 4 : Real64 constexpr MinFraction(0.0); // Limit the lowest allowed fraction for heat transfer parts
250 4 : Real64 constexpr MinThrottlingRange(0.5); // Smallest throttling range allowed in degrees Celsius
251 : // INTEGER, PARAMETER :: MaxDistribSurfaces = 20 ! Maximum number of surfaces that a radiant heater can radiate to
252 4 : int constexpr iHeatCAPMAlphaNum(4); // get input index to High Temperature Radiant system heating capacity sizing method
253 4 : int constexpr iHeatDesignCapacityNumericNum(1); // get input index to High Temperature Radiant system heating capacity
254 4 : int constexpr iHeatCapacityPerFloorAreaNumericNum(
255 : 2); // get input index to High Temperature Radiant system heating capacity per floor area sizing
256 4 : int constexpr iHeatFracOfAutosizedCapacityNumericNum(
257 : 3); // get input index to High Temperature Radiant system heating capacity sizing as fraction of autozized heating capacity
258 :
259 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
260 : Real64 AllFracsSummed; // Sum of the fractions radiant, latent, and lost (must be <= 1)
261 : Real64 FracOfRadPotentiallyLost; // Difference between unity and AllFracsSummed for error reporting
262 : int IOStatus; // Used in GetObjectItem
263 : int Item; // Item to be "gotten"
264 : int NumAlphas; // Number of Alphas for each GetObjectItem call
265 : int NumNumbers; // Number of Numbers for each GetObjectItem call
266 : int SurfNum; // Surface number DO loop counter
267 : Real64 TotalFracToSurfs; // Sum of fractions of radiation to surfaces
268 :
269 : // Initializations and allocations
270 4 : state.dataHighTempRadSys->NumOfHighTempRadSys =
271 8 : state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "ZoneHVAC:HighTemperatureRadiant");
272 :
273 4 : state.dataHighTempRadSys->HighTempRadSys.allocate(state.dataHighTempRadSys->NumOfHighTempRadSys);
274 4 : state.dataHighTempRadSys->CheckEquipName.allocate(state.dataHighTempRadSys->NumOfHighTempRadSys);
275 4 : state.dataHighTempRadSys->HighTempRadSysNumericFields.allocate(state.dataHighTempRadSys->NumOfHighTempRadSys);
276 4 : state.dataHighTempRadSys->CheckEquipName = true;
277 :
278 : // extensible object, do not need max args because using IPShortCuts
279 4 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
280 4 : cCurrentModuleObject = "ZoneHVAC:HighTemperatureRadiant";
281 : // Obtain all of the user data related to high temperature radiant systems...
282 14 : for (Item = 1; Item <= state.dataHighTempRadSys->NumOfHighTempRadSys; ++Item) {
283 :
284 70 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
285 : cCurrentModuleObject,
286 : Item,
287 10 : state.dataIPShortCut->cAlphaArgs,
288 : NumAlphas,
289 10 : state.dataIPShortCut->rNumericArgs,
290 : NumNumbers,
291 : IOStatus,
292 10 : state.dataIPShortCut->lNumericFieldBlanks,
293 10 : state.dataIPShortCut->lAlphaFieldBlanks,
294 10 : state.dataIPShortCut->cAlphaFieldNames,
295 10 : state.dataIPShortCut->cNumericFieldNames);
296 :
297 10 : state.dataHighTempRadSys->HighTempRadSysNumericFields(Item).FieldNames.allocate(NumNumbers);
298 10 : state.dataHighTempRadSys->HighTempRadSysNumericFields(Item).FieldNames = "";
299 10 : state.dataHighTempRadSys->HighTempRadSysNumericFields(Item).FieldNames = state.dataIPShortCut->cNumericFieldNames;
300 10 : UtilityRoutines::IsNameEmpty(state, state.dataIPShortCut->cAlphaArgs(1), cCurrentModuleObject, ErrorsFound);
301 : // General user input data
302 10 : state.dataHighTempRadSys->HighTempRadSys(Item).Name = state.dataIPShortCut->cAlphaArgs(1);
303 :
304 10 : state.dataHighTempRadSys->HighTempRadSys(Item).SchedName = state.dataIPShortCut->cAlphaArgs(2);
305 10 : if (state.dataIPShortCut->lAlphaFieldBlanks(2)) {
306 0 : state.dataHighTempRadSys->HighTempRadSys(Item).SchedPtr = DataGlobalConstants::ScheduleAlwaysOn;
307 : } else {
308 10 : state.dataHighTempRadSys->HighTempRadSys(Item).SchedPtr = GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(2));
309 10 : if (state.dataHighTempRadSys->HighTempRadSys(Item).SchedPtr == 0) {
310 0 : ShowSevereError(state,
311 0 : cCurrentModuleObject + ": invalid " + state.dataIPShortCut->cAlphaFieldNames(2) +
312 0 : " entered =" + state.dataIPShortCut->cAlphaArgs(2) + " for " + state.dataIPShortCut->cAlphaFieldNames(1) +
313 0 : " = " + state.dataIPShortCut->cAlphaArgs(1));
314 0 : ErrorsFound = true;
315 : }
316 : }
317 :
318 10 : state.dataHighTempRadSys->HighTempRadSys(Item).ZoneName = state.dataIPShortCut->cAlphaArgs(3);
319 10 : state.dataHighTempRadSys->HighTempRadSys(Item).ZonePtr =
320 10 : UtilityRoutines::FindItemInList(state.dataIPShortCut->cAlphaArgs(3), state.dataHeatBal->Zone);
321 10 : if (state.dataHighTempRadSys->HighTempRadSys(Item).ZonePtr == 0) {
322 0 : ShowSevereError(state, "Invalid " + state.dataIPShortCut->cAlphaFieldNames(3) + " = " + state.dataIPShortCut->cAlphaArgs(3));
323 0 : ShowContinueError(state, "Occurs for " + cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1));
324 0 : ErrorsFound = true;
325 : }
326 :
327 : // state.dataHighTempRadSys->HighTempRadSys( Item ).MaxPowerCapac = state.dataIPShortCut->rNumericArgs( 1 );
328 :
329 : // Determine High Temp Radiant heating design capacity sizing method
330 10 : if (UtilityRoutines::SameString(state.dataIPShortCut->cAlphaArgs(iHeatCAPMAlphaNum), "HeatingDesignCapacity")) {
331 10 : state.dataHighTempRadSys->HighTempRadSys(Item).HeatingCapMethod = HeatingDesignCapacity;
332 :
333 10 : if (!state.dataIPShortCut->lNumericFieldBlanks(iHeatDesignCapacityNumericNum)) {
334 10 : state.dataHighTempRadSys->HighTempRadSys(Item).ScaledHeatingCapacity =
335 10 : state.dataIPShortCut->rNumericArgs(iHeatDesignCapacityNumericNum);
336 11 : if (state.dataHighTempRadSys->HighTempRadSys(Item).ScaledHeatingCapacity < 0.0 &&
337 1 : state.dataHighTempRadSys->HighTempRadSys(Item).ScaledHeatingCapacity != AutoSize) {
338 0 : ShowSevereError(state, cCurrentModuleObject + " = " + state.dataHighTempRadSys->HighTempRadSys(Item).Name);
339 0 : ShowContinueError(state,
340 0 : format("Illegal {} = {:.7T}",
341 0 : state.dataIPShortCut->cNumericFieldNames(iHeatDesignCapacityNumericNum),
342 0 : state.dataIPShortCut->rNumericArgs(iHeatDesignCapacityNumericNum)));
343 0 : ErrorsFound = true;
344 : }
345 : } else {
346 0 : ShowSevereError(state, cCurrentModuleObject + " = " + state.dataHighTempRadSys->HighTempRadSys(Item).Name);
347 0 : ShowContinueError(state,
348 0 : "Input for " + state.dataIPShortCut->cAlphaFieldNames(iHeatCAPMAlphaNum) + " = " +
349 0 : state.dataIPShortCut->cAlphaArgs(iHeatCAPMAlphaNum));
350 0 : ShowContinueError(state,
351 0 : "Blank field not allowed for " + state.dataIPShortCut->cNumericFieldNames(iHeatDesignCapacityNumericNum));
352 0 : ErrorsFound = true;
353 : }
354 0 : } else if (UtilityRoutines::SameString(state.dataIPShortCut->cAlphaArgs(iHeatCAPMAlphaNum), "CapacityPerFloorArea")) {
355 0 : state.dataHighTempRadSys->HighTempRadSys(Item).HeatingCapMethod = CapacityPerFloorArea;
356 0 : if (!state.dataIPShortCut->lNumericFieldBlanks(iHeatCapacityPerFloorAreaNumericNum)) {
357 0 : state.dataHighTempRadSys->HighTempRadSys(Item).ScaledHeatingCapacity =
358 0 : state.dataIPShortCut->rNumericArgs(iHeatCapacityPerFloorAreaNumericNum);
359 0 : if (state.dataHighTempRadSys->HighTempRadSys(Item).ScaledHeatingCapacity <= 0.0) {
360 0 : ShowSevereError(state, cCurrentModuleObject + " = " + state.dataHighTempRadSys->HighTempRadSys(Item).Name);
361 0 : ShowContinueError(state,
362 0 : "Input for " + state.dataIPShortCut->cAlphaFieldNames(iHeatCAPMAlphaNum) + " = " +
363 0 : state.dataIPShortCut->cAlphaArgs(iHeatCAPMAlphaNum));
364 0 : ShowContinueError(state,
365 0 : format("Illegal {} = {:.7T}",
366 0 : state.dataIPShortCut->cNumericFieldNames(iHeatCapacityPerFloorAreaNumericNum),
367 0 : state.dataIPShortCut->rNumericArgs(iHeatCapacityPerFloorAreaNumericNum)));
368 0 : ErrorsFound = true;
369 0 : } else if (state.dataHighTempRadSys->HighTempRadSys(Item).ScaledHeatingCapacity == AutoSize) {
370 0 : ShowSevereError(state, cCurrentModuleObject + " = " + state.dataHighTempRadSys->HighTempRadSys(Item).Name);
371 0 : ShowContinueError(state,
372 0 : "Input for " + state.dataIPShortCut->cAlphaFieldNames(iHeatCAPMAlphaNum) + " = " +
373 0 : state.dataIPShortCut->cAlphaArgs(iHeatCAPMAlphaNum));
374 0 : ShowContinueError(state,
375 0 : "Illegal " + state.dataIPShortCut->cNumericFieldNames(iHeatCapacityPerFloorAreaNumericNum) + " = Autosize");
376 0 : ErrorsFound = true;
377 : }
378 : } else {
379 0 : ShowSevereError(state, cCurrentModuleObject + " = " + state.dataHighTempRadSys->HighTempRadSys(Item).Name);
380 0 : ShowContinueError(state,
381 0 : "Input for " + state.dataIPShortCut->cAlphaFieldNames(iHeatCAPMAlphaNum) + " = " +
382 0 : state.dataIPShortCut->cAlphaArgs(iHeatCAPMAlphaNum));
383 0 : ShowContinueError(state,
384 0 : "Blank field not allowed for " + state.dataIPShortCut->cNumericFieldNames(iHeatCapacityPerFloorAreaNumericNum));
385 0 : ErrorsFound = true;
386 : }
387 0 : } else if (UtilityRoutines::SameString(state.dataIPShortCut->cAlphaArgs(iHeatCAPMAlphaNum), "FractionOfAutosizedHeatingCapacity")) {
388 0 : state.dataHighTempRadSys->HighTempRadSys(Item).HeatingCapMethod = FractionOfAutosizedHeatingCapacity;
389 0 : if (!state.dataIPShortCut->lNumericFieldBlanks(iHeatFracOfAutosizedCapacityNumericNum)) {
390 0 : state.dataHighTempRadSys->HighTempRadSys(Item).ScaledHeatingCapacity =
391 0 : state.dataIPShortCut->rNumericArgs(iHeatFracOfAutosizedCapacityNumericNum);
392 0 : if (state.dataHighTempRadSys->HighTempRadSys(Item).ScaledHeatingCapacity < 0.0) {
393 0 : ShowSevereError(state, cCurrentModuleObject + " = " + state.dataHighTempRadSys->HighTempRadSys(Item).Name);
394 0 : ShowContinueError(state,
395 0 : format("Illegal {} = {:.7T}",
396 0 : state.dataIPShortCut->cNumericFieldNames(iHeatFracOfAutosizedCapacityNumericNum),
397 0 : state.dataIPShortCut->rNumericArgs(iHeatFracOfAutosizedCapacityNumericNum)));
398 0 : ErrorsFound = true;
399 : }
400 : } else {
401 0 : ShowSevereError(state, cCurrentModuleObject + " = " + state.dataHighTempRadSys->HighTempRadSys(Item).Name);
402 0 : ShowContinueError(state,
403 0 : "Input for " + state.dataIPShortCut->cAlphaFieldNames(iHeatCAPMAlphaNum) + " = " +
404 0 : state.dataIPShortCut->cAlphaArgs(iHeatCAPMAlphaNum));
405 0 : ShowContinueError(
406 0 : state, "Blank field not allowed for " + state.dataIPShortCut->cNumericFieldNames(iHeatFracOfAutosizedCapacityNumericNum));
407 0 : ErrorsFound = true;
408 : }
409 : } else {
410 0 : ShowSevereError(state, cCurrentModuleObject + " = " + state.dataHighTempRadSys->HighTempRadSys(Item).Name);
411 0 : ShowContinueError(state,
412 0 : "Illegal " + state.dataIPShortCut->cAlphaFieldNames(iHeatCAPMAlphaNum) + " = " +
413 0 : state.dataIPShortCut->cAlphaArgs(iHeatCAPMAlphaNum));
414 0 : ErrorsFound = true;
415 : }
416 :
417 10 : if (UtilityRoutines::SameString(state.dataIPShortCut->cAlphaArgs(5), cNaturalGas)) {
418 7 : state.dataHighTempRadSys->HighTempRadSys(Item).HeaterType = RadHeaterType::Gas;
419 3 : } else if (UtilityRoutines::SameString(state.dataIPShortCut->cAlphaArgs(5), cElectricity)) {
420 3 : state.dataHighTempRadSys->HighTempRadSys(Item).HeaterType = RadHeaterType::Electric;
421 0 : } else if (UtilityRoutines::SameString(state.dataIPShortCut->cAlphaArgs(5), cGas)) {
422 0 : state.dataHighTempRadSys->HighTempRadSys(Item).HeaterType = RadHeaterType::Gas;
423 0 : } else if (UtilityRoutines::SameString(state.dataIPShortCut->cAlphaArgs(5), cElectric)) {
424 0 : state.dataHighTempRadSys->HighTempRadSys(Item).HeaterType = RadHeaterType::Electric;
425 : } else {
426 0 : ShowSevereError(state, "Invalid " + state.dataIPShortCut->cAlphaFieldNames(5) + " = " + state.dataIPShortCut->cAlphaArgs(5));
427 0 : ShowContinueError(state, "Occurs for " + cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1));
428 0 : ErrorsFound = true;
429 : }
430 :
431 10 : if (state.dataHighTempRadSys->HighTempRadSys(Item).HeaterType == RadHeaterType::Gas) {
432 7 : state.dataHighTempRadSys->HighTempRadSys(Item).CombustionEffic = state.dataIPShortCut->rNumericArgs(4);
433 : // Limit the combustion efficiency to between zero and one...
434 7 : if (state.dataHighTempRadSys->HighTempRadSys(Item).CombustionEffic < MinCombustionEffic) {
435 0 : state.dataHighTempRadSys->HighTempRadSys(Item).CombustionEffic = MinCombustionEffic;
436 0 : ShowWarningError(state,
437 0 : state.dataIPShortCut->cNumericFieldNames(4) + " was less than the allowable minimum, reset to minimum value.");
438 0 : ShowContinueError(state, "Occurs for " + cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1));
439 : }
440 7 : if (state.dataHighTempRadSys->HighTempRadSys(Item).CombustionEffic > MaxCombustionEffic) {
441 0 : state.dataHighTempRadSys->HighTempRadSys(Item).CombustionEffic = MaxCombustionEffic;
442 0 : ShowWarningError(
443 0 : state, state.dataIPShortCut->cNumericFieldNames(4) + " was greater than the allowable maximum, reset to maximum value.");
444 0 : ShowContinueError(state, "Occurs for " + cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1));
445 : }
446 : } else {
447 3 : state.dataHighTempRadSys->HighTempRadSys(Item).CombustionEffic = MaxCombustionEffic; // No inefficiency in the heater
448 : }
449 :
450 10 : state.dataHighTempRadSys->HighTempRadSys(Item).FracRadiant = state.dataIPShortCut->rNumericArgs(5);
451 10 : if (state.dataHighTempRadSys->HighTempRadSys(Item).FracRadiant < MinFraction) {
452 0 : state.dataHighTempRadSys->HighTempRadSys(Item).FracRadiant = MinFraction;
453 0 : ShowWarningError(state,
454 0 : state.dataIPShortCut->cNumericFieldNames(5) + " was less than the allowable minimum, reset to minimum value.");
455 0 : ShowContinueError(state, "Occurs for " + cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1));
456 : }
457 10 : if (state.dataHighTempRadSys->HighTempRadSys(Item).FracRadiant > MaxFraction) {
458 0 : state.dataHighTempRadSys->HighTempRadSys(Item).FracRadiant = MaxFraction;
459 0 : ShowWarningError(state,
460 0 : state.dataIPShortCut->cNumericFieldNames(5) + " was greater than the allowable maximum, reset to maximum value.");
461 0 : ShowContinueError(state, "Occurs for " + cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1));
462 : }
463 :
464 10 : state.dataHighTempRadSys->HighTempRadSys(Item).FracLatent = state.dataIPShortCut->rNumericArgs(6);
465 10 : if (state.dataHighTempRadSys->HighTempRadSys(Item).FracLatent < MinFraction) {
466 0 : state.dataHighTempRadSys->HighTempRadSys(Item).FracLatent = MinFraction;
467 0 : ShowWarningError(state,
468 0 : state.dataIPShortCut->cNumericFieldNames(6) + " was less than the allowable minimum, reset to minimum value.");
469 0 : ShowContinueError(state, "Occurs for " + cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1));
470 : }
471 10 : if (state.dataHighTempRadSys->HighTempRadSys(Item).FracLatent > MaxFraction) {
472 0 : state.dataHighTempRadSys->HighTempRadSys(Item).FracLatent = MaxFraction;
473 0 : ShowWarningError(state,
474 0 : state.dataIPShortCut->cNumericFieldNames(6) + " was greater than the allowable maximum, reset to maximum value.");
475 0 : ShowContinueError(state, "Occurs for " + cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1));
476 : }
477 :
478 10 : state.dataHighTempRadSys->HighTempRadSys(Item).FracLost = state.dataIPShortCut->rNumericArgs(7);
479 10 : if (state.dataHighTempRadSys->HighTempRadSys(Item).FracLost < MinFraction) {
480 0 : state.dataHighTempRadSys->HighTempRadSys(Item).FracLost = MinFraction;
481 0 : ShowWarningError(state,
482 0 : state.dataIPShortCut->cNumericFieldNames(7) + " was less than the allowable minimum, reset to minimum value.");
483 0 : ShowContinueError(state, "Occurs for " + cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1));
484 : }
485 10 : if (state.dataHighTempRadSys->HighTempRadSys(Item).FracLost > MaxFraction) {
486 0 : state.dataHighTempRadSys->HighTempRadSys(Item).FracLost = MaxFraction;
487 0 : ShowWarningError(state,
488 0 : state.dataIPShortCut->cNumericFieldNames(7) + " was greater than the allowable maximum, reset to maximum value.");
489 0 : ShowContinueError(state, "Occurs for " + cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1));
490 : }
491 :
492 : // Based on the input for fractions radiant, latent, and lost, determine the fraction convective (remaining fraction)
493 20 : AllFracsSummed = state.dataHighTempRadSys->HighTempRadSys(Item).FracRadiant + state.dataHighTempRadSys->HighTempRadSys(Item).FracLatent +
494 10 : state.dataHighTempRadSys->HighTempRadSys(Item).FracLost;
495 10 : if (AllFracsSummed > MaxFraction) {
496 0 : ShowSevereError(state, "Fractions radiant, latent, and lost sum up to greater than 1 for" + state.dataIPShortCut->cAlphaArgs(1));
497 0 : ShowContinueError(state, "Occurs for " + cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1));
498 0 : ErrorsFound = true;
499 0 : state.dataHighTempRadSys->HighTempRadSys(Item).FracConvect = 0.0;
500 : } else {
501 10 : state.dataHighTempRadSys->HighTempRadSys(Item).FracConvect = 1.0 - AllFracsSummed;
502 : }
503 :
504 : // Process the temperature control type
505 10 : if (UtilityRoutines::SameString(state.dataIPShortCut->cAlphaArgs(6), cMATControl)) {
506 1 : state.dataHighTempRadSys->HighTempRadSys(Item).ControlType = RadControlType::MATControl;
507 9 : } else if (UtilityRoutines::SameString(state.dataIPShortCut->cAlphaArgs(6), cMRTControl)) {
508 1 : state.dataHighTempRadSys->HighTempRadSys(Item).ControlType = RadControlType::MRTControl;
509 8 : } else if (UtilityRoutines::SameString(state.dataIPShortCut->cAlphaArgs(6), cOperativeControl)) {
510 5 : state.dataHighTempRadSys->HighTempRadSys(Item).ControlType = RadControlType::OperativeControl;
511 3 : } else if (UtilityRoutines::SameString(state.dataIPShortCut->cAlphaArgs(6), cMATSPControl)) {
512 1 : state.dataHighTempRadSys->HighTempRadSys(Item).ControlType = RadControlType::MATSPControl;
513 2 : } else if (UtilityRoutines::SameString(state.dataIPShortCut->cAlphaArgs(6), cMRTSPControl)) {
514 1 : state.dataHighTempRadSys->HighTempRadSys(Item).ControlType = RadControlType::MRTSPControl;
515 1 : } else if (UtilityRoutines::SameString(state.dataIPShortCut->cAlphaArgs(6), cOperativeSPControl)) {
516 1 : state.dataHighTempRadSys->HighTempRadSys(Item).ControlType = RadControlType::OperativeSPControl;
517 : } else {
518 0 : ShowWarningError(state, "Invalid " + state.dataIPShortCut->cAlphaFieldNames(6) + " = " + state.dataIPShortCut->cAlphaArgs(6));
519 0 : ShowContinueError(state, "Occurs for " + cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1));
520 0 : ShowContinueError(state, "Control reset to OPERATIVE control for this " + cCurrentModuleObject);
521 0 : state.dataHighTempRadSys->HighTempRadSys(Item).ControlType = RadControlType::OperativeControl;
522 : }
523 :
524 10 : state.dataHighTempRadSys->HighTempRadSys(Item).ThrottlRange = state.dataIPShortCut->rNumericArgs(8);
525 10 : if (state.dataHighTempRadSys->HighTempRadSys(Item).ThrottlRange < MinThrottlingRange) {
526 0 : state.dataHighTempRadSys->HighTempRadSys(Item).ThrottlRange = 1.0;
527 0 : ShowWarningError(state, state.dataIPShortCut->cNumericFieldNames(8) + " is below the minimum allowed.");
528 0 : ShowContinueError(state, "Occurs for " + cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1));
529 0 : ShowContinueError(state, "Thus, the throttling range value has been reset to 1.0");
530 : }
531 :
532 10 : state.dataHighTempRadSys->HighTempRadSys(Item).SetptSched = state.dataIPShortCut->cAlphaArgs(7);
533 10 : state.dataHighTempRadSys->HighTempRadSys(Item).SetptSchedPtr = GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(7));
534 10 : if ((state.dataHighTempRadSys->HighTempRadSys(Item).SetptSchedPtr == 0) && (!state.dataIPShortCut->lAlphaFieldBlanks(7))) {
535 0 : ShowSevereError(state, state.dataIPShortCut->cAlphaFieldNames(7) + " not found: " + state.dataIPShortCut->cAlphaArgs(7));
536 0 : ShowContinueError(state, "Occurs for " + cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1));
537 0 : ErrorsFound = true;
538 : }
539 :
540 10 : state.dataHighTempRadSys->HighTempRadSys(Item).FracDistribPerson = state.dataIPShortCut->rNumericArgs(9);
541 10 : if (state.dataHighTempRadSys->HighTempRadSys(Item).FracDistribPerson < MinFraction) {
542 0 : state.dataHighTempRadSys->HighTempRadSys(Item).FracDistribPerson = MinFraction;
543 0 : ShowWarningError(state,
544 0 : state.dataIPShortCut->cNumericFieldNames(9) + " was less than the allowable minimum, reset to minimum value.");
545 0 : ShowContinueError(state, "Occurs for " + cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1));
546 : }
547 10 : if (state.dataHighTempRadSys->HighTempRadSys(Item).FracDistribPerson > MaxFraction) {
548 0 : state.dataHighTempRadSys->HighTempRadSys(Item).FracDistribPerson = MaxFraction;
549 0 : ShowWarningError(state,
550 0 : state.dataIPShortCut->cNumericFieldNames(9) + " was greater than the allowable maximum, reset to maximum value.");
551 0 : ShowContinueError(state, "Occurs for " + cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1));
552 : }
553 :
554 10 : state.dataHighTempRadSys->HighTempRadSys(Item).TotSurfToDistrib = NumNumbers - 9;
555 : // IF (state.dataHighTempRadSys->HighTempRadSys(Item)%TotSurfToDistrib > MaxDistribSurfaces) THEN
556 : // CALL ShowSevereError(state, 'Trying to distribute radiant energy to too many surfaces for heater
557 : // '//TRIM(state.dataIPShortCut->cAlphaArgs(1))) CALL ShowContinueError(state, 'Occurs for '//TRIM(cCurrentModuleObject)//' =
558 : // '//TRIM(state.dataIPShortCut->cAlphaArgs(1))) ErrorsFound=.TRUE.
559 : // END IF
560 10 : state.dataHighTempRadSys->HighTempRadSys(Item).SurfaceName.allocate(state.dataHighTempRadSys->HighTempRadSys(Item).TotSurfToDistrib);
561 10 : state.dataHighTempRadSys->HighTempRadSys(Item).SurfacePtr.allocate(state.dataHighTempRadSys->HighTempRadSys(Item).TotSurfToDistrib);
562 20 : state.dataHighTempRadSys->HighTempRadSys(Item).FracDistribToSurf.allocate(
563 20 : state.dataHighTempRadSys->HighTempRadSys(Item).TotSurfToDistrib);
564 :
565 10 : AllFracsSummed = state.dataHighTempRadSys->HighTempRadSys(Item).FracDistribPerson;
566 59 : for (SurfNum = 1; SurfNum <= state.dataHighTempRadSys->HighTempRadSys(Item).TotSurfToDistrib; ++SurfNum) {
567 49 : state.dataHighTempRadSys->HighTempRadSys(Item).SurfaceName(SurfNum) = state.dataIPShortCut->cAlphaArgs(SurfNum + 7);
568 49 : state.dataHighTempRadSys->HighTempRadSys(Item).SurfacePtr(SurfNum) =
569 98 : HeatBalanceIntRadExchange::GetRadiantSystemSurface(state,
570 : cCurrentModuleObject,
571 49 : state.dataHighTempRadSys->HighTempRadSys(Item).Name,
572 49 : state.dataHighTempRadSys->HighTempRadSys(Item).ZonePtr,
573 49 : state.dataHighTempRadSys->HighTempRadSys(Item).SurfaceName(SurfNum),
574 : ErrorsFound);
575 49 : state.dataHighTempRadSys->HighTempRadSys(Item).FracDistribToSurf(SurfNum) = state.dataIPShortCut->rNumericArgs(SurfNum + 9);
576 : // Error trap for fractions that are out of range
577 49 : if (state.dataHighTempRadSys->HighTempRadSys(Item).FracDistribToSurf(SurfNum) < MinFraction) {
578 0 : state.dataHighTempRadSys->HighTempRadSys(Item).FracDistribToSurf(SurfNum) = MinFraction;
579 0 : ShowWarningError(state,
580 0 : state.dataIPShortCut->cNumericFieldNames(SurfNum + 9) +
581 : " was less than the allowable minimum, reset to minimum value.");
582 0 : ShowContinueError(state, "Occurs for " + cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1));
583 : }
584 49 : if (state.dataHighTempRadSys->HighTempRadSys(Item).FracDistribToSurf(SurfNum) > MaxFraction) {
585 0 : state.dataHighTempRadSys->HighTempRadSys(Item).FracDistribToSurf(SurfNum) = MaxFraction;
586 0 : ShowWarningError(state,
587 0 : state.dataIPShortCut->cNumericFieldNames(SurfNum + 9) +
588 : " was greater than the allowable maximum, reset to maximum value.");
589 0 : ShowContinueError(state, "Occurs for " + cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1));
590 : }
591 :
592 49 : if (state.dataHighTempRadSys->HighTempRadSys(Item).SurfacePtr(SurfNum) != 0) {
593 49 : state.dataSurface->SurfIntConvSurfGetsRadiantHeat(state.dataHighTempRadSys->HighTempRadSys(Item).SurfacePtr(SurfNum)) = true;
594 : }
595 :
596 49 : AllFracsSummed += state.dataHighTempRadSys->HighTempRadSys(Item).FracDistribToSurf(SurfNum);
597 :
598 : } // ...end of DO loop through surfaces that the heater radiates to.
599 :
600 : // Error trap if the fractions add up to greater than 1.0
601 10 : if (AllFracsSummed > (MaxFraction + 0.01)) {
602 0 : ShowSevereError(state,
603 0 : "Fraction of radiation distributed to surfaces sums up to greater than 1 for " + state.dataIPShortCut->cAlphaArgs(1));
604 0 : ShowContinueError(state, "Occurs for " + cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1));
605 0 : ErrorsFound = true;
606 : }
607 10 : if (AllFracsSummed < (MaxFraction - 0.01)) { // User didn't distribute all of the radiation warn that some will be lost
608 0 : TotalFracToSurfs = AllFracsSummed - state.dataHighTempRadSys->HighTempRadSys(Item).FracDistribPerson;
609 0 : FracOfRadPotentiallyLost = 1.0 - AllFracsSummed;
610 0 : ShowSevereError(state,
611 0 : "Fraction of radiation distributed to surfaces and people sums up to less than 1 for " +
612 0 : state.dataIPShortCut->cAlphaArgs(1));
613 0 : ShowContinueError(state, "This would result in some of the radiant energy delivered by the high temp radiant heater being lost.");
614 0 : ShowContinueError(state, format("The sum of all radiation fractions to surfaces = {:.5T}", TotalFracToSurfs));
615 0 : ShowContinueError(
616 0 : state, format("The radiant fraction to people = {:.5T}", state.dataHighTempRadSys->HighTempRadSys(Item).FracDistribPerson));
617 0 : ShowContinueError(state, format("So, all radiant fractions including surfaces and people = {:.5T}", AllFracsSummed));
618 0 : ShowContinueError(state,
619 0 : format("This means that the fraction of radiant energy that would be lost from the high temperature radiant heater "
620 : "would be = {:.5T}",
621 0 : FracOfRadPotentiallyLost));
622 0 : ShowContinueError(state,
623 0 : "Please check and correct this so that all radiant energy is accounted for in " + cCurrentModuleObject + " = " +
624 0 : state.dataIPShortCut->cAlphaArgs(1));
625 0 : ErrorsFound = true;
626 : }
627 :
628 : } // ...end of DO loop through all of the high temperature radiant heaters
629 :
630 : // Set up the output variables for high temperature radiant heaters
631 : // cCurrentModuleObject = "ZoneHVAC:HighTemperatureRadiant"
632 14 : for (Item = 1; Item <= state.dataHighTempRadSys->NumOfHighTempRadSys; ++Item) {
633 40 : SetupOutputVariable(state,
634 : "Zone Radiant HVAC Heating Rate",
635 : OutputProcessor::Unit::W,
636 10 : state.dataHighTempRadSys->HighTempRadSys(Item).HeatPower,
637 : OutputProcessor::SOVTimeStepType::System,
638 : OutputProcessor::SOVStoreType::Average,
639 20 : state.dataHighTempRadSys->HighTempRadSys(Item).Name);
640 40 : SetupOutputVariable(state,
641 : "Zone Radiant HVAC Heating Energy",
642 : OutputProcessor::Unit::J,
643 10 : state.dataHighTempRadSys->HighTempRadSys(Item).HeatEnergy,
644 : OutputProcessor::SOVTimeStepType::System,
645 : OutputProcessor::SOVStoreType::Summed,
646 10 : state.dataHighTempRadSys->HighTempRadSys(Item).Name,
647 : _,
648 : "ENERGYTRANSFER",
649 : "HEATINGCOILS",
650 : _,
651 10 : "System");
652 10 : if (state.dataHighTempRadSys->HighTempRadSys(Item).HeaterType == RadHeaterType::Gas) {
653 28 : SetupOutputVariable(state,
654 : "Zone Radiant HVAC NaturalGas Rate",
655 : OutputProcessor::Unit::W,
656 7 : state.dataHighTempRadSys->HighTempRadSys(Item).GasPower,
657 : OutputProcessor::SOVTimeStepType::System,
658 : OutputProcessor::SOVStoreType::Average,
659 14 : state.dataHighTempRadSys->HighTempRadSys(Item).Name);
660 28 : SetupOutputVariable(state,
661 : "Zone Radiant HVAC NaturalGas Energy",
662 : OutputProcessor::Unit::J,
663 7 : state.dataHighTempRadSys->HighTempRadSys(Item).GasEnergy,
664 : OutputProcessor::SOVTimeStepType::System,
665 : OutputProcessor::SOVStoreType::Summed,
666 7 : state.dataHighTempRadSys->HighTempRadSys(Item).Name,
667 : _,
668 : "NaturalGas",
669 : "Heating",
670 : _,
671 7 : "System");
672 3 : } else if (state.dataHighTempRadSys->HighTempRadSys(Item).HeaterType == RadHeaterType::Electric) {
673 12 : SetupOutputVariable(state,
674 : "Zone Radiant HVAC Electricity Rate",
675 : OutputProcessor::Unit::W,
676 3 : state.dataHighTempRadSys->HighTempRadSys(Item).ElecPower,
677 : OutputProcessor::SOVTimeStepType::System,
678 : OutputProcessor::SOVStoreType::Average,
679 6 : state.dataHighTempRadSys->HighTempRadSys(Item).Name);
680 12 : SetupOutputVariable(state,
681 : "Zone Radiant HVAC Electricity Energy",
682 : OutputProcessor::Unit::J,
683 3 : state.dataHighTempRadSys->HighTempRadSys(Item).ElecEnergy,
684 : OutputProcessor::SOVTimeStepType::System,
685 : OutputProcessor::SOVStoreType::Summed,
686 3 : state.dataHighTempRadSys->HighTempRadSys(Item).Name,
687 : _,
688 : "ELECTRICITY",
689 : "Heating",
690 : _,
691 3 : "System");
692 : }
693 : }
694 4 : }
695 :
696 128052 : void InitHighTempRadiantSystem(EnergyPlusData &state,
697 : bool const FirstHVACIteration, // TRUE if 1st HVAC simulation of system timestep
698 : int const RadSysNum // Index for the low temperature radiant system under consideration within the derived types
699 : )
700 : {
701 :
702 : // SUBROUTINE INFORMATION:
703 : // AUTHOR Rick Strand
704 : // DATE WRITTEN February 2001
705 : // MODIFIED na
706 : // RE-ENGINEERED na
707 :
708 : // PURPOSE OF THIS SUBROUTINE:
709 : // This subroutine initializes variables relating to high temperature
710 : // radiant heating systems.
711 :
712 : // METHODOLOGY EMPLOYED:
713 : // Simply initializes whatever needs initializing.
714 :
715 : // Using/Aliasing
716 : using DataZoneEquipment::CheckZoneEquipmentList;
717 :
718 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
719 : int ZoneNum; // Intermediate variable for keeping track of the zone number
720 : int Loop;
721 :
722 128052 : if (state.dataHighTempRadSys->firstTime) {
723 4 : state.dataHighTempRadSys->ZeroSourceSumHATsurf.dimension(state.dataGlobal->NumOfZones, 0.0);
724 4 : state.dataHighTempRadSys->QHTRadSource.dimension(state.dataHighTempRadSys->NumOfHighTempRadSys, 0.0);
725 4 : state.dataHighTempRadSys->QHTRadSrcAvg.dimension(state.dataHighTempRadSys->NumOfHighTempRadSys, 0.0);
726 4 : state.dataHighTempRadSys->LastQHTRadSrc.dimension(state.dataHighTempRadSys->NumOfHighTempRadSys, 0.0);
727 4 : state.dataHighTempRadSys->LastSysTimeElapsed.dimension(state.dataHighTempRadSys->NumOfHighTempRadSys, 0.0);
728 4 : state.dataHighTempRadSys->LastTimeStepSys.dimension(state.dataHighTempRadSys->NumOfHighTempRadSys, 0.0);
729 4 : state.dataHighTempRadSys->MySizeFlag.dimension(state.dataHighTempRadSys->NumOfHighTempRadSys, true);
730 4 : state.dataHighTempRadSys->firstTime = false;
731 : }
732 :
733 : // need to check all units to see if they are on Zone Equipment List or issue warning
734 128052 : if (!state.dataHighTempRadSys->ZoneEquipmentListChecked && state.dataZoneEquip->ZoneEquipInputsFilled) {
735 4 : state.dataHighTempRadSys->ZoneEquipmentListChecked = true;
736 14 : for (Loop = 1; Loop <= state.dataHighTempRadSys->NumOfHighTempRadSys; ++Loop) {
737 10 : if (CheckZoneEquipmentList(state, "ZoneHVAC:HighTemperatureRadiant", state.dataHighTempRadSys->HighTempRadSys(Loop).Name)) continue;
738 0 : ShowSevereError(state,
739 0 : "InitHighTempRadiantSystem: Unit=[ZoneHVAC:HighTemperatureRadiant," +
740 0 : state.dataHighTempRadSys->HighTempRadSys(Loop).Name +
741 : "] is not on any ZoneHVAC:EquipmentList. It will not be simulated.");
742 : }
743 : }
744 :
745 128052 : if (!state.dataGlobal->SysSizingCalc && state.dataHighTempRadSys->MySizeFlag(RadSysNum)) {
746 : // for each radiant systen do the sizing once.
747 10 : SizeHighTempRadiantSystem(state, RadSysNum);
748 10 : state.dataHighTempRadSys->MySizeFlag(RadSysNum) = false;
749 : }
750 :
751 128052 : if (state.dataGlobal->BeginEnvrnFlag && state.dataHighTempRadSys->MyEnvrnFlag) {
752 22 : state.dataHighTempRadSys->ZeroSourceSumHATsurf = 0.0;
753 22 : state.dataHighTempRadSys->QHTRadSource = 0.0;
754 22 : state.dataHighTempRadSys->QHTRadSrcAvg = 0.0;
755 22 : state.dataHighTempRadSys->LastQHTRadSrc = 0.0;
756 22 : state.dataHighTempRadSys->LastSysTimeElapsed = 0.0;
757 22 : state.dataHighTempRadSys->LastTimeStepSys = 0.0;
758 22 : state.dataHighTempRadSys->MyEnvrnFlag = false;
759 : }
760 128052 : if (!state.dataGlobal->BeginEnvrnFlag) {
761 127757 : state.dataHighTempRadSys->MyEnvrnFlag = true;
762 : }
763 :
764 128052 : if (state.dataGlobal->BeginTimeStepFlag && FirstHVACIteration) { // This is the first pass through in a particular time step
765 19957 : ZoneNum = state.dataHighTempRadSys->HighTempRadSys(RadSysNum).ZonePtr;
766 19957 : state.dataHighTempRadSys->ZeroSourceSumHATsurf(ZoneNum) =
767 19957 : state.dataHeatBal->Zone(ZoneNum).sumHATsurf(state); // Set this to figure out what part of the load the radiant system meets
768 19957 : state.dataHighTempRadSys->QHTRadSrcAvg(RadSysNum) = 0.0; // Initialize this variable to zero (radiant system defaults to off)
769 19957 : state.dataHighTempRadSys->LastQHTRadSrc(RadSysNum) =
770 : 0.0; // At the beginning of a time step, reset to zero so average calculation can start again
771 19957 : state.dataHighTempRadSys->LastSysTimeElapsed(RadSysNum) =
772 : 0.0; // At the beginning of a time step, reset to zero so average calculation can start again
773 19957 : state.dataHighTempRadSys->LastTimeStepSys(RadSysNum) =
774 : 0.0; // At the beginning of a time step, reset to zero so average calculation can start again
775 : }
776 128052 : }
777 :
778 10 : void SizeHighTempRadiantSystem(EnergyPlusData &state, int const RadSysNum)
779 : {
780 :
781 : // SUBROUTINE INFORMATION:
782 : // AUTHOR Fred Buhl
783 : // DATE WRITTEN February 2002
784 : // MODIFIED August 2013 Daeho Kang, add component sizing table entries
785 : // July 2014, B. Nigusse, added scalable sizing
786 : // RE-ENGINEERED na
787 :
788 : // PURPOSE OF THIS SUBROUTINE:
789 : // This subroutine is for sizing high temperature radiant components for which max power input has not been
790 : // specified in the input.
791 :
792 : // METHODOLOGY EMPLOYED:
793 : // Obtains design heating load from the zone sizing arrays
794 :
795 : // REFERENCES:
796 : // na
797 :
798 : // Using/Aliasing
799 : using namespace DataSizing;
800 : using DataHVACGlobals::HeatingCapacitySizing;
801 :
802 : // SUBROUTINE PARAMETER DEFINITIONS:
803 10 : constexpr const char *RoutineName("SizeHighTempRadiantSystem");
804 :
805 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS
806 : Real64 MaxPowerCapacDes; // Design maximum capacity for reproting
807 : Real64 MaxPowerCapacUser; // User hard-sized maximum capacity for reproting
808 : bool IsAutoSize; // Indicator to autosizing nominal capacity
809 :
810 20 : std::string CompName; // component name
811 20 : std::string CompType; // component type
812 20 : std::string SizingString; // input field sizing description (e.g., Nominal Capacity)
813 : Real64 TempSize; // autosized value of coil input field
814 10 : int FieldNum = 1; // IDD numeric field number where input field description is found
815 : int SizingMethod; // Integer representation of sizing method name (e.g., CoolingAirflowSizing, HeatingAirflowSizing, CoolingCapacitySizing,
816 : // HeatingCapacitySizing, etc.)
817 : bool PrintFlag; // TRUE when sizing information is reported in the eio file
818 10 : int CapSizingMethod(0); // capacity sizing methods (HeatingDesignCapacity, CapacityPerFloorArea, FractionOfAutosizedCoolingCapacity, and
819 : // FractionOfAutosizedHeatingCapacity )
820 :
821 10 : IsAutoSize = false;
822 10 : MaxPowerCapacDes = 0.0;
823 10 : MaxPowerCapacUser = 0.0;
824 10 : state.dataSize->DataScalableCapSizingON = false;
825 :
826 10 : auto &ZoneEqSizing(state.dataSize->ZoneEqSizing);
827 10 : auto &CurZoneEqNum(state.dataSize->CurZoneEqNum);
828 10 : auto &FinalZoneSizing(state.dataSize->FinalZoneSizing);
829 :
830 10 : if (state.dataSize->CurZoneEqNum > 0) {
831 :
832 10 : CompType = "ZoneHVAC:HighTemperatureRadiant";
833 10 : CompName = state.dataHighTempRadSys->HighTempRadSys(RadSysNum).Name;
834 10 : state.dataSize->DataFracOfAutosizedHeatingCapacity = 1.0;
835 10 : state.dataSize->DataZoneNumber = state.dataHighTempRadSys->HighTempRadSys(RadSysNum).ZonePtr;
836 10 : SizingMethod = HeatingCapacitySizing;
837 10 : FieldNum = 1;
838 10 : PrintFlag = true;
839 10 : SizingString = state.dataHighTempRadSys->HighTempRadSysNumericFields(RadSysNum).FieldNames(FieldNum) + " [W]";
840 10 : CapSizingMethod = state.dataHighTempRadSys->HighTempRadSys(RadSysNum).HeatingCapMethod;
841 10 : ZoneEqSizing(CurZoneEqNum).SizingMethod(SizingMethod) = CapSizingMethod;
842 10 : if (CapSizingMethod == HeatingDesignCapacity || CapSizingMethod == CapacityPerFloorArea ||
843 : CapSizingMethod == FractionOfAutosizedHeatingCapacity) {
844 :
845 10 : if (CapSizingMethod == HeatingDesignCapacity) {
846 10 : if (state.dataHighTempRadSys->HighTempRadSys(RadSysNum).ScaledHeatingCapacity == AutoSize) {
847 1 : CheckZoneSizing(state, CompType, CompName);
848 1 : ZoneEqSizing(CurZoneEqNum).DesHeatingLoad =
849 2 : FinalZoneSizing(CurZoneEqNum).NonAirSysDesHeatLoad / (state.dataHighTempRadSys->HighTempRadSys(RadSysNum).FracRadiant +
850 1 : state.dataHighTempRadSys->HighTempRadSys(RadSysNum).FracConvect);
851 : } else {
852 9 : ZoneEqSizing(CurZoneEqNum).DesHeatingLoad = state.dataHighTempRadSys->HighTempRadSys(RadSysNum).ScaledHeatingCapacity;
853 : }
854 10 : ZoneEqSizing(CurZoneEqNum).HeatingCapacity = true;
855 10 : TempSize = ZoneEqSizing(CurZoneEqNum).DesHeatingLoad;
856 0 : } else if (CapSizingMethod == CapacityPerFloorArea) {
857 0 : ZoneEqSizing(CurZoneEqNum).HeatingCapacity = true;
858 0 : ZoneEqSizing(CurZoneEqNum).DesHeatingLoad = state.dataHighTempRadSys->HighTempRadSys(RadSysNum).ScaledHeatingCapacity *
859 0 : state.dataHeatBal->Zone(state.dataSize->DataZoneNumber).FloorArea;
860 0 : TempSize = ZoneEqSizing(CurZoneEqNum).DesHeatingLoad;
861 0 : state.dataSize->DataScalableCapSizingON = true;
862 0 : } else if (CapSizingMethod == FractionOfAutosizedHeatingCapacity) {
863 0 : CheckZoneSizing(state, CompType, CompName);
864 0 : ZoneEqSizing(CurZoneEqNum).HeatingCapacity = true;
865 0 : state.dataSize->DataFracOfAutosizedHeatingCapacity = state.dataHighTempRadSys->HighTempRadSys(RadSysNum).ScaledHeatingCapacity;
866 0 : ZoneEqSizing(CurZoneEqNum).DesHeatingLoad =
867 0 : FinalZoneSizing(CurZoneEqNum).NonAirSysDesHeatLoad / (state.dataHighTempRadSys->HighTempRadSys(RadSysNum).FracRadiant +
868 0 : state.dataHighTempRadSys->HighTempRadSys(RadSysNum).FracConvect);
869 0 : TempSize = AutoSize;
870 0 : state.dataSize->DataScalableCapSizingON = true;
871 : } else {
872 0 : TempSize = state.dataHighTempRadSys->HighTempRadSys(RadSysNum).ScaledHeatingCapacity;
873 : }
874 10 : bool errorsFound = false;
875 20 : HeatingCapacitySizer sizerHeatingCapacity;
876 10 : sizerHeatingCapacity.overrideSizingString(SizingString);
877 10 : sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
878 10 : state.dataHighTempRadSys->HighTempRadSys(RadSysNum).MaxPowerCapac = sizerHeatingCapacity.size(state, TempSize, errorsFound);
879 10 : state.dataSize->DataScalableCapSizingON = false;
880 : }
881 : }
882 10 : }
883 :
884 42969 : void CalcHighTempRadiantSystem(EnergyPlusData &state, int const RadSysNum) // name of the low temperature radiant system
885 : {
886 :
887 : // SUBROUTINE INFORMATION:
888 : // AUTHOR Rick Strand
889 : // DATE WRITTEN February 2001
890 : // MODIFIED na
891 : // RE-ENGINEERED na
892 :
893 : // PURPOSE OF THIS SUBROUTINE:
894 : // This subroutine does all of the stuff that is necessary to simulate
895 : // a high temperature radiant heating system.
896 :
897 : // METHODOLOGY EMPLOYED:
898 : // Follows the methods used by many other pieces of zone equipment except
899 : // that we are controlling the input to the heater element. Note that
900 : // cooling is not allowed for such a system. Controls are very basic at
901 : // this point using just a linear interpolation between being off at
902 : // one end of the throttling range, fully on at the other end, and varying
903 : // linearly in between.
904 :
905 : // REFERENCES:
906 : // Other EnergyPlus modules
907 : // Building Systems Laboratory, BLAST User's Guide/Reference.
908 : // Fanger, P.O. "Analysis and Applications in Environmental Engineering",
909 : // Danish Technical Press, 1970.
910 : // Maloney, Dan. 1987. "Development of a radiant heater model and the
911 : // incorporation of thermal comfort considerations into the BLAST
912 : // energy analysis program", M.S. thesis, University of Illinois at
913 : // Urbana-Champaign (Dept. of Mechanical and Industrial Engineering).
914 :
915 : // Using/Aliasing
916 : using ScheduleManager::GetCurrentScheduleValue;
917 :
918 : // Locals
919 : // SUBROUTINE ARGUMENT DEFINITIONS:
920 :
921 : // SUBROUTINE PARAMETER DEFINITIONS:
922 : // na
923 :
924 : // INTERFACE BLOCK SPECIFICATIONS
925 : // na
926 :
927 : // DERIVED TYPE DEFINITIONS
928 : // na
929 :
930 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
931 : Real64 HeatFrac; // fraction of maximum energy input to radiant system [dimensionless]
932 : Real64 OffTemp; // Temperature above which the radiant system should be completely off [C]
933 : Real64 OpTemp; // Operative temperature [C]
934 : // REAL(r64) :: QZnReq ! heating or cooling needed by zone [Watts]
935 : Real64 SetPtTemp; // Setpoint temperature [C]
936 : int ZoneNum; // number of zone being served
937 :
938 : // initialize local variables
939 42969 : ZoneNum = state.dataHighTempRadSys->HighTempRadSys(RadSysNum).ZonePtr;
940 42969 : HeatFrac = 0.0;
941 :
942 42969 : if (GetCurrentScheduleValue(state, state.dataHighTempRadSys->HighTempRadSys(RadSysNum).SchedPtr) <= 0) {
943 :
944 : // Unit is off or has no load upon it; set the flow rates to zero and then
945 : // simulate the components with the no flow conditions
946 22971 : state.dataHighTempRadSys->QHTRadSource(RadSysNum) = 0.0;
947 :
948 : } else { // Unit might be on-->this section is intended to control the output of the
949 : // high temperature radiant heater (temperature controlled)
950 :
951 : // Determine the current setpoint temperature and the temperature at which the unit should be completely off
952 19998 : SetPtTemp = GetCurrentScheduleValue(state, state.dataHighTempRadSys->HighTempRadSys(RadSysNum).SetptSchedPtr);
953 19998 : OffTemp = SetPtTemp + 0.5 * state.dataHighTempRadSys->HighTempRadSys(RadSysNum).ThrottlRange;
954 19998 : OpTemp = (state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum).MAT + state.dataHeatBal->ZoneMRT(ZoneNum)) /
955 : 2.0; // Approximate the "operative" temperature
956 :
957 : // Determine the fraction of maximum power to the unit (limiting the fraction range from zero to unity)
958 19998 : switch (state.dataHighTempRadSys->HighTempRadSys(RadSysNum).ControlType) {
959 3511 : case RadControlType::MATControl: {
960 7022 : HeatFrac = (OffTemp - state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum).MAT) /
961 3511 : state.dataHighTempRadSys->HighTempRadSys(RadSysNum).ThrottlRange;
962 3511 : } break;
963 3511 : case RadControlType::MRTControl: {
964 3511 : HeatFrac = (OffTemp - state.dataHeatBal->ZoneMRT(ZoneNum)) / state.dataHighTempRadSys->HighTempRadSys(RadSysNum).ThrottlRange;
965 3511 : } break;
966 12976 : case RadControlType::OperativeControl: {
967 12976 : OpTemp = 0.5 * (state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum).MAT + state.dataHeatBal->ZoneMRT(ZoneNum));
968 12976 : HeatFrac = (OffTemp - OpTemp) / state.dataHighTempRadSys->HighTempRadSys(RadSysNum).ThrottlRange;
969 12976 : } break;
970 0 : default:
971 0 : break;
972 : }
973 19998 : if (HeatFrac < 0.0) HeatFrac = 0.0;
974 19998 : if (HeatFrac > 1.0) HeatFrac = 1.0;
975 :
976 : // Set the heat source for the high temperature electric radiant system
977 19998 : state.dataHighTempRadSys->QHTRadSource(RadSysNum) = HeatFrac * state.dataHighTempRadSys->HighTempRadSys(RadSysNum).MaxPowerCapac;
978 : }
979 42969 : }
980 :
981 85083 : void CalcHighTempRadiantSystemSP(
982 : EnergyPlusData &state,
983 : [[maybe_unused]] bool const FirstHVACIteration, // true if this is the first HVAC iteration at this system time step !unused1208
984 : int const RadSysNum // name of the low temperature radiant system
985 : )
986 : {
987 :
988 : // SUBROUTINE INFORMATION:
989 : // AUTHOR Rick Strand
990 : // DATE WRITTEN February 2008
991 : // MODIFIED Sep 2011 LKL/BG - resimulate only zones needing it for Radiant systems
992 : // RE-ENGINEERED na
993 :
994 : // PURPOSE OF THIS SUBROUTINE:
995 : // This subroutine does all of the stuff that is necessary to simulate
996 : // a high temperature radiant heating system using setpoint temperature control.
997 :
998 : // METHODOLOGY EMPLOYED:
999 : // Follows the methods used by many other pieces of zone equipment except
1000 : // that we are controlling the input to the heater element. Note that
1001 : // cooling is not allowed for such a system. Controls are very basic and
1002 : // use an iterative approach to get close to what we need.
1003 :
1004 : // REFERENCES:
1005 : // Other EnergyPlus modules
1006 : // Building Systems Laboratory, BLAST User's Guide/Reference.
1007 : // Fanger, P.O. "Analysis and Applications in Environmental Engineering",
1008 : // Danish Technical Press, 1970.
1009 : // Maloney, Dan. 1987. "Development of a radiant heater model and the
1010 : // incorporation of thermal comfort considerations into the BLAST
1011 : // energy analysis program", M.S. thesis, University of Illinois at
1012 : // Urbana-Champaign (Dept. of Mechanical and Industrial Engineering).
1013 :
1014 : // Using/Aliasing
1015 : using ScheduleManager::GetCurrentScheduleValue;
1016 :
1017 : // Locals
1018 : // SUBROUTINE ARGUMENT DEFINITIONS:
1019 :
1020 : // SUBROUTINE PARAMETER DEFINITIONS:
1021 85083 : float const TempConvToler(0.1f); // Temperature controller tries to converge to within 0.1C
1022 85083 : int constexpr MaxIterations(10); // Maximum number of iterations to achieve temperature control
1023 : // (10 interval halvings achieves control to 0.1% of capacity)
1024 : // These two parameters are intended to achieve reasonable control
1025 : // without excessive run times.
1026 :
1027 : // INTERFACE BLOCK SPECIFICATIONS
1028 : // na
1029 :
1030 : // DERIVED TYPE DEFINITIONS
1031 : // na
1032 :
1033 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1034 : bool ConvergFlag; // convergence flag for temperature control
1035 : // unused INTEGER, SAVE :: ErrIterCount=0 ! number of time max iterations has been exceeded
1036 : float HeatFrac; // fraction of maximum energy input to radiant system [dimensionless]
1037 : float HeatFracMax; // maximum range of heat fraction
1038 : float HeatFracMin; // minimum range of heat fraction
1039 : int IterNum; // iteration number
1040 : Real64 SetPtTemp; // Setpoint temperature [C]
1041 : int ZoneNum; // number of zone being served
1042 85083 : Real64 ZoneTemp(0.0); // zone temperature (MAT, MRT, or Operative Temperature, depending on control type) [C]
1043 :
1044 : // initialize local variables
1045 85083 : ZoneNum = state.dataHighTempRadSys->HighTempRadSys(RadSysNum).ZonePtr;
1046 85083 : state.dataHighTempRadSys->QHTRadSource(RadSysNum) = 0.0;
1047 :
1048 85083 : if (GetCurrentScheduleValue(state, state.dataHighTempRadSys->HighTempRadSys(RadSysNum).SchedPtr) > 0) {
1049 :
1050 : // Unit is scheduled on-->this section is intended to control the output of the
1051 : // high temperature radiant heater (temperature controlled)
1052 :
1053 : // Determine the current setpoint temperature and the temperature at which the unit should be completely off
1054 85083 : SetPtTemp = GetCurrentScheduleValue(state, state.dataHighTempRadSys->HighTempRadSys(RadSysNum).SetptSchedPtr);
1055 :
1056 : // Now, distribute the radiant energy of all systems to the appropriate
1057 : // surfaces, to people, and the air; determine the latent portion
1058 85083 : DistributeHTRadGains(state);
1059 :
1060 : // Now "simulate" the system by recalculating the heat balances
1061 85083 : HeatBalanceSurfaceManager::CalcHeatBalanceOutsideSurf(state, ZoneNum);
1062 85083 : HeatBalanceSurfaceManager::CalcHeatBalanceInsideSurf(state, ZoneNum);
1063 :
1064 : // First determine whether or not the unit should be on
1065 : // Determine the proper temperature on which to control
1066 85083 : switch (state.dataHighTempRadSys->HighTempRadSys(RadSysNum).ControlType) {
1067 28361 : case RadControlType::MATSPControl: {
1068 28361 : ZoneTemp = state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum).MAT;
1069 28361 : } break;
1070 28361 : case RadControlType::MRTSPControl: {
1071 28361 : ZoneTemp = state.dataHeatBal->ZoneMRT(ZoneNum);
1072 28361 : } break;
1073 28361 : case RadControlType::OperativeSPControl: {
1074 28361 : ZoneTemp = 0.5 * (state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum).MAT + state.dataHeatBal->ZoneMRT(ZoneNum));
1075 28361 : } break;
1076 0 : default: {
1077 0 : assert(false);
1078 : } break;
1079 : }
1080 :
1081 85083 : if (ZoneTemp < (SetPtTemp - TempConvToler)) {
1082 :
1083 : // Use simple interval halving to find the best operating fraction to achieve proper temperature control
1084 21562 : IterNum = 0;
1085 21562 : ConvergFlag = false;
1086 21562 : HeatFracMax = 1.0;
1087 21562 : HeatFracMin = 0.0;
1088 :
1089 64686 : while ((IterNum <= MaxIterations) && (!ConvergFlag)) {
1090 :
1091 : // In the first iteration (IterNum=0), try full capacity and see if that is the best solution
1092 21562 : if (IterNum == 0) {
1093 21562 : HeatFrac = 1.0;
1094 : } else {
1095 0 : HeatFrac = (HeatFracMin + HeatFracMax) / 2.0;
1096 : }
1097 :
1098 : // Set the heat source for the high temperature radiant system
1099 21562 : state.dataHighTempRadSys->QHTRadSource(RadSysNum) = HeatFrac * state.dataHighTempRadSys->HighTempRadSys(RadSysNum).MaxPowerCapac;
1100 :
1101 : // Now, distribute the radiant energy of all systems to the appropriate
1102 : // surfaces, to people, and the air; determine the latent portion
1103 21562 : DistributeHTRadGains(state);
1104 :
1105 : // Now "simulate" the system by recalculating the heat balances
1106 21562 : HeatBalanceSurfaceManager::CalcHeatBalanceOutsideSurf(state, ZoneNum);
1107 21562 : HeatBalanceSurfaceManager::CalcHeatBalanceInsideSurf(state, ZoneNum);
1108 :
1109 : // Redetermine the current value of the controlling temperature
1110 21562 : switch (state.dataHighTempRadSys->HighTempRadSys(RadSysNum).ControlType) {
1111 0 : case RadControlType::MATControl: {
1112 0 : ZoneTemp = state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum).MAT;
1113 0 : } break;
1114 0 : case RadControlType::MRTControl: {
1115 0 : ZoneTemp = state.dataHeatBal->ZoneMRT(ZoneNum);
1116 0 : } break;
1117 0 : case RadControlType::OperativeControl: {
1118 0 : ZoneTemp = 0.5 * (state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum).MAT + state.dataHeatBal->ZoneMRT(ZoneNum));
1119 0 : } break;
1120 21562 : default:
1121 21562 : break;
1122 : }
1123 :
1124 21562 : if ((std::abs(ZoneTemp - SetPtTemp)) <= TempConvToler) {
1125 : // The radiant heater has controlled the zone temperature to the appropriate level--stop iterating
1126 0 : ConvergFlag = true;
1127 21562 : } else if (ZoneTemp < SetPtTemp) {
1128 : // The zone temperature is too low--try increasing the radiant heater output
1129 21562 : if (IterNum == 0) {
1130 : // Heater already at capacity--this is the best that we can do
1131 21562 : ConvergFlag = true;
1132 : } else {
1133 0 : HeatFracMin = HeatFrac;
1134 : }
1135 : } else { // (ZoneTemp > SetPtTemp)
1136 : // The zone temperature is too high--try decreasing the radiant heater output
1137 0 : if (IterNum > 0) HeatFracMax = HeatFrac;
1138 : }
1139 :
1140 21562 : ++IterNum;
1141 : }
1142 : }
1143 : }
1144 85083 : }
1145 :
1146 128052 : void UpdateHighTempRadiantSystem(EnergyPlusData &state,
1147 : int const RadSysNum, // Index for the low temperature radiant system under consideration within the derived types
1148 : Real64 &LoadMet // load met by the radiant system, in Watts
1149 : )
1150 : {
1151 :
1152 : // SUBROUTINE INFORMATION:
1153 : // AUTHOR Rick Strand
1154 : // DATE WRITTEN February 2001
1155 : // MODIFIED na
1156 : // RE-ENGINEERED na
1157 :
1158 : // PURPOSE OF THIS SUBROUTINE:
1159 : // This subroutine does any updating that needs to be done for high
1160 : // temperature radiant heating systems. This routine has two functions.
1161 : // First, it needs to keep track of the average high temperature
1162 : // radiant source. The method for doing this is similar to low
1163 : // temperature systems except that heat input is kept locally on
1164 : // a system basis rather than a surface basis. This is because a high
1165 : // temperature system affects many surfaces while a low temperature
1166 : // system directly affects only one surface. This leads to the second
1167 : // function of this subroutine which is to account for the affect of
1168 : // all high temperature radiant systems on each surface. This
1169 : // distribution must be "redone" every time to be sure that we have
1170 : // properly accounted for all of the systems.
1171 :
1172 : // METHODOLOGY EMPLOYED:
1173 : // For the source average update, if the system time step elapsed is
1174 : // still what it used to be, then either we are still iterating or we
1175 : // had to go back and shorten the time step. As a result, we have to
1176 : // subtract out the previous value that we added. If the system time
1177 : // step elapsed is different, then we just need to add the new values
1178 : // to the running average.
1179 :
1180 : // REFERENCES:
1181 : // na
1182 :
1183 : // Using/Aliasing
1184 128052 : auto &SysTimeElapsed = state.dataHVACGlobal->SysTimeElapsed;
1185 128052 : auto &TimeStepSys = state.dataHVACGlobal->TimeStepSys;
1186 :
1187 : // Locals
1188 : // SUBROUTINE ARGUMENT DEFINITIONS:
1189 :
1190 : // SUBROUTINE PARAMETER DEFINITIONS:
1191 : // na
1192 :
1193 : // INTERFACE BLOCK SPECIFICATIONS
1194 : // na
1195 :
1196 : // DERIVED TYPE DEFINITIONS
1197 : // na
1198 :
1199 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1200 : int ZoneNum; // Zone index number for the current radiant system
1201 :
1202 : // First, update the running average if necessary...
1203 128052 : if (state.dataHighTempRadSys->LastSysTimeElapsed(RadSysNum) == SysTimeElapsed) {
1204 : // Still iterating or reducing system time step, so subtract old values which were
1205 : // not valid
1206 272622 : state.dataHighTempRadSys->QHTRadSrcAvg(RadSysNum) -= state.dataHighTempRadSys->LastQHTRadSrc(RadSysNum) *
1207 181748 : state.dataHighTempRadSys->LastTimeStepSys(RadSysNum) /
1208 90874 : state.dataGlobal->TimeStepZone;
1209 : }
1210 :
1211 : // Update the running average and the "last" values with the current values of the appropriate variables
1212 128052 : state.dataHighTempRadSys->QHTRadSrcAvg(RadSysNum) +=
1213 128052 : state.dataHighTempRadSys->QHTRadSource(RadSysNum) * TimeStepSys / state.dataGlobal->TimeStepZone;
1214 :
1215 128052 : state.dataHighTempRadSys->LastQHTRadSrc(RadSysNum) = state.dataHighTempRadSys->QHTRadSource(RadSysNum);
1216 128052 : state.dataHighTempRadSys->LastSysTimeElapsed(RadSysNum) = SysTimeElapsed;
1217 128052 : state.dataHighTempRadSys->LastTimeStepSys(RadSysNum) = TimeStepSys;
1218 :
1219 128052 : switch (state.dataHighTempRadSys->HighTempRadSys(RadSysNum).ControlType) {
1220 42969 : case RadControlType::MATControl:
1221 : case RadControlType::MRTControl:
1222 : case RadControlType::OperativeControl: {
1223 : // Only need to do this for the non-SP controls (SP has already done this enough)
1224 : // Now, distribute the radiant energy of all systems to the appropriate
1225 : // surfaces, to people, and the air; determine the latent portion
1226 42969 : DistributeHTRadGains(state);
1227 :
1228 : // Now "simulate" the system by recalculating the heat balances
1229 42969 : ZoneNum = state.dataHighTempRadSys->HighTempRadSys(RadSysNum).ZonePtr;
1230 42969 : HeatBalanceSurfaceManager::CalcHeatBalanceOutsideSurf(state, ZoneNum);
1231 42969 : HeatBalanceSurfaceManager::CalcHeatBalanceInsideSurf(state, ZoneNum);
1232 42969 : } break;
1233 85083 : default:
1234 85083 : break;
1235 : }
1236 :
1237 128052 : if (state.dataHighTempRadSys->QHTRadSource(RadSysNum) <= 0.0) {
1238 91038 : LoadMet = 0.0; // System wasn't running so it can't meet a load
1239 : } else {
1240 37014 : ZoneNum = state.dataHighTempRadSys->HighTempRadSys(RadSysNum).ZonePtr;
1241 74028 : LoadMet = (state.dataHeatBal->Zone(ZoneNum).sumHATsurf(state) - state.dataHighTempRadSys->ZeroSourceSumHATsurf(ZoneNum)) +
1242 37014 : state.dataHeatBalFanSys->SumConvHTRadSys(ZoneNum);
1243 : }
1244 128052 : }
1245 :
1246 2568313 : void UpdateHTRadSourceValAvg(EnergyPlusData &state, bool &HighTempRadSysOn) // .TRUE. if the radiant system has run this zone time step
1247 : {
1248 :
1249 : // SUBROUTINE INFORMATION:
1250 : // AUTHOR Rick Strand
1251 : // DATE WRITTEN February 2001
1252 : // MODIFIED na
1253 : // RE-ENGINEERED na
1254 :
1255 : // PURPOSE OF THIS SUBROUTINE:
1256 : // To transfer the average value of the heat source over the entire
1257 : // zone time step back to the heat balance routines so that the heat
1258 : // balance algorithms can simulate one last time with the average source
1259 : // to maintain some reasonable amount of continuity and energy balance
1260 : // in the temperature and flux histories.
1261 :
1262 : // METHODOLOGY EMPLOYED:
1263 : // All of the record keeping for the average term is done in the Update
1264 : // routine so the only other thing that this subroutine does is check to
1265 : // see if the system was even on. If any average term is non-zero, then
1266 : // one or more of the radiant systems was running.
1267 :
1268 : // REFERENCES:
1269 : // na
1270 :
1271 : // USE STATEMENTS:
1272 : // na
1273 :
1274 : // Locals
1275 : // SUBROUTINE ARGUMENT DEFINITIONS:
1276 :
1277 : // SUBROUTINE PARAMETER DEFINITIONS:
1278 : // na
1279 :
1280 : // INTERFACE BLOCK SPECIFICATIONS
1281 : // na
1282 :
1283 : // DERIVED TYPE DEFINITIONS
1284 : // na
1285 :
1286 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1287 : int RadSysNum; // DO loop counter for surface index
1288 :
1289 2568313 : HighTempRadSysOn = false;
1290 :
1291 : // If this was never allocated, then there are no radiant systems in this input file (just RETURN)
1292 2568313 : if (!allocated(state.dataHighTempRadSys->QHTRadSrcAvg)) return;
1293 :
1294 : // If it was allocated, then we have to check to see if this was running at all...
1295 18163 : for (RadSysNum = 1; RadSysNum <= state.dataHighTempRadSys->NumOfHighTempRadSys; ++RadSysNum) {
1296 13651 : if (state.dataHighTempRadSys->QHTRadSrcAvg(RadSysNum) != 0.0) {
1297 3306 : HighTempRadSysOn = true;
1298 3306 : break; // DO loop
1299 : }
1300 : }
1301 :
1302 7818 : state.dataHighTempRadSys->QHTRadSource = state.dataHighTempRadSys->QHTRadSrcAvg;
1303 :
1304 7818 : DistributeHTRadGains(state); // state.dataHighTempRadSys->QHTRadSource has been modified so we need to redistribute gains
1305 : }
1306 :
1307 157432 : void DistributeHTRadGains(EnergyPlusData &state)
1308 : {
1309 :
1310 : // SUBROUTINE INFORMATION:
1311 : // AUTHOR Rick Strand
1312 : // DATE WRITTEN February 2001
1313 : // MODIFIED April 2010 Brent Griffith, max limit to protect surface temperature calcs
1314 : // RE-ENGINEERED na
1315 :
1316 : // PURPOSE OF THIS SUBROUTINE:
1317 : // To distribute the gains from the high temperature radiant heater
1318 : // as specified in the user input file. This includes distribution
1319 : // of long wavelength radiant gains to surfaces and "people" as well
1320 : // as latent, lost, and convective portions of the total gain.
1321 :
1322 : // METHODOLOGY EMPLOYED:
1323 : // We must cycle through all of the radiant systems because each
1324 : // surface could feel the effect of more than one radiant system.
1325 : // Note that the energy radiated to people is assumed to affect them
1326 : // but them it is assumed to be convected to the air. This is why
1327 : // the convective portion shown below has two parts to it.
1328 :
1329 : // Using/Aliasing
1330 : using DataHeatBalFanSys::MaxRadHeatFlux;
1331 :
1332 : // SUBROUTINE PARAMETER DEFINITIONS:
1333 157432 : Real64 constexpr SmallestArea(0.001); // Smallest area in meters squared (to avoid a divide by zero)
1334 :
1335 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1336 : int RadSurfNum; // Counter for surfaces receiving radiation from radiant heater
1337 : int RadSysNum; // Counter for the radiant systems
1338 : int SurfNum; // Pointer to the Surface derived type
1339 : int ZoneNum; // Pointer to the Zone derived type
1340 : Real64 ThisSurfIntensity; // temporary for W/m2 term for rad on a surface
1341 :
1342 : // Initialize arrays
1343 157432 : state.dataHeatBalFanSys->SumConvHTRadSys = 0.0;
1344 157432 : state.dataHeatBalFanSys->SumLatentHTRadSys = 0.0;
1345 157432 : state.dataHeatBalFanSys->SurfQHTRadSys = 0.0;
1346 157432 : state.dataHeatBalFanSys->ZoneQHTRadSysToPerson = 0.0;
1347 :
1348 619252 : for (RadSysNum = 1; RadSysNum <= state.dataHighTempRadSys->NumOfHighTempRadSys; ++RadSysNum) {
1349 :
1350 461820 : ZoneNum = state.dataHighTempRadSys->HighTempRadSys(RadSysNum).ZonePtr;
1351 :
1352 1385460 : state.dataHeatBalFanSys->ZoneQHTRadSysToPerson(ZoneNum) = state.dataHighTempRadSys->QHTRadSource(RadSysNum) *
1353 923640 : state.dataHighTempRadSys->HighTempRadSys(RadSysNum).FracRadiant *
1354 461820 : state.dataHighTempRadSys->HighTempRadSys(RadSysNum).FracDistribPerson;
1355 :
1356 461820 : state.dataHeatBalFanSys->SumConvHTRadSys(ZoneNum) +=
1357 461820 : state.dataHighTempRadSys->QHTRadSource(RadSysNum) * state.dataHighTempRadSys->HighTempRadSys(RadSysNum).FracConvect;
1358 :
1359 461820 : state.dataHeatBalFanSys->SumLatentHTRadSys(ZoneNum) +=
1360 461820 : state.dataHighTempRadSys->QHTRadSource(RadSysNum) * state.dataHighTempRadSys->HighTempRadSys(RadSysNum).FracLatent;
1361 :
1362 2765682 : for (RadSurfNum = 1; RadSurfNum <= state.dataHighTempRadSys->HighTempRadSys(RadSysNum).TotSurfToDistrib; ++RadSurfNum) {
1363 2303862 : SurfNum = state.dataHighTempRadSys->HighTempRadSys(RadSysNum).SurfacePtr(RadSurfNum);
1364 2303862 : if (state.dataSurface->Surface(SurfNum).Area > SmallestArea) {
1365 2303862 : ThisSurfIntensity =
1366 4607724 : (state.dataHighTempRadSys->QHTRadSource(RadSysNum) * state.dataHighTempRadSys->HighTempRadSys(RadSysNum).FracRadiant *
1367 4607724 : state.dataHighTempRadSys->HighTempRadSys(RadSysNum).FracDistribToSurf(RadSurfNum) /
1368 2303862 : state.dataSurface->Surface(SurfNum).Area);
1369 2303862 : state.dataHeatBalFanSys->SurfQHTRadSys(SurfNum) += ThisSurfIntensity;
1370 2303862 : state.dataHeatBalSurf->AnyRadiantSystems = true;
1371 :
1372 2303862 : if (ThisSurfIntensity > MaxRadHeatFlux) { // CR 8074, trap for excessive intensity (throws off surface balance )
1373 0 : ShowSevereError(state, "DistributeHTRadGains: excessive thermal radiation heat flux intensity detected");
1374 0 : ShowContinueError(state, "Surface = " + state.dataSurface->Surface(SurfNum).Name);
1375 0 : ShowContinueError(state, format("Surface area = {:.3R} [m2]", state.dataSurface->Surface(SurfNum).Area));
1376 0 : ShowContinueError(state,
1377 0 : "Occurs in ZoneHVAC:HighTemperatureRadiant = " + state.dataHighTempRadSys->HighTempRadSys(RadSysNum).Name);
1378 0 : ShowContinueError(state, format("Radiation intensity = {:.2R} [W/m2]", ThisSurfIntensity));
1379 0 : ShowContinueError(state, "Assign a larger surface area or more surfaces in ZoneHVAC:HighTemperatureRadiant");
1380 0 : ShowFatalError(state, "DistributeHTRadGains: excessive thermal radiation heat flux intensity detected");
1381 : }
1382 : } else { // small surface
1383 0 : ShowSevereError(state, "DistributeHTRadGains: surface not large enough to receive thermal radiation heat flux");
1384 0 : ShowContinueError(state, "Surface = " + state.dataSurface->Surface(SurfNum).Name);
1385 0 : ShowContinueError(state, format("Surface area = {:.3R} [m2]", state.dataSurface->Surface(SurfNum).Area));
1386 0 : ShowContinueError(state,
1387 0 : "Occurs in ZoneHVAC:HighTemperatureRadiant = " + state.dataHighTempRadSys->HighTempRadSys(RadSysNum).Name);
1388 0 : ShowContinueError(state, "Assign a larger surface area or more surfaces in ZoneHVAC:HighTemperatureRadiant");
1389 0 : ShowFatalError(state, "DistributeHTRadGains: surface not large enough to receive thermal radiation heat flux");
1390 : }
1391 : }
1392 : }
1393 :
1394 : // Here an assumption is made regarding radiant heat transfer to people.
1395 : // While the ZoneQHTRadSysToPerson array will be used by the thermal comfort
1396 : // routines, the energy transfer to people would get lost from the perspective
1397 : // of the heat balance. So, to avoid this net loss of energy which clearly
1398 : // gets added to the zones, we must account for it somehow. This assumption
1399 : // that all energy radiated to people is converted to convective energy is
1400 : // not very precise, but at least it conserves energy.
1401 629728 : for (ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
1402 472296 : state.dataHeatBalFanSys->SumConvHTRadSys(ZoneNum) += state.dataHeatBalFanSys->ZoneQHTRadSysToPerson(ZoneNum);
1403 : }
1404 157432 : }
1405 :
1406 128052 : void ReportHighTempRadiantSystem(EnergyPlusData &state,
1407 : int const RadSysNum) // Index for the low temperature radiant system under consideration within the derived types
1408 : {
1409 :
1410 : // SUBROUTINE INFORMATION:
1411 : // AUTHOR Rick Strand
1412 : // DATE WRITTEN February 2001
1413 : // MODIFIED na
1414 : // RE-ENGINEERED na
1415 :
1416 : // PURPOSE OF THIS SUBROUTINE:
1417 : // This subroutine simply produces output for the high temperature radiant system.
1418 :
1419 : // Using/Aliasing
1420 128052 : auto &TimeStepSys = state.dataHVACGlobal->TimeStepSys;
1421 :
1422 128052 : if (state.dataHighTempRadSys->HighTempRadSys(RadSysNum).HeaterType == RadHeaterType::Gas) {
1423 107781 : state.dataHighTempRadSys->HighTempRadSys(RadSysNum).GasPower =
1424 107781 : state.dataHighTempRadSys->QHTRadSource(RadSysNum) / state.dataHighTempRadSys->HighTempRadSys(RadSysNum).CombustionEffic;
1425 107781 : state.dataHighTempRadSys->HighTempRadSys(RadSysNum).GasEnergy =
1426 107781 : state.dataHighTempRadSys->HighTempRadSys(RadSysNum).GasPower * TimeStepSys * DataGlobalConstants::SecInHour;
1427 107781 : state.dataHighTempRadSys->HighTempRadSys(RadSysNum).ElecPower = 0.0;
1428 107781 : state.dataHighTempRadSys->HighTempRadSys(RadSysNum).ElecEnergy = 0.0;
1429 20271 : } else if (state.dataHighTempRadSys->HighTempRadSys(RadSysNum).HeaterType == RadHeaterType::Electric) {
1430 20271 : state.dataHighTempRadSys->HighTempRadSys(RadSysNum).GasPower = 0.0;
1431 20271 : state.dataHighTempRadSys->HighTempRadSys(RadSysNum).GasEnergy = 0.0;
1432 20271 : state.dataHighTempRadSys->HighTempRadSys(RadSysNum).ElecPower = state.dataHighTempRadSys->QHTRadSource(RadSysNum);
1433 20271 : state.dataHighTempRadSys->HighTempRadSys(RadSysNum).ElecEnergy =
1434 20271 : state.dataHighTempRadSys->HighTempRadSys(RadSysNum).ElecPower * TimeStepSys * DataGlobalConstants::SecInHour;
1435 : } else {
1436 0 : ShowWarningError(state, "Someone forgot to add a high temperature radiant heater type to the reporting subroutine");
1437 : }
1438 128052 : state.dataHighTempRadSys->HighTempRadSys(RadSysNum).HeatPower = state.dataHighTempRadSys->QHTRadSource(RadSysNum);
1439 128052 : state.dataHighTempRadSys->HighTempRadSys(RadSysNum).HeatEnergy =
1440 128052 : state.dataHighTempRadSys->HighTempRadSys(RadSysNum).HeatPower * TimeStepSys * DataGlobalConstants::SecInHour;
1441 128052 : }
1442 :
1443 : } // namespace HighTempRadiantSystem
1444 :
1445 2313 : } // namespace EnergyPlus
|