Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2023, The Board of Trustees of the University of Illinois,
2 : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
3 : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
4 : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
5 : // contributors. All rights reserved.
6 : //
7 : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
8 : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
9 : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
10 : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
11 : // derivative works, and perform publicly and display publicly, and to permit others to do so.
12 : //
13 : // Redistribution and use in source and binary forms, with or without modification, are permitted
14 : // provided that the following conditions are met:
15 : //
16 : // (1) Redistributions of source code must retain the above copyright notice, this list of
17 : // conditions and the following disclaimer.
18 : //
19 : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
20 : // conditions and the following disclaimer in the documentation and/or other materials
21 : // provided with the distribution.
22 : //
23 : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
24 : // the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
25 : // used to endorse or promote products derived from this software without specific prior
26 : // written permission.
27 : //
28 : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
29 : // without changes from the version obtained under this License, or (ii) Licensee makes a
30 : // reference solely to the software portion of its product, Licensee must refer to the
31 : // software as "EnergyPlus version X" software, where "X" is the version number Licensee
32 : // obtained under this License and may not use a different name for the software. Except as
33 : // specifically required in this Section (4), Licensee shall not use in a company name, a
34 : // product name, in advertising, publicity, or other promotional activities any name, trade
35 : // name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
36 : // similar designation, without the U.S. Department of Energy's prior written consent.
37 : //
38 : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
39 : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
40 : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
41 : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
42 : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
43 : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
44 : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
45 : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
46 : // POSSIBILITY OF SUCH DAMAGE.
47 :
48 : // C++ Headers
49 : #include <cmath>
50 :
51 : // ObjexxFCL Headers
52 : #include <ObjexxFCL/Array.functions.hh>
53 : #include <ObjexxFCL/Fmath.hh>
54 :
55 : // EnergyPlus Headers
56 : #include <EnergyPlus/Construction.hh>
57 : #include <EnergyPlus/Data/EnergyPlusData.hh>
58 : #include <EnergyPlus/DataDaylighting.hh>
59 : #include <EnergyPlus/DataEnvironment.hh>
60 : #include <EnergyPlus/DataHeatBalSurface.hh>
61 : #include <EnergyPlus/DataHeatBalance.hh>
62 : #include <EnergyPlus/DataSurfaces.hh>
63 : #include <EnergyPlus/Material.hh>
64 : #include <EnergyPlus/OutputProcessor.hh>
65 : #include <EnergyPlus/UtilityRoutines.hh>
66 :
67 : namespace EnergyPlus::DataHeatBalance {
68 :
69 : // MODULE INFORMATION:
70 : // AUTHOR Rick Strand
71 : // DATE WRITTEN August 1997 (rewritten)
72 : // MODIFIED Aug-Oct 1997 RKS (added derived types)
73 : // MODIFIED Feb 1999 (FW) Added visible radiation parameters,
74 : // WindowShadingControl type and SurfaceWindowCalc type
75 : // Sep 1999 (FW) Added/modified Window4 gas variables
76 : // Jul 2003 (CC) Added reference temperature variable for air models
77 : // Aug 2003 (FW) Added FractionReturnAirPlenTempCoeff1 and
78 : // FractionReturnAirPlenTempCoeff2 to Type LightsData
79 : // Nov 2003 (FW) Add FullExteriorWithRefl and FullInteriorExteriorWithRefl
80 : // as SolarDistribution values
81 : // Dec 2003 (PGE) Added Zone List and Zone Group; added SNLoad variables
82 : // August 2006 (COP) Added variable k coefficient and PCM enthalpy.
83 : // Dec 2006 (DJS-PSU) Added ecoroof material
84 : // Dec 2008 TH added new properties to MaterialProperties and
85 : // ConstructionData for thermochromic windows
86 : // RE-ENGINEERED na
87 :
88 : // PURPOSE OF THIS MODULE:
89 : // This module should contain the information that is needed to pass
90 : // from the Heat Balance Module and all of the Zone Initializations
91 : // such as ConductionTransferFunction, GlassCalculation,
92 : // SolarShading, etc. Modules.
93 :
94 : // Using/Aliasing
95 : using DataSurfaces::MaxSlatAngs;
96 : using namespace DataVectorTypes;
97 : using DataBSDFWindow::BSDFLayerAbsorpStruct;
98 : using DataBSDFWindow::BSDFWindowInputStruct;
99 :
100 : // Functions
101 :
102 971050 : Real64 SpaceData::sumHATsurf(EnergyPlusData &state)
103 : {
104 : // PURPOSE OF THIS FUNCTION:
105 : // This function calculates the space sum of Hc*Area*Tsurf.
106 :
107 971050 : Real64 sumHATsurf = 0.0;
108 :
109 7999460 : for (int surfNum = this->HTSurfaceFirst; surfNum <= this->HTSurfaceLast; ++surfNum) {
110 7028410 : Real64 Area = state.dataSurface->Surface(surfNum).Area;
111 :
112 7028410 : if (state.dataSurface->Surface(surfNum).Class == DataSurfaces::SurfaceClass::Window) {
113 523860 : if (state.dataSurface->SurfWinDividerArea(surfNum) > 0.0) {
114 0 : if (ANY_INTERIOR_SHADE_BLIND(state.dataSurface->SurfWinShadingFlag(surfNum))) {
115 : // The area is the shade or blind area = sum of the glazing area and the divider area (which is zero if no divider)
116 0 : Area += state.dataSurface->SurfWinDividerArea(surfNum);
117 : } else {
118 : // Window divider contribution (only for window with divider and no interior shade or blind)
119 0 : sumHATsurf += state.dataHeatBalSurf->SurfHConvInt(surfNum) * state.dataSurface->SurfWinDividerArea(surfNum) *
120 0 : (1.0 + 2.0 * state.dataSurface->SurfWinProjCorrDivIn(surfNum)) * state.dataSurface->SurfWinDividerTempIn(surfNum);
121 : }
122 : }
123 :
124 523860 : if (state.dataSurface->SurfWinFrameArea(surfNum) > 0.0) {
125 : // Window frame contribution
126 0 : sumHATsurf += state.dataHeatBalSurf->SurfHConvInt(surfNum) * state.dataSurface->SurfWinFrameArea(surfNum) *
127 0 : (1.0 + state.dataSurface->SurfWinProjCorrFrIn(surfNum)) * state.dataSurface->SurfWinFrameTempIn(surfNum);
128 : }
129 : }
130 :
131 7028410 : sumHATsurf += state.dataHeatBalSurf->SurfHConvInt(surfNum) * Area * state.dataHeatBalSurf->SurfTempInTmp(surfNum);
132 : }
133 :
134 971050 : return sumHATsurf;
135 : }
136 :
137 971050 : Real64 ZoneData::sumHATsurf(EnergyPlusData &state)
138 : {
139 971050 : Real64 sumHATsurf = 0.0;
140 1942100 : for (int spaceNum : this->spaceIndexes) {
141 971050 : sumHATsurf += state.dataHeatBal->space(spaceNum).sumHATsurf(state);
142 : }
143 971050 : return sumHATsurf;
144 : }
145 18450203 : void ZoneData::SetOutBulbTempAt(EnergyPlusData &state)
146 : {
147 : // SUBROUTINE INFORMATION:
148 : // AUTHOR Noel Keen (LBL)/Linda Lawrie
149 : // DATE WRITTEN August 2010
150 : // MODIFIED na
151 : // RE-ENGINEERED na
152 :
153 : // PURPOSE OF THIS SUBROUTINE:
154 : // Routine provides facility for doing bulk Set Temperature at Height.
155 :
156 18450203 : if (state.dataEnvrn->SiteTempGradient == 0.0) {
157 0 : OutDryBulbTemp = state.dataEnvrn->OutDryBulbTemp;
158 0 : OutWetBulbTemp = state.dataEnvrn->OutWetBulbTemp;
159 : } else {
160 : // Base temperatures at Z = 0 (C)
161 18450203 : Real64 const BaseDryTemp(state.dataEnvrn->OutDryBulbTemp + state.dataEnvrn->WeatherFileTempModCoeff);
162 18450203 : Real64 const BaseWetTemp(state.dataEnvrn->OutWetBulbTemp + state.dataEnvrn->WeatherFileTempModCoeff);
163 :
164 18450203 : Real64 const Z(Centroid.z); // Centroid value
165 18450203 : if (Z <= 0.0) {
166 201105 : OutDryBulbTemp = BaseDryTemp;
167 201105 : OutWetBulbTemp = BaseWetTemp;
168 : } else {
169 18249098 : OutDryBulbTemp = BaseDryTemp - state.dataEnvrn->SiteTempGradient * DataEnvironment::EarthRadius * Z / (DataEnvironment::EarthRadius + Z);
170 18249098 : OutWetBulbTemp = BaseWetTemp - state.dataEnvrn->SiteTempGradient * DataEnvironment::EarthRadius * Z / (DataEnvironment::EarthRadius + Z);
171 : }
172 : }
173 18450203 : }
174 :
175 18445389 : void ZoneData::SetWindSpeedAt(EnergyPlusData &state, Real64 const fac)
176 : {
177 : // SUBROUTINE INFORMATION:
178 : // AUTHOR Linda Lawrie
179 : // DATE WRITTEN June 2013
180 : // MODIFIED na
181 : // RE-ENGINEERED na
182 :
183 : // PURPOSE OF THIS SUBROUTINE:
184 : // Routine provides facility for doing bulk Set Windspeed at Height.
185 :
186 18445389 : if (state.dataEnvrn->SiteWindExp == 0.0) {
187 0 : WindSpeed = state.dataEnvrn->WindSpeed;
188 : } else {
189 18445389 : Real64 const Z(Centroid.z); // Centroid value
190 18445389 : if (Z <= 0.0) {
191 201054 : WindSpeed = 0.0;
192 : } else {
193 : // [Met] - at meterological Station, Height of measurement is usually 10m above ground
194 : // LocalWindSpeed = Windspeed [Met] * (Wind Boundary LayerThickness [Met]/Height [Met])**Wind Exponent[Met] &
195 : // * (Height above ground / Site Wind Boundary Layer Thickness) ** Site Wind Exponent
196 18244335 : WindSpeed = fac * std::pow(Z, state.dataEnvrn->SiteWindExp);
197 : }
198 : }
199 18445389 : }
200 :
201 18445389 : void ZoneData::SetWindDirAt(Real64 const fac)
202 : {
203 18445389 : WindDir = fac;
204 18445389 : }
205 :
206 4820 : void AirReportVars::setUpOutputVars(EnergyPlusData &state, std::string_view prefix, std::string_view name)
207 : {
208 14460 : SetupOutputVariable(state,
209 9640 : format("{} Mean Air Temperature", prefix),
210 : OutputProcessor::Unit::C,
211 : this->MeanAirTemp,
212 : OutputProcessor::SOVTimeStepType::Zone,
213 : OutputProcessor::SOVStoreType::Average,
214 : name);
215 14460 : SetupOutputVariable(state,
216 9640 : format("{} Operative Temperature", prefix),
217 : OutputProcessor::Unit::C,
218 : this->OperativeTemp,
219 : OutputProcessor::SOVTimeStepType::Zone,
220 : OutputProcessor::SOVStoreType::Average,
221 : name);
222 14460 : SetupOutputVariable(state,
223 9640 : format("{} Mean Air Dewpoint Temperature", prefix),
224 : OutputProcessor::Unit::C,
225 : this->MeanAirDewPointTemp,
226 : OutputProcessor::SOVTimeStepType::Zone,
227 : OutputProcessor::SOVStoreType::Average,
228 : name);
229 14460 : SetupOutputVariable(state,
230 9640 : format("{} Mean Air Humidity Ratio", prefix),
231 : OutputProcessor::Unit::kgWater_kgDryAir,
232 : this->MeanAirHumRat,
233 : OutputProcessor::SOVTimeStepType::Zone,
234 : OutputProcessor::SOVStoreType::Average,
235 : name);
236 14460 : SetupOutputVariable(state,
237 9640 : format("{} Air Heat Balance Internal Convective Heat Gain Rate", prefix),
238 : OutputProcessor::Unit::W,
239 : this->SumIntGains,
240 : OutputProcessor::SOVTimeStepType::System,
241 : OutputProcessor::SOVStoreType::Average,
242 : name);
243 14460 : SetupOutputVariable(state,
244 9640 : format("{} Air Heat Balance Surface Convection Rate", prefix),
245 : OutputProcessor::Unit::W,
246 : this->SumHADTsurfs,
247 : OutputProcessor::SOVTimeStepType::System,
248 : OutputProcessor::SOVStoreType::Average,
249 : name);
250 14460 : SetupOutputVariable(state,
251 9640 : format("{} Air Heat Balance Interzone Air Transfer Rate", prefix),
252 : OutputProcessor::Unit::W,
253 : this->SumMCpDTzones,
254 : OutputProcessor::SOVTimeStepType::System,
255 : OutputProcessor::SOVStoreType::Average,
256 : name);
257 14460 : SetupOutputVariable(state,
258 9640 : format("{} Air Heat Balance Outdoor Air Transfer Rate", prefix),
259 : OutputProcessor::Unit::W,
260 : this->SumMCpDtInfil,
261 : OutputProcessor::SOVTimeStepType::System,
262 : OutputProcessor::SOVStoreType::Average,
263 : name);
264 14460 : SetupOutputVariable(state,
265 9640 : format("{} Air Heat Balance System Air Transfer Rate", prefix),
266 : OutputProcessor::Unit::W,
267 : this->SumMCpDTsystem,
268 : OutputProcessor::SOVTimeStepType::System,
269 : OutputProcessor::SOVStoreType::Average,
270 : name);
271 14460 : SetupOutputVariable(state,
272 9640 : format("{} Air Heat Balance System Convective Heat Gain Rate", prefix),
273 : OutputProcessor::Unit::W,
274 : this->SumNonAirSystem,
275 : OutputProcessor::SOVTimeStepType::System,
276 : OutputProcessor::SOVStoreType::Average,
277 : name);
278 14460 : SetupOutputVariable(state,
279 9640 : format("{} Air Heat Balance Air Energy Storage Rate", prefix),
280 : OutputProcessor::Unit::W,
281 : this->CzdTdt,
282 : OutputProcessor::SOVTimeStepType::System,
283 : OutputProcessor::SOVStoreType::Average,
284 : name);
285 4820 : if (state.dataGlobal->DisplayAdvancedReportVariables) {
286 171 : SetupOutputVariable(state,
287 114 : format("{} Air Heat Balance Deviation Rate", prefix),
288 : OutputProcessor::Unit::W,
289 : this->imBalance,
290 : OutputProcessor::SOVTimeStepType::System,
291 : OutputProcessor::SOVStoreType::Average,
292 : name);
293 : }
294 4820 : }
295 :
296 2569084 : void SetZoneOutBulbTempAt(EnergyPlusData &state)
297 : {
298 21019287 : for (auto &zone : state.dataHeatBal->Zone) {
299 18450203 : zone.SetOutBulbTempAt(state);
300 : }
301 2569084 : }
302 :
303 2569084 : void CheckZoneOutBulbTempAt(EnergyPlusData &state)
304 : {
305 : // Using/Aliasing
306 : using DataEnvironment::SetOutBulbTempAt_error;
307 :
308 2569084 : Real64 minBulb = 0.0;
309 21019287 : for (auto &zone : state.dataHeatBal->Zone) {
310 18450203 : minBulb = min(minBulb, zone.OutDryBulbTemp, zone.OutWetBulbTemp);
311 18450203 : if (minBulb < -100.0) SetOutBulbTempAt_error(state, "Zone", zone.Centroid.z, zone.Name);
312 : }
313 2569084 : }
314 :
315 2568313 : void SetZoneWindSpeedAt(EnergyPlusData &state)
316 : {
317 2568313 : Real64 const fac(state.dataEnvrn->WindSpeed * state.dataEnvrn->WeatherFileWindModCoeff *
318 2568313 : std::pow(state.dataEnvrn->SiteWindBLHeight, -state.dataEnvrn->SiteWindExp));
319 21013702 : for (auto &zone : state.dataHeatBal->Zone) {
320 18445389 : zone.SetWindSpeedAt(state, fac);
321 : }
322 2568313 : }
323 :
324 2568313 : void SetZoneWindDirAt(EnergyPlusData &state)
325 : {
326 : // Using/Aliasing
327 2568313 : Real64 const fac(state.dataEnvrn->WindDir);
328 21013702 : for (auto &zone : state.dataHeatBal->Zone) {
329 18445389 : zone.SetWindDirAt(fac);
330 : }
331 2568313 : }
332 :
333 5827 : void CheckAndSetConstructionProperties(EnergyPlusData &state,
334 : int const ConstrNum, // Construction number to be set/checked
335 : bool &ErrorsFound // error flag that is set when certain errors have occurred
336 : )
337 : {
338 :
339 : // SUBROUTINE INFORMATION:
340 : // AUTHOR Linda Lawrie
341 : // DATE WRITTEN December 2006
342 :
343 : // This routine checks some properties of entered constructions; sets some properties; and sets
344 : // an error flag for certain error conditions.
345 :
346 : int InsideLayer; // Inside Layer of Construct; for window construct, layer no. of inside glass
347 : int MaterNum; // Counters to keep track of the material number for a layer
348 : int OutsideMaterNum; // Material "number" of the Outside layer
349 : int InsideMaterNum; // Material "number" of the Inside layer
350 : int Layer; // loop index for each of the construction layers
351 : int TotLayers; // Number of layers in a construction
352 : int TotGlassLayers; // Number of glass layers in a construction
353 : int TotShadeLayers; // Number of shade layers in a construction
354 : int TotGasLayers; // Number of gas layers in a construction
355 : bool WrongMaterialsMix; // True if window construction has a layer that is not glass, gas or shade
356 : bool WrongWindowLayering; // True if error in layering of a window construction
357 : int MaterNumNext; // Next material number in the layer sequence
358 : int IGas; // Index for gases in a mixture of gases in a window gap
359 : int LayNumSh; // Number of shade/blind layer in a construction
360 : int MatSh; // Material number of a shade/blind layer
361 : int MatGapL; // Material number of the gas layer to the left (outer side) of a shade/blind layer
362 : int MatGapR; // Material number of the gas layer to the right (innner side) of a shade/blind layer
363 : int BlNum; // Blind number
364 : bool ValidBGShadeBlindConst; // True if a valid window construction with between-glass shade/blind
365 : int GlassLayNum; // Glass layer number
366 :
367 5827 : TotLayers = state.dataConstruction->Construct(ConstrNum).TotLayers;
368 5827 : if (TotLayers == 0) return; // error condition, hopefully caught elsewhere
369 5827 : InsideLayer = TotLayers;
370 5827 : if (state.dataConstruction->Construct(ConstrNum).LayerPoint(InsideLayer) <= 0) return; // Error condition
371 :
372 : // window screen is not allowed on inside layer
373 :
374 5827 : state.dataConstruction->Construct(ConstrNum).DayltPropPtr = 0;
375 5827 : InsideMaterNum = state.dataConstruction->Construct(ConstrNum).LayerPoint(InsideLayer);
376 5827 : if (InsideMaterNum != 0) {
377 5827 : state.dataConstruction->Construct(ConstrNum).InsideAbsorpVis = state.dataMaterial->Material(InsideMaterNum).AbsorpVisible;
378 5827 : state.dataConstruction->Construct(ConstrNum).InsideAbsorpSolar = state.dataMaterial->Material(InsideMaterNum).AbsorpSolar;
379 :
380 : // Following line applies only to opaque surfaces; it is recalculated later for windows.
381 5827 : state.dataConstruction->Construct(ConstrNum).ReflectVisDiffBack = 1.0 - state.dataMaterial->Material(InsideMaterNum).AbsorpVisible;
382 : }
383 :
384 5827 : OutsideMaterNum = state.dataConstruction->Construct(ConstrNum).LayerPoint(1);
385 5827 : if (OutsideMaterNum != 0) {
386 5827 : state.dataConstruction->Construct(ConstrNum).OutsideAbsorpVis = state.dataMaterial->Material(OutsideMaterNum).AbsorpVisible;
387 5827 : state.dataConstruction->Construct(ConstrNum).OutsideAbsorpSolar = state.dataMaterial->Material(OutsideMaterNum).AbsorpSolar;
388 : }
389 :
390 5827 : state.dataConstruction->Construct(ConstrNum).TotSolidLayers = 0;
391 5827 : state.dataConstruction->Construct(ConstrNum).TotGlassLayers = 0;
392 5827 : state.dataConstruction->Construct(ConstrNum).AbsDiffShade = 0.0;
393 :
394 : // Check if any layer is glass, gas, shade, screen or blind; if so it is considered a window construction for
395 : // purposes of error checking.
396 :
397 5827 : state.dataConstruction->Construct(ConstrNum).TypeIsWindow = false;
398 19518 : for (Layer = 1; Layer <= TotLayers; ++Layer) {
399 13691 : MaterNum = state.dataConstruction->Construct(ConstrNum).LayerPoint(Layer);
400 13691 : if (MaterNum == 0) continue; // error -- has been caught will stop program later
401 13691 : switch (state.dataMaterial->Material(MaterNum).Group) {
402 2606 : case DataHeatBalance::MaterialGroup::WindowGlass:
403 : case DataHeatBalance::MaterialGroup::WindowGas:
404 : case DataHeatBalance::MaterialGroup::WindowGasMixture:
405 : case DataHeatBalance::MaterialGroup::Shade:
406 : case DataHeatBalance::MaterialGroup::WindowBlind:
407 : case DataHeatBalance::MaterialGroup::Screen:
408 : case DataHeatBalance::MaterialGroup::WindowSimpleGlazing:
409 : case DataHeatBalance::MaterialGroup::ComplexWindowShade:
410 : case DataHeatBalance::MaterialGroup::ComplexWindowGap:
411 : case DataHeatBalance::MaterialGroup::GlassEquivalentLayer:
412 : case DataHeatBalance::MaterialGroup::ShadeEquivalentLayer:
413 : case DataHeatBalance::MaterialGroup::DrapeEquivalentLayer:
414 : case DataHeatBalance::MaterialGroup::ScreenEquivalentLayer:
415 : case DataHeatBalance::MaterialGroup::BlindEquivalentLayer:
416 : case DataHeatBalance::MaterialGroup::GapEquivalentLayer:
417 2606 : state.dataConstruction->Construct(ConstrNum).TypeIsWindow = true;
418 2606 : break;
419 11085 : case DataHeatBalance::MaterialGroup::Invalid:
420 : case DataHeatBalance::MaterialGroup::Air:
421 : case DataHeatBalance::MaterialGroup::RegularMaterial:
422 : case DataHeatBalance::MaterialGroup::EcoRoof:
423 : case DataHeatBalance::MaterialGroup::IRTMaterial:
424 11085 : break; // Purposely not doing anything
425 0 : default:
426 0 : assert(false);
427 : }
428 : }
429 :
430 5827 : if (InsideMaterNum == 0) return;
431 5827 : if (OutsideMaterNum == 0) return;
432 :
433 5827 : if (state.dataConstruction->Construct(ConstrNum).TypeIsWindow) {
434 :
435 1294 : state.dataConstruction->Construct(ConstrNum).NumCTFTerms = 0;
436 1294 : state.dataConstruction->Construct(ConstrNum).NumHistories = 0;
437 1294 : WrongMaterialsMix = false;
438 1294 : WrongWindowLayering = false;
439 3900 : for (Layer = 1; Layer <= TotLayers; ++Layer) {
440 2606 : MaterNum = state.dataConstruction->Construct(ConstrNum).LayerPoint(Layer);
441 2606 : if (MaterNum == 0) continue; // error -- has been caught will stop program later
442 2606 : switch (state.dataMaterial->Material(MaterNum).Group) {
443 2606 : case DataHeatBalance::MaterialGroup::WindowGlass:
444 : case DataHeatBalance::MaterialGroup::WindowGas:
445 : case DataHeatBalance::MaterialGroup::WindowGasMixture:
446 : case DataHeatBalance::MaterialGroup::Shade:
447 : case DataHeatBalance::MaterialGroup::WindowBlind:
448 : case DataHeatBalance::MaterialGroup::Screen:
449 : case DataHeatBalance::MaterialGroup::WindowSimpleGlazing:
450 : case DataHeatBalance::MaterialGroup::ComplexWindowShade:
451 : case DataHeatBalance::MaterialGroup::ComplexWindowGap:
452 : case DataHeatBalance::MaterialGroup::GlassEquivalentLayer:
453 : case DataHeatBalance::MaterialGroup::ShadeEquivalentLayer:
454 : case DataHeatBalance::MaterialGroup::DrapeEquivalentLayer:
455 : case DataHeatBalance::MaterialGroup::ScreenEquivalentLayer:
456 : case DataHeatBalance::MaterialGroup::BlindEquivalentLayer:
457 : case DataHeatBalance::MaterialGroup::GapEquivalentLayer:
458 2606 : break; // everything is OK
459 0 : default:
460 0 : WrongMaterialsMix = true; // found a bad one
461 : }
462 : }
463 :
464 1294 : if (WrongMaterialsMix) { // Illegal material for a window construction
465 0 : ShowSevereError(state,
466 0 : "Error: Window construction=" + state.dataConstruction->Construct(ConstrNum).Name +
467 : " has materials other than glass, gas, shade, screen, blind, complex shading, complex gap, or simple system.");
468 0 : ErrorsFound = true;
469 : // Do not check number of layers for BSDF type of window since that can be handled
470 1295 : } else if ((TotLayers > 8) && (!state.dataConstruction->Construct(ConstrNum).WindowTypeBSDF) &&
471 1 : (!state.dataConstruction->Construct(ConstrNum).WindowTypeEQL)) { // Too many layers for a window construction
472 0 : ShowSevereError(state,
473 0 : "CheckAndSetConstructionProperties: Window construction=" + state.dataConstruction->Construct(ConstrNum).Name +
474 : " has too many layers (max of 8 allowed -- 4 glass + 3 gap + 1 shading device).");
475 0 : ErrorsFound = true;
476 :
477 1294 : } else if (TotLayers == 1) {
478 :
479 712 : if (BITF_TEST_ANY(BITF(state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(1)).Group),
480 : BITF(DataHeatBalance::MaterialGroup::Shade) | BITF(DataHeatBalance::MaterialGroup::WindowGas) |
481 : BITF(DataHeatBalance::MaterialGroup::WindowGasMixture) | BITF(DataHeatBalance::MaterialGroup::WindowBlind) |
482 : BITF(DataHeatBalance::MaterialGroup::Screen) | BITF(DataHeatBalance::MaterialGroup::ComplexWindowShade) |
483 : BITF(DataHeatBalance::MaterialGroup::ComplexWindowGap))) {
484 0 : ShowSevereError(
485 : state,
486 0 : "CheckAndSetConstructionProperties: The single-layer window construction=" + state.dataConstruction->Construct(ConstrNum).Name +
487 : " has a gas, complex gap, shade, complex shade, screen or blind material; it should be glass of simple glazing system.");
488 0 : ErrorsFound = true;
489 : }
490 : }
491 :
492 : // Find total glass layers, total shade/blind layers and total gas layers in a window construction
493 :
494 1294 : TotGlassLayers = 0;
495 1294 : TotShadeLayers = 0; // Includes shades, blinds, and screens
496 1294 : TotGasLayers = 0;
497 3900 : for (Layer = 1; Layer <= TotLayers; ++Layer) {
498 2606 : MaterNum = state.dataConstruction->Construct(ConstrNum).LayerPoint(Layer);
499 2606 : if (MaterNum == 0) continue; // error -- has been caught will stop program later
500 2606 : if (state.dataMaterial->Material(MaterNum).Group == DataHeatBalance::MaterialGroup::WindowGlass) ++TotGlassLayers;
501 2606 : if (state.dataMaterial->Material(MaterNum).Group == DataHeatBalance::MaterialGroup::WindowSimpleGlazing) ++TotGlassLayers;
502 2606 : if (BITF_TEST_ANY(BITF(state.dataMaterial->Material(MaterNum).Group),
503 : BITF(DataHeatBalance::MaterialGroup::Shade) | BITF(DataHeatBalance::MaterialGroup::WindowBlind) |
504 : BITF(DataHeatBalance::MaterialGroup::Screen) | BITF(DataHeatBalance::MaterialGroup::ComplexWindowShade)))
505 40 : ++TotShadeLayers;
506 2606 : if (BITF_TEST_ANY(BITF(state.dataMaterial->Material(MaterNum).Group),
507 : BITF(DataHeatBalance::MaterialGroup::WindowGas) | BITF(DataHeatBalance::MaterialGroup::WindowGasMixture) |
508 : BITF(DataHeatBalance::MaterialGroup::ComplexWindowGap)))
509 635 : ++TotGasLayers;
510 2606 : if (Layer < TotLayers) {
511 1312 : MaterNumNext = state.dataConstruction->Construct(ConstrNum).LayerPoint(Layer + 1);
512 : // Adjacent layers of same type not allowed
513 1312 : if (MaterNumNext == 0) continue;
514 1312 : if (state.dataMaterial->Material(MaterNum).Group == state.dataMaterial->Material(MaterNumNext).Group) WrongWindowLayering = true;
515 : }
516 : }
517 :
518 : // It is not necessary to check rest of BSDF window structure since that is performed inside TARCOG90 routine.
519 : // That routine also allow structures which are not allowed in rest of this routine
520 1294 : if (state.dataConstruction->Construct(ConstrNum).WindowTypeBSDF) {
521 14 : state.dataConstruction->Construct(ConstrNum).TotGlassLayers = TotGlassLayers;
522 14 : state.dataConstruction->Construct(ConstrNum).TotSolidLayers = TotGlassLayers + TotShadeLayers;
523 14 : state.dataConstruction->Construct(ConstrNum).InsideAbsorpThermal =
524 14 : state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(InsideLayer)).AbsorpThermalBack;
525 14 : state.dataConstruction->Construct(ConstrNum).OutsideAbsorpThermal =
526 14 : state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(1)).AbsorpThermalFront;
527 14 : return;
528 : }
529 :
530 1280 : if (state.dataConstruction->Construct(ConstrNum).WindowTypeEQL) {
531 3 : state.dataConstruction->Construct(ConstrNum).InsideAbsorpThermal =
532 3 : state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(InsideLayer)).AbsorpThermalBack;
533 3 : state.dataConstruction->Construct(ConstrNum).OutsideAbsorpThermal =
534 3 : state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(1)).AbsorpThermalFront;
535 3 : return;
536 : }
537 :
538 2554 : if (state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(1)).Group ==
539 1277 : DataHeatBalance::MaterialGroup::WindowGas ||
540 1277 : state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(1)).Group ==
541 1277 : DataHeatBalance::MaterialGroup::WindowGasMixture ||
542 1277 : state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(TotLayers)).Group ==
543 2554 : DataHeatBalance::MaterialGroup::WindowGas ||
544 1277 : state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(TotLayers)).Group ==
545 : DataHeatBalance::MaterialGroup::WindowGasMixture)
546 0 : WrongWindowLayering = true; // Gas cannot be first or last layer
547 1277 : if (TotShadeLayers > 1) WrongWindowLayering = true; // At most one shade, screen or blind allowed
548 :
549 : // If there is a diffusing glass layer no shade, screen or blind is allowed
550 3802 : for (Layer = 1; Layer <= TotLayers; ++Layer) {
551 2525 : MaterNum = state.dataConstruction->Construct(ConstrNum).LayerPoint(Layer);
552 2525 : if (MaterNum == 0) continue; // error -- has been caught will stop program later
553 2525 : if (state.dataMaterial->Material(MaterNum).SolarDiffusing && TotShadeLayers > 0) {
554 0 : ErrorsFound = true;
555 0 : ShowSevereError(state, "CheckAndSetConstructionProperties: Window construction=" + state.dataConstruction->Construct(ConstrNum).Name);
556 0 : ShowContinueError(state,
557 0 : "has diffusing glass=" + state.dataMaterial->Material(MaterNum).Name + " and a shade, screen or blind layer.");
558 0 : break;
559 : }
560 : }
561 :
562 : // If there is a diffusing glass layer it must be the innermost layer
563 1277 : if (TotGlassLayers > 1) {
564 546 : GlassLayNum = 0;
565 2321 : for (Layer = 1; Layer <= TotLayers; ++Layer) {
566 1775 : MaterNum = state.dataConstruction->Construct(ConstrNum).LayerPoint(Layer);
567 1775 : if (MaterNum == 0) continue; // error -- has been caught will stop program later
568 1775 : if (state.dataMaterial->Material(MaterNum).Group == DataHeatBalance::MaterialGroup::WindowGlass) {
569 1152 : ++GlassLayNum;
570 1152 : if (GlassLayNum < TotGlassLayers && state.dataMaterial->Material(MaterNum).SolarDiffusing) {
571 0 : ErrorsFound = true;
572 0 : ShowSevereError(
573 0 : state, "CheckAndSetConstructionProperties: Window construction=" + state.dataConstruction->Construct(ConstrNum).Name);
574 0 : ShowContinueError(
575 0 : state, "has diffusing glass=" + state.dataMaterial->Material(MaterNum).Name + " that is not the innermost glass layer.");
576 : }
577 : }
578 : }
579 : }
580 :
581 : // interior window screen is not allowed. Check for invalid between-glass screen is checked below.
582 1308 : if (TotShadeLayers == 1 &&
583 31 : state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(TotLayers)).Group ==
584 1277 : DataHeatBalance::MaterialGroup::Screen &&
585 : TotLayers != 1) {
586 0 : WrongWindowLayering = true;
587 : }
588 :
589 : // Consistency checks for a construction with a between-glass shade or blind
590 :
591 1308 : if (TotShadeLayers == 1 &&
592 59 : state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(1)).Group != DataHeatBalance::MaterialGroup::Shade &&
593 28 : state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(1)).Group !=
594 26 : DataHeatBalance::MaterialGroup::WindowBlind &&
595 26 : state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(1)).Group !=
596 24 : DataHeatBalance::MaterialGroup::Screen &&
597 24 : state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(TotLayers)).Group !=
598 17 : DataHeatBalance::MaterialGroup::Shade &&
599 17 : state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(TotLayers)).Group !=
600 5 : DataHeatBalance::MaterialGroup::WindowBlind &&
601 5 : state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(TotLayers)).Group !=
602 1282 : DataHeatBalance::MaterialGroup::ComplexWindowShade &&
603 5 : !WrongWindowLayering) {
604 :
605 : // This is a construction with a between-glass shade or blind
606 :
607 5 : if (TotGlassLayers >= 4) {
608 : // Quadruple pane not allowed.
609 0 : WrongWindowLayering = true;
610 5 : } else if (TotGlassLayers == 2 || TotGlassLayers == 3) {
611 5 : ValidBGShadeBlindConst = false;
612 5 : if (TotGlassLayers == 2) {
613 3 : if (TotLayers != 5) {
614 0 : WrongWindowLayering = true;
615 : } else {
616 6 : if (state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(1)).Group ==
617 3 : DataHeatBalance::MaterialGroup::WindowGlass &&
618 3 : (state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(2)).Group ==
619 0 : DataHeatBalance::MaterialGroup::WindowGas ||
620 0 : state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(2)).Group ==
621 3 : DataHeatBalance::MaterialGroup::WindowGasMixture) &&
622 3 : ((state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(3)).Group ==
623 2 : DataHeatBalance::MaterialGroup::Shade ||
624 2 : state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(3)).Group ==
625 3 : DataHeatBalance::MaterialGroup::WindowBlind) &&
626 3 : state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(3)).Group !=
627 3 : DataHeatBalance::MaterialGroup::Screen) &&
628 3 : (state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(4)).Group ==
629 0 : DataHeatBalance::MaterialGroup::WindowGas ||
630 0 : state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(4)).Group ==
631 6 : DataHeatBalance::MaterialGroup::WindowGasMixture) &&
632 3 : state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(5)).Group ==
633 : DataHeatBalance::MaterialGroup::WindowGlass)
634 3 : ValidBGShadeBlindConst = true;
635 : }
636 : } else { // TotGlassLayers = 3
637 2 : if (TotLayers != 7) {
638 0 : WrongWindowLayering = true;
639 : } else {
640 4 : if (state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(1)).Group ==
641 2 : DataHeatBalance::MaterialGroup::WindowGlass &&
642 2 : (state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(2)).Group ==
643 0 : DataHeatBalance::MaterialGroup::WindowGas ||
644 0 : state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(2)).Group ==
645 2 : DataHeatBalance::MaterialGroup::WindowGasMixture) &&
646 2 : state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(3)).Group ==
647 2 : DataHeatBalance::MaterialGroup::WindowGlass &&
648 2 : (state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(4)).Group ==
649 0 : DataHeatBalance::MaterialGroup::WindowGas ||
650 0 : state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(4)).Group ==
651 2 : DataHeatBalance::MaterialGroup::WindowGasMixture) &&
652 2 : ((state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(5)).Group ==
653 1 : DataHeatBalance::MaterialGroup::Shade ||
654 1 : state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(5)).Group ==
655 2 : DataHeatBalance::MaterialGroup::WindowBlind) &&
656 2 : state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(5)).Group !=
657 2 : DataHeatBalance::MaterialGroup::Screen) &&
658 2 : (state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(6)).Group ==
659 0 : DataHeatBalance::MaterialGroup::WindowGas ||
660 0 : state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(6)).Group ==
661 4 : DataHeatBalance::MaterialGroup::WindowGasMixture) &&
662 2 : state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(7)).Group ==
663 : DataHeatBalance::MaterialGroup::WindowGlass)
664 2 : ValidBGShadeBlindConst = true;
665 : }
666 : } // End of check if TotGlassLayers = 2 or 3
667 5 : if (!ValidBGShadeBlindConst) WrongWindowLayering = true;
668 5 : if (!WrongWindowLayering) {
669 5 : LayNumSh = 2 * TotGlassLayers - 1;
670 5 : MatSh = state.dataConstruction->Construct(ConstrNum).LayerPoint(LayNumSh);
671 : // For double pane, shade/blind must be layer #3.
672 : // For triple pane, it must be layer #5 (i.e., between two inner panes).
673 8 : if (state.dataMaterial->Material(MatSh).Group != DataHeatBalance::MaterialGroup::Shade &&
674 3 : state.dataMaterial->Material(MatSh).Group != DataHeatBalance::MaterialGroup::WindowBlind)
675 0 : WrongWindowLayering = true;
676 5 : if (TotLayers != 2 * TotGlassLayers + 1) WrongWindowLayering = true;
677 5 : if (!WrongWindowLayering) {
678 : // Gas on either side of a between-glass shade/blind must be the same
679 5 : MatGapL = state.dataConstruction->Construct(ConstrNum).LayerPoint(LayNumSh - 1);
680 5 : MatGapR = state.dataConstruction->Construct(ConstrNum).LayerPoint(LayNumSh + 1);
681 30 : for (IGas = 1; IGas <= 5; ++IGas) {
682 50 : if ((state.dataMaterial->Material(MatGapL).GasType(IGas) != state.dataMaterial->Material(MatGapR).GasType(IGas)) ||
683 25 : (state.dataMaterial->Material(MatGapL).GasFract(IGas) != state.dataMaterial->Material(MatGapR).GasFract(IGas)))
684 0 : WrongWindowLayering = true;
685 : }
686 : // Gap width on either side of a between-glass shade/blind must be the same
687 5 : if (std::abs(state.dataMaterial->Material(MatGapL).Thickness - state.dataMaterial->Material(MatGapR).Thickness) > 0.0005)
688 0 : WrongWindowLayering = true;
689 5 : if (state.dataMaterial->Material(MatSh).Group == DataHeatBalance::MaterialGroup::WindowBlind) {
690 3 : BlNum = state.dataMaterial->Material(MatSh).BlindDataPtr;
691 3 : if (BlNum > 0) {
692 6 : if ((state.dataMaterial->Material(MatGapL).Thickness + state.dataMaterial->Material(MatGapR).Thickness) <
693 3 : state.dataHeatBal->Blind(BlNum).SlatWidth) {
694 0 : ErrorsFound = true;
695 0 : ShowSevereError(state,
696 0 : "CheckAndSetConstructionProperties: For window construction " +
697 0 : state.dataConstruction->Construct(ConstrNum).Name);
698 0 : ShowContinueError(state, "the slat width of the between-glass blind is greater than");
699 0 : ShowContinueError(state, "the sum of the widths of the gas layers adjacent to the blind.");
700 : }
701 : } // End of check if BlNum > 0
702 : } // End of check if material is window blind
703 : } // End of check if WrongWindowLayering
704 : } // End of check if WrongWindowLayering
705 : } // End of check on total glass layers
706 : } // End of check if construction has between-glass shade/blind
707 :
708 : // Check Simple Windows,
709 1277 : if (state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(1)).Group ==
710 : DataHeatBalance::MaterialGroup::WindowSimpleGlazing) {
711 114 : if (TotLayers > 1) {
712 : // check that none of the other layers are glazing or gas
713 12 : for (Layer = 1; Layer <= TotLayers; ++Layer) {
714 8 : MaterNum = state.dataConstruction->Construct(ConstrNum).LayerPoint(Layer);
715 8 : if (MaterNum == 0) continue; // error -- has been caught will stop program later
716 8 : if (state.dataMaterial->Material(MaterNum).Group == DataHeatBalance::MaterialGroup::WindowGlass) {
717 0 : ErrorsFound = true;
718 0 : ShowSevereError(state,
719 0 : "CheckAndSetConstructionProperties: Error in window construction " +
720 0 : state.dataConstruction->Construct(ConstrNum).Name + "--");
721 0 : ShowContinueError(state, "For simple window constructions, no other glazing layers are allowed.");
722 : }
723 8 : if (state.dataMaterial->Material(MaterNum).Group == DataHeatBalance::MaterialGroup::WindowGas) {
724 0 : ErrorsFound = true;
725 0 : ShowSevereError(state,
726 0 : "CheckAndSetConstructionProperties: Error in window construction " +
727 0 : state.dataConstruction->Construct(ConstrNum).Name + "--");
728 0 : ShowContinueError(state, "For simple window constructions, no other gas layers are allowed.");
729 : }
730 : }
731 : }
732 : }
733 :
734 1277 : if (WrongWindowLayering) {
735 0 : ShowSevereError(
736 0 : state, "CheckAndSetConstructionProperties: Error in window construction " + state.dataConstruction->Construct(ConstrNum).Name + "--");
737 0 : ShowContinueError(state, " For multi-layer window constructions the following rules apply:");
738 0 : ShowContinueError(state, " --The first and last layer must be a solid layer (glass or shade/screen/blind),");
739 0 : ShowContinueError(state, " --Adjacent glass layers must be separated by one and only one gas layer,");
740 0 : ShowContinueError(state, " --Adjacent layers must not be of the same type,");
741 0 : ShowContinueError(state, " --Only one shade/screen/blind layer is allowed,");
742 0 : ShowContinueError(state, " --An exterior shade/screen/blind must be the first layer,");
743 0 : ShowContinueError(state, " --An interior shade/blind must be the last layer,");
744 0 : ShowContinueError(state, " --An interior screen is not allowed,");
745 0 : ShowContinueError(state, " --For an exterior shade/screen/blind or interior shade/blind, there should not be a gas layer");
746 0 : ShowContinueError(state, " ----between the shade/screen/blind and adjacent glass,");
747 0 : ShowContinueError(state, " --A between-glass screen is not allowed,");
748 0 : ShowContinueError(state, " --A between-glass shade/blind is allowed only for double and triple glazing,");
749 0 : ShowContinueError(state, " --A between-glass shade/blind must have adjacent gas layers of the same type and width,");
750 0 : ShowContinueError(state, " --For triple glazing the between-glass shade/blind must be between the two inner glass layers,");
751 0 : ShowContinueError(state, " --The slat width of a between-glass blind must be less than the sum of the widths");
752 0 : ShowContinueError(state, " ----of the gas layers adjacent to the blind.");
753 0 : ErrorsFound = true;
754 : }
755 :
756 1277 : state.dataConstruction->Construct(ConstrNum).TotGlassLayers = TotGlassLayers;
757 1277 : state.dataConstruction->Construct(ConstrNum).TotSolidLayers = TotGlassLayers + TotShadeLayers;
758 :
759 : // In following, InsideLayer is layer number of inside glass and InsideAbsorpThermal applies
760 : // only to inside glass; it is corrected later in InitGlassOpticalCalculations
761 : // if construction has inside shade or blind.
762 2554 : if (state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(InsideLayer)).Group ==
763 2547 : DataHeatBalance::MaterialGroup::Shade ||
764 1270 : state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(InsideLayer)).Group ==
765 : DataHeatBalance::MaterialGroup::WindowBlind) {
766 19 : --InsideLayer;
767 : }
768 1277 : if (InsideLayer > 0) {
769 1277 : InsideMaterNum = state.dataConstruction->Construct(ConstrNum).LayerPoint(InsideLayer);
770 1277 : state.dataConstruction->Construct(ConstrNum).InsideAbsorpThermal =
771 1277 : state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(InsideLayer)).AbsorpThermalBack;
772 : }
773 1277 : if (InsideMaterNum != 0) {
774 1277 : state.dataConstruction->Construct(ConstrNum).InsideAbsorpVis = state.dataMaterial->Material(InsideMaterNum).AbsorpVisible;
775 1277 : state.dataConstruction->Construct(ConstrNum).InsideAbsorpSolar = state.dataMaterial->Material(InsideMaterNum).AbsorpSolar;
776 : }
777 :
778 2554 : if ((state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(1)).Group ==
779 1398 : DataHeatBalance::MaterialGroup::WindowGlass) ||
780 121 : (state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(1)).Group ==
781 : DataHeatBalance::MaterialGroup::WindowSimpleGlazing)) { // Glass
782 1270 : state.dataConstruction->Construct(ConstrNum).OutsideAbsorpThermal =
783 1270 : state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(1)).AbsorpThermalFront;
784 : } else { // Exterior shade, blind or screen
785 7 : state.dataConstruction->Construct(ConstrNum).OutsideAbsorpThermal =
786 7 : state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(1)).AbsorpThermal;
787 : }
788 :
789 : } else { // Opaque surface
790 4533 : state.dataConstruction->Construct(ConstrNum).InsideAbsorpThermal =
791 4533 : state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(InsideLayer)).AbsorpThermal;
792 4533 : state.dataConstruction->Construct(ConstrNum).OutsideAbsorpThermal =
793 4533 : state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(1)).AbsorpThermal;
794 : }
795 :
796 5810 : state.dataConstruction->Construct(ConstrNum).OutsideRoughness =
797 5810 : state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(1)).Roughness;
798 :
799 5810 : if (state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(1)).Group == DataHeatBalance::MaterialGroup::Air) {
800 0 : ShowSevereError(
801 0 : state, "CheckAndSetConstructionProperties: Outside Layer is Air for construction " + state.dataConstruction->Construct(ConstrNum).Name);
802 0 : ShowContinueError(state,
803 0 : " Error in material " + state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(1)).Name);
804 0 : ErrorsFound = true;
805 : }
806 5810 : if (InsideLayer > 0) {
807 5810 : if (state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(InsideLayer)).Group ==
808 : DataHeatBalance::MaterialGroup::Air) {
809 0 : ShowSevereError(state,
810 0 : "CheckAndSetConstructionProperties: Inside Layer is Air for construction " +
811 0 : state.dataConstruction->Construct(ConstrNum).Name);
812 0 : ShowContinueError(state,
813 0 : " Error in material " +
814 0 : state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(InsideLayer)).Name);
815 0 : ErrorsFound = true;
816 : }
817 : }
818 :
819 5810 : if (state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(1)).Group == DataHeatBalance::MaterialGroup::EcoRoof) {
820 4 : state.dataConstruction->Construct(ConstrNum).TypeIsEcoRoof = true;
821 : // need to check EcoRoof is not non-outside layer
822 12 : for (Layer = 2; Layer <= TotLayers; ++Layer) {
823 8 : if (state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(Layer)).Group ==
824 : DataHeatBalance::MaterialGroup::EcoRoof) {
825 0 : ShowSevereError(state,
826 0 : "CheckAndSetConstructionProperties: Interior Layer is EcoRoof for construction " +
827 0 : state.dataConstruction->Construct(ConstrNum).Name);
828 0 : ShowContinueError(state,
829 0 : " Error in material " +
830 0 : state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(Layer)).Name);
831 0 : ErrorsFound = true;
832 : }
833 : }
834 : }
835 :
836 5810 : if (state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(1)).Group ==
837 : DataHeatBalance::MaterialGroup::IRTMaterial) {
838 2 : state.dataConstruction->Construct(ConstrNum).TypeIsIRT = true;
839 2 : if (state.dataConstruction->Construct(ConstrNum).TotLayers != 1) {
840 0 : ShowSevereError(state,
841 0 : "CheckAndSetConstructionProperties: Infrared Transparent (IRT) Construction is limited to 1 layer " +
842 0 : state.dataConstruction->Construct(ConstrNum).Name);
843 0 : ShowContinueError(state, " Too many layers in referenced construction.");
844 0 : ErrorsFound = true;
845 : }
846 : }
847 : }
848 :
849 368 : int AssignReverseConstructionNumber(EnergyPlusData &state,
850 : int const ConstrNum, // Existing Construction number of first surface
851 : bool &ErrorsFound)
852 : {
853 :
854 : // FUNCTION INFORMATION:
855 : // AUTHOR Linda Lawrie
856 : // DATE WRITTEN December 2006
857 : // MODIFIED na
858 : // RE-ENGINEERED na
859 :
860 : // PURPOSE OF THIS FUNCTION:
861 : // For interzone, unentered surfaces, we need to have "reverse" constructions
862 : // assigned to the created surfaces. These need to be the reverse (outside to inside layer)
863 : // of existing surfaces. Plus, there may be one already in the data structure so this is looked for as well.
864 :
865 : // METHODOLOGY EMPLOYED:
866 : // Create reverse layers. Look in current constructions to see if match. If no match, create a new one.
867 :
868 : // Return value
869 : int NewConstrNum; // Reverse Construction Number
870 :
871 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
872 : int nLayer;
873 : int Loop;
874 : bool Found;
875 :
876 368 : if (ConstrNum == 0) {
877 : // error caught elsewhere
878 0 : NewConstrNum = 0;
879 0 : return NewConstrNum;
880 : }
881 :
882 368 : state.dataConstruction->Construct(ConstrNum).IsUsed = true;
883 368 : nLayer = 0;
884 368 : state.dataConstruction->LayerPoint = 0;
885 1108 : for (Loop = state.dataConstruction->Construct(ConstrNum).TotLayers; Loop >= 1; --Loop) {
886 740 : ++nLayer;
887 740 : state.dataConstruction->LayerPoint(nLayer) = state.dataConstruction->Construct(ConstrNum).LayerPoint(Loop);
888 : }
889 :
890 : // now, got thru and see if there is a match already....
891 368 : NewConstrNum = 0;
892 2200 : for (Loop = 1; Loop <= state.dataHeatBal->TotConstructs; ++Loop) {
893 2196 : Found = true;
894 6205 : for (nLayer = 1; nLayer <= Construction::MaxLayersInConstruct; ++nLayer) {
895 5841 : if (state.dataConstruction->Construct(Loop).LayerPoint(nLayer) != state.dataConstruction->LayerPoint(nLayer)) {
896 1832 : Found = false;
897 1832 : break;
898 : }
899 : }
900 2196 : if (Found) {
901 364 : NewConstrNum = Loop;
902 364 : state.dataConstruction->Construct(Loop).IsUsed = true;
903 364 : break;
904 : }
905 : }
906 :
907 : // if need new one, bunch o stuff
908 368 : if (NewConstrNum == 0) {
909 4 : ++state.dataHeatBal->TotConstructs;
910 4 : state.dataConstruction->Construct.redimension(state.dataHeatBal->TotConstructs);
911 4 : state.dataHeatBal->NominalRforNominalUCalculation.redimension(state.dataHeatBal->TotConstructs);
912 4 : state.dataHeatBal->NominalRforNominalUCalculation(state.dataHeatBal->TotConstructs) = 0.0;
913 4 : state.dataHeatBal->NominalU.redimension(state.dataHeatBal->TotConstructs);
914 4 : state.dataHeatBal->NominalU(state.dataHeatBal->TotConstructs) = 0.0;
915 4 : state.dataHeatBal->NominalUBeforeAdjusted.redimension(state.dataHeatBal->TotConstructs);
916 4 : state.dataHeatBal->NominalUBeforeAdjusted(state.dataHeatBal->TotConstructs) = 0.0;
917 4 : state.dataHeatBal->CoeffAdjRatio.redimension(state.dataHeatBal->TotConstructs) = 1.0;
918 : // Put in new attributes
919 4 : NewConstrNum = state.dataHeatBal->TotConstructs;
920 4 : state.dataConstruction->Construct(NewConstrNum).IsUsed = true;
921 4 : state.dataConstruction->Construct(state.dataHeatBal->TotConstructs) =
922 4 : state.dataConstruction->Construct(ConstrNum); // preserve some of the attributes.
923 : // replace others...
924 4 : state.dataConstruction->Construct(state.dataHeatBal->TotConstructs).Name = "iz-" + state.dataConstruction->Construct(ConstrNum).Name;
925 4 : state.dataConstruction->Construct(state.dataHeatBal->TotConstructs).TotLayers = state.dataConstruction->Construct(ConstrNum).TotLayers;
926 48 : for (nLayer = 1; nLayer <= Construction::MaxLayersInConstruct; ++nLayer) {
927 44 : state.dataConstruction->Construct(state.dataHeatBal->TotConstructs).LayerPoint(nLayer) = state.dataConstruction->LayerPoint(nLayer);
928 44 : if (state.dataConstruction->LayerPoint(nLayer) != 0) {
929 13 : state.dataHeatBal->NominalRforNominalUCalculation(state.dataHeatBal->TotConstructs) +=
930 13 : state.dataHeatBal->NominalR(state.dataConstruction->LayerPoint(nLayer));
931 : }
932 : }
933 :
934 : // no error if zero -- that will have been caught with earlier construction
935 : // the following line was changed to fix CR7601
936 4 : if (state.dataHeatBal->NominalRforNominalUCalculation(state.dataHeatBal->TotConstructs) != 0.0) {
937 4 : state.dataHeatBal->NominalU(state.dataHeatBal->TotConstructs) =
938 4 : 1.0 / state.dataHeatBal->NominalRforNominalUCalculation(state.dataHeatBal->TotConstructs);
939 : }
940 :
941 4 : CheckAndSetConstructionProperties(state, state.dataHeatBal->TotConstructs, ErrorsFound);
942 : }
943 :
944 368 : return NewConstrNum;
945 : }
946 :
947 3 : void AddVariableSlatBlind(EnergyPlusData &state,
948 : int const inBlindNumber, // current Blind Number/pointer to name
949 : int &outBlindNumber, // resultant Blind Number to pass back
950 : bool &errFlag // error flag should one be needed
951 : )
952 : {
953 :
954 : // SUBROUTINE INFORMATION:
955 : // AUTHOR Linda Lawrie
956 : // DATE WRITTEN September 2009
957 : // MODIFIED na
958 : // RE-ENGINEERED na
959 :
960 : // PURPOSE OF THIS SUBROUTINE:
961 : // Window Blinds are presented as "fixed" slat blinds. However for certain Window Shading Controls,
962 : // the program needs to set the property to "variable"/movable slats. Since a blind could be in use
963 : // elsewhere with "fixed", a material needs to be added with variable properties -- having most of the
964 : // "fixed" properties in tact.
965 :
966 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
967 : int Found;
968 : Real64 MinSlatAngGeom;
969 : Real64 MaxSlatAngGeom;
970 :
971 : // Object Data
972 :
973 : // maybe it's already there
974 3 : errFlag = false;
975 3 : Found = UtilityRoutines::FindItemInList("~" + state.dataHeatBal->Blind(inBlindNumber).Name, state.dataHeatBal->Blind);
976 3 : if (Found == 0) {
977 : // Add a new blind
978 3 : state.dataHeatBal->Blind.redimension(++state.dataHeatBal->TotBlinds);
979 3 : state.dataHeatBal->Blind(state.dataHeatBal->TotBlinds) = state.dataHeatBal->Blind(inBlindNumber);
980 3 : state.dataHeatBal->Blind(state.dataHeatBal->TotBlinds).Name = "~" + state.dataHeatBal->Blind(inBlindNumber).Name;
981 3 : outBlindNumber = state.dataHeatBal->TotBlinds;
982 3 : state.dataHeatBal->Blind(state.dataHeatBal->TotBlinds).SlatAngleType = DataWindowEquivalentLayer::AngleType::Variable;
983 :
984 : // Minimum and maximum slat angles allowed by slat geometry
985 6 : if (state.dataHeatBal->Blind(state.dataHeatBal->TotBlinds).SlatWidth >
986 3 : state.dataHeatBal->Blind(state.dataHeatBal->TotBlinds).SlatSeparation) {
987 9 : MinSlatAngGeom = std::asin(state.dataHeatBal->Blind(state.dataHeatBal->TotBlinds).SlatThickness /
988 6 : (state.dataHeatBal->Blind(state.dataHeatBal->TotBlinds).SlatThickness +
989 6 : state.dataHeatBal->Blind(state.dataHeatBal->TotBlinds).SlatSeparation)) /
990 : DataGlobalConstants::DegToRadians;
991 : } else {
992 0 : MinSlatAngGeom = 0.0;
993 : }
994 3 : MaxSlatAngGeom = 180.0 - MinSlatAngGeom;
995 :
996 : // Error if maximum slat angle less than minimum
997 :
998 6 : if (state.dataHeatBal->Blind(state.dataHeatBal->TotBlinds).MaxSlatAngle <
999 3 : state.dataHeatBal->Blind(state.dataHeatBal->TotBlinds).MinSlatAngle) {
1000 0 : errFlag = true;
1001 0 : ShowSevereError(state, "WindowMaterial:Blind=\"" + state.dataHeatBal->Blind(inBlindNumber).Name + "\", Illegal value combination.");
1002 0 : ShowContinueError(state,
1003 0 : format("Minimum Slat Angle=[{:.1R}], is greater than Maximum Slat Angle=[{:.1R}] deg.",
1004 0 : state.dataHeatBal->Blind(state.dataHeatBal->TotBlinds).MinSlatAngle,
1005 0 : state.dataHeatBal->Blind(state.dataHeatBal->TotBlinds).MaxSlatAngle));
1006 : }
1007 :
1008 : // Error if input slat angle not in input min/max range
1009 :
1010 6 : if (state.dataHeatBal->Blind(state.dataHeatBal->TotBlinds).MaxSlatAngle >
1011 6 : state.dataHeatBal->Blind(state.dataHeatBal->TotBlinds).MinSlatAngle &&
1012 6 : (state.dataHeatBal->Blind(state.dataHeatBal->TotBlinds).SlatAngle < state.dataHeatBal->Blind(state.dataHeatBal->TotBlinds).MinSlatAngle ||
1013 3 : state.dataHeatBal->Blind(state.dataHeatBal->TotBlinds).SlatAngle >
1014 3 : state.dataHeatBal->Blind(state.dataHeatBal->TotBlinds).MaxSlatAngle)) {
1015 0 : errFlag = true;
1016 0 : ShowSevereError(state, "WindowMaterial:Blind=\"" + state.dataHeatBal->Blind(inBlindNumber).Name + "\", Illegal value combination.");
1017 0 : ShowContinueError(state,
1018 0 : format("Slat Angle=[{:.1R}] is outside of the input min/max range, min=[{:.1R}], max=[{:.1R}] deg.",
1019 0 : state.dataHeatBal->Blind(state.dataHeatBal->TotBlinds).SlatAngle,
1020 0 : state.dataHeatBal->Blind(state.dataHeatBal->TotBlinds).MinSlatAngle,
1021 0 : state.dataHeatBal->Blind(state.dataHeatBal->TotBlinds).MaxSlatAngle));
1022 : }
1023 :
1024 : // Warning if input minimum slat angle is less than that allowed by slat geometry
1025 :
1026 3 : if (state.dataHeatBal->Blind(state.dataHeatBal->TotBlinds).MinSlatAngle < MinSlatAngGeom) {
1027 3 : ShowWarningError(state, "WindowMaterial:Blind=\"" + state.dataHeatBal->Blind(inBlindNumber).Name + "\", Illegal value combination.");
1028 9 : ShowContinueError(
1029 : state,
1030 9 : format("Minimum Slat Angle=[{:.1R}] is less than the smallest allowed by slat dimensions and spacing, min=[{:.1R}] deg.",
1031 3 : state.dataHeatBal->Blind(state.dataHeatBal->TotBlinds).MinSlatAngle,
1032 3 : MinSlatAngGeom));
1033 3 : ShowContinueError(state, format("Minimum Slat Angle will be set to {:.1R} deg.", MinSlatAngGeom));
1034 3 : state.dataHeatBal->Blind(state.dataHeatBal->TotBlinds).MinSlatAngle = MinSlatAngGeom;
1035 : }
1036 :
1037 : // Warning if input maximum slat angle is greater than that allowed by slat geometry
1038 :
1039 3 : if (state.dataHeatBal->Blind(state.dataHeatBal->TotBlinds).MaxSlatAngle > MaxSlatAngGeom) {
1040 3 : ShowWarningError(state, "WindowMaterial:Blind=\"" + state.dataHeatBal->Blind(inBlindNumber).Name + "\", Illegal value combination.");
1041 9 : ShowContinueError(state,
1042 9 : format("Maximum Slat Angle=[{:.1R}] is greater than the largest allowed by slat dimensions and spacing, [{:.1R}] deg.",
1043 3 : state.dataHeatBal->Blind(state.dataHeatBal->TotBlinds).MaxSlatAngle,
1044 3 : MaxSlatAngGeom));
1045 3 : ShowContinueError(state, format("Maximum Slat Angle will be set to {:.1R} deg.", MaxSlatAngGeom));
1046 3 : state.dataHeatBal->Blind(state.dataHeatBal->TotBlinds).MaxSlatAngle = MaxSlatAngGeom;
1047 : }
1048 : } else {
1049 0 : outBlindNumber = Found;
1050 : }
1051 3 : }
1052 :
1053 6562 : void CalcScreenTransmittance(EnergyPlusData &state,
1054 : int const SurfaceNum,
1055 : Optional<Real64 const> Phi, // Optional sun altitude relative to surface outward normal (radians)
1056 : Optional<Real64 const> Theta, // Optional sun azimuth relative to surface outward normal (radians)
1057 : Optional_int_const ScreenNumber // Optional screen number
1058 : )
1059 : {
1060 :
1061 : // FUNCTION INFORMATION:
1062 : // AUTHOR Richard Raustad
1063 : // DATE WRITTEN May 2006
1064 : // MODIFIED na
1065 : // RE-ENGINEERED na
1066 :
1067 : // PURPOSE OF THIS FUNCTION:
1068 : // Calculate transmittance of window screen given azimuth and altitude angle
1069 : // of sun and surface orientation.
1070 :
1071 : // METHODOLOGY EMPLOYED:
1072 : // Window screen solar beam transmittance varies as the sun moves across the sky
1073 : // due to the geometry of the screen material and the angle of incidence
1074 : // of the solar beam. Azimuth and altitude angle are calculated with respect
1075 : // to the surface outward normal. Solar beam reflectance and absorptance are also
1076 : // accounted for.
1077 :
1078 : // CALLs to CalcScreenTransmittance are primarily based on surface index. A typical call is:
1079 : // CALL CalcScreenTransmittance(SurfaceNum)
1080 : // Since a single Material:WindowScreen object may be used for multiple windows, the
1081 : // screen's direct beam properties are calculated for the screen material attached to this surface.
1082 : // If a single Material:WindowScreen object is used for 3 windows then SurfaceScreens(3) is allocated.
1083 :
1084 : // CALLs to CalcScreenTransmittance may be done by using the optional arguments as follows:
1085 : // CALLs to CalcScreenTransmittance at normal incidence are:
1086 : // CALL with a screen number and relative azimuth and altitude angles
1087 : // CALL CalcScreenTransmittance(0, Phi=0.0, Theta=0.0, ScreenNumber=ScNum)
1088 : // -OR-
1089 : // CALL same as above using the material structure
1090 : // CALL CalcScreenTransmittance(0, Phi=0.0, Theta=0.0, ScreenNumber=dataMaterial.Material(MatShade)%ScreenDataPtr)
1091 : // -OR-
1092 : // CALL with the surface number and relative azimuth and altitude angles
1093 : // CALL CalcScreenTransmittance(SurfaceNum, Phi=0.0, Theta=0.0)
1094 :
1095 : // CALL's passing the screen number without the relative azimuth and altitude angles is not allowed
1096 : // CALL CalcScreenTransmittance(0, ScreenNumber=ScNum) ! DO NOT use this syntax
1097 :
1098 : // Locals
1099 : // FUNCTION ARGUMENT DEFINITIONS:
1100 : // The optional arguments Phi and Theta are used to integrate over a hemisphere and are passed as pairs
1101 : // The optional argument ScreenNumber is used during CalcWindowScreenProperties to integrate over a quarter hemispere
1102 : // "before" the surface # is known. Theta and Phi can be passed without ScreenNumber, but DO NOT pass ScreenNumber
1103 : // without Theta and Phi.
1104 :
1105 : // FUNCTION PARAMETER DEFINITIONS:
1106 6562 : Real64 constexpr Small(1.E-9); // Small Number used to approximate zero
1107 :
1108 : // FUNCTION PARAMETER DEFINITIONS:
1109 : int ScNum; // Index to screen data
1110 : Real64 Tdirect; // Beam solar transmitted through screen (dependent on sun angle)
1111 : Real64 Tscattered; // Beam solar reflected through screen (dependent on sun angle)
1112 : Real64 TscatteredVis; // Visible beam solar reflected through screen (dependent on sun angle)
1113 : Real64 SunAzimuth; // Solar azimuth angle from north (rad)
1114 : Real64 SunAltitude; // Solar altitude angle from horizon (rad)
1115 : Real64 SurfaceAzimuth; // Surface azimuth angle from north (rad)
1116 : Real64 SurfaceTilt; // Surface tilt angle from vertical (rad)
1117 : Real64 SunAzimuthToScreenNormal; // Relative solar azimuth (sun angle from screen normal, 0 to PiOvr2, rad)
1118 : Real64 SunAltitudeToScreenNormal; // Relative solar altitude (sun angle from screen normal, -PiOvr2 to PiOvr2, rad)
1119 : Real64 Beta; // Compliment of relative solar azimuth (rad)
1120 : Real64 TransXDir; // Horizontal component of direct beam transmittance
1121 : Real64 TransYDir; // Vertical component of direct beam transmittance
1122 : Real64 Delta; // Intermediate variable used for Tscatter calculation (deg)
1123 : Real64 DeltaMax; // Intermediate variable used for Tscatter calculation (deg)
1124 : Real64 Tscattermax; // Maximum solar beam scattered transmittance
1125 : Real64 TscattermaxVis; // Maximum visible beam scattered transmittance
1126 : Real64 ExponentInterior; // Exponent used in scattered transmittance calculation
1127 : // when Delta < DeltaMax (0,0 to peak)
1128 : Real64 ExponentExterior; // Exponent used in scattered transmittance calculation
1129 : // when Delta > DeltaMax (peak to max)
1130 : Real64 AlphaDblPrime; // Intermediate variables (used in Eng. Doc.)
1131 : Real64 COSMu;
1132 : Real64 Epsilon;
1133 : Real64 Eta;
1134 : Real64 MuPrime;
1135 : Real64 Gamma;
1136 : Real64 NormalAltitude; // Actual altitude angle of sun wrt surface outward normal (rad)
1137 : Real64 NormalAzimuth; // Actual azimuth angle of sun wrt surface outward normal (rad)
1138 : Real64 IncidentAngle; // Solar angle wrt surface outward normal to determine
1139 : // if sun is in front of screen (rad)
1140 : Real64 PeakToPlateauRatio; // Ratio of peak scattering to plateau at 0,0 incident angle
1141 : Real64 PeakToPlateauRatioVis; // Ratio of peak visible scattering to plateau at 0,0 incident angle
1142 : Real64 ReflectCyl; // Screen material reflectance
1143 : Real64 ReflectCylVis; // Screen material visible reflectance
1144 :
1145 : // SurfaceScreens structure may be accessed using either the surface or screen index
1146 : // The screen index is based on the number of Surface:HeatTransfer:Sub objects using any Material:WindowScreen object
1147 6562 : if (present(ScreenNumber)) {
1148 3314 : ScNum = ScreenNumber;
1149 3314 : if (!present(Theta) || !present(Phi)) {
1150 0 : ShowFatalError(state, "Syntax error, optional arguments Theta and Phi must be present when optional ScreenNumber is used.");
1151 : }
1152 : } else {
1153 3248 : ScNum = state.dataSurface->SurfWinScreenNumber(SurfaceNum);
1154 : }
1155 :
1156 6562 : if (present(Theta)) {
1157 3314 : SunAzimuthToScreenNormal = std::abs(Theta);
1158 3314 : if (SunAzimuthToScreenNormal > DataGlobalConstants::Pi) {
1159 0 : SunAzimuthToScreenNormal = 0.0;
1160 : } else {
1161 3314 : if (SunAzimuthToScreenNormal > DataGlobalConstants::PiOvr2) {
1162 0 : SunAzimuthToScreenNormal = DataGlobalConstants::Pi - SunAzimuthToScreenNormal;
1163 : }
1164 : }
1165 3314 : NormalAzimuth = SunAzimuthToScreenNormal;
1166 : } else {
1167 3248 : SunAzimuth = std::atan2(state.dataEnvrn->SOLCOS(1), state.dataEnvrn->SOLCOS(2));
1168 3248 : if (SunAzimuth < 0.0) SunAzimuth += 2.0 * DataGlobalConstants::Pi;
1169 3248 : SurfaceAzimuth = state.dataSurface->Surface(SurfaceNum).Azimuth * DataGlobalConstants::DegToRadians;
1170 3248 : NormalAzimuth = SunAzimuth - SurfaceAzimuth;
1171 : // Calculate the transmittance whether sun is in front of or behind screen, place result in BmBmTrans or BmBmTransBack
1172 3248 : if (std::abs(SunAzimuth - SurfaceAzimuth) > DataGlobalConstants::PiOvr2) {
1173 1792 : SunAzimuthToScreenNormal = std::abs(SunAzimuth - SurfaceAzimuth) - DataGlobalConstants::PiOvr2;
1174 : } else {
1175 1456 : SunAzimuthToScreenNormal = std::abs(SunAzimuth - SurfaceAzimuth);
1176 : }
1177 : }
1178 :
1179 6562 : if (present(Phi)) {
1180 3314 : SunAltitudeToScreenNormal = std::abs(Phi);
1181 3314 : if (SunAltitudeToScreenNormal > DataGlobalConstants::PiOvr2) {
1182 0 : SunAltitudeToScreenNormal = DataGlobalConstants::Pi - SunAltitudeToScreenNormal;
1183 : }
1184 3314 : SunAltitude = SunAltitudeToScreenNormal;
1185 : } else {
1186 3248 : SunAltitude = (DataGlobalConstants::PiOvr2 - std::acos(state.dataEnvrn->SOLCOS(3)));
1187 3248 : SurfaceTilt = state.dataSurface->Surface(SurfaceNum).Tilt * DataGlobalConstants::DegToRadians;
1188 3248 : SunAltitudeToScreenNormal = std::abs(SunAltitude + (SurfaceTilt - DataGlobalConstants::PiOvr2));
1189 3248 : if (SunAltitudeToScreenNormal > DataGlobalConstants::PiOvr2) {
1190 0 : SunAltitudeToScreenNormal -= DataGlobalConstants::PiOvr2;
1191 : }
1192 : }
1193 :
1194 6562 : if (SurfaceNum == 0 || !present(ScreenNumber)) {
1195 6562 : NormalAltitude = SunAltitude;
1196 : } else {
1197 0 : NormalAltitude = SunAltitude + (SurfaceTilt - DataGlobalConstants::PiOvr2);
1198 : }
1199 :
1200 6562 : if (NormalAltitude != 0.0 && NormalAzimuth != 0.0) {
1201 6208 : IncidentAngle = std::acos(std::sin(NormalAltitude) / (std::tan(NormalAzimuth) * std::tan(NormalAltitude) / std::sin(NormalAzimuth)));
1202 354 : } else if (NormalAltitude != 0.0 && NormalAzimuth == 0.0) {
1203 36 : IncidentAngle = NormalAltitude;
1204 318 : } else if (NormalAltitude == 0.0 && NormalAzimuth != 0.0) {
1205 172 : IncidentAngle = NormalAzimuth;
1206 : } else {
1207 146 : IncidentAngle = 0.0;
1208 : }
1209 :
1210 6562 : auto &thisScreen = state.dataHeatBal->SurfaceScreens(ScNum);
1211 :
1212 : // ratio of screen material diameter to screen material spacing
1213 6562 : Gamma = thisScreen.ScreenDiameterToSpacingRatio;
1214 :
1215 : // ************************************************************************************************
1216 : // * calculate transmittance of totally absorbing screen material (beam passing through open area)*
1217 : // ************************************************************************************************
1218 :
1219 : // calculate compliment of relative solar azimuth
1220 6562 : Beta = DataGlobalConstants::PiOvr2 - SunAzimuthToScreenNormal;
1221 :
1222 : // Catch all divide by zero instances
1223 6562 : if (Beta > Small) {
1224 5782 : if (std::abs(SunAltitudeToScreenNormal - DataGlobalConstants::PiOvr2) > Small) {
1225 5746 : AlphaDblPrime = std::atan(std::tan(SunAltitudeToScreenNormal) / std::cos(SunAzimuthToScreenNormal));
1226 11492 : TransYDir = 1.0 - Gamma * (std::cos(AlphaDblPrime) +
1227 5746 : std::sin(AlphaDblPrime) * std::tan(SunAltitudeToScreenNormal) * std::sqrt(1.0 + pow_2(1.0 / std::tan(Beta))));
1228 5746 : TransYDir = max(0.0, TransYDir);
1229 : } else {
1230 36 : TransYDir = 0.0;
1231 : }
1232 : } else {
1233 780 : TransYDir = 0.0;
1234 : }
1235 :
1236 13124 : COSMu = std::sqrt(pow_2(std::cos(SunAltitudeToScreenNormal)) * pow_2(std::cos(SunAzimuthToScreenNormal)) +
1237 6562 : pow_2(std::sin(SunAltitudeToScreenNormal)));
1238 6562 : if (COSMu > Small) {
1239 6560 : Epsilon = std::acos(std::cos(SunAltitudeToScreenNormal) * std::cos(SunAzimuthToScreenNormal) / COSMu);
1240 6560 : Eta = DataGlobalConstants::PiOvr2 - Epsilon;
1241 6560 : if (std::cos(Epsilon) != 0.0) {
1242 6560 : MuPrime = std::atan(std::tan(std::acos(COSMu)) / std::cos(Epsilon));
1243 6560 : if (Eta != 0.0) {
1244 6494 : TransXDir =
1245 6494 : 1.0 - Gamma * (std::cos(MuPrime) + std::sin(MuPrime) * std::tan(std::acos(COSMu)) * std::sqrt(1.0 + pow_2(1.0 / std::tan(Eta))));
1246 6494 : TransXDir = max(0.0, TransXDir);
1247 : } else {
1248 66 : TransXDir = 0.0;
1249 : }
1250 : } else {
1251 0 : TransXDir = 0.0;
1252 : }
1253 : } else {
1254 2 : TransXDir = 1.0 - Gamma;
1255 : }
1256 6562 : Tdirect = max(0.0, TransXDir * TransYDir);
1257 :
1258 : // *******************************************************************************
1259 : // * calculate transmittance of scattered beam due to reflecting screen material *
1260 : // *******************************************************************************
1261 :
1262 6562 : ReflectCyl = thisScreen.ReflectCylinder;
1263 6562 : ReflectCylVis = thisScreen.ReflectCylinderVis;
1264 :
1265 13086 : if (std::abs(SunAzimuthToScreenNormal - DataGlobalConstants::PiOvr2) < Small ||
1266 6524 : std::abs(SunAltitudeToScreenNormal - DataGlobalConstants::PiOvr2) < Small) {
1267 74 : Tscattered = 0.0;
1268 74 : TscatteredVis = 0.0;
1269 : } else {
1270 : // DeltaMax and Delta are in degrees
1271 6488 : DeltaMax = 89.7 - (10.0 * Gamma / 0.16);
1272 12976 : Delta = std::sqrt(pow_2(SunAzimuthToScreenNormal / DataGlobalConstants::DegToRadians) +
1273 6488 : pow_2(SunAltitudeToScreenNormal / DataGlobalConstants::DegToRadians));
1274 :
1275 : // Use empirical model to determine maximum (peak) scattering
1276 6488 : Tscattermax = 0.0229 * Gamma + 0.2971 * ReflectCyl - 0.03624 * pow_2(Gamma) + 0.04763 * pow_2(ReflectCyl) - 0.44416 * Gamma * ReflectCyl;
1277 6488 : TscattermaxVis =
1278 6488 : 0.0229 * Gamma + 0.2971 * ReflectCylVis - 0.03624 * pow_2(Gamma) + 0.04763 * pow_2(ReflectCylVis) - 0.44416 * Gamma * ReflectCylVis;
1279 :
1280 : // Vary slope of interior and exterior surface of scattering model
1281 6488 : ExponentInterior = -pow_2(Delta - DeltaMax) / 600.0;
1282 6488 : ExponentExterior = -std::pow(std::abs(Delta - DeltaMax), 2.5) / 600.0;
1283 :
1284 : // Determine ratio of scattering at 0,0 incident angle to maximum (peak) scattering
1285 6488 : PeakToPlateauRatio = 1.0 / (0.2 * (1 - Gamma) * ReflectCyl);
1286 6488 : PeakToPlateauRatioVis = 1.0 / (0.2 * (1 - Gamma) * ReflectCylVis);
1287 :
1288 6488 : if (Delta > DeltaMax) {
1289 : // Apply offset for plateau and use exterior exponential function to simulate actual scattering as a function of solar angles
1290 2266 : Tscattered = 0.2 * (1.0 - Gamma) * ReflectCyl * Tscattermax * (1.0 + (PeakToPlateauRatio - 1.0) * std::exp(ExponentExterior));
1291 2266 : TscatteredVis = 0.2 * (1.0 - Gamma) * ReflectCylVis * TscattermaxVis * (1.0 + (PeakToPlateauRatioVis - 1.0) * std::exp(ExponentExterior));
1292 : // Trim off offset if solar angle (delta) is greater than maximum (peak) scattering angle
1293 2266 : Tscattered -= (0.2 * (1.0 - Gamma) * ReflectCyl * Tscattermax) * max(0.0, (Delta - DeltaMax) / (90.0 - DeltaMax));
1294 2266 : TscatteredVis -= (0.2 * (1.0 - Gamma) * ReflectCylVis * TscattermaxVis) * max(0.0, (Delta - DeltaMax) / (90.0 - DeltaMax));
1295 : } else {
1296 : // Apply offset for plateau and use interior exponential function to simulate actual scattering as a function of solar angles
1297 4222 : Tscattered = 0.2 * (1.0 - Gamma) * ReflectCyl * Tscattermax * (1.0 + (PeakToPlateauRatio - 1.0) * std::exp(ExponentInterior));
1298 4222 : TscatteredVis = 0.2 * (1.0 - Gamma) * ReflectCylVis * TscattermaxVis * (1.0 + (PeakToPlateauRatioVis - 1.0) * std::exp(ExponentInterior));
1299 : }
1300 : }
1301 6562 : Tscattered = max(0.0, Tscattered);
1302 6562 : TscatteredVis = max(0.0, TscatteredVis);
1303 :
1304 6562 : if (thisScreen.screenBeamReflectanceModel == DataSurfaces::ScreenBeamReflectanceModel::DoNotModel) {
1305 0 : if (std::abs(IncidentAngle) <= DataGlobalConstants::PiOvr2) {
1306 0 : thisScreen.BmBmTrans = Tdirect;
1307 0 : thisScreen.BmBmTransVis = Tdirect;
1308 0 : thisScreen.BmBmTransBack = 0.0;
1309 : } else {
1310 0 : thisScreen.BmBmTrans = 0.0;
1311 0 : thisScreen.BmBmTransVis = 0.0;
1312 0 : thisScreen.BmBmTransBack = Tdirect;
1313 : }
1314 0 : Tscattered = 0.0;
1315 0 : TscatteredVis = 0.0;
1316 6562 : } else if (thisScreen.screenBeamReflectanceModel == DataSurfaces::ScreenBeamReflectanceModel::DirectBeam) {
1317 0 : if (std::abs(IncidentAngle) <= DataGlobalConstants::PiOvr2) {
1318 0 : thisScreen.BmBmTrans = Tdirect + Tscattered;
1319 0 : thisScreen.BmBmTransVis = Tdirect + TscatteredVis;
1320 0 : thisScreen.BmBmTransBack = 0.0;
1321 : } else {
1322 0 : thisScreen.BmBmTrans = 0.0;
1323 0 : thisScreen.BmBmTransVis = 0.0;
1324 0 : thisScreen.BmBmTransBack = Tdirect + Tscattered;
1325 : }
1326 0 : Tscattered = 0.0;
1327 0 : TscatteredVis = 0.0;
1328 6562 : } else if (thisScreen.screenBeamReflectanceModel == DataSurfaces::ScreenBeamReflectanceModel::Diffuse) {
1329 6562 : if (std::abs(IncidentAngle) <= DataGlobalConstants::PiOvr2) {
1330 4938 : thisScreen.BmBmTrans = Tdirect;
1331 4938 : thisScreen.BmBmTransVis = Tdirect;
1332 4938 : thisScreen.BmBmTransBack = 0.0;
1333 : } else {
1334 1624 : thisScreen.BmBmTrans = 0.0;
1335 1624 : thisScreen.BmBmTransVis = 0.0;
1336 1624 : thisScreen.BmBmTransBack = Tdirect;
1337 : }
1338 : }
1339 :
1340 6562 : if (std::abs(IncidentAngle) <= DataGlobalConstants::PiOvr2) {
1341 4938 : thisScreen.BmDifTrans = Tscattered;
1342 4938 : thisScreen.BmDifTransVis = TscatteredVis;
1343 4938 : thisScreen.BmDifTransBack = 0.0;
1344 4938 : thisScreen.ReflectSolBeamFront = max(0.0, ReflectCyl * (1.0 - Tdirect) - Tscattered);
1345 4938 : thisScreen.ReflectVisBeamFront = max(0.0, ReflectCylVis * (1.0 - Tdirect) - TscatteredVis);
1346 4938 : thisScreen.AbsorpSolarBeamFront = max(0.0, (1.0 - Tdirect) * (1.0 - ReflectCyl));
1347 4938 : thisScreen.ReflectSolBeamBack = 0.0;
1348 4938 : thisScreen.ReflectVisBeamBack = 0.0;
1349 4938 : thisScreen.AbsorpSolarBeamBack = 0.0;
1350 : } else {
1351 1624 : thisScreen.BmDifTrans = 0.0;
1352 1624 : thisScreen.BmDifTransVis = 0.0;
1353 1624 : thisScreen.BmDifTransBack = Tscattered;
1354 1624 : thisScreen.ReflectSolBeamBack = max(0.0, ReflectCyl * (1.0 - Tdirect) - Tscattered);
1355 1624 : thisScreen.ReflectVisBeamBack = max(0.0, ReflectCylVis * (1.0 - Tdirect) - TscatteredVis);
1356 1624 : thisScreen.AbsorpSolarBeamBack = max(0.0, (1.0 - Tdirect) * (1.0 - ReflectCyl));
1357 1624 : thisScreen.ReflectSolBeamFront = 0.0;
1358 1624 : thisScreen.ReflectVisBeamFront = 0.0;
1359 1624 : thisScreen.AbsorpSolarBeamFront = 0.0;
1360 : }
1361 6562 : }
1362 :
1363 2034 : std::string DisplayMaterialRoughness(DataSurfaces::SurfaceRoughness const Roughness) // Roughness String
1364 : {
1365 :
1366 : // SUBROUTINE INFORMATION:
1367 : // AUTHOR Linda K. Lawrie
1368 : // DATE WRITTEN October 2005
1369 : // MODIFIED na
1370 : // RE-ENGINEERED na
1371 :
1372 : // PURPOSE OF THIS SUBROUTINE:
1373 : // This subroutine is given a roughness value and returns the character representation.
1374 :
1375 : // Return value
1376 2034 : std::string cRoughness; // Character representation of Roughness
1377 :
1378 : // Select the correct Number for the associated ascii name for the roughness type
1379 2034 : switch (Roughness) {
1380 191 : case DataSurfaces::SurfaceRoughness::VeryRough: {
1381 191 : cRoughness = "VeryRough";
1382 191 : } break;
1383 515 : case DataSurfaces::SurfaceRoughness::Rough: {
1384 515 : cRoughness = "Rough";
1385 515 : } break;
1386 481 : case DataSurfaces::SurfaceRoughness::MediumRough: {
1387 481 : cRoughness = "MediumRough";
1388 481 : } break;
1389 294 : case DataSurfaces::SurfaceRoughness::MediumSmooth: {
1390 294 : cRoughness = "MediumSmooth";
1391 294 : } break;
1392 533 : case DataSurfaces::SurfaceRoughness::Smooth: {
1393 533 : cRoughness = "Smooth";
1394 533 : } break;
1395 20 : case DataSurfaces::SurfaceRoughness::VerySmooth: {
1396 20 : cRoughness = "VerySmooth";
1397 20 : } break;
1398 0 : default: {
1399 0 : cRoughness = "";
1400 0 : } break;
1401 : }
1402 :
1403 2034 : return cRoughness;
1404 : }
1405 :
1406 42220 : Real64 ComputeNominalUwithConvCoeffs(EnergyPlusData &state,
1407 : int const numSurf, // index for Surface array.
1408 : bool &isValid // returns true if result is valid
1409 : )
1410 : {
1411 :
1412 : // SUBROUTINE INFORMATION:
1413 : // AUTHOR Jason Glazer
1414 : // DATE WRITTEN September 2013
1415 : // MODIFIED na
1416 : // RE-ENGINEERED na
1417 :
1418 : // PURPOSE OF THIS SUBROUTINE:
1419 : // Calculate Nominal U-value with convection/film coefficients for reporting by
1420 : // adding on prescribed R-values for interior and exterior convection coefficients
1421 : // as found in ASHRAE 90.1-2004, Appendix A. Used in EIO and tabular reports.
1422 : // ASHRAE 90.1-2004 Section A9.4.1 shows the following:
1423 : // R-value Condition
1424 : // All exterior conditions IP: 0.17 SI: 0.0299
1425 : // All semi-exterior surfaces IP: 0.46 SI: 0.0810
1426 : // Interior horizontal surfaces, heat flow up IP: 0.61 SI: 0.1074
1427 : // Interior horizontal surfaces, heat flow down IP: 0.92 SI: 0.1620
1428 : // Interior vertical surfaces IP: 0.68 SI: 0.1198
1429 : // This section shows the same value in 90.1-2010 and 90.2-2010
1430 : // Note that this report does not use the semi-exterior surface value because
1431 : // EnergyPlus does not have a way to specifically tell whether or not a surface
1432 : // is connected to a semi-exterior area of the building. Users can always use
1433 : // the Nominal U-Value to manually calculated this. The values calculated here
1434 : // are simply reported to the EIO file and not used for any calculations.
1435 :
1436 : // Return value
1437 : Real64 NominalUwithConvCoeffs; // return value
1438 :
1439 : static constexpr std::array<Real64, static_cast<int>(DataSurfaces::SurfaceClass::Num)> filmCoefs = {
1440 : 0.0, // None
1441 : 0.1197548, // Wall
1442 : 0.1620212, // Floor
1443 : 0.1074271, // Roof
1444 : 0.0, // IntMass
1445 : 0.0, // Detached_B
1446 : 0.0, // Detached_F
1447 : 0.1197548, // Window
1448 : 0.1197548, // GlassDoor
1449 : 0.1197548, // Door
1450 : 0.0, // Shading
1451 : 0.0, // Overhang
1452 : 0.0, // Fin
1453 : 0.0, // TDD_Dome
1454 : 0.0 // TDD_Diffuser
1455 : }; // If anything added to the enum SurfaceClass, adjust this list appropriately
1456 :
1457 : Real64 insideFilm;
1458 : Real64 outsideFilm;
1459 :
1460 42220 : isValid = true;
1461 :
1462 42220 : auto &thisSurface = state.dataSurface->Surface(numSurf);
1463 :
1464 : // exterior conditions
1465 42220 : switch (thisSurface.ExtBoundCond) {
1466 17079 : case DataSurfaces::ExternalEnvironment: { // ExtBoundCond = 0
1467 17079 : outsideFilm = 0.0299387; // All exterior conditions
1468 17079 : } break;
1469 1 : case DataSurfaces::OtherSideCoefCalcExt: {
1470 1 : outsideFilm = state.dataSurface->OSC(thisSurface.OSCPtr).SurfFilmCoef;
1471 1 : } break;
1472 2408 : case DataSurfaces::Ground:
1473 : case DataSurfaces::OtherSideCoefNoCalcExt:
1474 : case DataSurfaces::OtherSideCondModeledExt:
1475 : case DataSurfaces::GroundFCfactorMethod:
1476 : case DataSurfaces::KivaFoundation: { // All these cases have a negative ExtBoundCond so don't use film coefficients
1477 2408 : outsideFilm = 0.0;
1478 2408 : } break;
1479 22732 : default: { // Interior Surface Attached to a Zone (ExtBoundCond is a surface)
1480 22732 : outsideFilm = filmCoefs[static_cast<int>(state.dataSurface->Surface(thisSurface.ExtBoundCond).Class)];
1481 22732 : } break;
1482 : }
1483 : // interior conditions and calculate the return value
1484 42220 : if (state.dataHeatBal->NominalU(thisSurface.Construction) > 0.0) {
1485 42206 : insideFilm = filmCoefs[static_cast<int>(thisSurface.Class)];
1486 42206 : if (insideFilm == 0.0) outsideFilm = 0.0;
1487 42206 : NominalUwithConvCoeffs =
1488 42206 : 1.0 / (insideFilm + (1.0 / state.dataHeatBal->NominalU(state.dataSurface->Surface(numSurf).Construction)) + outsideFilm);
1489 : } else {
1490 14 : isValid = false;
1491 14 : NominalUwithConvCoeffs = state.dataHeatBal->NominalU(state.dataSurface->Surface(numSurf).Construction);
1492 : }
1493 :
1494 42220 : return NominalUwithConvCoeffs;
1495 : }
1496 :
1497 771 : void SetFlagForWindowConstructionWithShadeOrBlindLayer(EnergyPlusData &state)
1498 : {
1499 :
1500 : // PURPOSE OF THIS SUBROUTINE:
1501 : // check fenestrations with shading control and set a flag to true if its construction has
1502 : // either shade or blind material layer
1503 :
1504 : // METHODOLOGY EMPLOYED:
1505 : // Loop through Surface and register any shading controls, and loop through the construction
1506 : // material layer
1507 :
1508 : // Using/Aliasing
1509 : using DataSurfaces::ExternalEnvironment;
1510 :
1511 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1512 771 : int loopSurfNum(0); // surface index
1513 771 : int ConstrNum(0); // construction index
1514 771 : int NumLayers(0); // number of material layers in a construction
1515 771 : int Layer(0); // construction material layer index
1516 771 : int MaterNum(0); // construction material index
1517 :
1518 44533 : for (loopSurfNum = 1; loopSurfNum <= state.dataSurface->TotSurfaces; ++loopSurfNum) {
1519 :
1520 43762 : if (state.dataSurface->Surface(loopSurfNum).Class != DataSurfaces::SurfaceClass::Window) continue;
1521 5974 : if (state.dataSurface->Surface(loopSurfNum).ExtBoundCond != ExternalEnvironment) continue;
1522 5960 : if (!state.dataSurface->Surface(loopSurfNum).HasShadeControl) continue;
1523 143 : if (state.dataSurface->Surface(loopSurfNum).activeShadedConstruction == 0) continue;
1524 :
1525 143 : ConstrNum = state.dataSurface->Surface(loopSurfNum).activeShadedConstruction;
1526 143 : if (state.dataConstruction->Construct(ConstrNum).TypeIsWindow) {
1527 143 : NumLayers = state.dataConstruction->Construct(ConstrNum).TotLayers;
1528 586 : for (Layer = 1; Layer <= NumLayers; ++Layer) {
1529 443 : MaterNum = state.dataConstruction->Construct(ConstrNum).LayerPoint(Layer);
1530 443 : if (MaterNum == 0) continue;
1531 815 : if (state.dataMaterial->Material(MaterNum).Group == DataHeatBalance::MaterialGroup::Shade ||
1532 372 : state.dataMaterial->Material(MaterNum).Group == DataHeatBalance::MaterialGroup::WindowBlind)
1533 105 : state.dataSurface->SurfWinHasShadeOrBlindLayer(loopSurfNum) = true;
1534 : }
1535 : }
1536 : }
1537 771 : }
1538 :
1539 771 : void AllocateIntGains(EnergyPlusData &state)
1540 : {
1541 771 : state.dataHeatBal->ZoneIntGain.allocate(state.dataGlobal->NumOfZones);
1542 771 : state.dataHeatBal->spaceIntGain.allocate(state.dataGlobal->numSpaces);
1543 771 : state.dataHeatBal->spaceIntGainDevices.allocate(state.dataGlobal->numSpaces);
1544 771 : state.dataDaylightingData->spacePowerReductionFactor.dimension(state.dataGlobal->numSpaces, 1.0);
1545 771 : }
1546 :
1547 2313 : } // namespace EnergyPlus::DataHeatBalance
|