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