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