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) {
786 0 : thisCP.ZonePtr = ControlledZoneNum;
787 : }
788 :
789 : // Need to check all units to see if they are on ZoneHVAC:EquipmentList or issue warning
790 0 : if (!thisCP.ZoneEquipmentListChecked && state.dataZoneEquip->ZoneEquipInputsFilled) {
791 0 : thisCP.ZoneEquipmentListChecked = true;
792 0 : if (!DataZoneEquipment::CheckZoneEquipmentList(state, cCMO_CoolingPanel_Simple, thisCP.Name)) {
793 0 : ShowSevereError(state,
794 0 : format("InitCoolingPanel: Unit=[{},{}] is not on any ZoneHVAC:EquipmentList. It will not be simulated.",
795 : cCMO_CoolingPanel_Simple,
796 0 : thisCP.Name));
797 : }
798 : }
799 :
800 0 : if (thisCP.SetLoopIndexFlag) {
801 0 : if (allocated(state.dataPlnt->PlantLoop)) {
802 0 : bool errFlag = false;
803 0 : PlantUtilities::ScanPlantLoopsForObject(state, thisCP.Name, thisCP.EquipType, thisCP.plantLoc, errFlag, _, _, _, _, _);
804 0 : if (errFlag) {
805 0 : ShowFatalError(state, "InitCoolingPanel: Program terminated for previous conditions.");
806 : }
807 0 : thisCP.SetLoopIndexFlag = false;
808 : }
809 : }
810 :
811 0 : if (!state.dataGlobal->SysSizingCalc) {
812 0 : if (thisCP.MySizeFlagCoolPanel && !thisCP.SetLoopIndexFlag) {
813 : // for each cooling panel do the sizing once.
814 0 : SizeCoolingPanel(state, CoolingPanelNum);
815 0 : thisCP.MySizeFlagCoolPanel = false;
816 :
817 : // set design mass flow rates
818 0 : if (thisCP.WaterInletNode > 0) {
819 0 : rho = thisCP.plantLoc.loop->glycol->getDensity(state, Constant::CWInitConvTemp, RoutineName);
820 0 : thisCP.WaterMassFlowRateMax = rho * thisCP.WaterVolFlowRateMax;
821 0 : PlantUtilities::InitComponentNodes(state, 0.0, thisCP.WaterMassFlowRateMax, thisCP.WaterInletNode, thisCP.WaterOutletNode);
822 : }
823 : }
824 : }
825 :
826 : // Do the Begin Environment initializations
827 0 : if (state.dataGlobal->BeginEnvrnFlag && thisCP.MyEnvrnFlag) {
828 : // Initialize
829 :
830 0 : rho = thisCP.plantLoc.loop->glycol->getDensity(state, Constant::InitConvTemp, RoutineName);
831 :
832 0 : thisCP.WaterMassFlowRateMax = rho * thisCP.WaterVolFlowRateMax;
833 :
834 0 : PlantUtilities::InitComponentNodes(state, 0.0, thisCP.WaterMassFlowRateMax, thisCP.WaterInletNode, thisCP.WaterOutletNode);
835 :
836 0 : ThisInNode.Temp = 7.0;
837 :
838 0 : Cp = thisCP.plantLoc.loop->glycol->getSpecificHeat(state, ThisInNode.Temp, RoutineName);
839 :
840 0 : ThisInNode.Enthalpy = Cp * ThisInNode.Temp;
841 0 : ThisInNode.Quality = 0.0;
842 0 : ThisInNode.Press = 0.0;
843 0 : ThisInNode.HumRat = 0.0;
844 :
845 0 : thisCP.ZeroCPSourceSumHATsurf = 0.0;
846 0 : thisCP.CoolingPanelSource = 0.0;
847 0 : thisCP.CoolingPanelSrcAvg = 0.0;
848 0 : thisCP.LastCoolingPanelSrc = 0.0;
849 0 : thisCP.LastSysTimeElapsed = 0.0;
850 0 : thisCP.LastTimeStepSys = 0.0;
851 :
852 0 : thisCP.MyEnvrnFlag = false;
853 : }
854 :
855 0 : if (!state.dataGlobal->BeginEnvrnFlag) {
856 0 : thisCP.MyEnvrnFlag = true;
857 : }
858 :
859 0 : if (state.dataGlobal->BeginTimeStepFlag && FirstHVACIteration) {
860 0 : int ZoneNum = thisCP.ZonePtr;
861 0 : thisCP.ZeroCPSourceSumHATsurf = state.dataHeatBal->Zone(ZoneNum).sumHATsurf(state);
862 0 : thisCP.CoolingPanelSrcAvg = 0.0;
863 0 : thisCP.LastCoolingPanelSrc = 0.0;
864 0 : thisCP.LastSysTimeElapsed = 0.0;
865 0 : thisCP.LastTimeStepSys = 0.0;
866 : }
867 :
868 : // Do the every time step initializations
869 0 : thisCP.WaterMassFlowRate = ThisInNode.MassFlowRate;
870 0 : thisCP.WaterInletTemp = ThisInNode.Temp;
871 0 : thisCP.WaterInletEnthalpy = ThisInNode.Enthalpy;
872 0 : thisCP.TotPower = 0.0;
873 0 : thisCP.Power = 0.0;
874 0 : thisCP.ConvPower = 0.0;
875 0 : thisCP.RadPower = 0.0;
876 0 : thisCP.TotEnergy = 0.0;
877 0 : thisCP.Energy = 0.0;
878 0 : thisCP.ConvEnergy = 0.0;
879 0 : thisCP.RadEnergy = 0.0;
880 0 : }
881 :
882 0 : void SizeCoolingPanel(EnergyPlusData &state, int const CoolingPanelNum)
883 : {
884 : // SUBROUTINE INFORMATION:
885 : // AUTHOR Rick Strand
886 : // DATE WRITTEN Sept 2016
887 :
888 : // PURPOSE OF THIS SUBROUTINE:
889 : // This subroutine sizes the simple chilled ceiling panel. The process used here
890 : // was derived from the low temperature radiant system model and adapted for
891 : // cooling only.
892 :
893 : // SUBROUTINE PARAMETER DEFINITIONS:
894 : static constexpr std::string_view RoutineName("SizeCoolingPanel");
895 :
896 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
897 0 : bool ErrorsFound(false); // If errors detected in input
898 0 : bool IsAutoSize(false); // Indicator to autosize
899 : Real64 DesCoilLoad; // design autosized or user specified capacity
900 : Real64 TempSize; // autosized value of coil input field
901 : Real64 rho;
902 : Real64 Cp;
903 0 : Real64 WaterVolFlowMaxCoolDes(0.0); // Design chilled water flow for reporting
904 0 : Real64 WaterVolFlowMaxCoolUser(0.0); // User hard-sized chilled water flow for reporting
905 :
906 0 : DesCoilLoad = 0.0;
907 0 : state.dataSize->DataScalableCapSizingON = false;
908 :
909 0 : auto &thisCP(state.dataChilledCeilingPanelSimple->CoolingPanel(CoolingPanelNum));
910 :
911 0 : std::string_view const CompType = "ZoneHVAC:CoolingPanel:RadiantConvective:Water";
912 0 : std::string_view const CompName = thisCP.Name;
913 :
914 0 : IsAutoSize = false;
915 0 : if (thisCP.ScaledCoolingCapacity == DataSizing::AutoSize) {
916 0 : IsAutoSize = true;
917 : }
918 :
919 0 : if (state.dataSize->CurZoneEqNum > 0) {
920 :
921 0 : auto &zoneEqSizing = state.dataSize->ZoneEqSizing(state.dataSize->CurZoneEqNum);
922 0 : int SizingMethod = HVAC::CoolingCapacitySizing;
923 0 : bool PrintFlag = true; // TRUE when sizing information is reported in the eio file
924 0 : bool errorsFound = false;
925 0 : int CapSizingMethod = thisCP.CoolingCapMethod;
926 0 : zoneEqSizing.SizingMethod(SizingMethod) = CapSizingMethod;
927 :
928 0 : if (!IsAutoSize && !state.dataSize->ZoneSizingRunDone) { // simulation continue
929 0 : if (CapSizingMethod == DataSizing::CoolingDesignCapacity && thisCP.ScaledCoolingCapacity > 0.0) {
930 0 : TempSize = thisCP.ScaledCoolingCapacity;
931 0 : CoolingCapacitySizer sizerCoolingCapacity;
932 0 : sizerCoolingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
933 0 : DesCoilLoad = sizerCoolingCapacity.size(state, TempSize, errorsFound);
934 0 : } else if (CapSizingMethod == DataSizing::CapacityPerFloorArea) {
935 0 : state.dataSize->DataScalableCapSizingON = true;
936 0 : TempSize = thisCP.ScaledCoolingCapacity * state.dataHeatBal->Zone(thisCP.ZonePtr).FloorArea;
937 0 : CoolingCapacitySizer sizerCoolingCapacity;
938 0 : sizerCoolingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
939 0 : DesCoilLoad = sizerCoolingCapacity.size(state, TempSize, errorsFound);
940 0 : state.dataSize->DataScalableCapSizingON = false;
941 0 : } else if (CapSizingMethod == DataSizing::FractionOfAutosizedCoolingCapacity) {
942 0 : if (thisCP.WaterVolFlowRateMax == DataSizing::AutoSize) {
943 0 : ShowSevereError(state, format("{}: auto-sizing cannot be done for {} = {}\".", RoutineName, CompType, thisCP.Name));
944 0 : ShowContinueError(state,
945 : "The \"SimulationControl\" object must have the field \"Do Zone Sizing Calculation\" set to Yes when the "
946 : "Cooling Design Capacity Method = \"FractionOfAutosizedCoolingCapacity\".");
947 0 : ErrorsFound = true;
948 : }
949 : }
950 : } else { // Autosize or hard-size with sizing run
951 0 : if (CapSizingMethod == DataSizing::CoolingDesignCapacity || CapSizingMethod == DataSizing::CapacityPerFloorArea ||
952 : CapSizingMethod == DataSizing::FractionOfAutosizedCoolingCapacity) {
953 0 : if (CapSizingMethod == DataSizing::CoolingDesignCapacity) {
954 0 : if (state.dataSize->ZoneSizingRunDone) {
955 0 : CheckZoneSizing(state, CompType, CompName);
956 0 : state.dataSize->DataConstantUsedForSizing =
957 0 : state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).NonAirSysDesCoolLoad;
958 0 : state.dataSize->DataFractionUsedForSizing = 1.0;
959 : }
960 0 : TempSize = thisCP.ScaledCoolingCapacity;
961 0 : } else if (CapSizingMethod == DataSizing::CapacityPerFloorArea) {
962 0 : if (state.dataSize->ZoneSizingRunDone) {
963 0 : CheckZoneSizing(state, CompType, CompName);
964 0 : zoneEqSizing.CoolingCapacity = true;
965 0 : zoneEqSizing.DesCoolingLoad = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).NonAirSysDesCoolLoad;
966 : }
967 0 : TempSize = thisCP.ScaledCoolingCapacity * state.dataHeatBal->Zone(thisCP.ZonePtr).FloorArea;
968 0 : state.dataSize->DataScalableCapSizingON = true;
969 0 : } else if (CapSizingMethod == DataSizing::FractionOfAutosizedCoolingCapacity) {
970 0 : CheckZoneSizing(state, CompType, CompName);
971 0 : zoneEqSizing.CoolingCapacity = true;
972 0 : zoneEqSizing.DesCoolingLoad = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).NonAirSysDesCoolLoad;
973 0 : TempSize = zoneEqSizing.DesCoolingLoad * thisCP.ScaledCoolingCapacity;
974 0 : state.dataSize->DataScalableCapSizingON = true;
975 :
976 : } else {
977 0 : TempSize = thisCP.ScaledCoolingCapacity;
978 : }
979 0 : CoolingCapacitySizer sizerCoolingCapacity;
980 0 : sizerCoolingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
981 0 : DesCoilLoad = sizerCoolingCapacity.size(state, TempSize, errorsFound);
982 0 : state.dataSize->DataConstantUsedForSizing = 0.0;
983 0 : state.dataSize->DataFractionUsedForSizing = 0.0;
984 0 : state.dataSize->DataScalableCapSizingON = false;
985 0 : } else {
986 0 : DesCoilLoad = 0.0;
987 : }
988 : }
989 : // finally cooling capacity is saved in this variable
990 0 : thisCP.ScaledCoolingCapacity = DesCoilLoad;
991 : }
992 :
993 0 : IsAutoSize = false;
994 0 : if (thisCP.WaterVolFlowRateMax == DataSizing::AutoSize) {
995 0 : IsAutoSize = true;
996 : }
997 0 : if (state.dataSize->CurZoneEqNum > 0) {
998 0 : if (!IsAutoSize && !state.dataSize->ZoneSizingRunDone) { // simulation continue
999 0 : if (thisCP.WaterVolFlowRateMax > 0.0) {
1000 0 : BaseSizer::reportSizerOutput(
1001 : state, CompType, thisCP.Name, "User-Specified Maximum Cold Water Flow [m3/s]", thisCP.WaterVolFlowRateMax);
1002 : }
1003 : } else { // Autosize or hard-size with sizing run
1004 0 : if (thisCP.WaterInletNode > 0 && thisCP.WaterOutletNode > 0) {
1005 : int PltSizCoolNum =
1006 0 : PlantUtilities::MyPlantSizingIndex(state, CompType, thisCP.Name, thisCP.WaterInletNode, thisCP.WaterOutletNode, ErrorsFound);
1007 0 : if (PltSizCoolNum > 0) {
1008 0 : if (DesCoilLoad >= HVAC::SmallLoad) {
1009 0 : rho = thisCP.plantLoc.loop->glycol->getDensity(state, 5., RoutineName);
1010 0 : Cp = thisCP.plantLoc.loop->glycol->getSpecificHeat(state, 5.0, RoutineName);
1011 0 : WaterVolFlowMaxCoolDes = DesCoilLoad / (state.dataSize->PlantSizData(PltSizCoolNum).DeltaT * Cp * rho);
1012 : } else {
1013 0 : WaterVolFlowMaxCoolDes = 0.0;
1014 : }
1015 : } else {
1016 0 : ShowSevereError(state, "Autosizing of water flow requires a cooling loop Sizing:Plant object");
1017 0 : ShowContinueError(state, format("Occurs in ZoneHVAC:CoolingPanel:RadiantConvective:Water Object={}", thisCP.Name));
1018 : }
1019 : }
1020 :
1021 0 : if (IsAutoSize) {
1022 0 : thisCP.WaterVolFlowRateMax = WaterVolFlowMaxCoolDes;
1023 0 : BaseSizer::reportSizerOutput(state, CompType, thisCP.Name, "Design Size Maximum Cold Water Flow [m3/s]", WaterVolFlowMaxCoolDes);
1024 : } else { // hard-size with sizing data
1025 0 : if (thisCP.WaterVolFlowRateMax > 0.0 && WaterVolFlowMaxCoolDes > 0.0) {
1026 0 : WaterVolFlowMaxCoolUser = thisCP.WaterVolFlowRateMax;
1027 0 : BaseSizer::reportSizerOutput(state,
1028 : CompType,
1029 : thisCP.Name,
1030 : "Design Size Maximum Cold Water Flow [m3/s]",
1031 : WaterVolFlowMaxCoolDes,
1032 : "User-Specified Maximum Cold Water Flow [m3/s]",
1033 : WaterVolFlowMaxCoolUser);
1034 0 : if (state.dataGlobal->DisplayExtraWarnings) {
1035 0 : if ((std::abs(WaterVolFlowMaxCoolDes - WaterVolFlowMaxCoolUser) / WaterVolFlowMaxCoolUser) >
1036 0 : state.dataSize->AutoVsHardSizingThreshold) {
1037 0 : ShowMessage(state,
1038 0 : format("SizeCoolingPanel: Potential issue with equipment sizing for "
1039 : "ZoneHVAC:CoolingPanel:RadiantConvective:Water = \"{}\".",
1040 0 : thisCP.Name));
1041 0 : ShowContinueError(state, format("User-Specified Maximum Cool Water Flow of {:.5R} [m3/s]", WaterVolFlowMaxCoolUser));
1042 0 : ShowContinueError(state,
1043 0 : format("differs from Design Size Maximum Cool Water Flow of {:.5R} [m3/s]", WaterVolFlowMaxCoolDes));
1044 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
1045 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
1046 : }
1047 : }
1048 : }
1049 : }
1050 : }
1051 : }
1052 :
1053 0 : PlantUtilities::RegisterPlantCompDesignFlow(state, thisCP.WaterInletNode, thisCP.WaterVolFlowRateMax);
1054 :
1055 0 : if (!thisCP.SizeCoolingPanelUA(state)) {
1056 0 : ShowFatalError(state, "SizeCoolingPanelUA: Program terminated for previous conditions.");
1057 : }
1058 0 : }
1059 :
1060 5 : bool CoolingPanelParams::SizeCoolingPanelUA(EnergyPlusData &state)
1061 : {
1062 :
1063 : // SUBROUTINE INFORMATION:
1064 : // AUTHOR Rick Strand
1065 : // DATE WRITTEN June 2017
1066 :
1067 : // PURPOSE OF THIS SUBROUTINE:
1068 : // This subroutine sizes UA value for the simple chilled ceiling panel.
1069 :
1070 : // These initializations are mainly the calculation of the UA value for the heat exchanger formulation of the simple cooling panel
1071 : Real64 RatCapToTheoMax; // Ratio of unit capacity to theoretical maximum output based on rated parameters
1072 :
1073 5 : Real64 constexpr Cp = 4120.0; // Just an approximation, don't need to get an exact number
1074 5 : Real64 const MDot = this->RatedWaterFlowRate;
1075 5 : Real64 const MDotXCp = Cp * MDot;
1076 5 : Real64 const Qrated = this->ScaledCoolingCapacity;
1077 5 : Real64 const Tinletr = this->RatedWaterTemp;
1078 5 : Real64 const Tzoner = this->RatedZoneAirTemp;
1079 :
1080 5 : if (Tinletr >= Tzoner) {
1081 2 : ShowSevereError(state,
1082 2 : format("SizeCoolingPanelUA: Unit=[{},{}] has a rated water temperature that is higher than the rated zone temperature.",
1083 : cCMO_CoolingPanel_Simple,
1084 1 : this->Name));
1085 2 : ShowContinueError(state,
1086 : "Such a situation would not lead to cooling and thus the rated water or zone temperature or both should be adjusted.");
1087 1 : this->UA = 1.0;
1088 1 : return false;
1089 : }
1090 :
1091 4 : if ((Tzoner - Tinletr) < 0.5) {
1092 1 : RatCapToTheoMax = std::abs(Qrated) / (MDotXCp * 0.5); // Avoid a divide by zero error
1093 : } else {
1094 3 : RatCapToTheoMax = std::abs(Qrated) / (MDotXCp * std::abs(Tinletr - Tzoner));
1095 : }
1096 4 : if ((RatCapToTheoMax < 1.1) && (RatCapToTheoMax > 0.9999)) {
1097 : // close to unity with some graciousness given in case the approximation of Cp causes a problem
1098 1 : RatCapToTheoMax = 0.9999;
1099 3 : } else if (RatCapToTheoMax >= 1.1) {
1100 2 : ShowSevereError(state,
1101 2 : format("SizeCoolingPanelUA: Unit=[{},{}] has a cooling capacity that is greater than the maximum possible value.",
1102 : cCMO_CoolingPanel_Simple,
1103 1 : this->Name));
1104 2 : ShowContinueError(state, "The result of this is that a UA value is impossible to calculate.");
1105 2 : ShowContinueError(state, "Check the rated input for temperatures, flow, and capacity for this unit.");
1106 2 : ShowContinueError(state, "The ratio of the capacity to the rated theoretical maximum must be less than unity.");
1107 2 : ShowContinueError(state,
1108 : "The most likely cause for this is probably either the capacity (whether autosized or hardwired) being too high, the "
1109 : "rated flow being too low, rated temperatures being too close to each other, or all of those reasons.");
1110 2 : ShowContinueError(state,
1111 : "Compare the rated capacity in your input to the product of the rated mass flow rate, Cp of water, and the difference "
1112 : "between the rated temperatures.");
1113 2 : ShowContinueError(
1114 : state, "If the rated capacity is higher than this product, then the cooling panel would violate the Second Law of Thermodynamics.");
1115 1 : this->UA = 1.0;
1116 1 : return false;
1117 : }
1118 :
1119 3 : this->UA = -MDotXCp * log(1.0 - RatCapToTheoMax);
1120 3 : if (this->UA <= 0.0) {
1121 0 : ShowSevereError(state,
1122 0 : format("SizeCoolingPanelUA: Unit=[{},{}] has a zero or negative calculated UA value.", cCMO_CoolingPanel_Simple, this->Name));
1123 0 : ShowContinueError(state,
1124 : "This is not allowed. Please check the rated input parameters for this device to ensure that the values are correct.");
1125 0 : return false;
1126 : }
1127 :
1128 3 : return true;
1129 : }
1130 :
1131 0 : void CoolingPanelParams::CalcCoolingPanel(EnergyPlusData &state, int const CoolingPanelNum)
1132 : {
1133 : // SUBROUTINE INFORMATION:
1134 : // AUTHOR Rick Strand
1135 : // DATE WRITTEN Sept 2014
1136 :
1137 : // PURPOSE OF THIS SUBROUTINE:
1138 : // This subroutine calculates both the convective and radiant heat transfer rate
1139 : // for the simple cooling panel. The process used here was derived from the hot
1140 : // water baseboard radiant/convective heater and adapted for cooling.
1141 :
1142 : // REFERENCES:
1143 : // Existing code for hot water baseboard models (radiant-convective variety)
1144 : // Incropera and DeWitt, Fundamentals of Heat and Mass Transfer
1145 :
1146 : // SUBROUTINE PARAMETER DEFINITIONS:
1147 0 : Real64 constexpr MinFrac(0.0005); // Minimum fraction that delivers radiant heats to surfaces
1148 0 : int constexpr Maxiter(20); // Maximum number of iterations to achieve tolerance
1149 0 : Real64 constexpr IterTol(0.005); // Tolerance of 0.5%
1150 : static constexpr std::string_view RoutineName("CalcCoolingPanel");
1151 :
1152 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1153 : Real64 RadHeat;
1154 : Real64 CoolingPanelCool;
1155 : Real64 waterMassFlowRate;
1156 : Real64 CapacitanceWater;
1157 : Real64 NTU;
1158 : Real64 Effectiveness;
1159 : Real64 Cp;
1160 : Real64 MCpEpsAct;
1161 : Real64 MCpEpsLow;
1162 : Real64 MCpEpsHigh;
1163 : Real64 MdotLow;
1164 : Real64 MdotHigh;
1165 : Real64 FracGuess;
1166 : Real64 MdotGuess;
1167 : Real64 MCpEpsGuess;
1168 : Real64 ControlTemp;
1169 : Real64 SetPointTemp;
1170 : Real64 OffTempCool;
1171 : Real64 FullOnTempCool;
1172 : Real64 MassFlowFrac;
1173 : Real64 LoadMet;
1174 : bool CoolingPanelOn;
1175 : Real64 waterOutletTemp;
1176 :
1177 0 : int ZoneNum = this->ZonePtr;
1178 0 : Real64 QZnReq = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).RemainingOutputReqToCoolSP;
1179 0 : Real64 waterInletTemp = this->WaterInletTemp;
1180 0 : Real64 waterMassFlowRateMax = this->WaterMassFlowRateMax;
1181 0 : Real64 Xr = this->FracRadiant;
1182 :
1183 0 : CoolingPanelOn = this->availSched->getCurrentVal() > 0;
1184 :
1185 : // Calculate the "zone" temperature for determining the output of the cooling panel
1186 0 : auto &thisZoneHB = state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum);
1187 0 : Real64 Tzone = Xr * thisZoneHB.MRT + ((1.0 - Xr) * thisZoneHB.MAT);
1188 :
1189 : // Logical controls: if the WaterInletTemperature is higher than Tzone, do not run the panel
1190 0 : if (waterInletTemp >= Tzone) {
1191 0 : CoolingPanelOn = false;
1192 : }
1193 :
1194 : // Condensation Controls based on dewpoint temperature of the zone.
1195 : // The assumption here is that condensation might take place if the inlet water temperature
1196 : // is below the dewpoint temperature of the space. This assumption is made because we are
1197 : // probably dealing with a metal panel and the surface temperature of the panel will be very
1198 : // close to the inlet water temperature in certain places. Thus, if the water inlet temperature
1199 : // is below the dewpoint temperature, then we might have condensation. We need to deal with this
1200 : // possibility based on the user selected method. The good news here is that we don't have to
1201 : // iterate like in the low temperature radiant systems because the inlet water condition is known
1202 : // not calculated. So, we can deal with this upfront rather than after calculation and then more
1203 : // iteration.
1204 : Real64 DewPointTemp =
1205 0 : Psychrometrics::PsyTdpFnWPb(state, state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum).airHumRat, state.dataEnvrn->OutBaroPress);
1206 :
1207 0 : if (waterInletTemp < (DewPointTemp + this->CondDewPtDeltaT) && (CoolingPanelOn)) {
1208 :
1209 : // Condensation is possible so invoke the three possible ways of handling this based on the user's choice...
1210 :
1211 0 : if (this->CondCtrlType == CondCtrl::NONE) {
1212 : // Condensation control is "off" which means don't do anything, simply let it run and ignore condensation
1213 0 : } else if (this->CondCtrlType == CondCtrl::SIMPLEOFF) {
1214 : // For "simple off", simply turn the simple cooling panel off to avoid condensation
1215 0 : waterMassFlowRate = 0.0;
1216 0 : CoolingPanelOn = false;
1217 : // Produce a warning message so that user knows the system was shut-off due to potential for condensation
1218 0 : if (!state.dataGlobal->WarmupFlag) {
1219 0 : if (this->CondErrIndex == 0) { // allow errors up to number of radiant systems
1220 0 : ShowWarningMessage(state,
1221 0 : format("{} [{}] inlet water temperature below dew-point temperature--potential for condensation exists",
1222 : cCMO_CoolingPanel_Simple,
1223 0 : this->Name));
1224 0 : ShowContinueError(state, "Flow to the simple cooling panel will be shut-off to avoid condensation");
1225 0 : ShowContinueError(state, format("Water inlet temperature = {:.2R}", waterInletTemp));
1226 0 : ShowContinueError(state, format("Zone dew-point temperature + safety delta T= {:.2R}", DewPointTemp + this->CondDewPtDeltaT));
1227 0 : ShowContinueErrorTimeStamp(state, "");
1228 0 : ShowContinueError(state,
1229 0 : format("Note that a {:.4R} C safety was chosen in the input for the shut-off criteria", this->CondDewPtDeltaT));
1230 : }
1231 0 : ShowRecurringWarningErrorAtEnd(state,
1232 0 : cCMO_CoolingPanel_Simple + " [" + this->Name + "] condensation shut-off occurrence continues.",
1233 0 : this->CondErrIndex,
1234 : DewPointTemp,
1235 : DewPointTemp,
1236 : _,
1237 : "C",
1238 : "C");
1239 : }
1240 :
1241 0 : } else if (this->CondCtrlType == CondCtrl::VARIEDOFF) {
1242 : // Varied off is the most complex because it tries to run by reducing the inlet temperature
1243 : // As a result of this, there is some bypass/recirculation that has to take place.
1244 : // We might not have enough flow rate to meet whatever load we have, but at least
1245 : // the system is still running at some partial load and avoiding condensation.
1246 0 : waterInletTemp = DewPointTemp + this->CondDewPtDeltaT;
1247 : }
1248 : }
1249 :
1250 : // The next IF block is to find the mass flow rate based on what type of control the user has requested. Load based controls
1251 : // vary the flow to meet the zone load calculated by the user-defined thermostat. Temperature based controls vary the flow
1252 : // based on a comparison between the control temperature and the setpoint schedule and throttling range.
1253 :
1254 0 : if ((this->controlType == ClgPanelCtrlType::ZoneTotalLoad) || (this->controlType == ClgPanelCtrlType::ZoneConvectiveLoad)) {
1255 :
1256 0 : if (QZnReq < -HVAC::SmallLoad && !state.dataZoneEnergyDemand->CurDeadBandOrSetback(ZoneNum) && (CoolingPanelOn)) {
1257 :
1258 0 : Cp = this->plantLoc.loop->glycol->getSpecificHeat(state, waterInletTemp, RoutineName);
1259 :
1260 : // Find the actual load: this parameter modifies what the response of the system should be. For total load control, the system tries
1261 : // to meet the QZnReq. For convective load control, the convective output of the device equals QZnReq which means that the load on
1262 : // the panel is higher as is its output. Total load control will miss the setpoint temperature but will likely get there with time.
1263 : // Convective load control will hit the setpoint short term better but will result in overcooling in the long run probably.
1264 0 : if (this->controlType == ClgPanelCtrlType::ZoneConvectiveLoad) {
1265 0 : QZnReq = QZnReq / this->FracConvect;
1266 : }
1267 :
1268 : // Now for a small amount of iteration. Try to find the value of mass flow rate that will come the closest to giving
1269 : // the proper value for MCpEpsAct. Limit iterations to avoid too much time wasting.
1270 0 : MCpEpsAct = QZnReq / (waterInletTemp - Tzone);
1271 0 : MCpEpsLow = 0.0;
1272 0 : MdotLow = 0.0;
1273 0 : MCpEpsHigh = waterMassFlowRateMax * Cp * (1.0 - exp(-this->UA / (waterMassFlowRateMax * Cp)));
1274 0 : MdotHigh = waterMassFlowRateMax;
1275 0 : if (MCpEpsAct <= MCpEpsLow) {
1276 0 : MCpEpsAct = MCpEpsLow;
1277 0 : waterMassFlowRate = 0.0;
1278 0 : state.dataLoopNodes->Node(this->WaterInletNode).MassFlowRate = 0.0;
1279 0 : CoolingPanelOn = false;
1280 0 : } else if (MCpEpsAct >= MCpEpsHigh) {
1281 0 : MCpEpsAct = MCpEpsHigh;
1282 0 : waterMassFlowRate = waterMassFlowRateMax;
1283 0 : state.dataLoopNodes->Node(this->WaterInletNode).MassFlowRate = waterMassFlowRateMax;
1284 : } else {
1285 0 : for (int iter = 1; iter <= Maxiter; ++iter) {
1286 0 : FracGuess = (MCpEpsAct - MCpEpsLow) / (MCpEpsHigh - MCpEpsLow);
1287 0 : MdotGuess = MdotHigh * FracGuess;
1288 0 : MCpEpsGuess = MdotGuess * Cp * (1.0 - exp(-this->UA / (MdotGuess * Cp)));
1289 0 : if (MCpEpsGuess <= MCpEpsAct) {
1290 0 : MCpEpsLow = MCpEpsGuess;
1291 0 : MdotLow = MdotGuess;
1292 : } else { // MCpEpsGuess > MCpEpsAct
1293 0 : MCpEpsHigh = MCpEpsGuess;
1294 0 : MdotHigh = MdotGuess;
1295 : }
1296 0 : if (((MCpEpsAct - MCpEpsGuess) / MCpEpsAct) <= IterTol) {
1297 0 : waterMassFlowRate = MdotGuess;
1298 0 : state.dataLoopNodes->Node(this->WaterInletNode).MassFlowRate = waterMassFlowRate;
1299 0 : break;
1300 : }
1301 : }
1302 : }
1303 :
1304 : } else {
1305 0 : CoolingPanelOn = false;
1306 : }
1307 :
1308 0 : } else { // temperature control rather than zone load control
1309 :
1310 0 : if (CoolingPanelOn) {
1311 :
1312 0 : ControlTemp = this->getCoolingPanelControlTemp(state, ZoneNum);
1313 :
1314 0 : SetPointTemp = this->coldSetptSched->getCurrentVal();
1315 0 : OffTempCool = SetPointTemp - 0.5 * this->ColdThrottlRange;
1316 0 : FullOnTempCool = SetPointTemp + 0.5 * this->ColdThrottlRange;
1317 :
1318 0 : if (ControlTemp <= OffTempCool) {
1319 0 : MassFlowFrac = 0.0;
1320 0 : CoolingPanelOn = false;
1321 0 : } else if (ControlTemp >= FullOnTempCool) {
1322 0 : MassFlowFrac = 1.0;
1323 : } else {
1324 0 : MassFlowFrac = (ControlTemp - OffTempCool) / this->ColdThrottlRange;
1325 0 : if (MassFlowFrac < MinFrac) {
1326 0 : MassFlowFrac = MinFrac;
1327 : }
1328 : }
1329 :
1330 0 : waterMassFlowRate = MassFlowFrac * waterMassFlowRateMax;
1331 : }
1332 : }
1333 :
1334 0 : if (CoolingPanelOn) {
1335 0 : PlantUtilities::SetComponentFlowRate(state, waterMassFlowRate, this->WaterInletNode, this->WaterOutletNode, this->plantLoc);
1336 0 : if (waterMassFlowRate <= 0.0) {
1337 0 : CoolingPanelOn = false;
1338 : }
1339 : }
1340 :
1341 0 : if (CoolingPanelOn) {
1342 : // Now simulate the system...
1343 0 : Cp = this->plantLoc.loop->glycol->getSpecificHeat(state, waterInletTemp, RoutineName);
1344 0 : Effectiveness = 1.0 - exp(-this->UA / (waterMassFlowRate * Cp));
1345 0 : if (Effectiveness <= 0.0) {
1346 0 : Effectiveness = 0.0;
1347 0 : } else if (Effectiveness >= 1.0) {
1348 0 : Effectiveness = 1.0;
1349 : }
1350 0 : CoolingPanelCool = (Effectiveness)*waterMassFlowRate * Cp * (waterInletTemp - Tzone);
1351 0 : waterOutletTemp = this->WaterInletTemp - (CoolingPanelCool / (waterMassFlowRate * Cp));
1352 0 : RadHeat = CoolingPanelCool * this->FracRadiant;
1353 0 : state.dataChilledCeilingPanelSimple->CoolingPanel(CoolingPanelNum).CoolingPanelSource = RadHeat;
1354 :
1355 0 : if (this->FracRadiant <= MinFrac) {
1356 0 : LoadMet = CoolingPanelCool;
1357 : } else {
1358 :
1359 : // Now, distribute the radiant energy of all systems to the appropriate surfaces, to people, and the air
1360 0 : DistributeCoolingPanelRadGains(state);
1361 : // Now "simulate" the system by recalculating the heat balances
1362 0 : HeatBalanceSurfaceManager::CalcHeatBalanceOutsideSurf(state, ZoneNum);
1363 :
1364 0 : HeatBalanceSurfaceManager::CalcHeatBalanceInsideSurf(state, ZoneNum);
1365 :
1366 : // Here an assumption is made regarding radiant heat transfer to people.
1367 : // While the radiant heat transfer to people array will be used by the thermal comfort
1368 : // routines, the energy transfer to people would get lost from the perspective
1369 : // of the heat balance. So, to avoid this net loss of energy which clearly
1370 : // gets added to the zones, we must account for it somehow. This assumption
1371 : // that all energy radiated to people is converted to convective energy is
1372 : // not very precise, but at least it conserves energy. The system impact to heat balance
1373 : // should include this.
1374 0 : LoadMet = (state.dataHeatBal->Zone(ZoneNum).sumHATsurf(state) - this->ZeroCPSourceSumHATsurf) + (CoolingPanelCool * this->FracConvect) +
1375 0 : (RadHeat * this->FracDistribPerson);
1376 : }
1377 0 : this->WaterOutletEnthalpy = this->WaterInletEnthalpy - CoolingPanelCool / waterMassFlowRate;
1378 :
1379 : } else { // cooling panel off
1380 0 : CapacitanceWater = 0.0;
1381 0 : NTU = 0.0;
1382 0 : Effectiveness = 0.0;
1383 0 : waterOutletTemp = waterInletTemp;
1384 0 : CoolingPanelCool = 0.0;
1385 0 : LoadMet = 0.0;
1386 0 : RadHeat = 0.0;
1387 0 : waterMassFlowRate = 0.0;
1388 0 : this->CoolingPanelSource = 0.0;
1389 0 : this->WaterOutletEnthalpy = this->WaterInletEnthalpy;
1390 : }
1391 :
1392 0 : this->WaterOutletTemp = waterOutletTemp;
1393 0 : this->WaterMassFlowRate = waterMassFlowRate;
1394 0 : this->TotPower = LoadMet;
1395 0 : this->Power = CoolingPanelCool;
1396 0 : this->ConvPower = CoolingPanelCool - RadHeat;
1397 0 : this->RadPower = RadHeat;
1398 0 : }
1399 :
1400 5 : Real64 CoolingPanelParams::getCoolingPanelControlTemp(EnergyPlusData &state, int const ZoneNum) const
1401 : {
1402 :
1403 : // SUBROUTINE INFORMATION:
1404 : // AUTHOR Rick Strand
1405 : // DATE WRITTEN July 2016
1406 :
1407 : // METHODOLOGY EMPLOYED:
1408 : // This subroutine sets the control temperature for the simple cooling panel.
1409 :
1410 : // Using/Aliasing
1411 :
1412 5 : switch (this->controlType) {
1413 1 : case ClgPanelCtrlType::MAT: {
1414 1 : return state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum).MAT;
1415 : } break;
1416 1 : case ClgPanelCtrlType::MRT: {
1417 1 : return state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum).MRT;
1418 : } break;
1419 1 : case ClgPanelCtrlType::Operative: {
1420 1 : return 0.5 * (state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum).MAT +
1421 1 : state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum).MRT);
1422 : } break;
1423 1 : case ClgPanelCtrlType::ODB: {
1424 1 : return state.dataHeatBal->Zone(ZoneNum).OutDryBulbTemp;
1425 : } break;
1426 1 : case ClgPanelCtrlType::OWB: {
1427 1 : return state.dataHeatBal->Zone(ZoneNum).OutWetBulbTemp;
1428 : } break;
1429 0 : default: { // Should never get here
1430 0 : assert(false);
1431 : return -99990; // Compiler wants a return value for every path, so give an invalid value
1432 : } break;
1433 : }
1434 : }
1435 :
1436 0 : void UpdateCoolingPanel(EnergyPlusData &state, int const CoolingPanelNum)
1437 : {
1438 :
1439 : // SUBROUTINE INFORMATION:
1440 : // AUTHOR Rick Strand
1441 : // DATE WRITTEN Sept 2014
1442 : // February 2001
1443 : // MODIFIED Aug 2007 Daeho Kang (Add the update of radiant source)
1444 :
1445 : // REFERENCES:
1446 : // Existing code for hot water baseboard models (radiant-convective variety)
1447 :
1448 : // Using/Aliasing
1449 0 : Real64 SysTimeElapsed = state.dataHVACGlobal->SysTimeElapsed;
1450 0 : Real64 TimeStepSys = state.dataHVACGlobal->TimeStepSys;
1451 0 : auto &thisCP(state.dataChilledCeilingPanelSimple->CoolingPanel(CoolingPanelNum));
1452 :
1453 : // First, update the running average if necessary...
1454 0 : if (thisCP.LastSysTimeElapsed == SysTimeElapsed) {
1455 0 : thisCP.CoolingPanelSrcAvg -= thisCP.LastCoolingPanelSrc * thisCP.LastTimeStepSys / state.dataGlobal->TimeStepZone;
1456 : }
1457 : // Update the running average and the "last" values with the current values of the appropriate variables
1458 0 : thisCP.CoolingPanelSrcAvg += thisCP.CoolingPanelSource * TimeStepSys / state.dataGlobal->TimeStepZone;
1459 :
1460 0 : thisCP.LastCoolingPanelSrc = thisCP.CoolingPanelSource;
1461 0 : thisCP.LastSysTimeElapsed = SysTimeElapsed;
1462 0 : thisCP.LastTimeStepSys = TimeStepSys;
1463 :
1464 0 : int WaterInletNode = thisCP.WaterInletNode;
1465 0 : int WaterOutletNode = thisCP.WaterOutletNode;
1466 :
1467 0 : auto &ThisInNode(state.dataLoopNodes->Node(WaterInletNode));
1468 0 : auto &ThisOutNode(state.dataLoopNodes->Node(WaterOutletNode));
1469 :
1470 : // Set the outlet water nodes for the panel
1471 0 : PlantUtilities::SafeCopyPlantNode(state, WaterInletNode, WaterOutletNode);
1472 0 : ThisOutNode.Temp = thisCP.WaterOutletTemp;
1473 0 : ThisOutNode.Enthalpy = thisCP.WaterOutletEnthalpy;
1474 0 : ThisInNode.MassFlowRate = thisCP.WaterMassFlowRate;
1475 0 : ThisOutNode.MassFlowRate = thisCP.WaterMassFlowRate;
1476 0 : ThisInNode.MassFlowRateMax = thisCP.WaterMassFlowRateMax;
1477 0 : ThisOutNode.MassFlowRateMax = thisCP.WaterMassFlowRateMax;
1478 0 : }
1479 :
1480 249945 : void UpdateCoolingPanelSourceValAvg(EnergyPlusData &state,
1481 : bool &CoolingPanelSysOn) // .TRUE. if the radiant system has run this zone time step
1482 : {
1483 :
1484 : // SUBROUTINE INFORMATION:
1485 : // AUTHOR Rick Strand
1486 : // DATE WRITTEN Sept 2014
1487 :
1488 : // PURPOSE OF THIS SUBROUTINE:
1489 : // To transfer the average value of the heat source over the entire
1490 : // zone time step back to the heat balance routines so that the heat
1491 : // balance algorithms can simulate one last time with the average source
1492 : // to maintain some reasonable amount of continuity and energy balance
1493 : // in the temperature and flux histories.
1494 :
1495 : // METHODOLOGY EMPLOYED:
1496 : // All of the record keeping for the average term is done in the Update
1497 : // routine so the only other thing that this subroutine does is check to
1498 : // see if the system was even on. If any average term is non-zero, then
1499 : // one or more of the radiant systems was running.
1500 :
1501 : // REFERENCES:
1502 : // Existing code for hot water baseboard models (radiant-convective variety)
1503 :
1504 249945 : CoolingPanelSysOn = false;
1505 :
1506 : // If this was never allocated, then there are no radiant systems in this input file (just RETURN)
1507 249945 : if (!allocated(state.dataChilledCeilingPanelSimple->CoolingPanel)) {
1508 249945 : return;
1509 : }
1510 :
1511 : // If it was allocated, then we have to check to see if this was running at all...
1512 0 : for (int CoolingPanelNum = 1; CoolingPanelNum <= (int)state.dataChilledCeilingPanelSimple->CoolingPanel.size(); ++CoolingPanelNum) {
1513 0 : if (state.dataChilledCeilingPanelSimple->CoolingPanel(CoolingPanelNum).CoolingPanelSrcAvg != 0.0) {
1514 0 : CoolingPanelSysOn = true;
1515 0 : break; // DO loop
1516 : }
1517 : }
1518 :
1519 0 : for (auto &cp : state.dataChilledCeilingPanelSimple->CoolingPanel) {
1520 0 : cp.CoolingPanelSource = cp.CoolingPanelSrcAvg;
1521 : }
1522 :
1523 0 : DistributeCoolingPanelRadGains(state); // CoolingPanelRadSource has been modified so we need to redistribute gains
1524 : }
1525 :
1526 0 : void DistributeCoolingPanelRadGains(EnergyPlusData &state)
1527 : {
1528 :
1529 : // SUBROUTINE INFORMATION:
1530 : // AUTHOR Rick Strand
1531 : // DATE WRITTEN Sept 2014
1532 :
1533 : // PURPOSE OF THIS SUBROUTINE:
1534 : // To distribute the gains from the hot water baseboard heater
1535 : // as specified in the user input file. This includes distribution
1536 : // of long wavelength radiant gains to surfaces and "people."
1537 :
1538 : // METHODOLOGY EMPLOYED:
1539 : // We must cycle through all of the radiant systems because each
1540 : // surface could feel the effect of more than one radiant system.
1541 : // Note that the energy radiated to people is assumed to affect them
1542 : // but them it is assumed to be convected to the air.
1543 :
1544 : // REFERENCES:
1545 : // Existing code for hot water baseboard models (radiant-convective variety)
1546 :
1547 : // SUBROUTINE PARAMETER DEFINITIONS:
1548 0 : Real64 constexpr SmallestArea(0.001); // Smallest area in meters squared (to avoid a divide by zero)
1549 :
1550 : // Initialize arrays
1551 0 : for (auto &thisCP : state.dataChilledCeilingPanelSimple->CoolingPanel) {
1552 0 : for (int radSurfNum = 1; radSurfNum <= thisCP.TotSurfToDistrib; ++radSurfNum) {
1553 0 : int surfNum = thisCP.SurfacePtr(radSurfNum);
1554 0 : state.dataHeatBalFanSys->surfQRadFromHVAC(surfNum).CoolingPanel = 0.0;
1555 : }
1556 : }
1557 0 : state.dataHeatBalFanSys->ZoneQCoolingPanelToPerson = 0.0;
1558 :
1559 0 : for (auto &thisCP : state.dataChilledCeilingPanelSimple->CoolingPanel) {
1560 0 : int ZoneNum = thisCP.ZonePtr;
1561 0 : if (ZoneNum <= 0) {
1562 0 : continue;
1563 : }
1564 0 : state.dataHeatBalFanSys->ZoneQCoolingPanelToPerson(ZoneNum) += thisCP.CoolingPanelSource * thisCP.FracDistribPerson;
1565 :
1566 0 : for (int RadSurfNum = 1; RadSurfNum <= thisCP.TotSurfToDistrib; ++RadSurfNum) {
1567 0 : int SurfNum = thisCP.SurfacePtr(RadSurfNum);
1568 0 : auto &ThisSurf(state.dataSurface->Surface(SurfNum));
1569 0 : if (ThisSurf.Area > SmallestArea) {
1570 0 : Real64 ThisSurfIntensity = (thisCP.CoolingPanelSource * thisCP.FracDistribToSurf(RadSurfNum) / ThisSurf.Area);
1571 0 : state.dataHeatBalFanSys->surfQRadFromHVAC(SurfNum).CoolingPanel += ThisSurfIntensity;
1572 : // CR 8074, trap for excessive intensity (throws off surface balance )
1573 0 : if (ThisSurfIntensity > DataHeatBalFanSys::MaxRadHeatFlux) {
1574 0 : ShowSevereError(state, "DistributeCoolingPanelRadGains: excessive thermal radiation heat flux intensity detected");
1575 0 : ShowContinueError(state, format("Surface = {}", ThisSurf.Name));
1576 0 : ShowContinueError(state, format("Surface area = {:.3R} [m2]", ThisSurf.Area));
1577 0 : ShowContinueError(state, format("Occurs in {} = {}", cCMO_CoolingPanel_Simple, thisCP.Name));
1578 0 : ShowContinueError(state, format("Radiation intensity = {:.2R} [W/m2]", ThisSurfIntensity));
1579 0 : ShowContinueError(state, format("Assign a larger surface area or more surfaces in {}", cCMO_CoolingPanel_Simple));
1580 0 : ShowFatalError(state, "DistributeCoolingPanelRadGains: excessive thermal radiation heat flux intensity detected");
1581 : }
1582 : } else {
1583 0 : ShowSevereError(state, "DistributeCoolingPanelRadGains: surface not large enough to receive thermal radiation heat flux");
1584 0 : ShowContinueError(state, format("Surface = {}", ThisSurf.Name));
1585 0 : ShowContinueError(state, format("Surface area = {:.3R} [m2]", ThisSurf.Area));
1586 0 : ShowContinueError(state, format("Occurs in {} = {}", cCMO_CoolingPanel_Simple, thisCP.Name));
1587 0 : ShowContinueError(state, format("Assign a larger surface area or more surfaces in {}", cCMO_CoolingPanel_Simple));
1588 0 : ShowFatalError(state, "DistributeCoolingPanelRadGains: surface not large enough to receive thermal radiation heat flux");
1589 : }
1590 : }
1591 : }
1592 0 : }
1593 :
1594 1 : void CoolingPanelParams::ReportCoolingPanel(EnergyPlusData &state)
1595 : {
1596 :
1597 : // SUBROUTINE INFORMATION:
1598 : // AUTHOR Rick Strand
1599 : // DATE WRITTEN Aug 2014
1600 :
1601 : // REFERENCES:
1602 : // Existing code for hot water baseboard models (radiant-convective variety)
1603 :
1604 1 : Real64 TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
1605 :
1606 : // All of the power numbers are negative for cooling. This is because they will have a negative
1607 : // or cooling impact on the surfaces/zones. However, the output variables are noted as cooling.
1608 : // So, their sign should be positive if actually cooling and we need to reverse the sign here.
1609 : // This should not have an impact on any of the internal variables or the heat balances because
1610 : // those use other variables.
1611 1 : this->TotPower = -this->TotPower;
1612 1 : this->Power = -this->Power;
1613 1 : this->ConvPower = -this->ConvPower;
1614 1 : this->RadPower = -this->RadPower;
1615 :
1616 1 : this->TotEnergy = this->TotPower * TimeStepSysSec;
1617 1 : this->Energy = this->Power * TimeStepSysSec;
1618 1 : this->ConvEnergy = this->ConvPower * TimeStepSysSec;
1619 1 : this->RadEnergy = this->RadPower * TimeStepSysSec;
1620 1 : }
1621 :
1622 : } // namespace EnergyPlus::CoolingPanelSimple
|