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 <cmath>
50 :
51 : // ObjexxFCL Headers
52 : #include <ObjexxFCL/Array.functions.hh>
53 : #include <ObjexxFCL/Fmath.hh>
54 :
55 : // EnergyPlus Headers
56 : #include <EnergyPlus/Autosizing/CoolingCapacitySizing.hh>
57 : #include <EnergyPlus/BranchNodeConnections.hh>
58 : #include <EnergyPlus/ChilledCeilingPanelSimple.hh>
59 : #include <EnergyPlus/Data/EnergyPlusData.hh>
60 : #include <EnergyPlus/DataEnvironment.hh>
61 : #include <EnergyPlus/DataHVACGlobals.hh>
62 : #include <EnergyPlus/DataHeatBalFanSys.hh>
63 : #include <EnergyPlus/DataHeatBalSurface.hh>
64 : #include <EnergyPlus/DataHeatBalance.hh>
65 : #include <EnergyPlus/DataIPShortCuts.hh>
66 : #include <EnergyPlus/DataSizing.hh>
67 : #include <EnergyPlus/DataSurfaces.hh>
68 : #include <EnergyPlus/DataZoneEnergyDemands.hh>
69 : #include <EnergyPlus/DataZoneEquipment.hh>
70 : #include <EnergyPlus/FluidProperties.hh>
71 : #include <EnergyPlus/GeneralRoutines.hh>
72 : #include <EnergyPlus/HeatBalanceIntRadExchange.hh>
73 : #include <EnergyPlus/HeatBalanceSurfaceManager.hh>
74 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
75 : #include <EnergyPlus/NodeInputManager.hh>
76 : #include <EnergyPlus/OutputProcessor.hh>
77 : #include <EnergyPlus/Plant/DataPlant.hh>
78 : #include <EnergyPlus/PlantUtilities.hh>
79 : #include <EnergyPlus/Psychrometrics.hh>
80 : #include <EnergyPlus/ScheduleManager.hh>
81 : #include <EnergyPlus/ZoneTempPredictorCorrector.hh>
82 :
83 : namespace EnergyPlus::CoolingPanelSimple {
84 :
85 : // Module -- (ref: Object: ZoneHVAC:CoolingPanel:RadiantConvective:Water)
86 :
87 : // Module containing the routines dealing with the simple (chilled ceiling) cooling panels
88 :
89 : // MODULE INFORMATION:
90 : // AUTHOR Rick Strand
91 : // DATE WRITTEN Aug 2014
92 :
93 : // PURPOSE OF THIS MODULE:
94 : // The purpose of this module is to simulate simple chilled ceiling panels. It is similar to
95 : // hot water radiant/convective baseboard units and the code for this model used that model as
96 : // a starting point.
97 :
98 : // REFERENCES:
99 : // Existing code for hot water baseboard models (radiant-convective variety)
100 :
101 : // USE STATEMENTS:
102 : // MODULE PARAMETER DEFINITIONS
103 771 : std::string const cCMO_CoolingPanel_Simple("ZoneHVAC:CoolingPanel:RadiantConvective:Water");
104 :
105 22551 : void SimCoolingPanel(
106 : EnergyPlusData &state, std::string const &EquipName, int const ControlledZoneNum, bool const FirstHVACIteration, Real64 &PowerMet, int &CompIndex)
107 : {
108 :
109 : // SUBROUTINE INFORMATION:
110 : // AUTHOR Rick Strand
111 : // DATE WRITTEN Aug 2014
112 :
113 : // PURPOSE OF THIS SUBROUTINE:
114 : // This subroutine simulates the simple cooling (chilled ceiling) panel. It borrows heavily
115 : // from the hot water radiant-convective baseboard model code.
116 :
117 : // REFERENCES:
118 : // Existing code for hot water baseboard models (radiant-convective variety)
119 :
120 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
121 : int CoolingPanelNum; // Index of unit in baseboard array
122 : Real64 QZnReq; // Zone load not yet satisfied
123 : Real64 MaxWaterFlow;
124 : Real64 MinWaterFlow;
125 :
126 22551 : if (state.dataChilledCeilingPanelSimple->GetInputFlag) {
127 4 : GetCoolingPanelInput(state);
128 4 : state.dataChilledCeilingPanelSimple->GetInputFlag = false;
129 : }
130 :
131 : // Find the correct Baseboard Equipment
132 22551 : if (CompIndex == 0) {
133 8 : CoolingPanelNum = UtilityRoutines::FindItemInList(EquipName,
134 4 : state.dataChilledCeilingPanelSimple->CoolingPanel,
135 : &CoolingPanelParams::EquipID,
136 4 : (int)state.dataChilledCeilingPanelSimple->CoolingPanel.size());
137 4 : if (CoolingPanelNum == 0) {
138 0 : ShowFatalError(state, "SimCoolingPanelSimple: Unit not found=" + EquipName);
139 : }
140 4 : CompIndex = CoolingPanelNum;
141 : } else {
142 22547 : CoolingPanelNum = CompIndex;
143 22547 : if (CoolingPanelNum > (int)state.dataChilledCeilingPanelSimple->CoolingPanel.size() || CoolingPanelNum < 1) {
144 0 : ShowFatalError(state,
145 0 : format("SimCoolingPanelSimple: Invalid CompIndex passed={}, Number of Units={}, Entered Unit name={}",
146 : CoolingPanelNum,
147 0 : (int)state.dataChilledCeilingPanelSimple->CoolingPanel.size(),
148 0 : EquipName));
149 : }
150 22547 : if (state.dataChilledCeilingPanelSimple->CoolingPanel(CoolingPanelNum).CheckEquipName) {
151 4 : if (EquipName != state.dataChilledCeilingPanelSimple->CoolingPanel(CoolingPanelNum).EquipID) {
152 0 : ShowFatalError(state,
153 0 : format("SimCoolingPanelSimple: Invalid CompIndex passed={}, Unit name={}, stored Unit Name for that index={}",
154 : CoolingPanelNum,
155 : EquipName,
156 0 : state.dataChilledCeilingPanelSimple->CoolingPanel(CoolingPanelNum).EquipID));
157 : }
158 4 : state.dataChilledCeilingPanelSimple->CoolingPanel(CoolingPanelNum).CheckEquipName = false;
159 : }
160 : }
161 :
162 22551 : if (CompIndex > 0) {
163 :
164 22551 : auto &ThisCP(state.dataChilledCeilingPanelSimple->CoolingPanel(CoolingPanelNum));
165 :
166 22551 : InitCoolingPanel(state, CoolingPanelNum, ControlledZoneNum, FirstHVACIteration);
167 :
168 22551 : QZnReq = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ControlledZoneNum).RemainingOutputReqToCoolSP;
169 :
170 : // On the first HVAC iteration the system values are given to the controller, but after that
171 : // the demand limits are in place and there needs to be feedback to the Zone Equipment
172 22551 : if (FirstHVACIteration) {
173 10333 : MaxWaterFlow = ThisCP.WaterMassFlowRateMax;
174 10333 : MinWaterFlow = 0.0;
175 : } else {
176 12218 : MaxWaterFlow = state.dataLoopNodes->Node(ThisCP.WaterInletNode).MassFlowRateMaxAvail;
177 12218 : MinWaterFlow = state.dataLoopNodes->Node(ThisCP.WaterInletNode).MassFlowRateMinAvail;
178 : }
179 :
180 22551 : switch (ThisCP.EquipType) {
181 22551 : case DataPlant::PlantEquipmentType::CoolingPanel_Simple: { // 'ZoneHVAC:CoolingPanel:RadiantConvective:Water'
182 22551 : ThisCP.CalcCoolingPanel(state, CoolingPanelNum);
183 22551 : } break;
184 0 : default: {
185 0 : ShowSevereError(
186 0 : state, "SimCoolingPanelSimple: Errors in CoolingPanel=" + state.dataChilledCeilingPanelSimple->CoolingPanel(CoolingPanelNum).EquipID);
187 0 : ShowContinueError(
188 : state,
189 0 : format("Invalid or unimplemented equipment type={}", state.dataChilledCeilingPanelSimple->CoolingPanel(CoolingPanelNum).EquipType));
190 0 : ShowFatalError(state, "Preceding condition causes termination.");
191 0 : } break;
192 : }
193 :
194 22551 : PowerMet = ThisCP.TotPower;
195 :
196 22551 : UpdateCoolingPanel(state, CoolingPanelNum);
197 :
198 22551 : state.dataChilledCeilingPanelSimple->CoolingPanel(CoolingPanelNum).ReportCoolingPanel(state);
199 :
200 : } else {
201 0 : ShowFatalError(state, "SimCoolingPanelSimple: Unit not found=" + EquipName);
202 : }
203 22551 : }
204 :
205 4 : void GetCoolingPanelInput(EnergyPlusData &state)
206 : {
207 :
208 : // SUBROUTINE INFORMATION:
209 : // AUTHOR Rick Strand
210 : // DATE WRITTEN Aug 2014
211 :
212 : // PURPOSE OF THIS SUBROUTINE:
213 : // This subroutine gets the input for the simple cooling panel units.
214 :
215 : // METHODOLOGY EMPLOYED:
216 : // Standard input processor calls--started from Daeho's radiant-convective water baseboard model.
217 :
218 : // Using/Aliasing
219 : using BranchNodeConnections::TestCompSet;
220 : using DataLoopNode::ObjectIsNotParent;
221 : using NodeInputManager::GetOnlySingleNode;
222 : using ScheduleManager::GetScheduleIndex;
223 :
224 : // SUBROUTINE PARAMETER DEFINITIONS:
225 : static constexpr std::string_view RoutineName("GetCoolingPanelInput:");
226 4 : Real64 constexpr MaxFraction(1.0);
227 4 : Real64 constexpr MinFraction(0.0);
228 4 : Real64 constexpr MaxWaterTempAvg(30.0); // Maximum limit of average water temperature in degree C
229 4 : Real64 constexpr MinWaterTempAvg(0.0); // Minimum limit of average water temperature in degree C
230 4 : Real64 constexpr MaxWaterFlowRate(10.0); // Maximum limit of water volume flow rate in m3/s
231 4 : Real64 constexpr MinWaterFlowRate(0.00001); // Minimum limit of water volume flow rate in m3/s
232 4 : Real64 constexpr WaterMassFlowDefault(0.063); // Default water mass flow rate in kg/s
233 4 : int constexpr MinDistribSurfaces(1); // Minimum number of surfaces that a baseboard heater can radiate to
234 4 : Real64 constexpr MinThrottlingRange(0.5); // Smallest throttling range allowed in degrees Celsius
235 : static constexpr std::string_view MeanAirTemperature("MeanAirTemperature");
236 : static constexpr std::string_view MeanRadiantTemperature("MeanRadiantTemperature");
237 : static constexpr std::string_view OperativeTemperature("OperativeTemperature");
238 : static constexpr std::string_view OutsideAirDryBulbTemperature("OutdoorDryBulbTemperature");
239 : static constexpr std::string_view OutsideAirWetBulbTemperature("OutdoorWetBulbTemperature");
240 : static constexpr std::string_view ZoneTotalLoad("ZoneTotalLoad");
241 : static constexpr std::string_view ZoneConvectiveLoad("ZoneConvectiveLoad");
242 : static constexpr std::string_view Off("Off");
243 : static constexpr std::string_view SimpleOff("SimpleOff");
244 : static constexpr std::string_view VariableOff("VariableOff");
245 :
246 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
247 : Real64 AllFracsSummed; // Sum of the fractions radiant
248 : int CoolingPanelNum; // Cooling panel number
249 : int CoolPanelNumI; // For loop index
250 : int NumAlphas; // Number of Alphas for each GetobjectItem call
251 : int NumNumbers; // Number of Numbers for each GetobjectItem call
252 : int SurfNum; // Surface number Do loop counter
253 : int IOStat;
254 4 : bool ErrorsFound(false); // If errors detected in input
255 4 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
256 4 : int NumCoolingPanels = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCMO_CoolingPanel_Simple);
257 :
258 : // Count total number of baseboard units
259 :
260 4 : state.dataChilledCeilingPanelSimple->CoolingPanel.allocate(NumCoolingPanels);
261 :
262 : // Get the data from the user input related to cooling panels
263 8 : for (CoolingPanelNum = 1; CoolingPanelNum <= NumCoolingPanels; ++CoolingPanelNum) {
264 :
265 28 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
266 : cCMO_CoolingPanel_Simple,
267 : CoolingPanelNum,
268 4 : state.dataIPShortCut->cAlphaArgs,
269 : NumAlphas,
270 4 : state.dataIPShortCut->rNumericArgs,
271 : NumNumbers,
272 : IOStat,
273 4 : state.dataIPShortCut->lNumericFieldBlanks,
274 4 : state.dataIPShortCut->lAlphaFieldBlanks,
275 4 : state.dataIPShortCut->cAlphaFieldNames,
276 4 : state.dataIPShortCut->cNumericFieldNames);
277 4 : UtilityRoutines::IsNameEmpty(state, state.dataIPShortCut->cAlphaArgs(1), cCurrentModuleObject, ErrorsFound);
278 :
279 4 : state.dataChilledCeilingPanelSimple->CoolingPanel(CoolingPanelNum).FieldNames.allocate(NumNumbers);
280 4 : state.dataChilledCeilingPanelSimple->CoolingPanel(CoolingPanelNum).FieldNames = "";
281 4 : state.dataChilledCeilingPanelSimple->CoolingPanel(CoolingPanelNum).FieldNames = state.dataIPShortCut->cNumericFieldNames;
282 :
283 4 : if (CoolingPanelNum > 1) {
284 0 : for (CoolPanelNumI = 2; CoolPanelNumI <= NumCoolingPanels; ++CoolPanelNumI) {
285 0 : if (state.dataIPShortCut->cAlphaArgs(1) == state.dataChilledCeilingPanelSimple->CoolingPanel(CoolPanelNumI).EquipID) {
286 0 : ErrorsFound = true;
287 0 : ShowSevereError(state, state.dataIPShortCut->cAlphaArgs(1) + " is used as a name for more than one simple COOLING PANEL.");
288 0 : ShowContinueError(state, "This is not allowed.");
289 : }
290 : }
291 : }
292 :
293 4 : auto &ThisCP(state.dataChilledCeilingPanelSimple->CoolingPanel(CoolingPanelNum));
294 4 : ThisCP.EquipID = state.dataIPShortCut->cAlphaArgs(1); // Name of this simple cooling panel
295 4 : ThisCP.EquipType = DataPlant::PlantEquipmentType::CoolingPanel_Simple; //'ZoneHVAC:CoolingPanel:RadiantConvective:Water'
296 :
297 : // Get schedule
298 4 : ThisCP.Schedule = state.dataIPShortCut->cAlphaArgs(2);
299 4 : if (state.dataIPShortCut->lAlphaFieldBlanks(2)) {
300 0 : ThisCP.SchedPtr = DataGlobalConstants::ScheduleAlwaysOn;
301 : } else {
302 4 : ThisCP.SchedPtr = GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(2));
303 4 : if (ThisCP.SchedPtr == 0) {
304 0 : ShowSevereError(state,
305 0 : std::string{RoutineName} + cCMO_CoolingPanel_Simple + "=\"" + state.dataIPShortCut->cAlphaArgs(1) + "\", " +
306 0 : state.dataIPShortCut->cAlphaFieldNames(2) + "=\"" + state.dataIPShortCut->cAlphaArgs(2) + "\" not found.");
307 0 : ErrorsFound = true;
308 : }
309 : }
310 :
311 : // Get inlet node number
312 4 : ThisCP.WaterInletNode = GetOnlySingleNode(state,
313 4 : state.dataIPShortCut->cAlphaArgs(3),
314 : ErrorsFound,
315 : DataLoopNode::ConnectionObjectType::ZoneHVACCoolingPanelRadiantConvectiveWater,
316 4 : state.dataIPShortCut->cAlphaArgs(1),
317 : DataLoopNode::NodeFluidType::Water,
318 : DataLoopNode::ConnectionType::Inlet,
319 : NodeInputManager::CompFluidStream::Primary,
320 4 : ObjectIsNotParent);
321 :
322 : // Get outlet node number
323 4 : ThisCP.WaterOutletNode = GetOnlySingleNode(state,
324 4 : state.dataIPShortCut->cAlphaArgs(4),
325 : ErrorsFound,
326 : DataLoopNode::ConnectionObjectType::ZoneHVACCoolingPanelRadiantConvectiveWater,
327 4 : state.dataIPShortCut->cAlphaArgs(1),
328 : DataLoopNode::NodeFluidType::Water,
329 : DataLoopNode::ConnectionType::Outlet,
330 : NodeInputManager::CompFluidStream::Primary,
331 4 : ObjectIsNotParent);
332 8 : TestCompSet(state,
333 : cCMO_CoolingPanel_Simple,
334 4 : state.dataIPShortCut->cAlphaArgs(1),
335 4 : state.dataIPShortCut->cAlphaArgs(3),
336 4 : state.dataIPShortCut->cAlphaArgs(4),
337 : "Chilled Water Nodes");
338 :
339 4 : ThisCP.RatedWaterTemp = state.dataIPShortCut->rNumericArgs(1);
340 4 : if (ThisCP.RatedWaterTemp > MaxWaterTempAvg + 0.001) {
341 0 : ShowWarningError(state,
342 0 : std::string{RoutineName} + cCMO_CoolingPanel_Simple + "=\"" + state.dataIPShortCut->cAlphaArgs(1) + "\", " +
343 0 : state.dataIPShortCut->cNumericFieldNames(1) + " was higher than the allowable maximum.");
344 0 : ShowContinueError(state, format("...reset to maximum value=[{:.2R}].", MaxWaterTempAvg));
345 0 : ThisCP.RatedWaterTemp = MaxWaterTempAvg;
346 4 : } else if (ThisCP.RatedWaterTemp < MinWaterTempAvg - 0.001) {
347 0 : ShowWarningError(state,
348 0 : std::string{RoutineName} + cCMO_CoolingPanel_Simple + "=\"" + state.dataIPShortCut->cAlphaArgs(1) + "\", " +
349 0 : state.dataIPShortCut->cNumericFieldNames(1) + " was lower than the allowable minimum.");
350 0 : ShowContinueError(state, format("...reset to minimum value=[{:.2R}].", MinWaterTempAvg));
351 0 : ThisCP.RatedWaterTemp = MinWaterTempAvg;
352 : }
353 :
354 4 : ThisCP.RatedZoneAirTemp = state.dataIPShortCut->rNumericArgs(2);
355 4 : if (ThisCP.RatedZoneAirTemp > MaxWaterTempAvg + 0.001) {
356 0 : ShowWarningError(state,
357 0 : std::string{RoutineName} + cCMO_CoolingPanel_Simple + "=\"" + state.dataIPShortCut->cAlphaArgs(1) + "\", " +
358 0 : state.dataIPShortCut->cNumericFieldNames(2) + " was higher than the allowable maximum.");
359 0 : ShowContinueError(state, format("...reset to maximum value=[{:.2R}].", MaxWaterTempAvg));
360 0 : ThisCP.RatedZoneAirTemp = MaxWaterTempAvg;
361 4 : } else if (ThisCP.RatedZoneAirTemp < MinWaterTempAvg - 0.001) {
362 0 : ShowWarningError(state,
363 0 : std::string{RoutineName} + cCMO_CoolingPanel_Simple + "=\"" + state.dataIPShortCut->cAlphaArgs(1) + "\", " +
364 0 : state.dataIPShortCut->cNumericFieldNames(2) + " was lower than the allowable minimum.");
365 0 : ShowContinueError(state, format("...reset to minimum value=[{:.2R}].", MinWaterTempAvg));
366 0 : ThisCP.RatedZoneAirTemp = MinWaterTempAvg;
367 : }
368 :
369 4 : ThisCP.RatedWaterFlowRate = state.dataIPShortCut->rNumericArgs(3);
370 4 : if (ThisCP.RatedWaterFlowRate < 0.00001 || ThisCP.RatedWaterFlowRate > 10.0) {
371 0 : ShowWarningError(state,
372 0 : std::string{RoutineName} + cCMO_CoolingPanel_Simple + "=\"" + state.dataIPShortCut->cAlphaArgs(1) + "\", " +
373 0 : state.dataIPShortCut->cNumericFieldNames(2) + " is an invalid Standard Water mass flow rate.");
374 0 : ShowContinueError(state, format("...reset to a default value=[{:.1R}].", WaterMassFlowDefault));
375 0 : ThisCP.RatedWaterFlowRate = WaterMassFlowDefault;
376 : }
377 :
378 4 : if (UtilityRoutines::SameString(state.dataIPShortCut->cAlphaArgs(5), "CoolingDesignCapacity")) {
379 2 : ThisCP.CoolingCapMethod = DataSizing::CoolingDesignCapacity;
380 2 : if (!state.dataIPShortCut->lNumericFieldBlanks(4)) {
381 2 : ThisCP.ScaledCoolingCapacity = state.dataIPShortCut->rNumericArgs(4);
382 2 : if (ThisCP.ScaledCoolingCapacity < 0.0 && ThisCP.ScaledCoolingCapacity != DataSizing::AutoSize) {
383 0 : ShowSevereError(state, cCMO_CoolingPanel_Simple + " = " + ThisCP.EquipID);
384 0 : ShowContinueError(
385 0 : state, format("Illegal {} = {:.7T}", state.dataIPShortCut->cNumericFieldNames(4), state.dataIPShortCut->rNumericArgs(4)));
386 0 : ErrorsFound = true;
387 : }
388 : } else {
389 0 : if ((!state.dataIPShortCut->lAlphaFieldBlanks(6)) || (!state.dataIPShortCut->lAlphaFieldBlanks(7))) {
390 0 : ShowSevereError(state, cCMO_CoolingPanel_Simple + " = " + ThisCP.EquipID);
391 0 : ShowContinueError(state, "Input for " + state.dataIPShortCut->cAlphaFieldNames(5) + " = " + state.dataIPShortCut->cAlphaArgs(5));
392 0 : ShowContinueError(state, "Blank field not allowed for " + state.dataIPShortCut->cNumericFieldNames(4));
393 0 : ErrorsFound = true;
394 : }
395 : }
396 2 : } else if (UtilityRoutines::SameString(state.dataIPShortCut->cAlphaArgs(5), "CapacityPerFloorArea")) {
397 1 : ThisCP.CoolingCapMethod = DataSizing::CapacityPerFloorArea;
398 1 : if (!state.dataIPShortCut->lNumericFieldBlanks(5)) {
399 1 : ThisCP.ScaledCoolingCapacity = state.dataIPShortCut->rNumericArgs(5);
400 1 : if (ThisCP.ScaledCoolingCapacity < 0.0) {
401 0 : ShowSevereError(state, cCMO_CoolingPanel_Simple + " = " + ThisCP.EquipID);
402 0 : ShowContinueError(state, "Input for " + state.dataIPShortCut->cAlphaFieldNames(5) + " = " + state.dataIPShortCut->cAlphaArgs(5));
403 0 : ShowContinueError(
404 0 : state, format("Illegal {} = {:.7T}", state.dataIPShortCut->cNumericFieldNames(5), state.dataIPShortCut->rNumericArgs(5)));
405 0 : ErrorsFound = true;
406 1 : } else if (ThisCP.ScaledCoolingCapacity == DataSizing::AutoSize) {
407 0 : ShowSevereError(state, cCMO_CoolingPanel_Simple + " = " + ThisCP.EquipID);
408 0 : ShowContinueError(state, "Input for " + state.dataIPShortCut->cAlphaFieldNames(5) + " = " + state.dataIPShortCut->cAlphaArgs(5));
409 0 : ShowContinueError(state, "Illegal " + state.dataIPShortCut->cNumericFieldNames(5) + " = Autosize");
410 0 : ErrorsFound = true;
411 : }
412 : } else {
413 0 : ShowSevereError(state, cCMO_CoolingPanel_Simple + " = " + ThisCP.EquipID);
414 0 : ShowContinueError(state, "Input for " + state.dataIPShortCut->cAlphaFieldNames(5) + " = " + state.dataIPShortCut->cAlphaArgs(5));
415 0 : ShowContinueError(state, "Blank field not allowed for " + state.dataIPShortCut->cNumericFieldNames(5));
416 0 : ErrorsFound = true;
417 : }
418 1 : } else if (UtilityRoutines::SameString(state.dataIPShortCut->cAlphaArgs(5), "FractionOfAutosizedCoolingCapacity")) {
419 1 : ThisCP.CoolingCapMethod = DataSizing::FractionOfAutosizedCoolingCapacity;
420 1 : if (!state.dataIPShortCut->lNumericFieldBlanks(6)) {
421 1 : ThisCP.ScaledCoolingCapacity = state.dataIPShortCut->rNumericArgs(6);
422 1 : if (ThisCP.ScaledCoolingCapacity < 0.0) {
423 0 : ShowSevereError(state, cCMO_CoolingPanel_Simple + " = " + ThisCP.EquipID);
424 0 : ShowContinueError(
425 0 : state, format("Illegal {} = {:.7T}", state.dataIPShortCut->cNumericFieldNames(6), state.dataIPShortCut->rNumericArgs(6)));
426 0 : ErrorsFound = true;
427 : }
428 : } else {
429 0 : ShowSevereError(state, cCMO_CoolingPanel_Simple + " = " + ThisCP.EquipID);
430 0 : ShowContinueError(state, "Input for " + state.dataIPShortCut->cAlphaFieldNames(5) + " = " + state.dataIPShortCut->cAlphaArgs(5));
431 0 : ShowContinueError(state, "Blank field not allowed for " + state.dataIPShortCut->cNumericFieldNames(6));
432 0 : ErrorsFound = true;
433 : }
434 : } else {
435 0 : ShowSevereError(state, cCMO_CoolingPanel_Simple + " = " + ThisCP.EquipID);
436 0 : ShowContinueError(state, "Illegal " + state.dataIPShortCut->cAlphaFieldNames(5) + " = " + state.dataIPShortCut->cAlphaArgs(5));
437 0 : ErrorsFound = true;
438 : }
439 :
440 4 : ThisCP.WaterVolFlowRateMax = state.dataIPShortCut->rNumericArgs(7);
441 4 : if ((ThisCP.WaterVolFlowRateMax <= MinWaterFlowRate) && ThisCP.WaterVolFlowRateMax != DataSizing::AutoSize) {
442 0 : ShowWarningError(state,
443 0 : std::string{RoutineName} + cCMO_CoolingPanel_Simple + "=\"" + state.dataIPShortCut->cAlphaArgs(1) + "\", " +
444 0 : state.dataIPShortCut->cNumericFieldNames(7) + " was less than the allowable minimum.");
445 0 : ShowContinueError(state, format("...reset to minimum value=[{:.2R}].", MinWaterFlowRate));
446 0 : ThisCP.WaterVolFlowRateMax = MinWaterFlowRate;
447 4 : } else if (ThisCP.WaterVolFlowRateMax > MaxWaterFlowRate) {
448 0 : ShowWarningError(state,
449 0 : std::string{RoutineName} + cCMO_CoolingPanel_Simple + "=\"" + state.dataIPShortCut->cAlphaArgs(1) + "\", " +
450 0 : state.dataIPShortCut->cNumericFieldNames(7) + " was higher than the allowable maximum.");
451 0 : ShowContinueError(state, format("...reset to maximum value=[{:.2R}].", MaxWaterFlowRate));
452 0 : ThisCP.WaterVolFlowRateMax = MaxWaterFlowRate;
453 : }
454 :
455 : // Process the temperature control type
456 4 : if (UtilityRoutines::SameString(state.dataIPShortCut->cAlphaArgs(6), MeanAirTemperature)) {
457 3 : ThisCP.controlType = ClgPanelCtrlType::MAT;
458 1 : } else if (UtilityRoutines::SameString(state.dataIPShortCut->cAlphaArgs(6), MeanRadiantTemperature)) {
459 0 : ThisCP.controlType = ClgPanelCtrlType::MRT;
460 1 : } else if (UtilityRoutines::SameString(state.dataIPShortCut->cAlphaArgs(6), OperativeTemperature)) {
461 0 : ThisCP.controlType = ClgPanelCtrlType::Operative;
462 1 : } else if (UtilityRoutines::SameString(state.dataIPShortCut->cAlphaArgs(6), OutsideAirDryBulbTemperature)) {
463 0 : ThisCP.controlType = ClgPanelCtrlType::ODB;
464 1 : } else if (UtilityRoutines::SameString(state.dataIPShortCut->cAlphaArgs(6), OutsideAirWetBulbTemperature)) {
465 0 : ThisCP.controlType = ClgPanelCtrlType::OWB;
466 1 : } else if (UtilityRoutines::SameString(state.dataIPShortCut->cAlphaArgs(6), ZoneTotalLoad)) {
467 1 : ThisCP.controlType = ClgPanelCtrlType::ZoneTotalLoad;
468 0 : } else if (UtilityRoutines::SameString(state.dataIPShortCut->cAlphaArgs(6), ZoneConvectiveLoad)) {
469 0 : ThisCP.controlType = ClgPanelCtrlType::ZoneConvectiveLoad;
470 : } else {
471 0 : ShowWarningError(state, "Invalid " + state.dataIPShortCut->cAlphaFieldNames(6) + " =" + state.dataIPShortCut->cAlphaArgs(6));
472 0 : ShowContinueError(state, "Occurs in " + std::string{RoutineName} + " = " + state.dataIPShortCut->cAlphaArgs(1));
473 0 : ShowContinueError(state, "Control reset to MAT control for this Simple Cooling Panel.");
474 0 : ThisCP.controlType = ClgPanelCtrlType::MAT;
475 : }
476 :
477 4 : ThisCP.ColdThrottlRange = state.dataIPShortCut->rNumericArgs(8);
478 4 : if (ThisCP.ColdThrottlRange < MinThrottlingRange) {
479 0 : ShowWarningError(state, cCMO_CoolingPanel_Simple + "Cooling throttling range too small, reset to 0.5");
480 0 : ShowContinueError(state, "Occurs in Cooling Panel=" + ThisCP.EquipID);
481 0 : ThisCP.ColdThrottlRange = MinThrottlingRange;
482 : }
483 :
484 4 : ThisCP.ColdSetptSched = state.dataIPShortCut->cAlphaArgs(7);
485 4 : ThisCP.ColdSetptSchedPtr = GetScheduleIndex(state, ThisCP.ColdSetptSched);
486 4 : if ((ThisCP.ColdSetptSchedPtr == 0) && (!state.dataIPShortCut->lAlphaFieldBlanks(7))) {
487 0 : ShowSevereError(state, state.dataIPShortCut->cAlphaFieldNames(7) + " not found: " + ThisCP.ColdSetptSched);
488 0 : ShowContinueError(state, "Occurs in " + std::string{RoutineName} + " = " + state.dataIPShortCut->cAlphaArgs(1));
489 0 : ErrorsFound = true;
490 : }
491 :
492 4 : if (UtilityRoutines::SameString(state.dataIPShortCut->cAlphaArgs(8), Off)) {
493 3 : ThisCP.CondCtrlType = CondCtrl::NONE;
494 1 : } else if (UtilityRoutines::SameString(state.dataIPShortCut->cAlphaArgs(8), SimpleOff)) {
495 0 : ThisCP.CondCtrlType = CondCtrl::SIMPLEOFF;
496 1 : } else if (UtilityRoutines::SameString(state.dataIPShortCut->cAlphaArgs(8), VariableOff)) {
497 1 : ThisCP.CondCtrlType = CondCtrl::VARIEDOFF;
498 : } else {
499 0 : ThisCP.CondCtrlType = CondCtrl::SIMPLEOFF;
500 : }
501 :
502 4 : ThisCP.CondDewPtDeltaT = state.dataIPShortCut->rNumericArgs(9);
503 :
504 4 : ThisCP.FracRadiant = state.dataIPShortCut->rNumericArgs(10);
505 4 : if (ThisCP.FracRadiant < MinFraction) {
506 0 : ShowWarningError(state,
507 0 : std::string{RoutineName} + cCMO_CoolingPanel_Simple + "=\"" + state.dataIPShortCut->cAlphaArgs(1) + "\", " +
508 0 : state.dataIPShortCut->cNumericFieldNames(10) + " was lower than the allowable minimum.");
509 0 : ShowContinueError(state, format("...reset to minimum value=[{:.2R}].", MinFraction));
510 0 : ThisCP.FracRadiant = MinFraction;
511 : }
512 4 : if (ThisCP.FracRadiant > MaxFraction) {
513 0 : ShowWarningError(state,
514 0 : std::string{RoutineName} + cCMO_CoolingPanel_Simple + "=\"" + state.dataIPShortCut->cAlphaArgs(1) + "\", " +
515 0 : state.dataIPShortCut->cNumericFieldNames(10) + " was higher than the allowable maximum.");
516 0 : ShowContinueError(state, format("...reset to maximum value=[{:.2R}].", MaxFraction));
517 0 : ThisCP.FracRadiant = MaxFraction;
518 : }
519 :
520 : // Remaining fraction is added to the zone as convective heat transfer
521 4 : AllFracsSummed = ThisCP.FracRadiant;
522 4 : if (AllFracsSummed > MaxFraction) {
523 0 : ShowWarningError(state,
524 0 : std::string{RoutineName} + cCMO_CoolingPanel_Simple + "=\"" + state.dataIPShortCut->cAlphaArgs(1) +
525 : "\", Fraction Radiant was higher than the allowable maximum.");
526 0 : ThisCP.FracRadiant = MaxFraction;
527 0 : ThisCP.FracConvect = 0.0;
528 : } else {
529 4 : ThisCP.FracConvect = 1.0 - AllFracsSummed;
530 : }
531 :
532 4 : ThisCP.FracDistribPerson = state.dataIPShortCut->rNumericArgs(11);
533 4 : if (ThisCP.FracDistribPerson < MinFraction) {
534 0 : ShowWarningError(state,
535 0 : std::string{RoutineName} + cCMO_CoolingPanel_Simple + "=\"" + state.dataIPShortCut->cAlphaArgs(1) + "\", " +
536 0 : state.dataIPShortCut->cNumericFieldNames(11) + " was lower than the allowable minimum.");
537 0 : ShowContinueError(state, format("...reset to minimum value=[{:.3R}].", MinFraction));
538 0 : ThisCP.FracDistribPerson = MinFraction;
539 : }
540 4 : if (ThisCP.FracDistribPerson > MaxFraction) {
541 0 : ShowWarningError(state,
542 0 : std::string{RoutineName} + cCMO_CoolingPanel_Simple + "=\"" + state.dataIPShortCut->cAlphaArgs(1) + "\", " +
543 0 : state.dataIPShortCut->cNumericFieldNames(11) + " was higher than the allowable maximum.");
544 0 : ShowContinueError(state, format("...reset to maximum value=[{:.3R}].", MaxFraction));
545 0 : ThisCP.FracDistribPerson = MaxFraction;
546 : }
547 :
548 4 : ThisCP.TotSurfToDistrib = NumNumbers - 11;
549 4 : if ((ThisCP.TotSurfToDistrib < MinDistribSurfaces) && (ThisCP.FracRadiant > MinFraction)) {
550 0 : ShowSevereError(state,
551 0 : std::string{RoutineName} + cCMO_CoolingPanel_Simple + "=\"" + state.dataIPShortCut->cAlphaArgs(1) +
552 : "\", the number of surface/radiant fraction groups entered was less than the allowable minimum.");
553 0 : ShowContinueError(state, format("...the minimum that must be entered=[{}].", MinDistribSurfaces));
554 0 : ErrorsFound = true;
555 0 : ThisCP.TotSurfToDistrib = 0; // error
556 : }
557 :
558 4 : ThisCP.SurfaceName.allocate(ThisCP.TotSurfToDistrib);
559 4 : ThisCP.SurfaceName = "";
560 4 : ThisCP.SurfacePtr.allocate(ThisCP.TotSurfToDistrib);
561 4 : ThisCP.SurfacePtr = 0;
562 4 : ThisCP.FracDistribToSurf.allocate(ThisCP.TotSurfToDistrib);
563 4 : ThisCP.FracDistribToSurf = 0.0;
564 :
565 : // search zone equipment list structure for zone index
566 28 : for (int ctrlZone = 1; ctrlZone <= state.dataGlobal->NumOfZones; ++ctrlZone) {
567 56 : for (int zoneEquipTypeNum = 1; zoneEquipTypeNum <= state.dataZoneEquip->ZoneEquipList(ctrlZone).NumOfEquipTypes; ++zoneEquipTypeNum) {
568 36 : if (state.dataZoneEquip->ZoneEquipList(ctrlZone).EquipTypeEnum(zoneEquipTypeNum) == DataZoneEquipment::ZoneEquip::CoolingPanel &&
569 4 : state.dataZoneEquip->ZoneEquipList(ctrlZone).EquipName(zoneEquipTypeNum) == ThisCP.EquipID) {
570 4 : ThisCP.ZonePtr = ctrlZone;
571 : }
572 : }
573 : }
574 4 : if (ThisCP.ZonePtr <= 0) {
575 0 : ShowSevereError(
576 0 : state, std::string{RoutineName} + cCMO_CoolingPanel_Simple + "=\"" + ThisCP.EquipID + "\" is not on any ZoneHVAC:EquipmentList.");
577 0 : ErrorsFound = true;
578 0 : continue;
579 : }
580 :
581 4 : AllFracsSummed = ThisCP.FracDistribPerson;
582 16 : for (SurfNum = 1; SurfNum <= ThisCP.TotSurfToDistrib; ++SurfNum) {
583 12 : ThisCP.SurfaceName(SurfNum) = state.dataIPShortCut->cAlphaArgs(SurfNum + 8);
584 12 : ThisCP.SurfacePtr(SurfNum) = HeatBalanceIntRadExchange::GetRadiantSystemSurface(
585 12 : state, cCMO_CoolingPanel_Simple, ThisCP.EquipID, ThisCP.ZonePtr, ThisCP.SurfaceName(SurfNum), ErrorsFound);
586 12 : ThisCP.FracDistribToSurf(SurfNum) = state.dataIPShortCut->rNumericArgs(SurfNum + 11);
587 12 : if (ThisCP.FracDistribToSurf(SurfNum) > MaxFraction) {
588 0 : ShowWarningError(state,
589 0 : std::string{RoutineName} + cCMO_CoolingPanel_Simple + "=\"" + state.dataIPShortCut->cAlphaArgs(1) + "\", " +
590 0 : state.dataIPShortCut->cNumericFieldNames(SurfNum + 8) + "was greater than the allowable maximum.");
591 0 : ShowContinueError(state, format("...reset to maximum value=[{:.2R}].", MaxFraction));
592 0 : ThisCP.TotSurfToDistrib = MaxFraction;
593 : }
594 12 : if (ThisCP.FracDistribToSurf(SurfNum) < MinFraction) {
595 0 : ShowWarningError(state,
596 0 : std::string{RoutineName} + cCMO_CoolingPanel_Simple + "=\"" + state.dataIPShortCut->cAlphaArgs(1) + "\", " +
597 0 : state.dataIPShortCut->cNumericFieldNames(SurfNum + 8) + "was less than the allowable minimum.");
598 0 : ShowContinueError(state, format("...reset to maximum value=[{:.2R}].", MinFraction));
599 0 : ThisCP.TotSurfToDistrib = MinFraction;
600 : }
601 12 : if (ThisCP.SurfacePtr(SurfNum) != 0) {
602 12 : state.dataSurface->SurfIntConvSurfGetsRadiantHeat(ThisCP.SurfacePtr(SurfNum)) = true;
603 : }
604 :
605 12 : AllFracsSummed += ThisCP.FracDistribToSurf(SurfNum);
606 : } // Surfaces
607 :
608 4 : if (AllFracsSummed > (MaxFraction + 0.01)) {
609 0 : ShowSevereError(state,
610 0 : std::string{RoutineName} + cCMO_CoolingPanel_Simple + "=\"" + state.dataIPShortCut->cAlphaArgs(1) +
611 : "\", Summed radiant fractions for people + surface groups > 1.0");
612 0 : ErrorsFound = true;
613 : }
614 4 : if ((AllFracsSummed < (MaxFraction - 0.01)) &&
615 0 : (ThisCP.FracRadiant > MinFraction)) { // User didn't distribute all of the | radiation warn that some will be lost
616 0 : ShowSevereError(state,
617 0 : std::string{RoutineName} + cCMO_CoolingPanel_Simple + "=\"" + state.dataIPShortCut->cAlphaArgs(1) +
618 : "\", Summed radiant fractions for people + surface groups < 1.0");
619 0 : ShowContinueError(state, "This would result in some of the radiant energy delivered by the high temp radiant heater being lost.");
620 0 : ShowContinueError(state, format("The sum of all radiation fractions to surfaces = {:.5T}", (AllFracsSummed - ThisCP.FracDistribPerson)));
621 0 : ShowContinueError(state, format("The radiant fraction to people = {:.5T}", ThisCP.FracDistribPerson));
622 0 : ShowContinueError(state, format("So, all radiant fractions including surfaces and people = {:.5T}", AllFracsSummed));
623 0 : ShowContinueError(state,
624 0 : format("This means that the fraction of radiant energy that would be lost from the high temperature radiant heater "
625 : "would be = {:.5T}",
626 0 : (1.0 - AllFracsSummed)));
627 0 : ShowContinueError(state,
628 0 : "Please check and correct this so that all radiant energy is accounted for in " + cCMO_CoolingPanel_Simple + " = " +
629 0 : state.dataIPShortCut->cAlphaArgs(1));
630 0 : ErrorsFound = true;
631 : }
632 : }
633 :
634 4 : if (ErrorsFound) {
635 0 : ShowFatalError(state, std::string{RoutineName} + cCMO_CoolingPanel_Simple + "Errors found getting input. Program terminates.");
636 : }
637 :
638 : // Setup Report variables for the Coils
639 8 : for (CoolingPanelNum = 1; CoolingPanelNum <= NumCoolingPanels; ++CoolingPanelNum) {
640 : // CurrentModuleObject='ZoneHVAC:CoolingPanel:RadiantConvective:Water'
641 16 : SetupOutputVariable(state,
642 : "Cooling Panel Total Cooling Rate",
643 : OutputProcessor::Unit::W,
644 4 : state.dataChilledCeilingPanelSimple->CoolingPanel(CoolingPanelNum).Power,
645 : OutputProcessor::SOVTimeStepType::System,
646 : OutputProcessor::SOVStoreType::Average,
647 8 : state.dataChilledCeilingPanelSimple->CoolingPanel(CoolingPanelNum).EquipID);
648 16 : SetupOutputVariable(state,
649 : "Cooling Panel Total System Cooling Rate",
650 : OutputProcessor::Unit::W,
651 4 : state.dataChilledCeilingPanelSimple->CoolingPanel(CoolingPanelNum).TotPower,
652 : OutputProcessor::SOVTimeStepType::System,
653 : OutputProcessor::SOVStoreType::Average,
654 8 : state.dataChilledCeilingPanelSimple->CoolingPanel(CoolingPanelNum).EquipID);
655 16 : SetupOutputVariable(state,
656 : "Cooling Panel Convective Cooling Rate",
657 : OutputProcessor::Unit::W,
658 4 : state.dataChilledCeilingPanelSimple->CoolingPanel(CoolingPanelNum).ConvPower,
659 : OutputProcessor::SOVTimeStepType::System,
660 : OutputProcessor::SOVStoreType::Average,
661 8 : state.dataChilledCeilingPanelSimple->CoolingPanel(CoolingPanelNum).EquipID);
662 16 : SetupOutputVariable(state,
663 : "Cooling Panel Radiant Cooling Rate",
664 : OutputProcessor::Unit::W,
665 4 : state.dataChilledCeilingPanelSimple->CoolingPanel(CoolingPanelNum).RadPower,
666 : OutputProcessor::SOVTimeStepType::System,
667 : OutputProcessor::SOVStoreType::Average,
668 8 : state.dataChilledCeilingPanelSimple->CoolingPanel(CoolingPanelNum).EquipID);
669 :
670 16 : SetupOutputVariable(state,
671 : "Cooling Panel Total Cooling Energy",
672 : OutputProcessor::Unit::J,
673 4 : state.dataChilledCeilingPanelSimple->CoolingPanel(CoolingPanelNum).Energy,
674 : OutputProcessor::SOVTimeStepType::System,
675 : OutputProcessor::SOVStoreType::Summed,
676 4 : state.dataChilledCeilingPanelSimple->CoolingPanel(CoolingPanelNum).EquipID,
677 : _,
678 : "ENERGYTRANSFER",
679 : "COOLINGPANEL",
680 : _,
681 4 : "System");
682 16 : SetupOutputVariable(state,
683 : "Cooling Panel Total System Cooling Energy",
684 : OutputProcessor::Unit::J,
685 4 : state.dataChilledCeilingPanelSimple->CoolingPanel(CoolingPanelNum).TotEnergy,
686 : OutputProcessor::SOVTimeStepType::System,
687 : OutputProcessor::SOVStoreType::Summed,
688 4 : state.dataChilledCeilingPanelSimple->CoolingPanel(CoolingPanelNum).EquipID,
689 : _,
690 : "ENERGYTRANSFER",
691 : "COOLINGPANEL",
692 : _,
693 4 : "System");
694 16 : SetupOutputVariable(state,
695 : "Cooling Panel Convective Cooling Energy",
696 : OutputProcessor::Unit::J,
697 4 : state.dataChilledCeilingPanelSimple->CoolingPanel(CoolingPanelNum).ConvEnergy,
698 : OutputProcessor::SOVTimeStepType::System,
699 : OutputProcessor::SOVStoreType::Summed,
700 8 : state.dataChilledCeilingPanelSimple->CoolingPanel(CoolingPanelNum).EquipID);
701 16 : SetupOutputVariable(state,
702 : "Cooling Panel Radiant Cooling Energy",
703 : OutputProcessor::Unit::J,
704 4 : state.dataChilledCeilingPanelSimple->CoolingPanel(CoolingPanelNum).RadEnergy,
705 : OutputProcessor::SOVTimeStepType::System,
706 : OutputProcessor::SOVStoreType::Summed,
707 8 : state.dataChilledCeilingPanelSimple->CoolingPanel(CoolingPanelNum).EquipID);
708 :
709 16 : SetupOutputVariable(state,
710 : "Cooling Panel Water Mass Flow Rate",
711 : OutputProcessor::Unit::kg_s,
712 4 : state.dataChilledCeilingPanelSimple->CoolingPanel(CoolingPanelNum).WaterMassFlowRate,
713 : OutputProcessor::SOVTimeStepType::System,
714 : OutputProcessor::SOVStoreType::Average,
715 8 : state.dataChilledCeilingPanelSimple->CoolingPanel(CoolingPanelNum).EquipID);
716 16 : SetupOutputVariable(state,
717 : "Cooling Panel Water Inlet Temperature",
718 : OutputProcessor::Unit::C,
719 4 : state.dataChilledCeilingPanelSimple->CoolingPanel(CoolingPanelNum).WaterInletTemp,
720 : OutputProcessor::SOVTimeStepType::System,
721 : OutputProcessor::SOVStoreType::Average,
722 8 : state.dataChilledCeilingPanelSimple->CoolingPanel(CoolingPanelNum).EquipID);
723 16 : SetupOutputVariable(state,
724 : "Cooling Panel Water Outlet Temperature",
725 : OutputProcessor::Unit::C,
726 4 : state.dataChilledCeilingPanelSimple->CoolingPanel(CoolingPanelNum).WaterOutletTemp,
727 : OutputProcessor::SOVTimeStepType::System,
728 : OutputProcessor::SOVStoreType::Average,
729 8 : state.dataChilledCeilingPanelSimple->CoolingPanel(CoolingPanelNum).EquipID);
730 : }
731 4 : }
732 :
733 22551 : void InitCoolingPanel(EnergyPlusData &state, int const CoolingPanelNum, int const ControlledZoneNum, bool const FirstHVACIteration)
734 : {
735 :
736 : // SUBROUTINE INFORMATION:
737 : // AUTHOR Rick Strand
738 : // DATE WRITTEN Sept 2014
739 :
740 : // PURPOSE OF THIS SUBROUTINE:
741 : // This subroutine initializes the cooling panel units, and determines the UA values during simulation.
742 :
743 : // METHODOLOGY EMPLOYED:
744 : // The initialization subrotines borrowed from other sources and heat exchanger formulation for cooling panel.
745 :
746 : // REFERENCES:
747 : // Incropera and DeWitt, Fundamentals of Heat and Mass Transfer
748 :
749 : // Using/Aliasing
750 : using DataZoneEquipment::CheckZoneEquipmentList;
751 : using FluidProperties::GetDensityGlycol;
752 : using FluidProperties::GetSpecificHeatGlycol;
753 : using PlantUtilities::InitComponentNodes;
754 : using PlantUtilities::ScanPlantLoopsForObject;
755 :
756 : // SUBROUTINE PARAMETER DEFINITIONS:
757 : static constexpr std::string_view RoutineName("ChilledCeilingPanelSimple:InitCoolingPanel");
758 :
759 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
760 : Real64 rho; // local fluid density
761 : Real64 Cp; // local fluid specific heat
762 : bool errFlag;
763 :
764 22551 : auto &ThisCP(state.dataChilledCeilingPanelSimple->CoolingPanel(CoolingPanelNum));
765 22551 : auto &ThisInNode(state.dataLoopNodes->Node(ThisCP.WaterInletNode));
766 :
767 22551 : if (ThisCP.ZonePtr <= 0) ThisCP.ZonePtr = ControlledZoneNum;
768 :
769 : // Need to check all units to see if they are on ZoneHVAC:EquipmentList or issue warning
770 22551 : if (!ThisCP.ZoneEquipmentListChecked && state.dataZoneEquip->ZoneEquipInputsFilled) {
771 4 : ThisCP.ZoneEquipmentListChecked = true;
772 4 : if (!CheckZoneEquipmentList(state, cCMO_CoolingPanel_Simple, ThisCP.EquipID)) {
773 0 : ShowSevereError(state,
774 0 : "InitCoolingPanel: Unit=[" + cCMO_CoolingPanel_Simple + ',' + ThisCP.EquipID +
775 : "] is not on any ZoneHVAC:EquipmentList. It will not be simulated.");
776 : }
777 : }
778 :
779 22551 : if (ThisCP.SetLoopIndexFlag) {
780 4 : if (allocated(state.dataPlnt->PlantLoop)) {
781 4 : errFlag = false;
782 4 : ScanPlantLoopsForObject(state, ThisCP.EquipID, ThisCP.EquipType, ThisCP.plantLoc, errFlag, _, _, _, _, _);
783 4 : if (errFlag) {
784 0 : ShowFatalError(state, "InitCoolingPanel: Program terminated for previous conditions.");
785 : }
786 4 : ThisCP.SetLoopIndexFlag = false;
787 : }
788 : }
789 :
790 22551 : if (!state.dataGlobal->SysSizingCalc) {
791 22547 : if (ThisCP.MySizeFlagCoolPanel && !ThisCP.SetLoopIndexFlag) {
792 : // for each cooling panel do the sizing once.
793 4 : SizeCoolingPanel(state, CoolingPanelNum);
794 4 : ThisCP.MySizeFlagCoolPanel = false;
795 :
796 : // set design mass flow rates
797 4 : if (ThisCP.WaterInletNode > 0) {
798 8 : rho = GetDensityGlycol(state,
799 4 : state.dataPlnt->PlantLoop(ThisCP.plantLoc.loopNum).FluidName,
800 : DataGlobalConstants::CWInitConvTemp,
801 4 : state.dataPlnt->PlantLoop(ThisCP.plantLoc.loopNum).FluidIndex,
802 : RoutineName);
803 4 : ThisCP.WaterMassFlowRateMax = rho * ThisCP.WaterVolFlowRateMax;
804 4 : InitComponentNodes(state, 0.0, ThisCP.WaterMassFlowRateMax, ThisCP.WaterInletNode, ThisCP.WaterOutletNode);
805 : }
806 : }
807 : }
808 :
809 : // Do the Begin Environment initializations
810 22551 : if (state.dataGlobal->BeginEnvrnFlag && ThisCP.MyEnvrnFlag) {
811 : // Initialize
812 :
813 48 : rho = GetDensityGlycol(state,
814 24 : state.dataPlnt->PlantLoop(ThisCP.plantLoc.loopNum).FluidName,
815 : DataGlobalConstants::InitConvTemp,
816 24 : state.dataPlnt->PlantLoop(ThisCP.plantLoc.loopNum).FluidIndex,
817 : RoutineName);
818 :
819 24 : ThisCP.WaterMassFlowRateMax = rho * ThisCP.WaterVolFlowRateMax;
820 :
821 24 : InitComponentNodes(state, 0.0, ThisCP.WaterMassFlowRateMax, ThisCP.WaterInletNode, ThisCP.WaterOutletNode);
822 :
823 24 : ThisInNode.Temp = 7.0;
824 :
825 48 : Cp = GetSpecificHeatGlycol(state,
826 24 : state.dataPlnt->PlantLoop(ThisCP.plantLoc.loopNum).FluidName,
827 : ThisInNode.Temp,
828 24 : state.dataPlnt->PlantLoop(ThisCP.plantLoc.loopNum).FluidIndex,
829 : RoutineName);
830 :
831 24 : ThisInNode.Enthalpy = Cp * ThisInNode.Temp;
832 24 : ThisInNode.Quality = 0.0;
833 24 : ThisInNode.Press = 0.0;
834 24 : ThisInNode.HumRat = 0.0;
835 :
836 24 : ThisCP.ZeroSourceSumHATsurf = 0.0;
837 24 : ThisCP.CoolingPanelSource = 0.0;
838 24 : ThisCP.CoolingPanelSrcAvg = 0.0;
839 24 : ThisCP.LastCoolingPanelSrc = 0.0;
840 24 : ThisCP.LastSysTimeElapsed = 0.0;
841 24 : ThisCP.LastTimeStepSys = 0.0;
842 :
843 24 : ThisCP.MyEnvrnFlag = false;
844 : }
845 :
846 22551 : if (!state.dataGlobal->BeginEnvrnFlag) {
847 22421 : ThisCP.MyEnvrnFlag = true;
848 : }
849 :
850 22551 : if (state.dataGlobal->BeginTimeStepFlag && FirstHVACIteration) {
851 8108 : int ZoneNum = ThisCP.ZonePtr;
852 8108 : state.dataHeatBal->Zone(ZoneNum).ZeroSourceSumHATsurf = state.dataHeatBal->Zone(ZoneNum).sumHATsurf(state);
853 8108 : ThisCP.CoolingPanelSrcAvg = 0.0;
854 8108 : ThisCP.LastCoolingPanelSrc = 0.0;
855 8108 : ThisCP.LastSysTimeElapsed = 0.0;
856 8108 : ThisCP.LastTimeStepSys = 0.0;
857 : }
858 :
859 : // Do the every time step initializations
860 22551 : ThisCP.WaterMassFlowRate = ThisInNode.MassFlowRate;
861 22551 : ThisCP.WaterInletTemp = ThisInNode.Temp;
862 22551 : ThisCP.WaterInletEnthalpy = ThisInNode.Enthalpy;
863 22551 : ThisCP.TotPower = 0.0;
864 22551 : ThisCP.Power = 0.0;
865 22551 : ThisCP.ConvPower = 0.0;
866 22551 : ThisCP.RadPower = 0.0;
867 22551 : ThisCP.TotEnergy = 0.0;
868 22551 : ThisCP.Energy = 0.0;
869 22551 : ThisCP.ConvEnergy = 0.0;
870 22551 : ThisCP.RadEnergy = 0.0;
871 22551 : }
872 :
873 4 : void SizeCoolingPanel(EnergyPlusData &state, int const CoolingPanelNum)
874 : {
875 : // SUBROUTINE INFORMATION:
876 : // AUTHOR Rick Strand
877 : // DATE WRITTEN Sept 2016
878 :
879 : // PURPOSE OF THIS SUBROUTINE:
880 : // This subroutine sizes the simple chilled ceiling panel. The process used here
881 : // was derived from the low temperature radiant system model and adapted for
882 : // cooling only.
883 :
884 : using DataHVACGlobals::AutoCalculateSizing;
885 : using DataHVACGlobals::CoolingCapacitySizing;
886 : using DataHVACGlobals::SmallLoad;
887 : using DataSizing::AutoSize;
888 : using DataSizing::CapacityPerFloorArea;
889 : using DataSizing::CoolingDesignCapacity;
890 : using DataSizing::FractionOfAutosizedCoolingCapacity;
891 : using FluidProperties::GetDensityGlycol;
892 : using FluidProperties::GetSpecificHeatGlycol;
893 : using PlantUtilities::MyPlantSizingIndex;
894 : using PlantUtilities::RegisterPlantCompDesignFlow;
895 :
896 : // SUBROUTINE PARAMETER DEFINITIONS:
897 : static constexpr std::string_view RoutineName("SizeCoolingPanel");
898 :
899 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
900 4 : bool ErrorsFound(false); // If errors detected in input
901 8 : std::string CompName; // component name
902 8 : std::string CompType; // component type
903 4 : bool IsAutoSize(false); // Indicator to autosize
904 : Real64 DesCoilLoad; // design autosized or user specified capacity
905 : int SizingMethod; // Integer representation of sizing method name (e.g. CoolingCapacitySizing, HeatingCapacitySizing)
906 4 : int FieldNum = 1; // IDD numeric field number where input field description is found
907 : bool PrintFlag; // TRUE when sizing information is reported in the eio file
908 8 : std::string SizingString; // input field sizing description (e.g., Nominal Capacity)
909 : Real64 TempSize; // autosized value of coil input field
910 4 : int CapSizingMethod(0); // capacity sizing methods (HeatingDesignCapacity, CapacityPerFloorArea, FractionOfAutosizedCoolingCapacity, and
911 : // FractionOfAutosizedHeatingCapacity )
912 4 : int PltSizCoolNum(0); // index of plant sizing object for 1st cooling loop
913 : Real64 rho;
914 : Real64 Cp;
915 4 : Real64 WaterVolFlowMaxCoolDes(0.0); // Design chilled water flow for reporting
916 4 : Real64 WaterVolFlowMaxCoolUser(0.0); // User hard-sized chilled water flow for reporting
917 :
918 4 : DesCoilLoad = 0.0;
919 4 : state.dataSize->DataScalableCapSizingON = false;
920 :
921 4 : auto &ThisCP(state.dataChilledCeilingPanelSimple->CoolingPanel(CoolingPanelNum));
922 4 : auto &ZoneEqSizing(state.dataSize->ZoneEqSizing);
923 :
924 4 : CompType = "ZoneHVAC:CoolingPanel:RadiantConvective:Water";
925 4 : CompName = ThisCP.EquipID;
926 :
927 4 : IsAutoSize = false;
928 4 : if (ThisCP.ScaledCoolingCapacity == AutoSize) {
929 1 : IsAutoSize = true;
930 : }
931 :
932 4 : if (state.dataSize->CurZoneEqNum > 0) {
933 :
934 4 : SizingMethod = CoolingCapacitySizing;
935 4 : FieldNum = 4;
936 4 : PrintFlag = true;
937 4 : bool errorsFound = false;
938 4 : SizingString = ThisCP.FieldNames(FieldNum) + " [W]";
939 4 : CapSizingMethod = ThisCP.CoolingCapMethod;
940 4 : ZoneEqSizing(state.dataSize->CurZoneEqNum).SizingMethod(SizingMethod) = CapSizingMethod;
941 :
942 4 : if (!IsAutoSize && !state.dataSize->ZoneSizingRunDone) { // simulation continue
943 0 : if (CapSizingMethod == CoolingDesignCapacity && ThisCP.ScaledCoolingCapacity > 0.0) {
944 0 : TempSize = ThisCP.ScaledCoolingCapacity;
945 0 : CoolingCapacitySizer sizerCoolingCapacity;
946 0 : sizerCoolingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
947 0 : DesCoilLoad = sizerCoolingCapacity.size(state, TempSize, errorsFound);
948 0 : } else if (CapSizingMethod == CapacityPerFloorArea) {
949 0 : state.dataSize->DataScalableCapSizingON = true;
950 0 : TempSize = ThisCP.ScaledCoolingCapacity * state.dataHeatBal->Zone(ThisCP.ZonePtr).FloorArea;
951 0 : CoolingCapacitySizer sizerCoolingCapacity;
952 0 : sizerCoolingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
953 0 : DesCoilLoad = sizerCoolingCapacity.size(state, TempSize, errorsFound);
954 0 : state.dataSize->DataScalableCapSizingON = false;
955 0 : } else if (CapSizingMethod == FractionOfAutosizedCoolingCapacity) {
956 0 : if (ThisCP.WaterVolFlowRateMax == AutoSize) {
957 0 : ShowSevereError(state,
958 0 : std::string{RoutineName} + ": auto-sizing cannot be done for " + CompType + " = " + ThisCP.EquipID + "\".");
959 0 : ShowContinueError(state,
960 : "The \"SimulationControl\" object must have the field \"Do Zone Sizing Calculation\" set to Yes when the "
961 : "Cooling Design Capacity Method = \"FractionOfAutosizedCoolingCapacity\".");
962 0 : ErrorsFound = true;
963 : }
964 : }
965 : } else { // Autosize or hard-size with sizing run
966 4 : if (CapSizingMethod == CoolingDesignCapacity || CapSizingMethod == CapacityPerFloorArea ||
967 : CapSizingMethod == FractionOfAutosizedCoolingCapacity) {
968 4 : if (CapSizingMethod == CoolingDesignCapacity) {
969 2 : if (state.dataSize->ZoneSizingRunDone) {
970 2 : CheckZoneSizing(state, CompType, CompName);
971 2 : SizingMethod = AutoCalculateSizing;
972 2 : state.dataSize->DataConstantUsedForSizing =
973 2 : state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).NonAirSysDesCoolLoad;
974 2 : state.dataSize->DataFractionUsedForSizing = 1.0;
975 : }
976 2 : if (ThisCP.ScaledCoolingCapacity == AutoSize) {
977 1 : TempSize = AutoSize;
978 : } else {
979 1 : TempSize = ThisCP.ScaledCoolingCapacity;
980 : }
981 2 : } else if (CapSizingMethod == CapacityPerFloorArea) {
982 1 : if (state.dataSize->ZoneSizingRunDone) {
983 1 : CheckZoneSizing(state, CompType, CompName);
984 1 : ZoneEqSizing(state.dataSize->CurZoneEqNum).CoolingCapacity = true;
985 1 : ZoneEqSizing(state.dataSize->CurZoneEqNum).DesCoolingLoad =
986 1 : state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).NonAirSysDesCoolLoad;
987 : }
988 1 : TempSize = ThisCP.ScaledCoolingCapacity * state.dataHeatBal->Zone(ThisCP.ZonePtr).FloorArea;
989 1 : state.dataSize->DataScalableCapSizingON = true;
990 1 : } else if (CapSizingMethod == FractionOfAutosizedCoolingCapacity) {
991 1 : CheckZoneSizing(state, CompType, CompName);
992 1 : ZoneEqSizing(state.dataSize->CurZoneEqNum).CoolingCapacity = true;
993 1 : ZoneEqSizing(state.dataSize->CurZoneEqNum).DesCoolingLoad =
994 1 : state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).NonAirSysDesCoolLoad;
995 1 : TempSize = ZoneEqSizing(state.dataSize->CurZoneEqNum).DesCoolingLoad * ThisCP.ScaledCoolingCapacity;
996 1 : state.dataSize->DataScalableCapSizingON = true;
997 :
998 : } else {
999 0 : TempSize = ThisCP.ScaledCoolingCapacity;
1000 : }
1001 8 : CoolingCapacitySizer sizerCoolingCapacity;
1002 4 : sizerCoolingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1003 4 : DesCoilLoad = sizerCoolingCapacity.size(state, TempSize, errorsFound);
1004 4 : state.dataSize->DataConstantUsedForSizing = 0.0;
1005 4 : state.dataSize->DataFractionUsedForSizing = 0.0;
1006 8 : state.dataSize->DataScalableCapSizingON = false;
1007 : } else {
1008 0 : DesCoilLoad = 0.0;
1009 : }
1010 : }
1011 : // finally cooling capacity is saved in this variable
1012 4 : ThisCP.ScaledCoolingCapacity = DesCoilLoad;
1013 : }
1014 :
1015 4 : IsAutoSize = false;
1016 4 : if (ThisCP.WaterVolFlowRateMax == AutoSize) {
1017 1 : IsAutoSize = true;
1018 : }
1019 4 : if (state.dataSize->CurZoneEqNum > 0) {
1020 4 : if (!IsAutoSize && !state.dataSize->ZoneSizingRunDone) { // simulation continue
1021 0 : if (ThisCP.WaterVolFlowRateMax > 0.0) {
1022 0 : BaseSizer::reportSizerOutput(
1023 0 : state, CompType, ThisCP.EquipID, "User-Specified Maximum Cold Water Flow [m3/s]", ThisCP.WaterVolFlowRateMax);
1024 : }
1025 : } else { // Autosize or hard-size with sizing run
1026 4 : if (ThisCP.WaterInletNode > 0 && ThisCP.WaterOutletNode > 0) {
1027 4 : PltSizCoolNum = MyPlantSizingIndex(state, CompType, ThisCP.EquipID, ThisCP.WaterInletNode, ThisCP.WaterOutletNode, ErrorsFound);
1028 4 : if (PltSizCoolNum > 0) {
1029 4 : if (DesCoilLoad >= SmallLoad) {
1030 8 : rho = GetDensityGlycol(state,
1031 4 : state.dataPlnt->PlantLoop(ThisCP.plantLoc.loopNum).FluidName,
1032 : 5.,
1033 4 : state.dataPlnt->PlantLoop(ThisCP.plantLoc.loopNum).FluidIndex,
1034 : RoutineName);
1035 8 : Cp = GetSpecificHeatGlycol(state,
1036 4 : state.dataPlnt->PlantLoop(ThisCP.plantLoc.loopNum).FluidName,
1037 : 5.0,
1038 4 : state.dataPlnt->PlantLoop(ThisCP.plantLoc.loopNum).FluidIndex,
1039 : RoutineName);
1040 4 : WaterVolFlowMaxCoolDes = DesCoilLoad / (state.dataSize->PlantSizData(PltSizCoolNum).DeltaT * Cp * rho);
1041 : } else {
1042 0 : WaterVolFlowMaxCoolDes = 0.0;
1043 : }
1044 : } else {
1045 0 : ShowSevereError(state, "Autosizing of water flow requires a cooling loop Sizing:Plant object");
1046 0 : ShowContinueError(state, "Occurs in ZoneHVAC:CoolingPanel:RadiantConvective:Water Object=" + ThisCP.EquipID);
1047 0 : ErrorsFound = true;
1048 : }
1049 : }
1050 :
1051 4 : if (IsAutoSize) {
1052 1 : ThisCP.WaterVolFlowRateMax = WaterVolFlowMaxCoolDes;
1053 1 : BaseSizer::reportSizerOutput(state, CompType, ThisCP.EquipID, "Design Size Maximum Cold Water Flow [m3/s]", WaterVolFlowMaxCoolDes);
1054 : } else { // hard-size with sizing data
1055 3 : if (ThisCP.WaterVolFlowRateMax > 0.0 && WaterVolFlowMaxCoolDes > 0.0) {
1056 3 : WaterVolFlowMaxCoolUser = ThisCP.WaterVolFlowRateMax;
1057 6 : BaseSizer::reportSizerOutput(state,
1058 : CompType,
1059 : ThisCP.EquipID,
1060 : "Design Size Maximum Cold Water Flow [m3/s]",
1061 : WaterVolFlowMaxCoolDes,
1062 : "User-Specified Maximum Cold Water Flow [m3/s]",
1063 3 : WaterVolFlowMaxCoolUser);
1064 3 : if (state.dataGlobal->DisplayExtraWarnings) {
1065 0 : if ((std::abs(WaterVolFlowMaxCoolDes - WaterVolFlowMaxCoolUser) / WaterVolFlowMaxCoolUser) >
1066 0 : state.dataSize->AutoVsHardSizingThreshold) {
1067 0 : ShowMessage(
1068 : state,
1069 0 : "SizeCoolingPanel: Potential issue with equipment sizing for ZoneHVAC:CoolingPanel:RadiantConvective:Water = \"" +
1070 0 : ThisCP.EquipID + "\".");
1071 0 : ShowContinueError(state, format("User-Specified Maximum Cool Water Flow of {:.5R} [m3/s]", WaterVolFlowMaxCoolUser));
1072 0 : ShowContinueError(state,
1073 0 : format("differs from Design Size Maximum Cool Water Flow of {:.5R} [m3/s]", WaterVolFlowMaxCoolDes));
1074 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
1075 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
1076 : }
1077 : }
1078 : }
1079 : }
1080 : }
1081 : }
1082 :
1083 4 : RegisterPlantCompDesignFlow(state, ThisCP.WaterInletNode, ThisCP.WaterVolFlowRateMax);
1084 :
1085 : bool SizeCoolingPanelUASuccess;
1086 4 : SizeCoolingPanelUASuccess = ThisCP.SizeCoolingPanelUA(state);
1087 4 : if (!SizeCoolingPanelUASuccess) ShowFatalError(state, "SizeCoolingPanelUA: Program terminated for previous conditions.");
1088 4 : }
1089 :
1090 4 : bool CoolingPanelParams::SizeCoolingPanelUA(EnergyPlusData &state)
1091 : {
1092 :
1093 : // SUBROUTINE INFORMATION:
1094 : // AUTHOR Rick Strand
1095 : // DATE WRITTEN June 2017
1096 :
1097 : // PURPOSE OF THIS SUBROUTINE:
1098 : // This subroutine sizes UA value for the simple chilled ceiling panel.
1099 :
1100 : // Return value
1101 : bool SizeCoolingPanelUA;
1102 :
1103 : // These initializations are mainly the calculation of the UA value for the heat exchanger formulation of the simple cooling panel
1104 : Real64 Cp;
1105 : Real64 MDot;
1106 : Real64 MDotXCp;
1107 : Real64 Qrated;
1108 : Real64 Tinletr;
1109 : Real64 Tzoner;
1110 : Real64 RatCapToTheoMax; // Ratio of unit capacity to theoretical maximum output based on rated parameters
1111 :
1112 4 : SizeCoolingPanelUA = true;
1113 4 : Cp = 4120.0; // Just an approximation, don't need to get an exact number
1114 4 : MDot = this->RatedWaterFlowRate;
1115 4 : MDotXCp = Cp * MDot;
1116 4 : Qrated = this->ScaledCoolingCapacity;
1117 4 : Tinletr = this->RatedWaterTemp;
1118 4 : Tzoner = this->RatedZoneAirTemp;
1119 4 : if (std::abs(Tinletr - Tzoner) < 0.5) {
1120 0 : RatCapToTheoMax = std::abs(Qrated) / (MDotXCp * 0.5); // Avoid a divide by zero error
1121 : } else {
1122 4 : RatCapToTheoMax = std::abs(Qrated) / (MDotXCp * std::abs(Tinletr - Tzoner));
1123 : }
1124 4 : if ((RatCapToTheoMax < 1.1) && (RatCapToTheoMax > 0.9999)) {
1125 : // close to unity with some graciousness given in case the approximation of Cp causes a problem
1126 0 : RatCapToTheoMax = 0.9999;
1127 4 : } else if (RatCapToTheoMax >= 1.1) {
1128 0 : ShowSevereError(state,
1129 0 : "SizeCoolingPanelUA: Unit=[" + cCMO_CoolingPanel_Simple + ',' + this->EquipID +
1130 : "] has a cooling capacity that is greater than the maximum possible value.");
1131 0 : ShowContinueError(state, "The result of this is that a UA value is impossible to calculate.");
1132 0 : ShowContinueError(state, "Check the rated input for temperatures, flow, and capacity for this unit.");
1133 0 : ShowContinueError(state, "The ratio of the capacity to the rated theoretical maximum must be less than unity.");
1134 0 : ShowContinueError(state,
1135 : "The most likely cause for this is probably either the capacity (whether autosized or hardwired) being too high, the "
1136 : "rated flow being too low, rated temperatures being too close to each other, or all of those reasons.");
1137 0 : ShowContinueError(state,
1138 : "Compare the rated capacity in your input to the product of the rated mass flow rate, Cp of water, and the difference "
1139 : "between the rated temperatures.");
1140 0 : ShowContinueError(
1141 : state, "If the rated capacity is higher than this product, then the cooling panel would violate the Second Law of Thermodynamics.");
1142 0 : SizeCoolingPanelUA = false;
1143 0 : this->UA = 1.0;
1144 : }
1145 4 : if (Tinletr >= Tzoner) {
1146 0 : ShowSevereError(state,
1147 0 : "SizeCoolingPanelUA: Unit=[" + cCMO_CoolingPanel_Simple + ',' + this->EquipID +
1148 : "] has a rated water temperature that is higher than the rated zone temperature.");
1149 0 : ShowContinueError(state,
1150 : "Such a situation would not lead to cooling and thus the rated water or zone temperature or both should be adjusted.");
1151 0 : SizeCoolingPanelUA = false;
1152 0 : this->UA = 1.0;
1153 : } else {
1154 4 : this->UA = -MDotXCp * log(1.0 - RatCapToTheoMax);
1155 4 : if (this->UA <= 0.0) {
1156 0 : ShowSevereError(state,
1157 0 : "SizeCoolingPanelUA: Unit=[" + cCMO_CoolingPanel_Simple + ',' + this->EquipID +
1158 : "] has a zero or negative calculated UA value.");
1159 0 : ShowContinueError(state,
1160 : "This is not allowed. Please check the rated input parameters for this device to ensure that the values are correct.");
1161 0 : SizeCoolingPanelUA = false;
1162 : }
1163 : }
1164 :
1165 4 : return SizeCoolingPanelUA;
1166 : }
1167 :
1168 22551 : void CoolingPanelParams::CalcCoolingPanel(EnergyPlusData &state, int const CoolingPanelNum)
1169 : {
1170 : // SUBROUTINE INFORMATION:
1171 : // AUTHOR Rick Strand
1172 : // DATE WRITTEN Sept 2014
1173 :
1174 : // PURPOSE OF THIS SUBROUTINE:
1175 : // This subroutine calculates both the convective and radiant heat transfer rate
1176 : // for the simple cooling panel. The process used here was derived from the hot
1177 : // water baseboard radiant/convective heater and adapted for cooling.
1178 :
1179 : // REFERENCES:
1180 : // Existing code for hot water baseboard models (radiant-convective variety)
1181 : // Incropera and DeWitt, Fundamentals of Heat and Mass Transfer
1182 :
1183 : // Using/Aliasing
1184 : using DataHVACGlobals::SmallLoad;
1185 : using FluidProperties::GetSpecificHeatGlycol;
1186 :
1187 : using PlantUtilities::SetComponentFlowRate;
1188 : using Psychrometrics::PsyTdpFnWPb;
1189 : using ScheduleManager::GetCurrentScheduleValue;
1190 :
1191 : // SUBROUTINE PARAMETER DEFINITIONS:
1192 22551 : Real64 constexpr MinFrac(0.0005); // Minimum fraction that delivers radiant heats to surfaces
1193 22551 : int constexpr Maxiter(20); // Maximum number of iterations to achieve tolerance
1194 22551 : Real64 constexpr IterTol(0.005); // Tolerance of 0.5%
1195 : static constexpr std::string_view RoutineName("CalcCoolingPanel");
1196 :
1197 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1198 : int ZoneNum;
1199 : int iter;
1200 : Real64 RadHeat;
1201 : Real64 CoolingPanelCool;
1202 : Real64 waterInletTemp;
1203 : Real64 waterOutletTemp;
1204 : Real64 waterMassFlowRate;
1205 : Real64 waterMassFlowRateMax;
1206 : Real64 CapacitanceWater;
1207 : Real64 NTU;
1208 : Real64 Effectiveness;
1209 : Real64 QZnReq;
1210 : Real64 Cp;
1211 : Real64 Tzone;
1212 : Real64 Xr;
1213 : Real64 MCpEpsAct;
1214 : Real64 MCpEpsLow;
1215 : Real64 MCpEpsHigh;
1216 : Real64 MdotLow;
1217 : Real64 MdotHigh;
1218 : Real64 FracGuess;
1219 : Real64 MdotGuess;
1220 : Real64 MCpEpsGuess;
1221 : Real64 ControlTemp;
1222 : Real64 SetPointTemp;
1223 : Real64 OffTempCool;
1224 : Real64 FullOnTempCool;
1225 : Real64 MassFlowFrac;
1226 : Real64 DewPointTemp;
1227 : Real64 LoadMet;
1228 : bool CoolingPanelOn;
1229 : bool ModifiedWaterInletTemp;
1230 :
1231 22551 : ModifiedWaterInletTemp = false;
1232 22551 : ZoneNum = this->ZonePtr;
1233 22551 : QZnReq = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).RemainingOutputReqToCoolSP;
1234 22551 : waterInletTemp = this->WaterInletTemp;
1235 22551 : waterOutletTemp = waterInletTemp;
1236 22551 : waterMassFlowRateMax = this->WaterMassFlowRateMax;
1237 22551 : Xr = this->FracRadiant;
1238 :
1239 22551 : if (GetCurrentScheduleValue(state, this->SchedPtr) > 0) {
1240 22551 : CoolingPanelOn = true;
1241 : } else {
1242 0 : CoolingPanelOn = false;
1243 : }
1244 : // Calculate the "zone" temperature for determining the output of the cooling panel
1245 22551 : Tzone = Xr * state.dataHeatBal->ZoneMRT(ZoneNum) + ((1.0 - Xr) * state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum).MAT);
1246 :
1247 : // Logical controls: if the WaterInletTemperature is higher than Tzone, do not run the panel
1248 22551 : if (waterInletTemp >= Tzone) CoolingPanelOn = false;
1249 :
1250 : // Condensation Controls based on dewpoint temperature of the zone.
1251 : // The assumption here is that condensation might take place if the inlet water temperature
1252 : // is below the dewpoint temperature of the space. This assumption is made because we are
1253 : // probably dealing with a metal panel and the surface temperature of the panel will be very
1254 : // close to the inlet water temperature in certain places. Thus, if the water inlet temperature
1255 : // is below the dewpoint temperature, then we might have condensation. We need to deal with this
1256 : // possibility based on the user selected method. The good news here is that we don't have to
1257 : // iterate like in the low temperature radiant systems because the inlet water condition is known
1258 : // not calculated. So, we can deal with this upfront rather than after calculation and then more
1259 : // iteration.
1260 22551 : DewPointTemp = PsyTdpFnWPb(state, state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum).ZoneAirHumRat, state.dataEnvrn->OutBaroPress);
1261 :
1262 22551 : if (waterInletTemp < (DewPointTemp + this->CondDewPtDeltaT) && (CoolingPanelOn)) {
1263 :
1264 : // Condensation is possible so invoke the three possible ways of handling this based on the user's choice...
1265 :
1266 11518 : if (this->CondCtrlType == CondCtrl::NONE) {
1267 : // Condensation control is "off" which means don't do anything, simply let it run and ignore condensation
1268 3386 : } else if (this->CondCtrlType == CondCtrl::SIMPLEOFF) {
1269 : // For "simple off", simply turn the simple cooling panel off to avoid condensation
1270 0 : waterMassFlowRate = 0.0;
1271 0 : CoolingPanelOn = false;
1272 : // Produce a warning message so that user knows the system was shut-off due to potential for condensation
1273 0 : if (!state.dataGlobal->WarmupFlag) {
1274 0 : if (this->CondErrIndex == 0) { // allow errors up to number of radiant systems
1275 0 : ShowWarningMessage(state,
1276 0 : cCMO_CoolingPanel_Simple + " [" + this->EquipID +
1277 : "] inlet water temperature below dew-point temperature--potential for condensation exists");
1278 0 : ShowContinueError(state, "Flow to the simple cooling panel will be shut-off to avoid condensation");
1279 0 : ShowContinueError(state, format("Water inlet temperature = {:.2R}", waterInletTemp));
1280 0 : ShowContinueError(state, format("Zone dew-point temperature + safety delta T= {:.2R}", DewPointTemp + this->CondDewPtDeltaT));
1281 0 : ShowContinueErrorTimeStamp(state, "");
1282 0 : ShowContinueError(state,
1283 0 : format("Note that a {:.4R} C safety was chosen in the input for the shut-off criteria", this->CondDewPtDeltaT));
1284 : }
1285 0 : ShowRecurringWarningErrorAtEnd(state,
1286 0 : cCMO_CoolingPanel_Simple + " [" + this->EquipID + "] condensation shut-off occurrence continues.",
1287 : this->CondErrIndex,
1288 : DewPointTemp,
1289 : DewPointTemp,
1290 : _,
1291 : "C",
1292 : "C");
1293 : }
1294 :
1295 3386 : } else if (this->CondCtrlType == CondCtrl::VARIEDOFF) {
1296 : // Varied off is the most complex because it tries to run by reducing the inlet temperature
1297 : // As a result of this, there is some bypass/recirculation that has to take place.
1298 : // We might not have enough flow rate to meet whatever load we have, but at least
1299 : // the system is still running at some partial load and avoiding condensation.
1300 3386 : waterInletTemp = DewPointTemp + this->CondDewPtDeltaT;
1301 3386 : ModifiedWaterInletTemp = true;
1302 : }
1303 : }
1304 :
1305 : // The next IF block is to find the mass flow rate based on what type of control the user has requested. Load based controls
1306 : // vary the flow to meet the zone load calculated by the user-defined thermostat. Temperature based controls vary the flow
1307 : // based on a comparison between the control temperature and the setpoint schedule and throttling range.
1308 :
1309 22551 : if ((this->controlType == ClgPanelCtrlType::ZoneTotalLoad) || (this->controlType == ClgPanelCtrlType::ZoneConvectiveLoad)) {
1310 :
1311 10646 : if (QZnReq < -SmallLoad && !state.dataZoneEnergyDemand->CurDeadBandOrSetback(ZoneNum) && (CoolingPanelOn)) {
1312 :
1313 2176 : Cp = GetSpecificHeatGlycol(state,
1314 1088 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
1315 : waterInletTemp,
1316 1088 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
1317 : RoutineName);
1318 :
1319 : // Find the actual load: this parameter modifies what the response of the system should be. For total load control, the system tries
1320 : // to meet the QZnReq. For convective load control, the convective output of the device equals QZnReq which means that the load on
1321 : // the panel is higher as is its output. Total load control will miss the setpoint temperature but will likely get there with time.
1322 : // Convective load control will hit the setpoint short term better but will result in overcooling in the long run probably.
1323 1088 : if (this->controlType == ClgPanelCtrlType::ZoneConvectiveLoad) {
1324 0 : QZnReq = QZnReq / this->FracConvect;
1325 : }
1326 :
1327 : // Now for a small amount of iteration. Try to find the value of mass flow rate that will come the closest to giving
1328 : // the proper value for MCpEpsAct. Limit iterations to avoid too much time wasting.
1329 1088 : MCpEpsAct = QZnReq / (waterInletTemp - Tzone);
1330 1088 : MCpEpsLow = 0.0;
1331 1088 : MdotLow = 0.0;
1332 1088 : MCpEpsHigh = waterMassFlowRateMax * Cp * (1.0 - exp(-this->UA / (waterMassFlowRateMax * Cp)));
1333 1088 : MdotHigh = waterMassFlowRateMax;
1334 1088 : if (MCpEpsAct <= MCpEpsLow) {
1335 0 : MCpEpsAct = MCpEpsLow;
1336 0 : waterMassFlowRate = 0.0;
1337 0 : state.dataLoopNodes->Node(this->WaterInletNode).MassFlowRate = 0.0;
1338 0 : CoolingPanelOn = false;
1339 1088 : } else if (MCpEpsAct >= MCpEpsHigh) {
1340 540 : MCpEpsAct = MCpEpsHigh;
1341 540 : waterMassFlowRate = waterMassFlowRateMax;
1342 540 : state.dataLoopNodes->Node(this->WaterInletNode).MassFlowRate = waterMassFlowRateMax;
1343 : } else {
1344 548 : for (iter = 1; iter <= Maxiter; ++iter) {
1345 548 : FracGuess = (MCpEpsAct - MCpEpsLow) / (MCpEpsHigh - MCpEpsLow);
1346 548 : MdotGuess = MdotHigh * FracGuess;
1347 548 : MCpEpsGuess = MdotGuess * Cp * (1.0 - exp(-this->UA / (MdotGuess * Cp)));
1348 548 : if (MCpEpsGuess <= MCpEpsAct) {
1349 0 : MCpEpsLow = MCpEpsGuess;
1350 0 : MdotLow = MdotGuess;
1351 : } else { // MCpEpsGuess > MCpEpsAct
1352 548 : MCpEpsHigh = MCpEpsGuess;
1353 548 : MdotHigh = MdotGuess;
1354 : }
1355 548 : if (((MCpEpsAct - MCpEpsGuess) / MCpEpsAct) <= IterTol) {
1356 548 : waterMassFlowRate = MdotGuess;
1357 548 : state.dataLoopNodes->Node(this->WaterInletNode).MassFlowRate = waterMassFlowRate;
1358 548 : break;
1359 : }
1360 : }
1361 : }
1362 :
1363 : } else {
1364 4235 : CoolingPanelOn = false;
1365 : }
1366 :
1367 : } else { // temperature control rather than zone load control
1368 :
1369 17228 : if (CoolingPanelOn) {
1370 :
1371 17228 : ControlTemp = this->getCoolingPanelControlTemp(state, ZoneNum);
1372 :
1373 17228 : SetPointTemp = GetCurrentScheduleValue(state, this->ColdSetptSchedPtr);
1374 17228 : OffTempCool = SetPointTemp - 0.5 * this->ColdThrottlRange;
1375 17228 : FullOnTempCool = SetPointTemp + 0.5 * this->ColdThrottlRange;
1376 :
1377 17228 : if (ControlTemp <= OffTempCool) {
1378 13431 : MassFlowFrac = 0.0;
1379 13431 : CoolingPanelOn = false;
1380 3797 : } else if (ControlTemp >= FullOnTempCool) {
1381 0 : MassFlowFrac = 1.0;
1382 : } else {
1383 3797 : MassFlowFrac = (ControlTemp - OffTempCool) / this->ColdThrottlRange;
1384 3797 : if (MassFlowFrac < MinFrac) MassFlowFrac = MinFrac;
1385 : }
1386 :
1387 17228 : waterMassFlowRate = MassFlowFrac * waterMassFlowRateMax;
1388 : }
1389 : }
1390 :
1391 22551 : if (CoolingPanelOn) {
1392 4885 : SetComponentFlowRate(state, waterMassFlowRate, this->WaterInletNode, this->WaterOutletNode, this->plantLoc);
1393 4885 : if (waterMassFlowRate <= 0.0) CoolingPanelOn = false;
1394 : }
1395 :
1396 22551 : if (CoolingPanelOn) {
1397 : // Now simulate the system...
1398 9764 : Cp = GetSpecificHeatGlycol(state,
1399 4882 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
1400 : waterInletTemp,
1401 4882 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
1402 : RoutineName);
1403 4882 : Effectiveness = 1.0 - exp(-this->UA / (waterMassFlowRate * Cp));
1404 4882 : if (Effectiveness <= 0.0) {
1405 0 : Effectiveness = 0.0;
1406 4882 : } else if (Effectiveness >= 1.0) {
1407 30 : Effectiveness = 1.0;
1408 : }
1409 4882 : CoolingPanelCool = (Effectiveness)*waterMassFlowRate * Cp * (waterInletTemp - Tzone);
1410 4882 : waterOutletTemp = this->WaterInletTemp - (CoolingPanelCool / (waterMassFlowRate * Cp));
1411 4882 : RadHeat = CoolingPanelCool * this->FracRadiant;
1412 4882 : state.dataChilledCeilingPanelSimple->CoolingPanel(CoolingPanelNum).CoolingPanelSource = RadHeat;
1413 :
1414 4882 : if (this->FracRadiant <= MinFrac) {
1415 0 : LoadMet = CoolingPanelCool;
1416 : } else {
1417 :
1418 : // Now, distribute the radiant energy of all systems to the appropriate surfaces, to people, and the air
1419 4882 : DistributeCoolingPanelRadGains(state);
1420 : // Now "simulate" the system by recalculating the heat balances
1421 4882 : HeatBalanceSurfaceManager::CalcHeatBalanceOutsideSurf(state, ZoneNum);
1422 :
1423 4882 : HeatBalanceSurfaceManager::CalcHeatBalanceInsideSurf(state, ZoneNum);
1424 :
1425 : // Here an assumption is made regarding radiant heat transfer to people.
1426 : // While the radiant heat transfer to people array will be used by the thermal comfort
1427 : // routines, the energy transfer to people would get lost from the perspective
1428 : // of the heat balance. So, to avoid this net loss of energy which clearly
1429 : // gets added to the zones, we must account for it somehow. This assumption
1430 : // that all energy radiated to people is converted to convective energy is
1431 : // not very precise, but at least it conserves energy. The system impact to heat balance
1432 : // should include this.
1433 14646 : LoadMet = (state.dataHeatBal->Zone(ZoneNum).sumHATsurf(state) - state.dataHeatBal->Zone(ZoneNum).ZeroSourceSumHATsurf) +
1434 9764 : (CoolingPanelCool * this->FracConvect) + (RadHeat * this->FracDistribPerson);
1435 : }
1436 4882 : this->WaterOutletEnthalpy = this->WaterInletEnthalpy - CoolingPanelCool / waterMassFlowRate;
1437 :
1438 : } else { // cooling panel off
1439 17669 : CapacitanceWater = 0.0;
1440 17669 : NTU = 0.0;
1441 17669 : Effectiveness = 0.0;
1442 17669 : waterOutletTemp = waterInletTemp;
1443 17669 : CoolingPanelCool = 0.0;
1444 17669 : LoadMet = 0.0;
1445 17669 : RadHeat = 0.0;
1446 17669 : waterMassFlowRate = 0.0;
1447 17669 : this->CoolingPanelSource = 0.0;
1448 17669 : this->WaterOutletEnthalpy = this->WaterInletEnthalpy;
1449 : }
1450 :
1451 22551 : this->WaterOutletTemp = waterOutletTemp;
1452 22551 : this->WaterMassFlowRate = waterMassFlowRate;
1453 22551 : this->TotPower = LoadMet;
1454 22551 : this->Power = CoolingPanelCool;
1455 22551 : this->ConvPower = CoolingPanelCool - RadHeat;
1456 22551 : this->RadPower = RadHeat;
1457 22551 : }
1458 :
1459 17228 : Real64 CoolingPanelParams::getCoolingPanelControlTemp(EnergyPlusData &state, int const ZoneNum) const
1460 : {
1461 :
1462 : // SUBROUTINE INFORMATION:
1463 : // AUTHOR Rick Strand
1464 : // DATE WRITTEN July 2016
1465 :
1466 : // METHODOLOGY EMPLOYED:
1467 : // This subroutine sets the control temperature for the simple cooling panel.
1468 :
1469 : // Using/Aliasing
1470 :
1471 17228 : switch (this->controlType) {
1472 17228 : case ClgPanelCtrlType::MAT: {
1473 17228 : return state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum).MAT;
1474 : } break;
1475 0 : case ClgPanelCtrlType::MRT: {
1476 0 : return state.dataHeatBal->ZoneMRT(ZoneNum);
1477 : } break;
1478 0 : case ClgPanelCtrlType::Operative: {
1479 0 : return 0.5 * (state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum).MAT + state.dataHeatBal->ZoneMRT(ZoneNum));
1480 : } break;
1481 0 : case ClgPanelCtrlType::ODB: {
1482 0 : return state.dataHeatBal->Zone(ZoneNum).OutDryBulbTemp;
1483 : } break;
1484 0 : case ClgPanelCtrlType::OWB: {
1485 0 : return state.dataHeatBal->Zone(ZoneNum).OutWetBulbTemp;
1486 : } break;
1487 0 : default: { // Should never get here
1488 0 : assert(false);
1489 : return -99990; // Compiler wants a return value for every path, so give an invalid value
1490 : } break;
1491 : }
1492 : }
1493 :
1494 22551 : void UpdateCoolingPanel(EnergyPlusData &state, int const CoolingPanelNum)
1495 : {
1496 :
1497 : // SUBROUTINE INFORMATION:
1498 : // AUTHOR Rick Strand
1499 : // DATE WRITTEN Sept 2014
1500 : // February 2001
1501 : // MODIFIED Aug 2007 Daeho Kang (Add the update of radiant source)
1502 :
1503 : // REFERENCES:
1504 : // Existing code for hot water baseboard models (radiant-convective variety)
1505 :
1506 : // Using/Aliasing
1507 22551 : auto &SysTimeElapsed = state.dataHVACGlobal->SysTimeElapsed;
1508 22551 : auto &TimeStepSys = state.dataHVACGlobal->TimeStepSys;
1509 22551 : auto &ThisCP(state.dataChilledCeilingPanelSimple->CoolingPanel(CoolingPanelNum));
1510 :
1511 : // First, update the running average if necessary...
1512 22551 : if (ThisCP.LastSysTimeElapsed == SysTimeElapsed) {
1513 21313 : ThisCP.CoolingPanelSrcAvg -= ThisCP.LastCoolingPanelSrc * ThisCP.LastTimeStepSys / state.dataGlobal->TimeStepZone;
1514 : }
1515 : // Update the running average and the "last" values with the current values of the appropriate variables
1516 22551 : ThisCP.CoolingPanelSrcAvg += ThisCP.CoolingPanelSource * TimeStepSys / state.dataGlobal->TimeStepZone;
1517 :
1518 22551 : ThisCP.LastCoolingPanelSrc = ThisCP.CoolingPanelSource;
1519 22551 : ThisCP.LastSysTimeElapsed = SysTimeElapsed;
1520 22551 : ThisCP.LastTimeStepSys = TimeStepSys;
1521 :
1522 22551 : int WaterInletNode = ThisCP.WaterInletNode;
1523 22551 : int WaterOutletNode = ThisCP.WaterOutletNode;
1524 :
1525 22551 : auto &ThisInNode(state.dataLoopNodes->Node(WaterInletNode));
1526 22551 : auto &ThisOutNode(state.dataLoopNodes->Node(WaterOutletNode));
1527 :
1528 : // Set the outlet water nodes for the panel
1529 22551 : PlantUtilities::SafeCopyPlantNode(state, WaterInletNode, WaterOutletNode);
1530 22551 : ThisOutNode.Temp = ThisCP.WaterOutletTemp;
1531 22551 : ThisOutNode.Enthalpy = ThisCP.WaterOutletEnthalpy;
1532 22551 : ThisInNode.MassFlowRate = ThisCP.WaterMassFlowRate;
1533 22551 : ThisOutNode.MassFlowRate = ThisCP.WaterMassFlowRate;
1534 22551 : ThisInNode.MassFlowRateMax = ThisCP.WaterMassFlowRateMax;
1535 22551 : ThisOutNode.MassFlowRateMax = ThisCP.WaterMassFlowRateMax;
1536 22551 : }
1537 :
1538 2568313 : void UpdateCoolingPanelSourceValAvg(EnergyPlusData &state,
1539 : bool &CoolingPanelSysOn) // .TRUE. if the radiant system has run this zone time step
1540 : {
1541 :
1542 : // SUBROUTINE INFORMATION:
1543 : // AUTHOR Rick Strand
1544 : // DATE WRITTEN Sept 2014
1545 :
1546 : // PURPOSE OF THIS SUBROUTINE:
1547 : // To transfer the average value of the heat source over the entire
1548 : // zone time step back to the heat balance routines so that the heat
1549 : // balance algorithms can simulate one last time with the average source
1550 : // to maintain some reasonable amount of continuity and energy balance
1551 : // in the temperature and flux histories.
1552 :
1553 : // METHODOLOGY EMPLOYED:
1554 : // All of the record keeping for the average term is done in the Update
1555 : // routine so the only other thing that this subroutine does is check to
1556 : // see if the system was even on. If any average term is non-zero, then
1557 : // one or more of the radiant systems was running.
1558 :
1559 : // REFERENCES:
1560 : // Existing code for hot water baseboard models (radiant-convective variety)
1561 :
1562 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1563 : int CoolingPanelNum; // DO loop counter for surface index
1564 :
1565 2568313 : CoolingPanelSysOn = false;
1566 :
1567 : // If this was never allocated, then there are no radiant systems in this input file (just RETURN)
1568 2568313 : if (!allocated(state.dataChilledCeilingPanelSimple->CoolingPanel)) return;
1569 :
1570 : // If it was allocated, then we have to check to see if this was running at all...
1571 14502 : for (CoolingPanelNum = 1; CoolingPanelNum <= (int)state.dataChilledCeilingPanelSimple->CoolingPanel.size(); ++CoolingPanelNum) {
1572 8112 : if (state.dataChilledCeilingPanelSimple->CoolingPanel(CoolingPanelNum).CoolingPanelSrcAvg != 0.0) {
1573 1722 : CoolingPanelSysOn = true;
1574 1722 : break; // DO loop
1575 : }
1576 : }
1577 :
1578 16224 : for (auto &cp : state.dataChilledCeilingPanelSimple->CoolingPanel) {
1579 8112 : cp.CoolingPanelSource = cp.CoolingPanelSrcAvg;
1580 : }
1581 :
1582 8112 : DistributeCoolingPanelRadGains(state); // CoolingPanelRadSource has been modified so we need to redistribute gains
1583 : }
1584 :
1585 12994 : void DistributeCoolingPanelRadGains(EnergyPlusData &state)
1586 : {
1587 :
1588 : // SUBROUTINE INFORMATION:
1589 : // AUTHOR Rick Strand
1590 : // DATE WRITTEN Sept 2014
1591 :
1592 : // PURPOSE OF THIS SUBROUTINE:
1593 : // To distribute the gains from the hot water basebaord heater
1594 : // as specified in the user input file. This includes distribution
1595 : // of long wavelength radiant gains to surfaces and "people."
1596 :
1597 : // METHODOLOGY EMPLOYED:
1598 : // We must cycle through all of the radiant systems because each
1599 : // surface could feel the effect of more than one radiant system.
1600 : // Note that the energy radiated to people is assumed to affect them
1601 : // but them it is assumed to be convected to the air.
1602 :
1603 : // REFERENCES:
1604 : // Existing code for hot water baseboard models (radiant-convective variety)
1605 :
1606 : // Using/Aliasing
1607 : using DataHeatBalFanSys::MaxRadHeatFlux;
1608 :
1609 : // SUBROUTINE PARAMETER DEFINITIONS:
1610 12994 : Real64 constexpr SmallestArea(0.001); // Smallest area in meters squared (to avoid a divide by zero)
1611 :
1612 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1613 : int RadSurfNum; // Counter for surfaces receiving radiation from radiant heater
1614 : int CoolingPanelNum; // Counter for the baseboard
1615 : int SurfNum; // Pointer to the Surface derived type
1616 : int ZoneNum; // Pointer to the Zone derived type
1617 : Real64 ThisSurfIntensity; // temporary for W/m2 term for rad on a surface
1618 :
1619 : // Initialize arrays
1620 12994 : state.dataHeatBalFanSys->SurfQCoolingPanel = 0.0;
1621 12994 : state.dataHeatBalFanSys->ZoneQCoolingPanelToPerson = 0.0;
1622 :
1623 25988 : for (CoolingPanelNum = 1; CoolingPanelNum <= (int)state.dataChilledCeilingPanelSimple->CoolingPanel.size(); ++CoolingPanelNum) {
1624 :
1625 12994 : auto &ThisCP(state.dataChilledCeilingPanelSimple->CoolingPanel(CoolingPanelNum));
1626 :
1627 12994 : ZoneNum = ThisCP.ZonePtr;
1628 12994 : if (ZoneNum <= 0) continue;
1629 12994 : state.dataHeatBalFanSys->ZoneQCoolingPanelToPerson(ZoneNum) += ThisCP.CoolingPanelSource * ThisCP.FracDistribPerson;
1630 :
1631 51976 : for (RadSurfNum = 1; RadSurfNum <= ThisCP.TotSurfToDistrib; ++RadSurfNum) {
1632 38982 : SurfNum = ThisCP.SurfacePtr(RadSurfNum);
1633 38982 : auto &ThisSurf(state.dataSurface->Surface(SurfNum));
1634 38982 : if (ThisSurf.Area > SmallestArea) {
1635 38982 : ThisSurfIntensity = (ThisCP.CoolingPanelSource * ThisCP.FracDistribToSurf(RadSurfNum) / ThisSurf.Area);
1636 38982 : state.dataHeatBalFanSys->SurfQCoolingPanel(SurfNum) += ThisSurfIntensity;
1637 38982 : state.dataHeatBalSurf->AnyRadiantSystems = true;
1638 : // CR 8074, trap for excessive intensity (throws off surface balance )
1639 38982 : if (ThisSurfIntensity > MaxRadHeatFlux) {
1640 0 : ShowSevereError(state, "DistributeCoolingPanelRadGains: excessive thermal radiation heat flux intensity detected");
1641 0 : ShowContinueError(state, "Surface = " + ThisSurf.Name);
1642 0 : ShowContinueError(state, format("Surface area = {:.3R} [m2]", ThisSurf.Area));
1643 0 : ShowContinueError(state, "Occurs in " + cCMO_CoolingPanel_Simple + " = " + ThisCP.EquipID);
1644 0 : ShowContinueError(state, format("Radiation intensity = {:.2R} [W/m2]", ThisSurfIntensity));
1645 0 : ShowContinueError(state, "Assign a larger surface area or more surfaces in " + cCMO_CoolingPanel_Simple);
1646 0 : ShowFatalError(state, "DistributeCoolingPanelRadGains: excessive thermal radiation heat flux intensity detected");
1647 : }
1648 : } else {
1649 0 : ShowSevereError(state, "DistributeCoolingPanelRadGains: surface not large enough to receive thermal radiation heat flux");
1650 0 : ShowContinueError(state, "Surface = " + ThisSurf.Name);
1651 0 : ShowContinueError(state, format("Surface area = {:.3R} [m2]", ThisSurf.Area));
1652 0 : ShowContinueError(state, "Occurs in " + cCMO_CoolingPanel_Simple + " = " + ThisCP.EquipID);
1653 0 : ShowContinueError(state, "Assign a larger surface area or more surfaces in " + cCMO_CoolingPanel_Simple);
1654 0 : ShowFatalError(state, "DistributeCoolingPanelRadGains: surface not large enough to receive thermal radiation heat flux");
1655 : }
1656 : }
1657 : }
1658 12994 : }
1659 :
1660 22551 : void CoolingPanelParams::ReportCoolingPanel(EnergyPlusData &state)
1661 : {
1662 :
1663 : // SUBROUTINE INFORMATION:
1664 : // AUTHOR Rick Strand
1665 : // DATE WRITTEN Aug 2014
1666 :
1667 : // REFERENCES:
1668 : // Existing code for hot water baseboard models (radiant-convective variety)
1669 :
1670 22551 : auto &TimeStepSys = state.dataHVACGlobal->TimeStepSys;
1671 :
1672 : // All of the power numbers are negative for cooling. This is because they will have a negative
1673 : // or cooling impact on the surfaces/zones. However, the output variables are noted as cooling.
1674 : // So, their sign should be positive if actually cooling and we need to reverse the sign here.
1675 : // This should not have an impact on any of the internal variables or the heat balances because
1676 : // those use other variables.
1677 22551 : this->TotPower = -this->TotPower;
1678 22551 : this->Power = -this->Power;
1679 22551 : this->ConvPower = -this->ConvPower;
1680 22551 : this->RadPower = -this->RadPower;
1681 :
1682 22551 : this->TotEnergy = this->TotPower * TimeStepSys * DataGlobalConstants::SecInHour;
1683 22551 : this->Energy = this->Power * TimeStepSys * DataGlobalConstants::SecInHour;
1684 22551 : this->ConvEnergy = this->ConvPower * TimeStepSys * DataGlobalConstants::SecInHour;
1685 22551 : this->RadEnergy = this->RadPower * TimeStepSys * DataGlobalConstants::SecInHour;
1686 22551 : }
1687 :
1688 2313 : } // namespace EnergyPlus::CoolingPanelSimple
|