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 : #include <string>
51 :
52 : // ObjexxFCL Headers
53 : #include <ObjexxFCL/Fmath.hh>
54 : #include <ObjexxFCL/member.functions.hh>
55 :
56 : // EnergyPlus Headers
57 : #include <EnergyPlus/Construction.hh>
58 : #include <EnergyPlus/Data/EnergyPlusData.hh>
59 : #include <EnergyPlus/DataEnvironment.hh>
60 : #include <EnergyPlus/DataHeatBalSurface.hh>
61 : #include <EnergyPlus/DataHeatBalance.hh>
62 : #include <EnergyPlus/DataIPShortCuts.hh>
63 : #include <EnergyPlus/DataMoistureBalance.hh>
64 : #include <EnergyPlus/DataSurfaces.hh>
65 : #include <EnergyPlus/DisplayRoutines.hh>
66 : #include <EnergyPlus/General.hh>
67 : #include <EnergyPlus/HeatBalanceHAMTManager.hh>
68 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
69 : #include <EnergyPlus/Material.hh>
70 : #include <EnergyPlus/OutputProcessor.hh>
71 : #include <EnergyPlus/Psychrometrics.hh>
72 : #include <EnergyPlus/UtilityRoutines.hh>
73 : #include <EnergyPlus/ZoneTempPredictorCorrector.hh>
74 :
75 : namespace EnergyPlus {
76 :
77 : namespace HeatBalanceHAMTManager {
78 :
79 : // MODULE INFORMATION:
80 : // AUTHOR Phillip Biddulph
81 : // DATE WRITTEN June 2008
82 : // MODIFIED
83 : // Bug fixes to make sure HAMT can cope with data limits ! PDB August 2009
84 : // RE-ENGINEERED
85 :
86 : // PURPOSE OF THIS MODULE:
87 : // Calculate, record and report the one dimentional heat and moisture transfer
88 : // through a surface given the material composition of the building surface and
89 : // the external and internal Temperatures and Relative Humidities.
90 :
91 : // METHODOLOGY EMPLOYED:
92 : // Each surface is split into "cells", where all characteristics are initiallised.
93 : // Cells are matched and links created in the initialisation routine.
94 : // The internal and external "surfaces" of the surface are virtual cells to allow for the
95 : // input of heat and vapor via heat transfer coefficients, radiation,
96 : // and vapor transfer coefficients
97 : // Uses Forward (implicit) finite difference alogorithm. Heat transfer is caclulated first,
98 : // with the option of including the latent heat, then liquid and vapor transfer. The process is ittereated.
99 : // Once the temperatures have converged the internal surface
100 : // temperature and vapor densities are passed back to EnergyPlus.
101 :
102 : // Temperatures and relative humidities are updated once EnergyPlus has checked that
103 : // the zone temperatures have converged.
104 :
105 : // REFERENCES:
106 : // K?zel, H.M. (1995) Simultaneous Heat and Moisture Transport in Building Components.
107 : // One- and two-dimensional calculation using simple parameters. IRB Verlag 1995
108 : // Holman, J.P. (2002) Heat Transfer, Ninth Edition. McGraw-Hill
109 : // Winterton, R.H.S. (1997) Heat Transfer. (Oxford Chemistry Primers; 50) Oxford University Press
110 : // Kumar Kumaran, M. (1996) IEA ANNEX 24, Final Report, Volume 3
111 :
112 : // USE STATEMENTS:
113 :
114 : // Using/Aliasing
115 : using namespace DataSurfaces;
116 : using DataHeatBalSurface::MinSurfaceTempLimit;
117 : using DataHeatBalSurface::MinSurfaceTempLimitBeforeFatal;
118 : using namespace DataHeatBalance;
119 : using namespace Psychrometrics;
120 :
121 353361 : void ManageHeatBalHAMT(EnergyPlusData &state, int const SurfNum, Real64 &SurfTempInTmp, Real64 &TempSurfOutTmp)
122 : {
123 :
124 : // SUBROUTINE INFORMATION:
125 : // AUTHOR Phillip Biddulph
126 : // DATE WRITTEN June 2008
127 : // MODIFIED na
128 : // RE-ENGINEERED na
129 :
130 : // PURPOSE OF THIS SUBROUTINE:
131 : // Manages the Heat and Moisture Transfer calculations.
132 :
133 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
134 353361 : if (state.dataHeatBalHAMTMgr->OneTimeFlag) {
135 3 : state.dataHeatBalHAMTMgr->OneTimeFlag = false;
136 3 : DisplayString(state, "Initialising Heat and Moisture Transfer Model");
137 3 : GetHeatBalHAMTInput(state);
138 3 : InitHeatBalHAMT(state);
139 : }
140 :
141 353361 : CalcHeatBalHAMT(state, SurfNum, SurfTempInTmp, TempSurfOutTmp);
142 353361 : }
143 :
144 3 : void GetHeatBalHAMTInput(EnergyPlusData &state)
145 : {
146 :
147 : // SUBROUTINE INFORMATION:
148 : // AUTHOR Phillip Biddulph
149 : // DATE WRITTEN June 2008
150 : // MODIFIED na
151 : // RE-ENGINEERED na
152 :
153 : // PURPOSE OF THIS SUBROUTINE:
154 : // gets input for the HAMT model
155 : static constexpr std::string_view routineName = "GetHeatBalHAMTInput";
156 :
157 : // SUBROUTINE PARAMETER DEFINITIONS:
158 9 : static std::string const cHAMTObject1("MaterialProperty:HeatAndMoistureTransfer:Settings");
159 9 : static std::string const cHAMTObject2("MaterialProperty:HeatAndMoistureTransfer:SorptionIsotherm");
160 9 : static std::string const cHAMTObject3("MaterialProperty:HeatAndMoistureTransfer:Suction");
161 9 : static std::string const cHAMTObject4("MaterialProperty:HeatAndMoistureTransfer:Redistribution");
162 9 : static std::string const cHAMTObject5("MaterialProperty:HeatAndMoistureTransfer:Diffusion");
163 9 : static std::string const cHAMTObject6("MaterialProperty:HeatAndMoistureTransfer:ThermalConductivity");
164 9 : static std::string const cHAMTObject7("SurfaceProperties:VaporCoefficients");
165 :
166 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
167 :
168 3 : Array1D_string AlphaArray;
169 3 : Array1D_string cAlphaFieldNames;
170 3 : Array1D_string cNumericFieldNames;
171 :
172 3 : Array1D_bool lAlphaBlanks;
173 3 : Array1D_bool lNumericBlanks;
174 :
175 3 : Array1D<Real64> NumArray;
176 :
177 : Real64 avdata;
178 :
179 : int MaxNums;
180 : int MaxAlphas;
181 : int NumParams;
182 : int NumNums;
183 : int NumAlphas;
184 : int status;
185 : int Numid;
186 :
187 : int HAMTitems;
188 : int vtcsid;
189 :
190 : bool ErrorsFound;
191 :
192 3 : auto &s_ip = state.dataInputProcessing->inputProcessor;
193 3 : auto &s_mat = state.dataMaterial;
194 :
195 3 : state.dataHeatBalHAMTMgr->watertot.allocate(state.dataSurface->TotSurfaces);
196 3 : state.dataHeatBalHAMTMgr->surfrh.allocate(state.dataSurface->TotSurfaces);
197 3 : state.dataHeatBalHAMTMgr->surfextrh.allocate(state.dataSurface->TotSurfaces);
198 3 : state.dataHeatBalHAMTMgr->surftemp.allocate(state.dataSurface->TotSurfaces);
199 3 : state.dataHeatBalHAMTMgr->surfexttemp.allocate(state.dataSurface->TotSurfaces);
200 3 : state.dataHeatBalHAMTMgr->surfvp.allocate(state.dataSurface->TotSurfaces);
201 :
202 3 : state.dataHeatBalHAMTMgr->firstcell.allocate(state.dataSurface->TotSurfaces);
203 3 : state.dataHeatBalHAMTMgr->lastcell.allocate(state.dataSurface->TotSurfaces);
204 3 : state.dataHeatBalHAMTMgr->Extcell.allocate(state.dataSurface->TotSurfaces);
205 3 : state.dataHeatBalHAMTMgr->ExtRadcell.allocate(state.dataSurface->TotSurfaces);
206 3 : state.dataHeatBalHAMTMgr->ExtConcell.allocate(state.dataSurface->TotSurfaces);
207 3 : state.dataHeatBalHAMTMgr->ExtSkycell.allocate(state.dataSurface->TotSurfaces);
208 3 : state.dataHeatBalHAMTMgr->ExtGrncell.allocate(state.dataSurface->TotSurfaces);
209 3 : state.dataHeatBalHAMTMgr->Intcell.allocate(state.dataSurface->TotSurfaces);
210 3 : state.dataHeatBalHAMTMgr->IntConcell.allocate(state.dataSurface->TotSurfaces);
211 :
212 3 : state.dataHeatBalHAMTMgr->extvtc.allocate(state.dataSurface->TotSurfaces);
213 3 : state.dataHeatBalHAMTMgr->intvtc.allocate(state.dataSurface->TotSurfaces);
214 3 : state.dataHeatBalHAMTMgr->extvtcflag.allocate(state.dataSurface->TotSurfaces);
215 3 : state.dataHeatBalHAMTMgr->intvtcflag.allocate(state.dataSurface->TotSurfaces);
216 3 : state.dataHeatBalHAMTMgr->MyEnvrnFlag.allocate(state.dataSurface->TotSurfaces);
217 :
218 3 : state.dataHeatBalHAMTMgr->extvtc = -1.0;
219 3 : state.dataHeatBalHAMTMgr->intvtc = -1.0;
220 3 : state.dataHeatBalHAMTMgr->extvtcflag = false;
221 3 : state.dataHeatBalHAMTMgr->intvtcflag = false;
222 3 : state.dataHeatBalHAMTMgr->MyEnvrnFlag = true;
223 :
224 3 : state.dataHeatBalHAMTMgr->latswitch = true;
225 3 : state.dataHeatBalHAMTMgr->rainswitch = true;
226 :
227 3 : MaxAlphas = 0;
228 3 : MaxNums = 0;
229 3 : s_ip->getObjectDefMaxArgs(state, cHAMTObject1, NumParams, NumAlphas, NumNums);
230 3 : MaxAlphas = max(MaxAlphas, NumAlphas);
231 3 : MaxNums = max(MaxNums, NumNums);
232 3 : s_ip->getObjectDefMaxArgs(state, cHAMTObject2, NumParams, NumAlphas, NumNums);
233 3 : MaxAlphas = max(MaxAlphas, NumAlphas);
234 3 : MaxNums = max(MaxNums, NumNums);
235 3 : s_ip->getObjectDefMaxArgs(state, cHAMTObject3, NumParams, NumAlphas, NumNums);
236 3 : MaxAlphas = max(MaxAlphas, NumAlphas);
237 3 : MaxNums = max(MaxNums, NumNums);
238 3 : s_ip->getObjectDefMaxArgs(state, cHAMTObject4, NumParams, NumAlphas, NumNums);
239 3 : MaxAlphas = max(MaxAlphas, NumAlphas);
240 3 : MaxNums = max(MaxNums, NumNums);
241 3 : s_ip->getObjectDefMaxArgs(state, cHAMTObject5, NumParams, NumAlphas, NumNums);
242 3 : MaxAlphas = max(MaxAlphas, NumAlphas);
243 3 : MaxNums = max(MaxNums, NumNums);
244 3 : s_ip->getObjectDefMaxArgs(state, cHAMTObject6, NumParams, NumAlphas, NumNums);
245 3 : MaxAlphas = max(MaxAlphas, NumAlphas);
246 3 : MaxNums = max(MaxNums, NumNums);
247 3 : s_ip->getObjectDefMaxArgs(state, cHAMTObject7, NumParams, NumAlphas, NumNums);
248 3 : MaxAlphas = max(MaxAlphas, NumAlphas);
249 3 : MaxNums = max(MaxNums, NumNums);
250 :
251 3 : ErrorsFound = false;
252 :
253 3 : AlphaArray.allocate(MaxAlphas);
254 3 : cAlphaFieldNames.allocate(MaxAlphas);
255 3 : cNumericFieldNames.allocate(MaxNums);
256 3 : NumArray.dimension(MaxNums, 0.0);
257 3 : lAlphaBlanks.dimension(MaxAlphas, false);
258 3 : lNumericBlanks.dimension(MaxNums, false);
259 :
260 3 : HAMTitems = s_ip->getNumObjectsFound(state, cHAMTObject1); // MaterialProperty:HeatAndMoistureTransfer:Settings
261 16 : for (int item = 1; item <= HAMTitems; ++item) {
262 13 : s_ip->getObjectItem(state,
263 : cHAMTObject1,
264 : item,
265 : AlphaArray,
266 : NumAlphas,
267 : NumArray,
268 : NumNums,
269 : status,
270 : lNumericBlanks,
271 : lAlphaBlanks,
272 : cAlphaFieldNames,
273 : cNumericFieldNames);
274 :
275 13 : ErrorObjectHeader eoh{routineName, cHAMTObject1, AlphaArray(1)};
276 13 : int matNum = Material::GetMaterialNum(state, AlphaArray(1));
277 :
278 13 : if (matNum == 0) {
279 0 : ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(1), AlphaArray(1));
280 0 : ShowContinueError(state, "The basic material must be defined in addition to specifying HeatAndMoistureTransfer properties.");
281 0 : ErrorsFound = true;
282 0 : continue;
283 : }
284 :
285 13 : auto *mat = s_mat->materials(matNum);
286 :
287 13 : if (mat->group != Material::Group::Regular) {
288 0 : ShowSevereCustom(state, eoh, format("{} = \"{}\" is not a regular material.", cAlphaFieldNames(1), AlphaArray(1)));
289 0 : ErrorsFound = true;
290 0 : continue;
291 : }
292 :
293 13 : if (mat->ROnly) {
294 0 : ShowWarningError(state,
295 0 : format("{} {}=\"{}\" is defined as an R-only value material.", cHAMTObject1, cAlphaFieldNames(1), AlphaArray(1)));
296 0 : continue;
297 : }
298 :
299 13 : auto *matHAMT = new MaterialHAMT;
300 13 : matHAMT->Material::MaterialBase::operator=(*mat); // deep copy
301 :
302 13 : delete mat;
303 13 : s_mat->materials(matNum) = matHAMT;
304 :
305 13 : matHAMT->hasHAMT = true;
306 13 : matHAMT->Porosity = NumArray(1);
307 13 : matHAMT->iwater = NumArray(2);
308 : }
309 :
310 3 : HAMTitems = s_ip->getNumObjectsFound(state, cHAMTObject2); // MaterialProperty:HeatAndMoistureTransfer:SorptionIsotherm
311 16 : for (int item = 1; item <= HAMTitems; ++item) {
312 13 : s_ip->getObjectItem(state,
313 : cHAMTObject2,
314 : item,
315 : AlphaArray,
316 : NumAlphas,
317 : NumArray,
318 : NumNums,
319 : status,
320 : lNumericBlanks,
321 : lAlphaBlanks,
322 : cAlphaFieldNames,
323 : cNumericFieldNames);
324 :
325 13 : ErrorObjectHeader eoh{routineName, cHAMTObject2, AlphaArray(1)};
326 13 : int matNum = Material::GetMaterialNum(state, AlphaArray(1));
327 :
328 13 : if (matNum == 0) {
329 0 : ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(1), AlphaArray(1));
330 0 : ShowContinueError(state, "The basic material must be defined in addition to specifying HeatAndMoistureTransfer properties.");
331 0 : ErrorsFound = true;
332 0 : continue;
333 : }
334 :
335 13 : auto *mat = s_mat->materials(matNum);
336 13 : if (!mat->hasHAMT) {
337 0 : ShowSevereCustom(state, eoh, format("{} is not defined for {} = \"{}\"", cHAMTObject1, cAlphaFieldNames(1), AlphaArray(1)));
338 0 : ErrorsFound = true;
339 0 : continue;
340 : }
341 :
342 13 : auto *matHAMT = dynamic_cast<MaterialHAMT *>(mat);
343 13 : assert(matHAMT != nullptr);
344 :
345 13 : Numid = 1;
346 :
347 13 : matHAMT->niso = int(NumArray(Numid));
348 :
349 115 : for (int iso = 1; iso <= matHAMT->niso; ++iso) {
350 102 : matHAMT->isorh(iso) = NumArray(++Numid);
351 102 : matHAMT->isodata(iso) = NumArray(++Numid);
352 : }
353 :
354 13 : ++matHAMT->niso;
355 13 : matHAMT->isorh(matHAMT->niso) = rhmax;
356 13 : matHAMT->isodata(matHAMT->niso) = matHAMT->Porosity * wdensity;
357 :
358 13 : ++matHAMT->niso;
359 13 : matHAMT->isorh(matHAMT->niso) = 0.0;
360 13 : matHAMT->isodata(matHAMT->niso) = 0.0;
361 :
362 : // check the isotherm
363 :
364 : // - First sort
365 128 : for (int jj = 1; jj <= matHAMT->niso - 1; ++jj) {
366 722 : for (int ii = jj + 1; ii <= matHAMT->niso; ++ii) {
367 607 : if (matHAMT->isorh(jj) > matHAMT->isorh(ii)) {
368 :
369 115 : Real64 dumrh = matHAMT->isorh(jj);
370 115 : Real64 dumdata = matHAMT->isodata(jj);
371 :
372 115 : matHAMT->isorh(jj) = matHAMT->isorh(ii);
373 115 : matHAMT->isodata(jj) = matHAMT->isodata(ii);
374 :
375 115 : matHAMT->isorh(ii) = dumrh;
376 115 : matHAMT->isodata(ii) = dumdata;
377 : }
378 : }
379 : }
380 :
381 : //- Now make sure the data rises
382 13 : bool isoerrrise = false;
383 13 : for (int ii = 1; ii <= 100; ++ii) {
384 13 : bool avflag = true;
385 128 : for (int jj = 1; jj <= matHAMT->niso - 1; ++jj) {
386 115 : if (matHAMT->isodata(jj) > matHAMT->isodata(jj + 1)) {
387 0 : isoerrrise = true;
388 0 : avdata = (matHAMT->isodata(jj) + matHAMT->isodata(jj + 1)) / 2.0;
389 0 : matHAMT->isodata(jj) = avdata;
390 0 : matHAMT->isodata(jj + 1) = avdata;
391 0 : avflag = false;
392 : }
393 : }
394 13 : if (avflag) {
395 13 : break;
396 : }
397 : }
398 13 : if (isoerrrise) {
399 0 : ShowWarningError(state, format("{}: data not rising - Check material {}", cHAMTObject2, matHAMT->Name));
400 0 : ShowContinueError(state, "Isotherm data has been fixed, and the simulation continues.");
401 : }
402 : }
403 :
404 3 : HAMTitems = s_ip->getNumObjectsFound(state, cHAMTObject3); // MaterialProperty:HeatAndMoistureTransfer:Suction
405 16 : for (int item = 1; item <= HAMTitems; ++item) {
406 13 : s_ip->getObjectItem(state,
407 : cHAMTObject3,
408 : item,
409 : AlphaArray,
410 : NumAlphas,
411 : NumArray,
412 : NumNums,
413 : status,
414 : lNumericBlanks,
415 : lAlphaBlanks,
416 : cAlphaFieldNames,
417 : cNumericFieldNames);
418 :
419 13 : ErrorObjectHeader eoh{routineName, cHAMTObject3, AlphaArray(1)};
420 13 : int matNum = Material::GetMaterialNum(state, AlphaArray(1));
421 :
422 13 : if (matNum == 0) {
423 0 : ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(1), AlphaArray(1));
424 0 : ShowContinueError(state, "The basic material must be defined in addition to specifying HeatAndMoistureTransfer properties.");
425 0 : ErrorsFound = true;
426 0 : continue;
427 : }
428 :
429 13 : auto *mat = s_mat->materials(matNum);
430 13 : if (!mat->hasHAMT) {
431 0 : ShowSevereCustom(state, eoh, format("{} is not defined for {} = \"{}\"", cHAMTObject1, cAlphaFieldNames(1), AlphaArray(1)));
432 0 : ErrorsFound = true;
433 0 : continue;
434 : }
435 :
436 13 : auto *matHAMT = dynamic_cast<MaterialHAMT *>(mat);
437 13 : assert(matHAMT != nullptr);
438 :
439 13 : Numid = 1;
440 :
441 13 : matHAMT->nsuc = NumArray(Numid);
442 44 : for (int suc = 1; suc <= matHAMT->nsuc; ++suc) {
443 31 : matHAMT->sucwater(suc) = NumArray(++Numid);
444 31 : matHAMT->sucdata(suc) = NumArray(++Numid);
445 : }
446 :
447 13 : ++matHAMT->nsuc;
448 13 : matHAMT->sucwater(matHAMT->nsuc) = matHAMT->isodata(matHAMT->niso);
449 13 : matHAMT->sucdata(matHAMT->nsuc) = matHAMT->sucdata(matHAMT->nsuc - 1);
450 : }
451 :
452 3 : HAMTitems = s_ip->getNumObjectsFound(state, cHAMTObject4); // MaterialProperty:HeatAndMoistureTransfer:Redistribution
453 16 : for (int item = 1; item <= HAMTitems; ++item) {
454 13 : s_ip->getObjectItem(state,
455 : cHAMTObject4,
456 : item,
457 : AlphaArray,
458 : NumAlphas,
459 : NumArray,
460 : NumNums,
461 : status,
462 : lNumericBlanks,
463 : lAlphaBlanks,
464 : cAlphaFieldNames,
465 : cNumericFieldNames);
466 :
467 13 : ErrorObjectHeader eoh{routineName, cHAMTObject4, AlphaArray(1)};
468 13 : int matNum = Material::GetMaterialNum(state, AlphaArray(1));
469 13 : if (matNum == 0) {
470 0 : ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(1), AlphaArray(1));
471 0 : ShowContinueError(state, "The basic material must be defined in addition to specifying HeatAndMoistureTransfer properties.");
472 0 : ErrorsFound = true;
473 0 : continue;
474 : }
475 :
476 13 : auto *mat = s_mat->materials(matNum);
477 13 : if (!mat->hasHAMT) {
478 0 : ShowSevereCustom(state, eoh, format("{} is not defined for {} = \"{}\"", cHAMTObject1, cAlphaFieldNames(1), AlphaArray(1)));
479 0 : ErrorsFound = true;
480 0 : continue;
481 : }
482 :
483 13 : auto *matHAMT = dynamic_cast<MaterialHAMT *>(mat);
484 13 : assert(matHAMT != nullptr);
485 :
486 13 : Numid = 1;
487 :
488 13 : matHAMT->nred = NumArray(Numid);
489 44 : for (int red = 1; red <= matHAMT->nred; ++red) {
490 31 : matHAMT->redwater(red) = NumArray(++Numid);
491 31 : matHAMT->reddata(red) = NumArray(++Numid);
492 : }
493 :
494 13 : ++matHAMT->nred;
495 13 : matHAMT->redwater(matHAMT->nred) = matHAMT->isodata(matHAMT->niso);
496 13 : matHAMT->reddata(matHAMT->nred) = matHAMT->reddata(matHAMT->nred - 1);
497 : }
498 :
499 3 : HAMTitems = s_ip->getNumObjectsFound(state, cHAMTObject5); // MaterialProperty:HeatAndMoistureTransfer:Diffusion
500 16 : for (int item = 1; item <= HAMTitems; ++item) {
501 13 : s_ip->getObjectItem(state,
502 : cHAMTObject5,
503 : item,
504 : AlphaArray,
505 : NumAlphas,
506 : NumArray,
507 : NumNums,
508 : status,
509 : lNumericBlanks,
510 : lAlphaBlanks,
511 : cAlphaFieldNames,
512 : cNumericFieldNames);
513 :
514 13 : ErrorObjectHeader eoh{routineName, cHAMTObject5, AlphaArray(1)};
515 13 : int matNum = Material::GetMaterialNum(state, AlphaArray(1));
516 13 : if (matNum == 0) {
517 0 : ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(1), AlphaArray(1));
518 0 : ShowContinueError(state, "The basic material must be defined in addition to specifying HeatAndMoistureTransfer properties.");
519 0 : ErrorsFound = true;
520 0 : continue;
521 : }
522 :
523 13 : auto *mat = s_mat->materials(matNum);
524 13 : if (!mat->hasHAMT) {
525 0 : ShowSevereCustom(state, eoh, format("{} is not defined for {} = \"{}\"", cHAMTObject1, cAlphaFieldNames(1), AlphaArray(1)));
526 0 : ErrorsFound = true;
527 0 : continue;
528 : }
529 :
530 13 : auto *matHAMT = dynamic_cast<MaterialHAMT *>(mat);
531 13 : assert(matHAMT != nullptr);
532 :
533 13 : Numid = 1;
534 :
535 13 : matHAMT->nmu = NumArray(Numid);
536 13 : if (matHAMT->nmu > 0) {
537 30 : for (int mu = 1; mu <= matHAMT->nmu; ++mu) {
538 17 : matHAMT->murh(mu) = NumArray(++Numid);
539 17 : matHAMT->mudata(mu) = NumArray(++Numid);
540 : }
541 :
542 13 : ++matHAMT->nmu;
543 13 : matHAMT->murh(matHAMT->nmu) = matHAMT->isorh(matHAMT->niso);
544 13 : matHAMT->mudata(matHAMT->nmu) = matHAMT->mudata(matHAMT->nmu - 1);
545 : }
546 : }
547 :
548 3 : HAMTitems = s_ip->getNumObjectsFound(state, cHAMTObject6); // MaterialProperty:HeatAndMoistureTransfer:ThermalConductivity
549 16 : for (int item = 1; item <= HAMTitems; ++item) {
550 13 : s_ip->getObjectItem(state,
551 : cHAMTObject6,
552 : item,
553 : AlphaArray,
554 : NumAlphas,
555 : NumArray,
556 : NumNums,
557 : status,
558 : lNumericBlanks,
559 : lAlphaBlanks,
560 : cAlphaFieldNames,
561 : cNumericFieldNames);
562 :
563 13 : ErrorObjectHeader eoh{routineName, cHAMTObject6, AlphaArray(1)};
564 13 : int matNum = Material::GetMaterialNum(state, AlphaArray(1));
565 13 : if (matNum == 0) {
566 0 : ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(1), AlphaArray(1));
567 0 : ShowContinueError(state, "The basic material must be defined in addition to specifying HeatAndMoistureTransfer properties.");
568 0 : ErrorsFound = true;
569 0 : continue;
570 : }
571 :
572 13 : auto *mat = s_mat->materials(matNum);
573 13 : if (!mat->hasHAMT) {
574 0 : ShowSevereCustom(state, eoh, format("{} is not defined for {} = \"{}\"", cHAMTObject1, cAlphaFieldNames(1), AlphaArray(1)));
575 0 : ErrorsFound = true;
576 0 : continue;
577 : }
578 :
579 13 : auto *matHAMT = dynamic_cast<MaterialHAMT *>(mat);
580 13 : assert(matHAMT != nullptr);
581 :
582 13 : Numid = 1;
583 :
584 13 : matHAMT->ntc = NumArray(Numid);
585 13 : if (matHAMT->ntc > 0) {
586 37 : for (int tc = 1; tc <= matHAMT->ntc; ++tc) {
587 24 : ++Numid;
588 24 : matHAMT->tcwater(tc) = NumArray(Numid);
589 24 : ++Numid;
590 24 : matHAMT->tcdata(tc) = NumArray(Numid);
591 : }
592 :
593 13 : ++matHAMT->ntc;
594 13 : matHAMT->tcwater(matHAMT->ntc) = matHAMT->isodata(matHAMT->niso);
595 13 : matHAMT->tcdata(matHAMT->ntc) = matHAMT->tcdata(matHAMT->ntc - 1);
596 : }
597 : }
598 :
599 : // Vapor Transfer coefficients
600 3 : HAMTitems = s_ip->getNumObjectsFound(state, cHAMTObject7); // SurfaceProperties:VaporCoefficients
601 15 : for (int item = 1; item <= HAMTitems; ++item) {
602 12 : s_ip->getObjectItem(state,
603 : cHAMTObject7,
604 : item,
605 : AlphaArray,
606 : NumAlphas,
607 : NumArray,
608 : NumNums,
609 : status,
610 : lNumericBlanks,
611 : lAlphaBlanks,
612 : cAlphaFieldNames,
613 : cNumericFieldNames);
614 :
615 12 : ErrorObjectHeader eoh{routineName, cHAMTObject7, AlphaArray(1)};
616 12 : vtcsid = Util::FindItemInList(AlphaArray(1), state.dataSurface->Surface);
617 12 : if (vtcsid == 0) {
618 0 : ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(1), AlphaArray(1));
619 0 : ShowContinueError(state, "The basic material must be defined in addition to specifying HeatAndMoistureTransfer properties.");
620 0 : ErrorsFound = true;
621 0 : continue;
622 : }
623 :
624 12 : if (AlphaArray(2) == "YES") {
625 12 : state.dataHeatBalHAMTMgr->extvtcflag(vtcsid) = true;
626 12 : state.dataHeatBalHAMTMgr->extvtc(vtcsid) = NumArray(1);
627 : }
628 :
629 12 : if (AlphaArray(3) == "YES") {
630 12 : state.dataHeatBalHAMTMgr->intvtcflag(vtcsid) = true;
631 12 : state.dataHeatBalHAMTMgr->intvtc(vtcsid) = NumArray(2);
632 : }
633 : }
634 :
635 3 : AlphaArray.deallocate();
636 3 : cAlphaFieldNames.deallocate();
637 3 : cNumericFieldNames.deallocate();
638 3 : NumArray.deallocate();
639 3 : lAlphaBlanks.deallocate();
640 3 : lNumericBlanks.deallocate();
641 :
642 3 : if (ErrorsFound) {
643 0 : ShowFatalError(state, "GetHeatBalHAMTInput: Errors found getting input. Program terminates.");
644 : }
645 3 : }
646 :
647 3 : void InitHeatBalHAMT(EnergyPlusData &state)
648 : {
649 : // SUBROUTINE INFORMATION:
650 : // AUTHOR Phillip Biddulph
651 : // DATE WRITTEN June 2008
652 : // MODIFIED B. Griffith, Aug 2012 for surface-specific algorithms
653 : // RE-ENGINEERED na
654 :
655 : // Using/Aliasing
656 : using General::ScanForReports;
657 :
658 : // Locals
659 : // SUBROUTINE PARAMETER DEFINITIONS:
660 3 : Real64 constexpr adjdist(0.00005); // Allowable distance between two cells, also used as limit on cell length
661 : static constexpr std::string_view RoutineName("InitCombinedHeatAndMoistureFiniteElement: ");
662 :
663 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
664 : int sid;
665 : int conid;
666 : int errorCount;
667 :
668 : Real64 runor;
669 : Real64 testlen;
670 : Real64 waterd; // water density
671 : bool DoReport;
672 :
673 3 : auto &s_mat = state.dataMaterial;
674 3 : auto &s_hbh = state.dataHeatBalHAMTMgr;
675 :
676 3 : s_hbh->deltat = state.dataGlobal->TimeStepZone * 3600.0;
677 :
678 : // Check the materials information and work out how many cells are required.
679 3 : errorCount = 0;
680 3 : s_hbh->TotCellsMax = 0;
681 27 : for (int sid = 1; sid <= state.dataSurface->TotSurfaces; ++sid) {
682 24 : auto const &surf = state.dataSurface->Surface(sid);
683 24 : if (surf.Class == SurfaceClass::Window) {
684 4 : continue;
685 : }
686 20 : if (surf.HeatTransferAlgorithm != DataSurfaces::HeatTransferModel::HAMT) {
687 7 : continue;
688 : }
689 :
690 13 : if (surf.Construction == 0) {
691 0 : continue;
692 : }
693 13 : auto const &constr = state.dataConstruction->Construct(surf.Construction);
694 :
695 59 : for (int lid = 1; lid <= constr.TotLayers; ++lid) {
696 46 : auto *mat = s_mat->materials(constr.LayerPoint(lid));
697 46 : if (mat->ROnly) {
698 0 : ShowSevereError(state, format("{}Construction={} cannot contain R-only value materials.", RoutineName, constr.Name));
699 0 : ShowContinueError(state, format("Reference Material=\"{}\".", mat->Name));
700 0 : ++errorCount;
701 0 : continue;
702 : }
703 :
704 46 : auto *matHAMT = dynamic_cast<MaterialHAMT *>(mat);
705 46 : assert(matHAMT != nullptr);
706 :
707 46 : if (matHAMT->nmu < 0) {
708 0 : ShowSevereError(state, format("{}Construction={}", RoutineName, constr.Name));
709 0 : ShowContinueError(
710 : state,
711 0 : format("Reference Material=\"{}\" does not have required Water Vapor Diffusion Resistance Factor (mu) data.", matHAMT->Name));
712 0 : ++errorCount;
713 : }
714 :
715 46 : if (matHAMT->niso < 0) {
716 0 : ShowSevereError(state, format("{}Construction={}", RoutineName, constr.Name));
717 0 : ShowContinueError(state, format("Reference Material=\"{}\" does not have required isotherm data.", matHAMT->Name));
718 0 : ++errorCount;
719 : }
720 46 : if (matHAMT->nsuc < 0) {
721 0 : ShowSevereError(state, format("{}Construction={}", RoutineName, constr.Name));
722 0 : ShowContinueError(
723 0 : state, format("Reference Material=\"{}\" does not have required liquid transport coefficient (suction) data.", mat->Name));
724 0 : ++errorCount;
725 : }
726 46 : if (matHAMT->nred < 0) {
727 0 : ShowSevereError(state, format("{}Construction={}", RoutineName, constr.Name));
728 0 : ShowContinueError(
729 : state,
730 0 : format("Reference Material=\"{}\" does not have required liquid transport coefficient (redistribution) data.", mat->Name));
731 0 : ++errorCount;
732 : }
733 46 : if (matHAMT->ntc < 0) {
734 0 : if (mat->Conductivity > 0) {
735 0 : ShowWarningError(state, format("{}Construction={}", RoutineName, constr.Name));
736 0 : ShowContinueError(
737 0 : state, format("Reference Material=\"{}\" does not have thermal conductivity data. Using fixed value.", matHAMT->Name));
738 0 : matHAMT->ntc = 2;
739 0 : matHAMT->tcwater(1) = 0.0;
740 0 : matHAMT->tcdata(1) = matHAMT->Conductivity;
741 0 : matHAMT->tcwater(2) = matHAMT->isodata(matHAMT->niso);
742 0 : matHAMT->tcdata(2) = matHAMT->Conductivity;
743 : } else {
744 0 : ShowSevereError(state, format("{}Construction={}", RoutineName, constr.Name));
745 0 : ShowContinueError(state,
746 0 : format("Reference Material=\"{}\" does not have required thermal conductivity data.", matHAMT->Name));
747 0 : ++errorCount;
748 : }
749 : }
750 :
751 : // convert material water content to RH
752 :
753 46 : waterd = matHAMT->iwater * matHAMT->Density;
754 46 : interp(matHAMT->niso, matHAMT->isodata, matHAMT->isorh, waterd, matHAMT->irh);
755 :
756 46 : matHAMT->divs = int(matHAMT->Thickness / matHAMT->divsize) + matHAMT->divmin;
757 46 : if (matHAMT->divs > matHAMT->divmax) {
758 22 : matHAMT->divs = matHAMT->divmax;
759 : }
760 : // Check length of cell - reduce number of divisions if necessary
761 46 : Real64 const sin_negPIOvr2 = std::sin(-Constant::Pi / 2.0);
762 : while (true) {
763 46 : testlen = matHAMT->Thickness *
764 46 : ((std::sin(Constant::Pi * (-1.0 / double(matHAMT->divs)) - Constant::Pi / 2.0) / 2.0) - (sin_negPIOvr2 / 2.0));
765 46 : if (testlen > adjdist) {
766 46 : break;
767 : }
768 0 : --matHAMT->divs;
769 0 : if (matHAMT->divs < 1) {
770 0 : ShowSevereError(state, format("{}Construction={}", RoutineName, constr.Name));
771 0 : ShowContinueError(state, format("Reference Material=\"{}\" is too thin.", matHAMT->Name));
772 0 : ++errorCount;
773 0 : break;
774 : }
775 : }
776 46 : s_hbh->TotCellsMax += matHAMT->divs;
777 : }
778 13 : s_hbh->TotCellsMax += 7;
779 : }
780 :
781 3 : if (errorCount > 0) {
782 0 : ShowFatalError(state, "CombinedHeatAndMoistureFiniteElement: Incomplete data to start solution, program terminates.");
783 : }
784 :
785 : // Make the cells and initialize
786 3 : s_hbh->cells.allocate(s_hbh->TotCellsMax);
787 440 : for (auto &e : s_hbh->cells) {
788 437 : e.adjs = -1;
789 437 : e.adjsl = -1;
790 : }
791 :
792 3 : int cid = 0;
793 :
794 : // Set up surface cell structure
795 27 : for (int sid = 1; sid <= state.dataSurface->TotSurfaces; ++sid) {
796 24 : auto &surf = state.dataSurface->Surface(sid);
797 24 : if (!surf.HeatTransSurf) {
798 2 : continue;
799 : }
800 22 : if (surf.Class == SurfaceClass::Window) {
801 4 : continue;
802 : }
803 18 : if (surf.HeatTransferAlgorithm != DataSurfaces::HeatTransferModel::HAMT) {
804 5 : continue;
805 : }
806 : // Boundary Cells
807 13 : runor = -0.02;
808 : // Air Convection Cell
809 13 : ++cid;
810 13 : s_hbh->firstcell(sid) = cid;
811 13 : s_hbh->ExtConcell(sid) = cid;
812 13 : auto &airConvCell = s_hbh->cells(cid);
813 13 : airConvCell.rh = 0.0;
814 13 : airConvCell.sid = sid;
815 13 : airConvCell.length(1) = 0.01;
816 13 : airConvCell.origin(1) = airConvCell.length(1) / 2.0 + runor;
817 :
818 : // Air Radiation Cell
819 13 : ++cid;
820 13 : s_hbh->ExtRadcell(sid) = cid;
821 13 : auto &airRadCell = s_hbh->cells(cid);
822 13 : airRadCell.rh = 0.0;
823 13 : airRadCell.sid = sid;
824 13 : airRadCell.length(1) = 0.01;
825 13 : airRadCell.origin(1) = airRadCell.length(1) / 2.0 + runor;
826 :
827 : // Sky Cell
828 13 : ++cid;
829 13 : s_hbh->ExtSkycell(sid) = cid;
830 13 : auto &skyCell = s_hbh->cells(cid);
831 13 : skyCell.rh = 0.0;
832 13 : skyCell.sid = sid;
833 13 : skyCell.length(1) = 0.01;
834 13 : skyCell.origin(1) = skyCell.length(1) / 2.0 + runor;
835 :
836 : // Ground Cell
837 13 : ++cid;
838 13 : s_hbh->ExtGrncell(sid) = cid;
839 13 : auto &groundCell = s_hbh->cells(cid);
840 13 : groundCell.rh = 0.0;
841 13 : groundCell.sid = sid;
842 13 : groundCell.length(1) = 0.01;
843 13 : groundCell.origin(1) = groundCell.length(1) / 2.0 + runor;
844 13 : runor += groundCell.length(1);
845 :
846 : // External Virtual Cell
847 13 : ++cid;
848 13 : s_hbh->Extcell(sid) = cid;
849 13 : auto &extVirtCell = s_hbh->cells(cid);
850 13 : extVirtCell.rh = 0.0;
851 13 : extVirtCell.sid = sid;
852 13 : extVirtCell.length(1) = 0.01;
853 13 : extVirtCell.origin(1) = extVirtCell.length(1) / 2.0 + runor;
854 13 : runor += extVirtCell.length(1);
855 :
856 : // Material Cells
857 13 : auto const &constr = state.dataConstruction->Construct(surf.Construction);
858 59 : for (int lid = 1; lid <= constr.TotLayers; ++lid) {
859 46 : auto const *mat = dynamic_cast<const MaterialHAMT *>(s_mat->materials(constr.LayerPoint(lid)));
860 46 : assert(mat != nullptr);
861 :
862 392 : for (int did = 1; did <= mat->divs; ++did) {
863 346 : ++cid;
864 :
865 346 : auto &matCell = s_hbh->cells(cid);
866 346 : matCell.matid = mat->Num;
867 346 : matCell.sid = sid;
868 :
869 346 : matCell.temp = mat->itemp;
870 346 : matCell.tempp1 = mat->itemp;
871 346 : matCell.tempp2 = mat->itemp;
872 :
873 346 : matCell.rh = mat->irh;
874 346 : matCell.rhp1 = mat->irh;
875 346 : matCell.rhp2 = mat->irh;
876 :
877 346 : matCell.density = mat->Density;
878 346 : matCell.spech = mat->SpecHeat;
879 :
880 : // Make cells smaller near the surface
881 692 : matCell.length(1) =
882 346 : mat->Thickness * ((std::sin(Constant::Pi * (-double(did) / double(mat->divs)) - Constant::Pi / 2.0) / 2.0) -
883 346 : (std::sin(Constant::Pi * (-double(did - 1) / double(mat->divs)) - Constant::Pi / 2.0) / 2.0));
884 :
885 346 : matCell.origin(1) = runor + matCell.length(1) / 2.0;
886 346 : runor += matCell.length(1);
887 :
888 346 : matCell.volume = matCell.length(1) * state.dataSurface->Surface(sid).Area;
889 : }
890 : }
891 :
892 : // Interior Virtual Cell
893 13 : ++cid;
894 13 : s_hbh->Intcell(sid) = cid;
895 13 : auto &intVirtCell = s_hbh->cells(cid);
896 13 : intVirtCell.sid = sid;
897 13 : intVirtCell.rh = 0.0;
898 13 : intVirtCell.length(1) = 0.01;
899 13 : intVirtCell.origin(1) = intVirtCell.length(1) / 2.0 + runor;
900 13 : runor += intVirtCell.length(1);
901 :
902 : // Air Convection Cell
903 13 : ++cid;
904 13 : s_hbh->lastcell(sid) = cid;
905 13 : s_hbh->IntConcell(sid) = cid;
906 13 : auto &airConvCell2 = s_hbh->cells(cid);
907 13 : airConvCell2.rh = 0.0;
908 13 : airConvCell2.sid = sid;
909 13 : airConvCell2.length(1) = 0.01;
910 13 : airConvCell2.origin(1) = airConvCell2.length(1) / 2.0 + runor;
911 : }
912 :
913 : // Find adjacent cells.
914 440 : for (int cid1 = 1; cid1 <= s_hbh->TotCellsMax; ++cid1) {
915 81806 : for (int cid2 = 1; cid2 <= s_hbh->TotCellsMax; ++cid2) {
916 81369 : if (cid1 == cid2) {
917 437 : continue;
918 : }
919 :
920 80932 : auto &cell1 = s_hbh->cells(cid1);
921 80932 : auto &cell2 = s_hbh->cells(cid2);
922 :
923 80932 : if (cell1.sid != cell2.sid) {
924 66280 : continue;
925 : }
926 :
927 14652 : Real64 high1 = cell1.origin(1) + cell1.length(1) / 2.0;
928 14652 : Real64 low2 = cell2.origin(1) - cell2.length(1) / 2.0;
929 14652 : if (std::abs(low2 - high1) < adjdist) {
930 424 : int adj1 = 0;
931 835 : for (int ii = 1; ii <= adjmax; ++ii) {
932 835 : ++adj1;
933 835 : if (cell1.adjs(adj1) == -1) {
934 424 : break;
935 : }
936 : }
937 424 : int adj2 = 0;
938 502 : for (int ii = 1; ii <= adjmax; ++ii) {
939 502 : ++adj2;
940 502 : if (cell2.adjs(adj2) == -1) {
941 424 : break;
942 : }
943 : }
944 424 : cell1.adjs(adj1) = cid2;
945 424 : cell2.adjs(adj2) = cid1;
946 :
947 424 : cell1.adjsl(adj1) = adj2;
948 424 : cell2.adjsl(adj2) = adj1;
949 :
950 424 : sid = cell1.sid;
951 424 : cell1.overlap(adj1) = state.dataSurface->Surface(sid).Area;
952 424 : cell2.overlap(adj2) = state.dataSurface->Surface(sid).Area;
953 424 : cell1.dist(adj1) = cell1.length(1) / 2.0;
954 424 : cell2.dist(adj2) = cell2.length(1) / 2.0;
955 : }
956 : }
957 : }
958 :
959 : // Reset surface virtual cell origins and volumes. Initialize report variables.
960 : static constexpr std::string_view Format_1966("! <HAMT cells>, Surface Name, Construction Name, Cell Numbers\n");
961 3 : print(state.files.eio, Format_1966);
962 : static constexpr std::string_view Format_1965("! <HAMT origins>, Surface Name, Construction Name, Cell origins (m) \n");
963 3 : print(state.files.eio, Format_1965);
964 : // cCurrentModuleObject='MaterialProperty:HeatAndMoistureTransfer:*'
965 27 : for (int sid = 1; sid <= state.dataSurface->TotSurfaces; ++sid) {
966 24 : if (!state.dataSurface->Surface(sid).HeatTransSurf) {
967 2 : continue;
968 : }
969 22 : if (state.dataSurface->Surface(sid).Class == SurfaceClass::Window) {
970 4 : continue;
971 : }
972 18 : if (state.dataSurface->Surface(sid).HeatTransferAlgorithm != DataSurfaces::HeatTransferModel::HAMT) {
973 5 : continue;
974 : }
975 13 : s_hbh->cells(s_hbh->Extcell(sid)).origin(1) += s_hbh->cells(s_hbh->Extcell(sid)).length(1) / 2.0;
976 13 : s_hbh->cells(s_hbh->Intcell(sid)).origin(1) -= s_hbh->cells(s_hbh->Intcell(sid)).length(1) / 2.0;
977 13 : s_hbh->cells(s_hbh->Extcell(sid)).volume = 0.0;
978 13 : s_hbh->cells(s_hbh->Intcell(sid)).volume = 0.0;
979 13 : s_hbh->watertot(sid) = 0.0;
980 13 : s_hbh->surfrh(sid) = 0.0;
981 13 : s_hbh->surfextrh(sid) = 0.0;
982 13 : s_hbh->surftemp(sid) = 0.0;
983 13 : s_hbh->surfexttemp(sid) = 0.0;
984 13 : s_hbh->surfvp(sid) = 0.0;
985 26 : SetupOutputVariable(state,
986 : "HAMT Surface Average Water Content Ratio",
987 : Constant::Units::kg_kg,
988 13 : s_hbh->watertot(sid),
989 : OutputProcessor::TimeStepType::Zone,
990 : OutputProcessor::StoreType::Average,
991 13 : state.dataSurface->Surface(sid).Name);
992 26 : SetupOutputVariable(state,
993 : "HAMT Surface Inside Face Temperature",
994 : Constant::Units::C,
995 13 : s_hbh->surftemp(sid),
996 : OutputProcessor::TimeStepType::Zone,
997 : OutputProcessor::StoreType::Average,
998 13 : state.dataSurface->Surface(sid).Name);
999 26 : SetupOutputVariable(state,
1000 : "HAMT Surface Inside Face Relative Humidity",
1001 : Constant::Units::Perc,
1002 13 : s_hbh->surfrh(sid),
1003 : OutputProcessor::TimeStepType::Zone,
1004 : OutputProcessor::StoreType::Average,
1005 13 : state.dataSurface->Surface(sid).Name);
1006 26 : SetupOutputVariable(state,
1007 : "HAMT Surface Inside Face Vapor Pressure",
1008 : Constant::Units::Pa,
1009 13 : s_hbh->surfvp(sid),
1010 : OutputProcessor::TimeStepType::Zone,
1011 : OutputProcessor::StoreType::Average,
1012 13 : state.dataSurface->Surface(sid).Name);
1013 26 : SetupOutputVariable(state,
1014 : "HAMT Surface Outside Face Temperature",
1015 : Constant::Units::C,
1016 13 : s_hbh->surfexttemp(sid),
1017 : OutputProcessor::TimeStepType::Zone,
1018 : OutputProcessor::StoreType::Average,
1019 13 : state.dataSurface->Surface(sid).Name);
1020 26 : SetupOutputVariable(state,
1021 : "HAMT Surface Outside Face Relative Humidity",
1022 : Constant::Units::Perc,
1023 13 : s_hbh->surfextrh(sid),
1024 : OutputProcessor::TimeStepType::Zone,
1025 : OutputProcessor::StoreType::Average,
1026 13 : state.dataSurface->Surface(sid).Name);
1027 :
1028 : // write cell origins to initialization output file
1029 13 : conid = state.dataSurface->Surface(sid).Construction;
1030 13 : print(state.files.eio, "HAMT cells, {},{}", state.dataSurface->Surface(sid).Name, state.dataConstruction->Construct(conid).Name);
1031 385 : for (int concell = 1, concell_end = s_hbh->Intcell(sid) - s_hbh->Extcell(sid) + 1; concell <= concell_end; ++concell) {
1032 372 : print(state.files.eio, ",{:4}", concell);
1033 : }
1034 13 : print(state.files.eio, "\n");
1035 13 : print(state.files.eio, "HAMT origins,{},{}", state.dataSurface->Surface(sid).Name, state.dataConstruction->Construct(conid).Name);
1036 385 : for (int cellid = s_hbh->Extcell(sid); cellid <= s_hbh->Intcell(sid); ++cellid) {
1037 372 : print(state.files.eio, ",{:10.7F}", s_hbh->cells(cellid).origin(1));
1038 : }
1039 13 : print(state.files.eio, "\n");
1040 :
1041 385 : for (int cellid = s_hbh->Extcell(sid), concell = 1; cellid <= s_hbh->Intcell(sid); ++cellid, ++concell) {
1042 1116 : SetupOutputVariable(state,
1043 744 : format("HAMT Surface Temperature Cell {}", concell),
1044 : Constant::Units::C,
1045 372 : s_hbh->cells(cellid).temp,
1046 : OutputProcessor::TimeStepType::Zone,
1047 : OutputProcessor::StoreType::Average,
1048 372 : state.dataSurface->Surface(sid).Name);
1049 : }
1050 385 : for (int cellid = s_hbh->Extcell(sid), concell = 1; cellid <= s_hbh->Intcell(sid); ++cellid, ++concell) {
1051 1116 : SetupOutputVariable(state,
1052 744 : format("HAMT Surface Water Content Cell {}", concell),
1053 : Constant::Units::kg_kg,
1054 372 : s_hbh->cells(cellid).wreport,
1055 : OutputProcessor::TimeStepType::Zone,
1056 : OutputProcessor::StoreType::Average,
1057 372 : state.dataSurface->Surface(sid).Name);
1058 : }
1059 385 : for (int cellid = s_hbh->Extcell(sid), concell = 1; cellid <= s_hbh->Intcell(sid); ++cellid, ++concell) {
1060 1116 : SetupOutputVariable(state,
1061 744 : format("HAMT Surface Relative Humidity Cell {}", concell),
1062 : Constant::Units::Perc,
1063 372 : s_hbh->cells(cellid).rhp,
1064 : OutputProcessor::TimeStepType::Zone,
1065 : OutputProcessor::StoreType::Average,
1066 372 : state.dataSurface->Surface(sid).Name);
1067 : }
1068 : }
1069 :
1070 9 : ScanForReports(state, "Constructions", DoReport, "Constructions");
1071 3 : if (DoReport) {
1072 :
1073 : static constexpr std::string_view Format_108("! <Material Nominal Resistance>, Material Name, Nominal R\n");
1074 2 : print(state.files.eio, Format_108);
1075 :
1076 19 : for (auto const *mat : s_mat->materials) {
1077 : static constexpr std::string_view Format_111("Material Nominal Resistance,{},{:.4R}\n");
1078 17 : print(state.files.eio, Format_111, mat->Name, mat->NominalR);
1079 : }
1080 : }
1081 3 : }
1082 :
1083 353361 : void CalcHeatBalHAMT(EnergyPlusData &state, int const sid, Real64 &SurfTempInTmp, Real64 &TempSurfOutTmp)
1084 : {
1085 : // SUBROUTINE INFORMATION:
1086 : // AUTHOR Phillip Biddulph
1087 : // DATE WRITTEN June 2008
1088 : // MODIFIED na
1089 : // RE-ENGINEERED na
1090 :
1091 : // PURPOSE OF THIS SUBROUTINE:
1092 : // To calculate the heat and moisture transfer through the surface
1093 :
1094 : // Using/Aliasing
1095 : using DataSurfaces::OtherSideCondModeledExt;
1096 :
1097 : // Locals
1098 : // SUBROUTINE ARGUMENT DEFINITIONS:
1099 :
1100 : // SUBROUTINE PARAMETER DEFINITIONS:
1101 353367 : static std::string const HAMTExt("HAMT-Ext");
1102 353367 : static std::string const HAMTInt("HAMT-Int");
1103 :
1104 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1105 : Real64 SurfTempInP;
1106 : Real64 RhoIn;
1107 : Real64 RhoOut;
1108 : Real64 torsum;
1109 : Real64 oorsum;
1110 : Real64 phioosum;
1111 : Real64 phiorsum;
1112 : Real64 vpoosum;
1113 : Real64 vporsum;
1114 : Real64 rhr1;
1115 : Real64 rhr2;
1116 : Real64 wcap;
1117 : Real64 thermr1;
1118 : Real64 thermr2;
1119 : Real64 tcap;
1120 : Real64 qvp;
1121 : Real64 vaporr1;
1122 : Real64 vaporr2;
1123 : Real64 vpdiff;
1124 : Real64 sumtp1;
1125 : Real64 tempmax;
1126 : Real64 tempmin;
1127 :
1128 : int itter;
1129 :
1130 : Real64 denominator;
1131 :
1132 353361 : auto &s_mat = state.dataMaterial;
1133 353361 : auto &s_hbh = state.dataHeatBalHAMTMgr;
1134 :
1135 353361 : if (state.dataGlobal->BeginEnvrnFlag && s_hbh->MyEnvrnFlag(sid)) {
1136 118 : auto &extCell = s_hbh->cells(s_hbh->Extcell(sid));
1137 118 : extCell.rh = 0.0;
1138 118 : extCell.rhp1 = 0.0;
1139 118 : extCell.rhp2 = 0.0;
1140 :
1141 118 : extCell.temp = 10.0;
1142 118 : extCell.tempp1 = 10.0;
1143 118 : extCell.tempp2 = 10.0;
1144 :
1145 118 : auto &intCell = s_hbh->cells(s_hbh->Intcell(sid));
1146 118 : intCell.rh = 0.0;
1147 118 : intCell.rhp1 = 0.0;
1148 118 : intCell.rhp2 = 0.0;
1149 :
1150 118 : intCell.temp = 10.0;
1151 118 : intCell.tempp1 = 10.0;
1152 118 : intCell.tempp2 = 10.0;
1153 :
1154 3240 : for (int cid = s_hbh->Extcell(sid) + 1; cid <= s_hbh->Intcell(sid) - 1; ++cid) {
1155 3122 : auto &cell = s_hbh->cells(cid);
1156 3122 : auto const *mat = dynamic_cast<const MaterialHAMT *>(s_mat->materials(cell.matid));
1157 3122 : assert(mat != nullptr);
1158 3122 : cell.temp = mat->itemp;
1159 3122 : cell.tempp1 = mat->itemp;
1160 3122 : cell.tempp2 = mat->itemp;
1161 :
1162 3122 : cell.rh = mat->irh;
1163 3122 : cell.rhp1 = mat->irh;
1164 3122 : cell.rhp2 = mat->irh;
1165 : }
1166 118 : s_hbh->MyEnvrnFlag(sid) = false;
1167 : }
1168 353361 : if (!state.dataGlobal->BeginEnvrnFlag) {
1169 352751 : s_hbh->MyEnvrnFlag(sid) = true;
1170 : }
1171 :
1172 353361 : auto &extCell = s_hbh->cells(s_hbh->Extcell(sid));
1173 353361 : auto &extRadCell = s_hbh->cells(s_hbh->ExtRadcell(sid));
1174 353361 : auto &extSkyCell = s_hbh->cells(s_hbh->ExtSkycell(sid));
1175 353361 : auto &extGrnCell = s_hbh->cells(s_hbh->ExtGrncell(sid));
1176 353361 : auto &extConCell = s_hbh->cells(s_hbh->ExtConcell(sid));
1177 :
1178 : // Set all the boundary values
1179 353361 : extRadCell.temp = state.dataMstBal->TempOutsideAirFD(sid);
1180 353361 : extConCell.temp = state.dataMstBal->TempOutsideAirFD(sid);
1181 353361 : Real64 spaceMAT = state.dataZoneTempPredictorCorrector->spaceHeatBalance(state.dataSurface->Surface(sid).spaceNum).MAT;
1182 353361 : if (state.dataSurface->Surface(sid).ExtBoundCond == OtherSideCondModeledExt) {
1183 : // CR8046 switch modeled rad temp for sky temp.
1184 0 : extSkyCell.temp = state.dataSurface->OSCM(state.dataSurface->Surface(sid).OSCMPtr).TRad;
1185 0 : extCell.Qadds = 0.0; // eliminate incident shortwave on underlying surface
1186 : } else {
1187 353361 : extSkyCell.temp = state.dataEnvrn->SkyTemp;
1188 353361 : extCell.Qadds = state.dataSurface->Surface(sid).Area * state.dataHeatBalSurf->SurfOpaqQRadSWOutAbs(sid);
1189 : }
1190 :
1191 353361 : extGrnCell.temp = state.dataMstBal->TempOutsideAirFD(sid);
1192 353361 : RhoOut = state.dataMstBal->RhoVaporAirOut(sid);
1193 :
1194 : // Special case when the surface is an internal mass
1195 353361 : if (state.dataSurface->Surface(sid).ExtBoundCond == sid) {
1196 0 : extConCell.temp = spaceMAT;
1197 0 : RhoOut = state.dataMstBal->RhoVaporAirIn(sid);
1198 : }
1199 :
1200 353361 : RhoIn = state.dataMstBal->RhoVaporAirIn(sid);
1201 :
1202 353361 : extRadCell.htc = state.dataMstBal->HAirFD(sid);
1203 353361 : extConCell.htc = state.dataMstBal->HConvExtFD(sid);
1204 353361 : extSkyCell.htc = state.dataMstBal->HSkyFD(sid);
1205 353361 : extGrnCell.htc = state.dataMstBal->HGrndFD(sid);
1206 :
1207 353361 : auto &intCell = s_hbh->cells(s_hbh->Intcell(sid));
1208 353361 : auto &intConCell = s_hbh->cells(s_hbh->IntConcell(sid));
1209 :
1210 353361 : intConCell.temp = spaceMAT;
1211 353361 : intConCell.htc = state.dataMstBal->HConvInFD(sid);
1212 :
1213 353361 : intCell.Qadds = state.dataSurface->Surface(sid).Area *
1214 353361 : (state.dataHeatBalSurf->SurfOpaqQRadSWInAbs(sid) + state.dataHeatBalSurf->SurfQdotRadNetLWInPerArea(sid) +
1215 353361 : state.dataHeatBalSurf->SurfQdotRadHVACInPerArea(sid) + state.dataHeatBal->SurfQdotRadIntGainsInPerArea(sid) +
1216 353361 : state.dataHeatBalSurf->SurfQAdditionalHeatSourceInside(sid));
1217 :
1218 353361 : extConCell.rh = PsyRhFnTdbRhov(state, extConCell.temp, RhoOut, HAMTExt);
1219 353361 : intConCell.rh = PsyRhFnTdbRhov(state, intConCell.temp, RhoIn, HAMTInt);
1220 :
1221 353361 : if (extConCell.rh > rhmax) {
1222 0 : extConCell.rh = rhmax;
1223 : }
1224 353361 : if (intConCell.rh > rhmax) {
1225 0 : intConCell.rh = rhmax;
1226 : }
1227 :
1228 : // PDB August 2009 Start! Correction for when no vapour transfer coefficient have been defined.
1229 353361 : if (s_hbh->extvtcflag(sid)) {
1230 312288 : extConCell.vtc = s_hbh->extvtc(sid);
1231 : } else {
1232 41073 : if (extConCell.rh > 0) {
1233 41073 : extConCell.vtc =
1234 41073 : state.dataMstBal->HMassConvExtFD(sid) * RhoOut / (PsyPsatFnTemp(state, state.dataMstBal->TempOutsideAirFD(sid)) * extConCell.rh);
1235 : } else {
1236 0 : extConCell.vtc = 10000.0;
1237 : }
1238 : }
1239 :
1240 353361 : if (s_hbh->intvtcflag(sid)) {
1241 312288 : intConCell.vtc = s_hbh->intvtc(sid);
1242 312288 : state.dataMstBal->HMassConvInFD(sid) = intConCell.vtc * PsyPsatFnTemp(state, spaceMAT) * intConCell.rh / RhoIn;
1243 : } else {
1244 41073 : if (intConCell.rh > 0) {
1245 41073 : intConCell.vtc = state.dataMstBal->HMassConvInFD(sid) * RhoIn / (PsyPsatFnTemp(state, spaceMAT) * intConCell.rh);
1246 : } else {
1247 0 : intConCell.vtc = 10000.0;
1248 : }
1249 : }
1250 : // PDB August 2009 End
1251 :
1252 : // Initialise
1253 1766805 : for (int cid = s_hbh->firstcell(sid); cid <= s_hbh->Extcell(sid) - 1; ++cid) {
1254 1413444 : auto &cell = s_hbh->cells(cid);
1255 1413444 : cell.tempp1 = cell.temp;
1256 1413444 : cell.tempp2 = cell.temp;
1257 1413444 : cell.rhp1 = cell.rh;
1258 1413444 : cell.rhp2 = cell.rh;
1259 : }
1260 706722 : for (int cid = s_hbh->Intcell(sid) + 1; cid <= s_hbh->lastcell(sid); ++cid) {
1261 353361 : auto &cell = s_hbh->cells(cid);
1262 353361 : cell.tempp1 = cell.temp;
1263 353361 : cell.tempp2 = cell.temp;
1264 353361 : cell.rhp1 = cell.rh;
1265 353361 : cell.rhp2 = cell.rh;
1266 : }
1267 :
1268 353361 : itter = 0;
1269 : while (true) {
1270 1397700 : ++itter;
1271 : // Update Moisture values
1272 :
1273 49373897 : for (int cid = s_hbh->firstcell(sid); cid <= s_hbh->lastcell(sid); ++cid) {
1274 47976197 : auto &cell = s_hbh->cells(cid);
1275 47976197 : cell.vp = RHtoVP(state, cell.rh, cell.temp);
1276 47976197 : cell.vpp1 = RHtoVP(state, cell.rhp1, cell.tempp1);
1277 47976197 : cell.vpsat = PsyPsatFnTemp(state, cell.tempp1);
1278 47976197 : if (cell.matid > 0) {
1279 38192297 : auto const *mat = dynamic_cast<const MaterialHAMT *>(s_mat->materials(cell.matid));
1280 38192297 : assert(mat != nullptr);
1281 38192297 : interp(mat->niso, mat->isorh, mat->isodata, cell.rhp1, cell.water, cell.dwdphi);
1282 38192297 : if (state.dataEnvrn->IsRain && s_hbh->rainswitch) {
1283 0 : interp(mat->nsuc, mat->sucwater, mat->sucdata, cell.water, cell.dw);
1284 : } else {
1285 38192297 : interp(mat->nred, mat->redwater, mat->reddata, cell.water, cell.dw);
1286 : }
1287 38192297 : interp(mat->nmu, mat->murh, mat->mudata, cell.rhp1, cell.mu);
1288 38192297 : interp(mat->ntc, mat->tcwater, mat->tcdata, cell.water, cell.wthermalc);
1289 : }
1290 : }
1291 :
1292 : // Calculate Heat and Vapor resistances,
1293 42385397 : for (int cid = s_hbh->Extcell(sid); cid <= s_hbh->Intcell(sid); ++cid) {
1294 40987697 : torsum = 0.0;
1295 40987697 : oorsum = 0.0;
1296 40987697 : vpdiff = 0.0;
1297 40987697 : auto &cell = s_hbh->cells(cid);
1298 127156191 : for (int ii = 1; ii <= adjmax; ++ii) {
1299 127156191 : int adj = cell.adjs(ii);
1300 127156191 : int adjl = cell.adjsl(ii);
1301 127156191 : if (adj == -1) {
1302 40987697 : break;
1303 : }
1304 :
1305 86168494 : if (cell.htc > 0) {
1306 0 : thermr1 = 1.0 / (cell.overlap(ii) * cell.htc);
1307 86168494 : } else if (cell.matid > 0) {
1308 76384594 : thermr1 = cell.dist(ii) / (cell.overlap(ii) * cell.wthermalc);
1309 : } else {
1310 9783900 : thermr1 = 0.0;
1311 : }
1312 :
1313 86168494 : if (cell.vtc > 0) {
1314 0 : vaporr1 = 1.0 / (cell.overlap(ii) * cell.vtc);
1315 86168494 : } else if (cell.matid > 0) {
1316 76384594 : vaporr1 = (cell.dist(ii) * cell.mu) / (cell.overlap(ii) * WVDC(cell.tempp1, state.dataEnvrn->OutBaroPress));
1317 : } else {
1318 9783900 : vaporr1 = 0.0;
1319 : }
1320 :
1321 86168494 : auto &adjCell = s_hbh->cells(adj);
1322 86168494 : if (adjCell.htc > 0) {
1323 6082962 : thermr2 = 1.0 / (cell.overlap(ii) * adjCell.htc);
1324 80085532 : } else if (adjCell.matid > 0) {
1325 76384594 : thermr2 = adjCell.dist(adjl) / (cell.overlap(ii) * adjCell.wthermalc);
1326 : } else {
1327 3700938 : thermr2 = 0.0;
1328 : }
1329 :
1330 86168494 : if (adjCell.vtc > 0) {
1331 2795400 : vaporr2 = 1.0 / (cell.overlap(ii) * adjCell.vtc);
1332 83373094 : } else if (adjCell.matid > 0) {
1333 76384594 : vaporr2 = adjCell.mu * adjCell.dist(adjl) / (WVDC(adjCell.tempp1, state.dataEnvrn->OutBaroPress) * cell.overlap(ii));
1334 : } else {
1335 6988500 : vaporr2 = 0.0;
1336 : }
1337 :
1338 86168494 : if (thermr1 + thermr2 > 0) {
1339 85262956 : oorsum += 1.0 / (thermr1 + thermr2);
1340 85262956 : torsum += adjCell.tempp1 / (thermr1 + thermr2);
1341 : }
1342 86168494 : if (vaporr1 + vaporr2 > 0) {
1343 81975394 : vpdiff += (adjCell.vp - cell.vp) / (vaporr1 + vaporr2);
1344 : }
1345 : }
1346 :
1347 : // Calculate Heat Capacitance
1348 40987697 : tcap = ((cell.density * cell.spech + cell.water * wspech) * cell.volume);
1349 :
1350 : // calculate the latent heat if wanted and check for divergence
1351 40987697 : qvp = 0.0;
1352 40987697 : if ((cell.matid > 0) && (s_hbh->latswitch)) {
1353 38192297 : qvp = vpdiff * whv;
1354 : }
1355 40987697 : if (std::abs(qvp) > qvplim) {
1356 0 : if (!state.dataGlobal->WarmupFlag) {
1357 0 : ++s_hbh->qvpErrCount;
1358 0 : if (s_hbh->qvpErrCount < 16) {
1359 0 : ShowWarningError(
1360 0 : state, format("HeatAndMoistureTransfer: Large Latent Heat for Surface {}", state.dataSurface->Surface(sid).Name));
1361 : } else {
1362 0 : ShowRecurringWarningErrorAtEnd(state, "HeatAndMoistureTransfer: Large Latent Heat Errors ", s_hbh->qvpErrReport);
1363 : }
1364 : }
1365 0 : qvp = 0.0;
1366 : }
1367 :
1368 : // Calculate the temperature for the next time step
1369 40987697 : cell.tempp1 = (torsum + qvp + cell.Qadds + (tcap * cell.temp / s_hbh->deltat)) / (oorsum + (tcap / s_hbh->deltat));
1370 : }
1371 :
1372 : // Check for silly temperatures
1373 1397700 : tempmax = maxval(s_hbh->cells, &subcell::tempp1);
1374 1397700 : tempmin = minval(s_hbh->cells, &subcell::tempp1);
1375 1397700 : if (tempmax > state.dataHeatBalSurf->MaxSurfaceTempLimit) {
1376 0 : if (!state.dataGlobal->WarmupFlag) {
1377 0 : if (state.dataSurface->SurfHighTempErrCount(sid) == 0) {
1378 0 : ShowSevereMessage(
1379 : state,
1380 0 : format("HAMT: Temperature (high) out of bounds ({:.2R}) for surface={}", tempmax, state.dataSurface->Surface(sid).Name));
1381 0 : ShowContinueErrorTimeStamp(state, "");
1382 : }
1383 0 : ShowRecurringWarningErrorAtEnd(state,
1384 0 : "HAMT: Temperature Temperature (high) out of bounds; Surface=" +
1385 0 : state.dataSurface->Surface(sid).Name,
1386 0 : state.dataSurface->SurfHighTempErrCount(sid),
1387 : tempmax,
1388 : tempmax,
1389 : _,
1390 : "C",
1391 : "C");
1392 : }
1393 : }
1394 1397700 : if (tempmax > state.dataHeatBalSurf->MaxSurfaceTempLimitBeforeFatal) {
1395 0 : if (!state.dataGlobal->WarmupFlag) {
1396 0 : ShowSevereError(state,
1397 0 : format("HAMT: HAMT: Temperature (high) out of bounds ( {:.2R}) for surface={}",
1398 : tempmax,
1399 0 : state.dataSurface->Surface(sid).Name));
1400 0 : ShowContinueErrorTimeStamp(state, "");
1401 0 : ShowFatalError(state, "Program terminates due to preceding condition.");
1402 : }
1403 : }
1404 1397700 : if (tempmin < MinSurfaceTempLimit) {
1405 0 : if (!state.dataGlobal->WarmupFlag) {
1406 0 : if (state.dataSurface->SurfHighTempErrCount(sid) == 0) {
1407 0 : ShowSevereMessage(
1408 : state,
1409 0 : format("HAMT: Temperature (low) out of bounds ({:.2R}) for surface={}", tempmin, state.dataSurface->Surface(sid).Name));
1410 0 : ShowContinueErrorTimeStamp(state, "");
1411 : }
1412 0 : ShowRecurringWarningErrorAtEnd(state,
1413 0 : "HAMT: Temperature Temperature (high) out of bounds; Surface=" +
1414 0 : state.dataSurface->Surface(sid).Name,
1415 0 : state.dataSurface->SurfHighTempErrCount(sid),
1416 : tempmin,
1417 : tempmin,
1418 : _,
1419 : "C",
1420 : "C");
1421 : }
1422 : }
1423 1397700 : if (tempmin < MinSurfaceTempLimitBeforeFatal) {
1424 0 : if (!state.dataGlobal->WarmupFlag) {
1425 0 : ShowSevereError(state,
1426 0 : format("HAMT: HAMT: Temperature (low) out of bounds ( {:.2R}) for surface={}",
1427 : tempmin,
1428 0 : state.dataSurface->Surface(sid).Name));
1429 0 : ShowContinueErrorTimeStamp(state, "");
1430 0 : ShowFatalError(state, "Program terminates due to preceding condition.");
1431 : }
1432 : }
1433 :
1434 : // Calculate the liquid and vapor resisitances
1435 42385397 : for (int cid = s_hbh->Extcell(sid); cid <= s_hbh->Intcell(sid); ++cid) {
1436 40987697 : phioosum = 0.0;
1437 40987697 : phiorsum = 0.0;
1438 40987697 : vpoosum = 0.0;
1439 40987697 : vporsum = 0.0;
1440 :
1441 40987697 : auto &cell = s_hbh->cells(cid);
1442 127156191 : for (int ii = 1; ii <= adjmax; ++ii) {
1443 127156191 : int adj = cell.adjs(ii);
1444 127156191 : int adjl = cell.adjsl(ii);
1445 127156191 : if (adj == -1) {
1446 40987697 : break;
1447 : }
1448 :
1449 86168494 : if (cell.vtc > 0) {
1450 0 : vaporr1 = 1.0 / (cell.overlap(ii) * cell.vtc);
1451 86168494 : } else if (cell.matid > 0) {
1452 76384594 : vaporr1 = (cell.dist(ii) * cell.mu) / (cell.overlap(ii) * WVDC(cell.tempp1, state.dataEnvrn->OutBaroPress));
1453 : } else {
1454 9783900 : vaporr1 = 0.0;
1455 : }
1456 :
1457 86168494 : auto &adjCell = s_hbh->cells(adj);
1458 86168494 : if (adjCell.vtc > 0) {
1459 2795400 : vaporr2 = 1.0 / (cell.overlap(ii) * adjCell.vtc);
1460 83373094 : } else if (adjCell.matid > 0) {
1461 76384594 : vaporr2 = (adjCell.dist(adjl) * adjCell.mu) / (cell.overlap(ii) * WVDC(adjCell.tempp1, state.dataEnvrn->OutBaroPress));
1462 : } else {
1463 6988500 : vaporr2 = 0.0;
1464 : }
1465 86168494 : if (vaporr1 + vaporr2 > 0) {
1466 81975394 : vpoosum += 1.0 / (vaporr1 + vaporr2);
1467 81975394 : vporsum += (adjCell.vpp1 / (vaporr1 + vaporr2));
1468 : }
1469 :
1470 86168494 : if ((cell.dw > 0) && (cell.dwdphi > 0)) {
1471 44430568 : rhr1 = cell.dist(ii) / (cell.overlap(ii) * cell.dw * cell.dwdphi);
1472 : } else {
1473 41737926 : rhr1 = 0.0;
1474 : }
1475 86168494 : if ((adjCell.dw > 0) && (adjCell.dwdphi > 0)) {
1476 44430568 : rhr2 = adjCell.dist(adjl) / (cell.overlap(ii) * adjCell.dw * adjCell.dwdphi);
1477 : } else {
1478 41737926 : rhr2 = 0.0;
1479 : }
1480 :
1481 : // IF(rhr1+rhr2>0)THEN
1482 86168494 : if (rhr1 * rhr2 > 0) {
1483 39602806 : phioosum += 1.0 / (rhr1 + rhr2);
1484 39602806 : phiorsum += (adjCell.rhp1 / (rhr1 + rhr2));
1485 : }
1486 : }
1487 :
1488 : // Moisture Capacitance
1489 40987697 : if (cell.dwdphi > 0.0) {
1490 38167326 : wcap = cell.dwdphi * cell.volume;
1491 : } else {
1492 2820371 : wcap = 0.0;
1493 : }
1494 :
1495 : // Calculate the RH for the next time step
1496 40987697 : denominator = (phioosum + vpoosum * cell.vpsat + wcap / s_hbh->deltat);
1497 40987697 : if (denominator != 0.0) {
1498 40987697 : cell.rhp1 = (phiorsum + vporsum + (wcap * cell.rh) / s_hbh->deltat) / denominator;
1499 : } else {
1500 0 : ShowSevereError(state, "CalcHeatBalHAMT: demoninator in calculating RH is zero. Check material properties for accuracy.");
1501 0 : ShowContinueError(state, format("...Problem occurs in Material=\"{}\".", s_mat->materials(cell.matid)->Name));
1502 0 : ShowFatalError(state, "Program terminates due to preceding condition.");
1503 : }
1504 :
1505 40987697 : if (cell.rhp1 > rhmax) {
1506 52987 : cell.rhp1 = rhmax;
1507 : }
1508 : }
1509 :
1510 : // Check for convergence or too many itterations
1511 1397700 : sumtp1 = 0.0;
1512 42385397 : for (int cid = s_hbh->Extcell(sid); cid <= s_hbh->Intcell(sid); ++cid) {
1513 40987697 : auto const &cell = s_hbh->cells(cid);
1514 40987697 : if (sumtp1 < std::abs(cell.tempp2 - cell.tempp1)) {
1515 6027736 : sumtp1 = std::abs(cell.tempp2 - cell.tempp1);
1516 : }
1517 : }
1518 1397700 : if (sumtp1 < convt) {
1519 353063 : break;
1520 : }
1521 1044637 : if (itter > ittermax) {
1522 298 : break;
1523 : }
1524 37091235 : for (int cid = s_hbh->firstcell(sid); cid <= s_hbh->lastcell(sid); ++cid) {
1525 36046896 : auto &cell = s_hbh->cells(cid);
1526 36046896 : cell.tempp2 = cell.tempp1;
1527 36046896 : cell.rhp2 = cell.rhp1;
1528 : }
1529 1044339 : }
1530 :
1531 : // report back to CalcHeatBalanceInsideSurf
1532 353361 : TempSurfOutTmp = extCell.tempp1;
1533 353361 : SurfTempInTmp = intCell.tempp1;
1534 :
1535 353361 : SurfTempInP = intCell.rhp1 * PsyPsatFnTemp(state, intCell.tempp1);
1536 :
1537 353361 : state.dataMstBal->RhoVaporSurfIn(sid) = SurfTempInP / (461.52 * (spaceMAT + Constant::Kelvin));
1538 353361 : }
1539 :
1540 171564 : void UpdateHeatBalHAMT(EnergyPlusData &state, int const sid)
1541 : {
1542 : // SUBROUTINE INFORMATION:
1543 : // AUTHOR Phillip Biddulph
1544 : // DATE WRITTEN June 2008
1545 : // MODIFIED na
1546 : // RE-ENGINEERED na
1547 :
1548 : // PURPOSE OF THIS SUBROUTINE:
1549 : // The zone heat balance equation has converged, so now the HAMT values are to be fixed
1550 : // ready for the next itteration.
1551 : // Fill all the report variables
1552 :
1553 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1554 : Real64 watermass;
1555 : Real64 matmass;
1556 : // unused1208 REAL(r64), SAVE :: InOld=0.0D0
1557 : // unused1208 REAL(r64), SAVE :: OutOld=0.0D0
1558 :
1559 171564 : auto &s_hbh = state.dataHeatBalHAMTMgr;
1560 :
1561 : // Update Temperatures and RHs. Calculate report variables
1562 171564 : matmass = 0.0;
1563 171564 : watermass = 0.0;
1564 5927346 : for (int cid = s_hbh->firstcell(sid); cid <= s_hbh->lastcell(sid); ++cid) {
1565 5755782 : auto &cell = s_hbh->cells(cid);
1566 : // fix HAMT values for this surface
1567 5755782 : cell.temp = cell.tempp1;
1568 5755782 : cell.rh = cell.rhp1;
1569 5755782 : cell.rhp = cell.rh * 100.0;
1570 5755782 : if (cell.density > 0.0) {
1571 4554834 : cell.wreport = cell.water / cell.density;
1572 4554834 : watermass += (cell.water * cell.volume);
1573 4554834 : matmass += (cell.density * cell.volume);
1574 : }
1575 : }
1576 :
1577 171564 : s_hbh->watertot(sid) = 0.0;
1578 171564 : if (matmass > 0) {
1579 171564 : s_hbh->watertot(sid) = watermass / matmass;
1580 : }
1581 :
1582 171564 : s_hbh->surfrh(sid) = 100.0 * s_hbh->cells(s_hbh->Intcell(sid)).rh;
1583 171564 : s_hbh->surfextrh(sid) = 100.0 * s_hbh->cells(s_hbh->Extcell(sid)).rh;
1584 171564 : s_hbh->surftemp(sid) = s_hbh->cells(s_hbh->Intcell(sid)).temp;
1585 171564 : s_hbh->surfexttemp(sid) = s_hbh->cells(s_hbh->Extcell(sid)).temp;
1586 171564 : s_hbh->surfvp(sid) = RHtoVP(state, s_hbh->cells(s_hbh->Intcell(sid)).rh, s_hbh->cells(s_hbh->Intcell(sid)).temp);
1587 171564 : }
1588 :
1589 152769234 : void interp(int const ndata,
1590 : const Array1D<Real64> &xx,
1591 : const Array1D<Real64> &yy,
1592 : Real64 const invalue,
1593 : Real64 &outvalue,
1594 : ObjexxFCL::Optional<Real64> outgrad)
1595 : {
1596 : // SUBROUTINE INFORMATION:
1597 : // AUTHOR Phillip Biddulph
1598 : // DATE WRITTEN June 2008
1599 : // MODIFIED na
1600 : // RE-ENGINEERED na
1601 :
1602 : // PURPOSE OF THIS SUBROUTINE:
1603 : // To find a value by searching an array and interpolating between two coordinates
1604 : // Also returns the gradient if required.
1605 :
1606 : // METHODOLOGY EMPLOYED:
1607 : // Simple search
1608 :
1609 : // Argument array dimensioning
1610 152769234 : EP_SIZE_CHECK(xx, ndata);
1611 152769234 : EP_SIZE_CHECK(yy, ndata);
1612 :
1613 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1614 : Real64 xxlow;
1615 : Real64 xxhigh;
1616 : Real64 yylow;
1617 : Real64 yyhigh;
1618 : Real64 mygrad;
1619 :
1620 152769234 : mygrad = 0.0;
1621 152769234 : outvalue = 0.0;
1622 :
1623 152769234 : if (ndata > 1) {
1624 152769234 : xxlow = xx(1);
1625 152769234 : yylow = yy(1);
1626 214872999 : for (int step = 2; step <= ndata; ++step) {
1627 214872999 : xxhigh = xx(step);
1628 214872999 : yyhigh = yy(step);
1629 214872999 : if (invalue <= xxhigh) {
1630 152769234 : break;
1631 : }
1632 62103765 : xxlow = xxhigh;
1633 62103765 : yylow = yyhigh;
1634 : }
1635 :
1636 152769234 : if (xxhigh > xxlow) {
1637 152769234 : mygrad = (yyhigh - yylow) / (xxhigh - xxlow);
1638 152769234 : outvalue = (invalue - xxlow) * mygrad + yylow;
1639 : // PDB August 2009 bug fix
1640 0 : } else if (std::abs(xxhigh - xxlow) < 0.0000000001) {
1641 0 : outvalue = yylow;
1642 : }
1643 : }
1644 :
1645 152769234 : if (present(outgrad)) {
1646 : // return gradient if required
1647 38192297 : outgrad = mygrad;
1648 : }
1649 152769234 : }
1650 :
1651 96123958 : Real64 RHtoVP(EnergyPlusData &state, Real64 const RH, Real64 const Temperature)
1652 : {
1653 : // FUNCTION INFORMATION:
1654 : // AUTHOR Phillip Biddulph
1655 : // DATE WRITTEN June 2008
1656 : // MODIFIED na
1657 : // RE-ENGINEERED na
1658 :
1659 : // PURPOSE OF THIS FUNCTION:
1660 : // Convert Relative Humidity and Temperature to Vapor Pressure
1661 :
1662 : // Return value
1663 : Real64 RHtoVP;
1664 :
1665 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
1666 : Real64 VPSat;
1667 :
1668 96123958 : VPSat = PsyPsatFnTemp(state, Temperature);
1669 :
1670 96123958 : RHtoVP = RH * VPSat;
1671 :
1672 96123958 : return RHtoVP;
1673 : }
1674 :
1675 305538376 : Real64 WVDC(Real64 const Temperature, Real64 const ambp)
1676 : {
1677 : // FUNCTION INFORMATION:
1678 : // AUTHOR Phillip Biddulph
1679 : // DATE WRITTEN June 2008
1680 : // MODIFIED na
1681 : // RE-ENGINEERED na
1682 :
1683 : // PURPOSE OF THIS FUNCTION:
1684 : // To calculate the Water Vapor Diffusion Coefficient in air
1685 : // using the temperature and ambient atmospheric pressor
1686 :
1687 : // REFERENCES:
1688 : // K?zel, H.M. (1995) Simultaneous Heat and Moisture Transport in Building Components.
1689 : // One- and two-dimensional calculation using simple parameters. IRB Verlag 1995
1690 :
1691 : // Return value
1692 : Real64 WVDC;
1693 :
1694 305538376 : WVDC = (2.e-7 * std::pow(Temperature + Constant::Kelvin, 0.81)) / ambp;
1695 :
1696 305538376 : return WVDC;
1697 : }
1698 :
1699 : // COPYRIGHT NOTICE
1700 :
1701 : // Portions Copyright (c) University College London 2007. All rights
1702 : // reserved.
1703 :
1704 : // UCL LEGAL NOTICE
1705 : // Neither UCL, members of UCL nor any person or organisation acting on
1706 : // behalf of either:
1707 :
1708 : // A. Makes any warranty of representation, express or implied with
1709 : // respect to the accuracy, completeness, or usefulness of the
1710 : // information contained in this program, including any warranty of
1711 : // merchantability or fitness of any purpose with respect to the
1712 : // program, or that the use of any information disclosed in this
1713 : // program may not infringe privately-owned rights, or
1714 :
1715 : // B. Assumes any liability with respect to the use of, or for any and
1716 : // all damages resulting from the use of the program or any portion
1717 : // thereof or any information disclosed therein.
1718 :
1719 : } // namespace HeatBalanceHAMTManager
1720 :
1721 : } // namespace EnergyPlus
|