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