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 : // ObjexxFCL Headers
49 : #include <ObjexxFCL/Array.functions.hh>
50 :
51 : // EnergyPlus Headers
52 : #include <EnergyPlus/CurveManager.hh>
53 : #include <EnergyPlus/Data/EnergyPlusData.hh>
54 : #include <EnergyPlus/DataEnvironment.hh>
55 : #include <EnergyPlus/DataIPShortCuts.hh>
56 : #include <EnergyPlus/EMSManager.hh>
57 : #include <EnergyPlus/General.hh>
58 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
59 : #include <EnergyPlus/Material.hh>
60 : #include <EnergyPlus/ScheduleManager.hh>
61 : #include <EnergyPlus/UtilityRoutines.hh>
62 : #include <EnergyPlus/WindowModel.hh>
63 :
64 : namespace EnergyPlus::Material {
65 :
66 : constexpr std::array<std::string_view, (int)GapVentType::Num> gapVentTypeNames = {"Sealed", "VentedIndoor", "VentedOutdoor"};
67 : constexpr std::array<std::string_view, (int)GasType::Num> gasTypeNames = {"Custom", "Air", "Argon", "Krypton", "Xenon"};
68 : constexpr std::array<std::string_view, (int)GasType::Num> gasTypeNamesUC = {"CUSTOM", "AIR", "ARGON", "KRYPTON", "XENON"};
69 : constexpr std::array<std::string_view, (int)SurfaceRoughness::Num> surfaceRoughnessNames = {
70 : "VeryRough", "Rough", "MediumRough", "MediumSmooth", "Smooth", "VerySmooth"};
71 :
72 : constexpr std::array<Material::Gas, 10> gases = {
73 : Gas(), // Empty
74 : {GasType::Air, {2.873e-3, 7.760e-5, 0.0}, {3.723e-6, 4.940e-8, 0.0}, {1002.737, 1.2324e-2, 0.0}, 28.97, 1.4}, // Air
75 : {GasType::Argon, {2.285e-3, 5.149e-5, 0.0}, {3.379e-6, 6.451e-8, 0.0}, {521.929, 0.0, 0.0}, 39.948, 1.67}, // Argon
76 : {GasType::Krypton, {9.443e-4, 2.826e-5, 0.0}, {2.213e-6, 7.777e-8, 0.0}, {248.091, 0.0, 0.0}, 83.8, 1.68}, // Krypton
77 : {GasType::Xenon, {4.538e-4, 1.723e-5, 0.0}, {1.069e-6, 7.414e-8, 0.0}, {158.340, 0.0, 0.0}, 131.3, 1.66}, // Xenon
78 : Gas(), // Empty
79 : Gas(), // Empty
80 : Gas(), // Empty
81 : Gas(), // Empty
82 : Gas() // Empty
83 : };
84 :
85 : constexpr std::array<std::string_view, (int)EcoRoofCalcMethod::Num> ecoRoofCalcMethodNamesUC = {"SIMPLE", "ADVANCED"};
86 :
87 1514 : int GetMaterialNum(EnergyPlusData const &state, std::string const &matName)
88 : {
89 1514 : auto const &s_mat = state.dataMaterial;
90 1514 : auto found = s_mat->materialMap.find(Util::makeUPPER(matName));
91 1514 : return (found != s_mat->materialMap.end()) ? found->second : 0;
92 : }
93 :
94 0 : MaterialBase *GetMaterial(EnergyPlusData &state, std::string const &matName)
95 : {
96 0 : auto &s_mat = state.dataMaterial;
97 0 : int matNum = GetMaterialNum(state, matName);
98 0 : return (matNum > 0) ? s_mat->materials(matNum) : nullptr;
99 : }
100 :
101 273 : void GetMaterialData(EnergyPlusData &state, bool &ErrorsFound) // set to true if errors found in input
102 : {
103 :
104 : // SUBROUTINE INFORMATION:
105 : // AUTHOR Richard Liesen
106 : // DATE WRITTEN September 1997
107 : // MODIFIED April 1999; L.Lawrie
108 : // Sept 1999, FCW, Window5 modifications
109 : // Mar 2001, FCW, WindowShade mods
110 : // Sep 2001, FCW, add Material:WindowGasMixture
111 : // Oct 2001, FCW, add Material:WindowBlind
112 : // Dec 2003, FCW, add glass solar/visible transmittance dirt factor
113 : // Feb 2009, TH, added WindowMaterial:GlazingGroup:Thermochromic
114 :
115 : // RE-ENGINEERED na
116 :
117 : // PURPOSE OF THIS SUBROUTINE:
118 : // The purpose of this subroutine is to serve as a transfer agent
119 : // between the input file and the material derived type. The new input
120 : // file is working, and this file reads the material data directly
121 : // from the input file and transfer that information to the new data
122 : // structure. Data read in this routine is stored in a
123 : // derived type (Material) defined in the DataHeatBalance module.
124 :
125 : // In April 1999, a new set of material definitions replaced the one "all-purpose"
126 : // material definition. There are now 10 flavors of materials. Definitions from
127 : // the IDD appear below before their counterpart "gets".
128 :
129 : using Curve::GetCurveIndex;
130 : using Curve::GetCurveMinMaxValues;
131 :
132 : using General::ScanForReports;
133 :
134 : int IOStat; // IO Status when calling get input subroutine
135 : int NumAlphas; // Number of material alpha names being passed
136 : int NumNums; // Number of material properties being passed
137 :
138 : int NumGas; // Index for loop over gap gases in a mixture
139 : int NumGases; // Number of gasses in a mixture
140 273 : GasType gasType = GasType::Invalid; // Gas type index: 1=air, 2=argon, 3=krypton, 4=xenon
141 : int ICoeff; // Gas property coefficient index
142 : Real64 MinSlatAngGeom; // Minimum and maximum slat angle allowed by slat geometry (deg)
143 : Real64 MaxSlatAngGeom;
144 : Real64 ReflectivitySol; // Glass reflectivity, solar
145 : Real64 ReflectivityVis; // Glass reflectivity, visible
146 : Real64 TransmittivitySol; // Glass transmittivity, solar
147 : Real64 TransmittivityVis; // Glass transmittivity, visible
148 : Real64 DenomRGas; // Denominator for WindowGas calculations of NominalR
149 : Real64 Openness; // insect screen openness fraction = (1-d/s)^2
150 : Real64 minAngValue; // minimum value of angle
151 : Real64 maxAngValue; // maximum value of angle
152 : Real64 minLamValue; // minimum value of wavelength
153 : Real64 maxLamValue; // maximum value of wavelength
154 :
155 : // Added TH 1/9/2009 to read the thermochromic glazings
156 :
157 : // Added TH 7/27/2009 for constructions defined with F or C factor method
158 : int TotFfactorConstructs; // Number of slabs-on-grade or underground floor constructions defined with F factors
159 : int TotCfactorConstructs; // Number of underground wall constructions defined with C factors
160 :
161 : static constexpr std::string_view routineName = "GetMaterialData";
162 :
163 273 : auto &s_mat = state.dataMaterial;
164 273 : auto &s_ip = state.dataInputProcessing->inputProcessor;
165 273 : auto &s_ipsc = state.dataIPShortCut;
166 :
167 273 : s_mat->NumNoMasses = s_ip->getNumObjectsFound(state, "Material:NoMass");
168 273 : s_mat->NumIRTs = s_ip->getNumObjectsFound(state, "Material:InfraredTransparent");
169 273 : s_mat->NumAirGaps = s_ip->getNumObjectsFound(state, "Material:AirGap");
170 :
171 273 : TotFfactorConstructs = s_ip->getNumObjectsFound(state, "Construction:FfactorGroundFloor");
172 273 : TotCfactorConstructs = s_ip->getNumObjectsFound(state, "Construction:CfactorUndergroundWall");
173 :
174 : // Regular Materials
175 :
176 273 : s_ipsc->cCurrentModuleObject = "Material";
177 273 : auto const instances = s_ip->epJSON.find(s_ipsc->cCurrentModuleObject);
178 273 : if (instances != s_ip->epJSON.end()) {
179 247 : auto const &objectSchemaProps = s_ip->getObjectSchemaProps(state, s_ipsc->cCurrentModuleObject);
180 :
181 247 : auto &instancesValue = instances.value();
182 :
183 247 : std::vector<std::string> idfSortedKeys = s_ip->getIDFOrderedKeys(state, s_ipsc->cCurrentModuleObject);
184 1090 : for (std::string const &key : idfSortedKeys) {
185 :
186 843 : auto instance = instancesValue.find(key);
187 843 : assert(instance != instancesValue.end());
188 :
189 843 : auto const &objectFields = instance.value();
190 843 : std::string matNameUC = Util::makeUPPER(key);
191 843 : s_ip->markObjectAsUsed(s_ipsc->cCurrentModuleObject, key);
192 :
193 843 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, key};
194 :
195 843 : if (s_mat->materialMap.find(matNameUC) != s_mat->materialMap.end()) {
196 0 : ShowSevereDuplicateName(state, eoh);
197 0 : ErrorsFound = true;
198 0 : continue;
199 : }
200 :
201 : // Load the material derived type from the input data.
202 843 : auto *mat = new MaterialBase;
203 843 : mat->group = Group::Regular;
204 843 : mat->Name = key;
205 :
206 843 : s_mat->materials.push_back(mat);
207 843 : mat->Num = s_mat->materials.isize();
208 843 : s_mat->materialMap.insert_or_assign(matNameUC, mat->Num);
209 :
210 1686 : std::string roughness = s_ip->getAlphaFieldValue(objectFields, objectSchemaProps, "roughness");
211 843 : mat->Roughness = static_cast<SurfaceRoughness>(getEnumValue(surfaceRoughnessNamesUC, Util::makeUPPER(roughness)));
212 1686 : mat->Thickness = s_ip->getRealFieldValue(objectFields, objectSchemaProps, "thickness");
213 1686 : mat->Conductivity = s_ip->getRealFieldValue(objectFields, objectSchemaProps, "conductivity");
214 1686 : mat->Density = s_ip->getRealFieldValue(objectFields, objectSchemaProps, "density");
215 1686 : mat->SpecHeat = s_ip->getRealFieldValue(objectFields, objectSchemaProps, "specific_heat");
216 1686 : mat->AbsorpThermal = s_ip->getRealFieldValue(objectFields, objectSchemaProps, "thermal_absorptance");
217 843 : mat->AbsorpThermalInput = mat->AbsorpThermal;
218 1686 : mat->AbsorpSolar = s_ip->getRealFieldValue(objectFields, objectSchemaProps, "solar_absorptance");
219 843 : mat->AbsorpSolarInput = mat->AbsorpSolar;
220 1686 : mat->AbsorpVisible = s_ip->getRealFieldValue(objectFields, objectSchemaProps, "visible_absorptance");
221 843 : mat->AbsorpVisibleInput = mat->AbsorpVisible;
222 :
223 843 : if (mat->Conductivity > 0.0) {
224 843 : mat->Resistance = mat->NominalR = mat->Thickness / mat->Conductivity;
225 : } else {
226 0 : ShowSevereError(state, format("Positive thermal conductivity required for material {}", mat->Name));
227 0 : ErrorsFound = true;
228 : }
229 843 : }
230 247 : }
231 :
232 : // Add the 6" heavy concrete for constructions defined with F or C factor method
233 273 : if (TotFfactorConstructs + TotCfactorConstructs >= 1) {
234 0 : auto *mat = new MaterialBase;
235 0 : mat->group = Group::Regular;
236 0 : mat->Name = "~FC_Concrete";
237 :
238 0 : s_mat->materials.push_back(mat);
239 0 : mat->Num = s_mat->materials.isize();
240 0 : s_mat->materialMap.insert_or_assign(Util::makeUPPER(mat->Name), mat->Num);
241 :
242 0 : mat->Thickness = 0.15; // m, 0.15m = 6 inches
243 0 : mat->Conductivity = 1.95; // W/mK
244 0 : mat->Density = 2240.0; // kg/m3
245 0 : mat->SpecHeat = 900.0; // J/kgK
246 0 : mat->Roughness = SurfaceRoughness::MediumRough;
247 0 : mat->AbsorpSolar = 0.7;
248 0 : mat->AbsorpThermal = 0.9;
249 0 : mat->AbsorpVisible = 0.7;
250 0 : mat->Resistance = mat->NominalR = mat->Thickness / mat->Conductivity;
251 : }
252 :
253 273 : s_ipsc->cCurrentModuleObject = "Material:NoMass";
254 475 : for (int Loop = 1; Loop <= s_mat->NumNoMasses; ++Loop) {
255 :
256 : // Call Input Get routine to retrieve material data
257 404 : s_ip->getObjectItem(state,
258 202 : s_ipsc->cCurrentModuleObject,
259 : Loop,
260 202 : s_ipsc->cAlphaArgs,
261 : NumAlphas,
262 202 : s_ipsc->rNumericArgs,
263 : NumNums,
264 : IOStat,
265 202 : s_ipsc->lNumericFieldBlanks,
266 202 : s_ipsc->lAlphaFieldBlanks,
267 202 : s_ipsc->cAlphaFieldNames,
268 202 : s_ipsc->cNumericFieldNames);
269 :
270 202 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
271 :
272 202 : if (s_mat->materialMap.find(s_ipsc->cAlphaArgs(1)) != s_mat->materialMap.end()) {
273 0 : ShowSevereDuplicateName(state, eoh);
274 0 : ErrorsFound = true;
275 0 : continue;
276 : }
277 :
278 202 : auto *mat = new MaterialBase;
279 202 : mat->group = Group::Regular;
280 202 : mat->Name = s_ipsc->cAlphaArgs(1);
281 :
282 202 : s_mat->materials.push_back(mat);
283 202 : mat->Num = s_mat->materials.isize();
284 202 : s_mat->materialMap.insert_or_assign(mat->Name, mat->Num);
285 :
286 202 : mat->Roughness = static_cast<SurfaceRoughness>(getEnumValue(surfaceRoughnessNamesUC, Util::makeUPPER(s_ipsc->cAlphaArgs(2))));
287 :
288 202 : mat->Resistance = s_ipsc->rNumericArgs(1);
289 202 : mat->ROnly = true;
290 202 : if (NumNums >= 2) {
291 199 : mat->AbsorpThermal = s_ipsc->rNumericArgs(2);
292 199 : mat->AbsorpThermalInput = s_ipsc->rNumericArgs(2);
293 : } else {
294 3 : mat->AbsorpThermal = 0.9;
295 3 : mat->AbsorpThermalInput = 0.9;
296 : }
297 202 : if (NumNums >= 3) {
298 199 : mat->AbsorpSolar = s_ipsc->rNumericArgs(3);
299 199 : mat->AbsorpSolarInput = s_ipsc->rNumericArgs(3);
300 : } else {
301 3 : mat->AbsorpSolar = 0.7;
302 3 : mat->AbsorpSolarInput = 0.7;
303 : }
304 202 : if (NumNums >= 4) {
305 197 : mat->AbsorpVisible = s_ipsc->rNumericArgs(4);
306 197 : mat->AbsorpVisibleInput = s_ipsc->rNumericArgs(4);
307 : } else {
308 5 : mat->AbsorpVisible = 0.7;
309 5 : mat->AbsorpVisibleInput = 0.7;
310 : }
311 :
312 202 : mat->NominalR = mat->Resistance;
313 : }
314 :
315 : // Add a fictitious insulation layer for each construction defined with F or C factor method
316 273 : if (TotFfactorConstructs + TotCfactorConstructs >= 1) {
317 0 : for (int Loop = 1; Loop <= TotFfactorConstructs + TotCfactorConstructs; ++Loop) {
318 0 : auto *mat = new MaterialBase;
319 0 : mat->group = Group::Regular;
320 0 : mat->Name = format("~FC_Insulation_{}", Loop);
321 :
322 0 : s_mat->materials.push_back(mat);
323 0 : mat->Num = s_mat->materials.isize();
324 0 : s_mat->materialMap.insert_or_assign(Util::makeUPPER(mat->Name), mat->Num);
325 :
326 0 : mat->ROnly = true;
327 0 : mat->Roughness = SurfaceRoughness::MediumRough;
328 0 : mat->AbsorpSolar = 0.0;
329 0 : mat->AbsorpThermal = 0.0;
330 0 : mat->AbsorpVisible = 0.0;
331 : }
332 : }
333 :
334 : // Air Materials (for air spaces in opaque constructions)
335 273 : s_ipsc->cCurrentModuleObject = "Material:AirGap";
336 307 : for (int Loop = 1; Loop <= s_mat->NumAirGaps; ++Loop) {
337 :
338 : // Call Input Get routine to retrieve material data
339 68 : s_ip->getObjectItem(state,
340 34 : s_ipsc->cCurrentModuleObject,
341 : Loop,
342 34 : s_ipsc->cAlphaArgs,
343 : NumAlphas,
344 34 : s_ipsc->rNumericArgs,
345 : NumNums,
346 : IOStat,
347 34 : s_ipsc->lNumericFieldBlanks,
348 34 : s_ipsc->lAlphaFieldBlanks,
349 34 : s_ipsc->cAlphaFieldNames,
350 34 : s_ipsc->cNumericFieldNames);
351 :
352 34 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
353 :
354 34 : if (s_mat->materialMap.find(s_ipsc->cAlphaArgs(1)) != s_mat->materialMap.end()) {
355 0 : ShowSevereDuplicateName(state, eoh);
356 0 : ErrorsFound = true;
357 0 : continue;
358 : }
359 :
360 : // Load the material derived type from the input data.
361 34 : auto *mat = new MaterialBase;
362 34 : mat->group = Group::AirGap;
363 34 : mat->Name = s_ipsc->cAlphaArgs(1);
364 :
365 34 : s_mat->materials.push_back(mat);
366 34 : mat->Num = s_mat->materials.isize();
367 34 : s_mat->materialMap.insert_or_assign(mat->Name, mat->Num);
368 :
369 34 : mat->Roughness = SurfaceRoughness::MediumRough;
370 :
371 34 : mat->NominalR = mat->Resistance = s_ipsc->rNumericArgs(1);
372 34 : mat->ROnly = true;
373 : }
374 :
375 273 : s_ipsc->cCurrentModuleObject = "Material:InfraredTransparent";
376 274 : for (int Loop = 1; Loop <= s_mat->NumIRTs; ++Loop) {
377 :
378 : // Call Input Get routine to retrieve material data
379 2 : s_ip->getObjectItem(state,
380 1 : s_ipsc->cCurrentModuleObject,
381 : Loop,
382 1 : s_ipsc->cAlphaArgs,
383 : NumAlphas,
384 1 : s_ipsc->rNumericArgs,
385 : NumNums,
386 : IOStat,
387 1 : s_ipsc->lNumericFieldBlanks,
388 1 : s_ipsc->lAlphaFieldBlanks,
389 1 : s_ipsc->cAlphaFieldNames,
390 1 : s_ipsc->cNumericFieldNames);
391 :
392 1 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
393 :
394 1 : if (s_mat->materialMap.find(s_ipsc->cAlphaArgs(1)) != s_mat->materialMap.end()) {
395 0 : ShowSevereDuplicateName(state, eoh);
396 0 : ErrorsFound = true;
397 0 : continue;
398 : }
399 :
400 1 : auto *mat = new MaterialBase;
401 1 : mat->group = Group::IRTransparent;
402 1 : mat->Name = s_ipsc->cAlphaArgs(1);
403 :
404 1 : s_mat->materials.push_back(mat);
405 1 : mat->Num = s_mat->materials.isize();
406 1 : s_mat->materialMap.insert_or_assign(mat->Name, mat->Num);
407 :
408 : // Load data for other properties that need defaults
409 1 : mat->ROnly = true;
410 1 : mat->NominalR = mat->Resistance = 0.01;
411 1 : mat->AbsorpThermal = 0.9999;
412 1 : mat->AbsorpThermalInput = 0.9999;
413 1 : mat->AbsorpSolar = 1.0;
414 1 : mat->AbsorpSolarInput = 1.0;
415 1 : mat->AbsorpVisible = 1.0;
416 1 : mat->AbsorpVisibleInput = 1.0;
417 : }
418 :
419 : // Glass materials, regular input: transmittance and front/back reflectance
420 :
421 273 : s_ipsc->cCurrentModuleObject = "WindowMaterial:Glazing";
422 273 : s_mat->NumW5Glazings = s_ip->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
423 369 : for (int Loop = 1; Loop <= s_mat->NumW5Glazings; ++Loop) {
424 :
425 : // Call Input Get routine to retrieve material data
426 192 : s_ip->getObjectItem(state,
427 96 : s_ipsc->cCurrentModuleObject,
428 : Loop,
429 96 : s_ipsc->cAlphaArgs,
430 : NumAlphas,
431 96 : s_ipsc->rNumericArgs,
432 : NumNums,
433 : IOStat,
434 96 : s_ipsc->lNumericFieldBlanks,
435 96 : s_ipsc->lAlphaFieldBlanks,
436 96 : s_ipsc->cAlphaFieldNames,
437 96 : s_ipsc->cNumericFieldNames);
438 :
439 96 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
440 :
441 96 : if (s_mat->materialMap.find(s_ipsc->cAlphaArgs(1)) != s_mat->materialMap.end()) {
442 0 : ShowSevereDuplicateName(state, eoh);
443 0 : ErrorsFound = true;
444 0 : continue;
445 : }
446 :
447 96 : auto *mat = new MaterialGlass;
448 96 : mat->Name = s_ipsc->cAlphaArgs(1);
449 :
450 96 : s_mat->materials.push_back(mat);
451 96 : mat->Num = s_mat->materials.isize();
452 96 : s_mat->materialMap.insert_or_assign(mat->Name, mat->Num);
453 :
454 96 : mat->Roughness = SurfaceRoughness::VerySmooth;
455 96 : mat->ROnly = true;
456 96 : mat->Thickness = s_ipsc->rNumericArgs(1);
457 :
458 96 : mat->windowOpticalData = static_cast<Window::OpticalDataModel>(getEnumValue(Window::opticalDataModelNamesUC, s_ipsc->cAlphaArgs(2)));
459 96 : if (mat->windowOpticalData != Window::OpticalDataModel::SpectralAndAngle) {
460 95 : mat->Trans = s_ipsc->rNumericArgs(2);
461 95 : mat->ReflectSolBeamFront = s_ipsc->rNumericArgs(3);
462 95 : mat->ReflectSolBeamBack = s_ipsc->rNumericArgs(4);
463 95 : mat->TransVis = s_ipsc->rNumericArgs(5);
464 95 : mat->ReflectVisBeamFront = s_ipsc->rNumericArgs(6);
465 95 : mat->ReflectVisBeamBack = s_ipsc->rNumericArgs(7);
466 95 : mat->TransThermal = s_ipsc->rNumericArgs(8);
467 : }
468 96 : mat->AbsorpThermalFront = s_ipsc->rNumericArgs(9);
469 96 : mat->AbsorpThermalBack = s_ipsc->rNumericArgs(10);
470 96 : mat->Conductivity = s_ipsc->rNumericArgs(11);
471 96 : mat->GlassTransDirtFactor = s_ipsc->rNumericArgs(12);
472 96 : mat->YoungModulus = s_ipsc->rNumericArgs(13);
473 96 : mat->PoissonsRatio = s_ipsc->rNumericArgs(14);
474 96 : if (s_ipsc->rNumericArgs(12) == 0.0) mat->GlassTransDirtFactor = 1.0;
475 96 : mat->AbsorpThermal = mat->AbsorpThermalBack;
476 :
477 96 : if (mat->Conductivity > 0.0) {
478 96 : mat->Resistance = mat->NominalR = mat->Thickness / mat->Conductivity;
479 : } else {
480 0 : ErrorsFound = true;
481 0 : ShowSevereError(state, format("Window glass material {} has Conductivity = 0.0, must be >0.0, default = .9", mat->Name));
482 : }
483 :
484 96 : mat->windowOpticalData = static_cast<Window::OpticalDataModel>(getEnumValue(Window::opticalDataModelNamesUC, s_ipsc->cAlphaArgs(2)));
485 :
486 96 : if (mat->windowOpticalData == Window::OpticalDataModel::Spectral) {
487 2 : if (s_ipsc->lAlphaFieldBlanks(3)) {
488 0 : ShowSevereCustom(state, eoh, format("{} = Spectral but {} is blank.", s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaFieldNames(3)));
489 0 : ErrorsFound = true;
490 2 : } else if ((mat->GlassSpectralDataPtr = Util::FindItemInList(s_ipsc->cAlphaArgs(3), s_mat->SpectralData)) == 0) {
491 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3));
492 0 : ErrorsFound = true;
493 : }
494 :
495 : // TH 8/24/2011, allow glazing properties s_ipsc->rNumericArgs(2 to 10) to equal 0 or 1: 0.0 =< Prop <= 1.0
496 : // Fixed CR 8413 - modeling spandrel panels as glazing systems
497 94 : } else if (mat->windowOpticalData == Window::OpticalDataModel::SpectralAverage) {
498 :
499 92 : if (s_ipsc->rNumericArgs(2) + s_ipsc->rNumericArgs(3) > 1.0) {
500 0 : ErrorsFound = true;
501 0 : ShowSevereCustom(state, eoh, format("{} + {} not <= 1.0", s_ipsc->cNumericFieldNames(2), s_ipsc->cNumericFieldNames(3)));
502 : }
503 :
504 92 : if (s_ipsc->rNumericArgs(2) + s_ipsc->rNumericArgs(4) > 1.0) {
505 0 : ErrorsFound = true;
506 0 : ShowSevereCustom(state, eoh, format("{} + {} not <= 1.0", s_ipsc->cNumericFieldNames(2), s_ipsc->cNumericFieldNames(4)));
507 : }
508 :
509 92 : if (s_ipsc->rNumericArgs(5) + s_ipsc->rNumericArgs(6) > 1.0) {
510 0 : ErrorsFound = true;
511 0 : ShowSevereCustom(state, eoh, format("{} + {} not <= 1.0", s_ipsc->cNumericFieldNames(5), s_ipsc->cNumericFieldNames(6)));
512 : }
513 :
514 92 : if (s_ipsc->rNumericArgs(5) + s_ipsc->rNumericArgs(7) > 1.0) {
515 0 : ErrorsFound = true;
516 0 : ShowSevereCustom(state, eoh, format("{} + {} not <= 1.0", s_ipsc->cNumericFieldNames(5), s_ipsc->cNumericFieldNames(7)));
517 : }
518 :
519 92 : if (s_ipsc->rNumericArgs(8) + s_ipsc->rNumericArgs(9) > 1.0) {
520 0 : ErrorsFound = true;
521 0 : ShowSevereCustom(state, eoh, format("{} + {} not <= 1.0", s_ipsc->cNumericFieldNames(8), s_ipsc->cNumericFieldNames(9)));
522 : }
523 :
524 92 : if (s_ipsc->rNumericArgs(8) + s_ipsc->rNumericArgs(10) > 1.0) {
525 0 : ErrorsFound = true;
526 0 : ShowSevereCustom(state, eoh, format("{} + {} not <= 1.0", s_ipsc->cNumericFieldNames(8), s_ipsc->cNumericFieldNames(10)));
527 : }
528 :
529 92 : if (s_ipsc->rNumericArgs(2) < 0.0) {
530 0 : ShowSevereCustom(state, eoh, format("{} not >= 0.0", s_ipsc->cNumericFieldNames(2)));
531 0 : ErrorsFound = true;
532 : }
533 :
534 92 : if (s_ipsc->rNumericArgs(2) > 1.0) {
535 0 : ErrorsFound = true;
536 0 : ShowSevereCustom(state, eoh, format("{} not <= 1.0", s_ipsc->cNumericFieldNames(2)));
537 : }
538 :
539 92 : if (s_ipsc->rNumericArgs(3) < 0.0 || s_ipsc->rNumericArgs(3) > 1.0) {
540 0 : ErrorsFound = true;
541 0 : ShowSevereCustom(state, eoh, format("{} not >= 0.0 and <= 1.0", s_ipsc->cNumericFieldNames(3)));
542 : }
543 :
544 92 : if (s_ipsc->rNumericArgs(4) < 0.0 || s_ipsc->rNumericArgs(4) > 1.0) {
545 0 : ErrorsFound = true;
546 0 : ShowSevereCustom(state, eoh, format("{} not >= 0.0 and <= 1.0", s_ipsc->cNumericFieldNames(4)));
547 : }
548 :
549 92 : if (s_ipsc->rNumericArgs(5) < 0.0) {
550 0 : ShowWarningCustom(state, eoh, format("{} not >= 0.0", s_ipsc->cNumericFieldNames(5)));
551 : }
552 :
553 92 : if (s_ipsc->rNumericArgs(5) > 1.0) {
554 0 : ErrorsFound = true;
555 0 : ShowSevereCustom(state, eoh, format("{} not <= 1.0", s_ipsc->cNumericFieldNames(5)));
556 : }
557 :
558 92 : if (s_ipsc->rNumericArgs(6) < 0.0 || s_ipsc->rNumericArgs(6) > 1.0) {
559 0 : ErrorsFound = true;
560 0 : ShowSevereCustom(state, eoh, format("{} not >= 0.0 and <= 1.0", s_ipsc->cNumericFieldNames(6)));
561 : }
562 :
563 92 : if (s_ipsc->rNumericArgs(7) < 0.0 || s_ipsc->rNumericArgs(7) > 1.0) {
564 0 : ErrorsFound = true;
565 0 : ShowSevereCustom(state, eoh, format("{} not >= 0.0 and <= 1.0", s_ipsc->cNumericFieldNames(7)));
566 : }
567 : }
568 :
569 96 : if (s_ipsc->rNumericArgs(8) > 1.0) {
570 0 : ErrorsFound = true;
571 0 : ShowSevereCustom(state, eoh, format("{} not <= 1.0", s_ipsc->cNumericFieldNames(8)));
572 : }
573 :
574 96 : if (s_ipsc->rNumericArgs(9) <= 0.0 || s_ipsc->rNumericArgs(9) >= 1.0) {
575 0 : ErrorsFound = true;
576 0 : ShowSevereCustom(state, eoh, format("{} not > 0.0 and < 1.0", s_ipsc->cNumericFieldNames(9)));
577 : }
578 :
579 96 : if (s_ipsc->rNumericArgs(10) <= 0.0 || s_ipsc->rNumericArgs(10) >= 1.0) {
580 0 : ErrorsFound = true;
581 0 : ShowSevereError(state, format("{}=\"{}\", Illegal value.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
582 0 : ShowContinueError(state, format("{} not > 0.0 and < 1.0", s_ipsc->cNumericFieldNames(10)));
583 : }
584 :
585 96 : if (s_ipsc->rNumericArgs(11) <= 0.0) {
586 0 : ErrorsFound = true;
587 0 : ShowSevereCustom(state, eoh, format("{} not > 0.0", s_ipsc->cNumericFieldNames(11)));
588 : }
589 :
590 96 : if (s_ipsc->rNumericArgs(13) < 0.0) {
591 0 : ErrorsFound = true;
592 0 : ShowSevereCustom(state, eoh, format("{} not > 0.0", s_ipsc->cNumericFieldNames(13)));
593 : }
594 :
595 96 : if (s_ipsc->rNumericArgs(14) < 0.0 || s_ipsc->rNumericArgs(14) >= 1.0) {
596 0 : ErrorsFound = true;
597 0 : ShowSevereCustom(state, eoh, format("{} not > 0.0 and < 1.0", s_ipsc->cNumericFieldNames(14)));
598 : }
599 :
600 96 : if (s_ipsc->cAlphaArgs(4) == "") {
601 0 : mat->SolarDiffusing = false;
602 : } else {
603 96 : BooleanSwitch answer = getYesNoValue(s_ipsc->cAlphaArgs(4));
604 96 : if (answer == BooleanSwitch::Invalid) {
605 0 : ErrorsFound = true;
606 0 : ShowSevereError(state, format("{}=\"{}\", Illegal value.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
607 0 : ShowContinueError(state, format("{} must be Yes or No, entered value={}", s_ipsc->cNumericFieldNames(4), s_ipsc->cAlphaArgs(4)));
608 : } else {
609 96 : mat->SolarDiffusing = (answer == BooleanSwitch::Yes);
610 : }
611 : }
612 :
613 : // Get SpectralAndAngle table names
614 96 : if (mat->windowOpticalData == Window::OpticalDataModel::SpectralAndAngle) {
615 1 : if (s_ipsc->lAlphaFieldBlanks(5)) {
616 0 : ErrorsFound = true;
617 0 : ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(5), s_ipsc->cAlphaFieldNames(2), "SpectralAndAngle");
618 1 : } else if ((mat->GlassSpecAngTransCurve = Curve::GetCurve(state, s_ipsc->cAlphaArgs(5))) == nullptr) {
619 0 : ErrorsFound = true;
620 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(5), s_ipsc->cAlphaArgs(5));
621 1 : } else if (mat->GlassSpecAngTransCurve->numDims != 2) {
622 0 : Curve::ShowSevereCurveDims(state, eoh, s_ipsc->cAlphaFieldNames(5), s_ipsc->cAlphaArgs(5), "2", mat->GlassSpecAngTransCurve->numDims);
623 0 : ErrorsFound = true;
624 : } else {
625 1 : Real64 minAng = mat->GlassSpecAngTransCurve->inputLimits[0].min;
626 1 : Real64 maxAng = mat->GlassSpecAngTransCurve->inputLimits[0].max;
627 1 : Real64 minLam = mat->GlassSpecAngTransCurve->inputLimits[1].min;
628 1 : Real64 maxLam = mat->GlassSpecAngTransCurve->inputLimits[1].max;
629 :
630 1 : if (minAng > 1.0e-6) {
631 0 : ErrorsFound = true;
632 0 : ShowSevereCustom(state,
633 : eoh,
634 0 : format("{} requires the minimum value = 0.0 in the entered table name={}",
635 0 : s_ipsc->cAlphaFieldNames(5),
636 0 : s_ipsc->cAlphaArgs(5)));
637 : }
638 :
639 1 : if (std::abs(maxAng - 90.0) > 1.0e-6) {
640 0 : ErrorsFound = true;
641 0 : ShowSevereCustom(state,
642 : eoh,
643 0 : format("{} requires the maximum value = 90.0 in the entered table name={}",
644 0 : s_ipsc->cAlphaFieldNames(5),
645 0 : s_ipsc->cAlphaArgs(5)));
646 : }
647 :
648 1 : if (minLam < 0.1) {
649 0 : ErrorsFound = true;
650 0 : ShowSevereCustom(state,
651 : eoh,
652 0 : format("{} requires the minumum value = 0.1 micron in the entered table name={}",
653 0 : s_ipsc->cAlphaFieldNames(5),
654 0 : s_ipsc->cAlphaArgs(5)));
655 : }
656 :
657 1 : if (maxLam > 4.0) {
658 0 : ErrorsFound = true;
659 0 : ShowSevereCustom(state,
660 : eoh,
661 0 : format("{} requires the maximum value = 4.0 microns in the entered table name={}",
662 0 : s_ipsc->cAlphaFieldNames(5),
663 0 : s_ipsc->cAlphaArgs(5)));
664 : }
665 : }
666 :
667 1 : if (s_ipsc->lAlphaFieldBlanks(6)) {
668 0 : ErrorsFound = true;
669 0 : ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(6), s_ipsc->cAlphaFieldNames(2), "SpectralAndAngle");
670 1 : } else if ((mat->GlassSpecAngFReflCurve = Curve::GetCurve(state, s_ipsc->cAlphaArgs(6))) == nullptr) {
671 0 : ErrorsFound = true;
672 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(6), s_ipsc->cAlphaArgs(6));
673 1 : } else if (mat->GlassSpecAngFReflCurve->numDims != 2) {
674 0 : Curve::ShowSevereCurveDims(state, eoh, s_ipsc->cAlphaFieldNames(6), s_ipsc->cAlphaArgs(6), "2", mat->GlassSpecAngFReflCurve->numDims);
675 0 : ErrorsFound = true;
676 : } else {
677 1 : Real64 minAng = mat->GlassSpecAngFReflCurve->inputLimits[0].min;
678 1 : Real64 maxAng = mat->GlassSpecAngFReflCurve->inputLimits[0].max;
679 1 : Real64 minLam = mat->GlassSpecAngFReflCurve->inputLimits[1].min;
680 1 : Real64 maxLam = mat->GlassSpecAngFReflCurve->inputLimits[1].max;
681 1 : if (minAng > 1.0e-6) {
682 0 : ErrorsFound = true;
683 0 : ShowSevereCustom(state,
684 : eoh,
685 0 : format("{} requires the minumum value = 0.0 in the entered table name={}",
686 0 : s_ipsc->cAlphaFieldNames(5),
687 0 : s_ipsc->cAlphaArgs(5)));
688 : }
689 1 : if (std::abs(maxAng - 90.0) > 1.0e-6) {
690 0 : ErrorsFound = true;
691 0 : ShowSevereCustom(state,
692 : eoh,
693 0 : format("{} requires the maximum value = 90.0 in the entered table name={}",
694 0 : s_ipsc->cAlphaFieldNames(5),
695 0 : s_ipsc->cAlphaArgs(5)));
696 : }
697 1 : if (minLam < 0.1) {
698 0 : ErrorsFound = true;
699 0 : ShowSevereCustom(state,
700 : eoh,
701 0 : format("{} requires the minumum value = 0.1 micron in the entered table name={}",
702 0 : s_ipsc->cAlphaFieldNames(5),
703 0 : s_ipsc->cAlphaArgs(5)));
704 : }
705 1 : if (maxLam > 4.0) {
706 0 : ErrorsFound = true;
707 0 : ShowSevereCustom(state,
708 : eoh,
709 0 : format("{} requires the maximum value = 4.0 microns in the entered table name={}",
710 0 : s_ipsc->cAlphaFieldNames(5),
711 0 : s_ipsc->cAlphaArgs(5)));
712 : }
713 : }
714 :
715 1 : if (s_ipsc->lAlphaFieldBlanks(7)) {
716 0 : ErrorsFound = true;
717 0 : ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(7), s_ipsc->cAlphaFieldNames(2), "SpectralAndAngle");
718 1 : } else if ((mat->GlassSpecAngBReflCurve = Curve::GetCurve(state, s_ipsc->cAlphaArgs(7))) == nullptr) {
719 0 : ErrorsFound = true;
720 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(7), s_ipsc->cAlphaArgs(7));
721 1 : } else if (mat->GlassSpecAngBReflCurve->numDims != 2) {
722 0 : Curve::ShowSevereCurveDims(state, eoh, s_ipsc->cAlphaFieldNames(7), s_ipsc->cAlphaArgs(7), "2", mat->GlassSpecAngBReflCurve->numDims);
723 0 : ErrorsFound = true;
724 : } else {
725 1 : Real64 minAng = mat->GlassSpecAngFReflCurve->inputLimits[0].min;
726 1 : Real64 maxAng = mat->GlassSpecAngFReflCurve->inputLimits[0].max;
727 1 : Real64 minLam = mat->GlassSpecAngFReflCurve->inputLimits[1].min;
728 1 : Real64 maxLam = mat->GlassSpecAngFReflCurve->inputLimits[1].max;
729 1 : if (minAng > 1.0e-6) {
730 0 : ErrorsFound = true;
731 0 : ShowSevereCustom(state,
732 : eoh,
733 0 : format("{} requires the minumum value = 0.0 in the entered table name={}",
734 0 : s_ipsc->cAlphaFieldNames(5),
735 0 : s_ipsc->cAlphaArgs(5)));
736 : }
737 1 : if (std::abs(maxAng - 90.0) > 1.0e-6) {
738 0 : ErrorsFound = true;
739 0 : ShowSevereCustom(state,
740 : eoh,
741 0 : format("{} requires the maximum value = 90.0 in the entered table name={}",
742 0 : s_ipsc->cAlphaFieldNames(5),
743 0 : s_ipsc->cAlphaArgs(5)));
744 : }
745 1 : if (minLam < 0.1) {
746 0 : ErrorsFound = true;
747 0 : ShowSevereCustom(state,
748 : eoh,
749 0 : format("{} requires the minumum value = 0.1 micron in the entered table name={}",
750 0 : s_ipsc->cAlphaFieldNames(5),
751 0 : s_ipsc->cAlphaArgs(5)));
752 : }
753 1 : if (maxLam > 4.0) {
754 0 : ErrorsFound = true;
755 0 : ShowSevereCustom(state,
756 : eoh,
757 0 : format("{} requires the maximum value = 4.0 microns in the entered table name={}",
758 0 : s_ipsc->cAlphaFieldNames(5),
759 0 : s_ipsc->cAlphaArgs(5)));
760 : }
761 : }
762 : }
763 : }
764 :
765 : // Glass materials, alternative input: index of refraction and extinction coefficient
766 :
767 273 : s_ipsc->cCurrentModuleObject = "WindowMaterial:Glazing:RefractionExtinctionMethod";
768 273 : s_mat->NumW5AltGlazings = s_ip->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
769 273 : for (int Loop = 1; Loop <= s_mat->NumW5AltGlazings; ++Loop) {
770 :
771 : // Call Input Get routine to retrieve material data
772 0 : s_ip->getObjectItem(state,
773 0 : s_ipsc->cCurrentModuleObject,
774 : Loop,
775 0 : s_ipsc->cAlphaArgs,
776 : NumAlphas,
777 0 : s_ipsc->rNumericArgs,
778 : NumNums,
779 : IOStat,
780 0 : s_ipsc->lNumericFieldBlanks,
781 0 : s_ipsc->lAlphaFieldBlanks,
782 0 : s_ipsc->cAlphaFieldNames,
783 0 : s_ipsc->cNumericFieldNames);
784 :
785 0 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
786 :
787 0 : if (s_mat->materialMap.find(s_ipsc->cAlphaArgs(1)) != s_mat->materialMap.end()) {
788 0 : ShowSevereDuplicateName(state, eoh);
789 0 : ErrorsFound = true;
790 0 : continue;
791 : }
792 :
793 0 : auto *mat = new MaterialGlass;
794 0 : mat->group = Group::Glass;
795 0 : mat->Name = s_ipsc->cAlphaArgs(1);
796 :
797 0 : s_mat->materials.push_back(mat);
798 0 : mat->Num = s_mat->materials.isize();
799 0 : s_mat->materialMap.insert_or_assign(mat->Name, mat->Num);
800 :
801 0 : mat->Roughness = SurfaceRoughness::VerySmooth;
802 0 : mat->Thickness = s_ipsc->rNumericArgs(1);
803 0 : mat->ROnly = true;
804 :
805 : // Calculate solar and visible transmittance and reflectance at normal incidence from thickness,
806 : // index of refraction and extinction coefficient. With the alternative input the front and back
807 : // properties are assumed to be the same.
808 :
809 0 : ReflectivitySol = pow_2((s_ipsc->rNumericArgs(2) - 1.0) / (s_ipsc->rNumericArgs(2) + 1.0));
810 0 : ReflectivityVis = pow_2((s_ipsc->rNumericArgs(4) - 1.0) / (s_ipsc->rNumericArgs(4) + 1.0));
811 0 : TransmittivitySol = std::exp(-s_ipsc->rNumericArgs(3) * s_ipsc->rNumericArgs(1));
812 0 : TransmittivityVis = std::exp(-s_ipsc->rNumericArgs(5) * s_ipsc->rNumericArgs(1));
813 0 : mat->Trans = TransmittivitySol * pow_2(1.0 - ReflectivitySol) / (1.0 - pow_2(ReflectivitySol * TransmittivitySol));
814 0 : mat->ReflectSolBeamFront =
815 0 : ReflectivitySol * (1.0 + pow_2(1.0 - ReflectivitySol) * pow_2(TransmittivitySol) / (1.0 - pow_2(ReflectivitySol * TransmittivitySol)));
816 0 : mat->ReflectSolBeamBack = mat->ReflectSolBeamFront;
817 0 : mat->TransVis = TransmittivityVis * pow_2(1.0 - ReflectivityVis) / (1.0 - pow_2(ReflectivityVis * TransmittivityVis));
818 :
819 0 : mat->ReflectVisBeamFront =
820 0 : ReflectivityVis * (1.0 + pow_2(1.0 - ReflectivityVis) * pow_2(TransmittivityVis) / (1.0 - pow_2(ReflectivityVis * TransmittivityVis)));
821 0 : mat->ReflectVisBeamBack = mat->ReflectSolBeamFront;
822 0 : mat->TransThermal = s_ipsc->rNumericArgs(6);
823 0 : mat->AbsorpThermalFront = s_ipsc->rNumericArgs(7);
824 0 : mat->AbsorpThermalBack = s_ipsc->rNumericArgs(7);
825 0 : mat->Conductivity = s_ipsc->rNumericArgs(8);
826 0 : mat->GlassTransDirtFactor = s_ipsc->rNumericArgs(9);
827 0 : if (s_ipsc->rNumericArgs(9) == 0.0) mat->GlassTransDirtFactor = 1.0;
828 0 : mat->AbsorpThermal = mat->AbsorpThermalBack;
829 :
830 0 : if (mat->Conductivity > 0.0) {
831 0 : mat->Resistance = mat->NominalR = mat->Thickness / mat->Conductivity;
832 : }
833 :
834 0 : mat->GlassSpectralDataPtr = 0;
835 :
836 0 : if (s_ipsc->rNumericArgs(6) + s_ipsc->rNumericArgs(7) >= 1.0) {
837 0 : ErrorsFound = true;
838 0 : ShowSevereCustom(state, eoh, format("{} + {} not < 1.0", s_ipsc->cNumericFieldNames(6), s_ipsc->cNumericFieldNames(7)));
839 : }
840 :
841 0 : if (s_ipsc->cAlphaArgs(2) == "") {
842 0 : mat->SolarDiffusing = false;
843 0 : } else if (s_ipsc->cAlphaArgs(2) == "YES") {
844 0 : mat->SolarDiffusing = true;
845 0 : } else if (s_ipsc->cAlphaArgs(2) == "NO") {
846 0 : mat->SolarDiffusing = false;
847 : } else {
848 0 : ErrorsFound = true;
849 0 : ShowSevereError(state, format("{}=\"{}\", Illegal value.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
850 0 : ShowContinueError(state, format("{} must be Yes or No, entered value={}", s_ipsc->cNumericFieldNames(2), s_ipsc->cAlphaArgs(4)));
851 : }
852 : }
853 :
854 : // Glass materials, equivalent layer (ASHWAT) method
855 273 : s_ipsc->cCurrentModuleObject = "WindowMaterial:Glazing:EquivalentLayer";
856 273 : s_mat->NumEQLGlazings = s_ip->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
857 282 : for (int Loop = 1; Loop <= s_mat->NumEQLGlazings; ++Loop) {
858 :
859 : // Call Input Get routine to retrieve material data
860 18 : s_ip->getObjectItem(state,
861 9 : s_ipsc->cCurrentModuleObject,
862 : Loop,
863 9 : s_ipsc->cAlphaArgs,
864 : NumAlphas,
865 9 : s_ipsc->rNumericArgs,
866 : NumNums,
867 : IOStat,
868 9 : s_ipsc->lNumericFieldBlanks,
869 9 : s_ipsc->lAlphaFieldBlanks,
870 9 : s_ipsc->cAlphaFieldNames,
871 9 : s_ipsc->cNumericFieldNames);
872 :
873 9 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
874 :
875 9 : if (s_mat->materialMap.find(s_ipsc->cAlphaArgs(1)) != s_mat->materialMap.end()) {
876 0 : ShowSevereDuplicateName(state, eoh);
877 0 : ErrorsFound = true;
878 0 : continue;
879 : }
880 :
881 9 : auto *mat = new MaterialGlassEQL;
882 9 : mat->group = Group::GlassEQL;
883 9 : mat->Name = s_ipsc->cAlphaArgs(1);
884 :
885 9 : s_mat->materials.push_back(mat);
886 9 : mat->Num = s_mat->materials.isize();
887 9 : s_mat->materialMap.insert_or_assign(mat->Name, mat->Num);
888 :
889 9 : mat->Roughness = SurfaceRoughness::VerySmooth;
890 9 : mat->ROnly = true;
891 :
892 9 : mat->TAR.Sol.Ft.Bm[0].BmTra = s_ipsc->rNumericArgs(1);
893 9 : mat->TAR.Sol.Bk.Bm[0].BmTra = s_ipsc->rNumericArgs(2);
894 9 : mat->TAR.Sol.Ft.Bm[0].BmRef = s_ipsc->rNumericArgs(3);
895 9 : mat->TAR.Sol.Bk.Bm[0].BmRef = s_ipsc->rNumericArgs(4);
896 9 : mat->TAR.Vis.Ft.Bm[0].BmTra = s_ipsc->rNumericArgs(5);
897 9 : mat->TAR.Vis.Bk.Bm[0].BmTra = s_ipsc->rNumericArgs(6);
898 9 : mat->TAR.Vis.Ft.Bm[0].BmRef = s_ipsc->rNumericArgs(7);
899 9 : mat->TAR.Vis.Bk.Bm[0].BmRef = s_ipsc->rNumericArgs(8);
900 9 : mat->TAR.Sol.Ft.Bm[0].DfTra = s_ipsc->rNumericArgs(9);
901 9 : mat->TAR.Sol.Bk.Bm[0].DfTra = s_ipsc->rNumericArgs(10);
902 9 : mat->TAR.Sol.Ft.Bm[0].DfRef = s_ipsc->rNumericArgs(11);
903 9 : mat->TAR.Sol.Bk.Bm[0].DfRef = s_ipsc->rNumericArgs(12);
904 9 : mat->TAR.Vis.Ft.Bm[0].DfTra = s_ipsc->rNumericArgs(13);
905 9 : mat->TAR.Vis.Bk.Bm[0].DfTra = s_ipsc->rNumericArgs(14);
906 9 : mat->TAR.Vis.Ft.Bm[0].DfRef = s_ipsc->rNumericArgs(15);
907 9 : mat->TAR.Vis.Bk.Bm[0].DfRef = s_ipsc->rNumericArgs(16);
908 9 : mat->TAR.Sol.Ft.Df.Tra = mat->TAR.Sol.Bk.Df.Tra = s_ipsc->rNumericArgs(17);
909 9 : mat->TAR.Sol.Ft.Df.Ref = s_ipsc->rNumericArgs(18);
910 9 : mat->TAR.Sol.Bk.Df.Ref = s_ipsc->rNumericArgs(19);
911 9 : mat->TAR.Vis.Ft.Df.Tra = mat->TAR.Vis.Bk.Df.Tra = s_ipsc->rNumericArgs(20);
912 9 : mat->TAR.Vis.Ft.Df.Ref = s_ipsc->rNumericArgs(21);
913 9 : mat->TAR.Vis.Bk.Df.Ref = s_ipsc->rNumericArgs(22);
914 9 : mat->TAR.IR.Ft.Tra = mat->TAR.IR.Bk.Tra = s_ipsc->rNumericArgs(23);
915 9 : mat->TAR.IR.Ft.Emi = s_ipsc->rNumericArgs(24);
916 9 : mat->TAR.IR.Bk.Emi = s_ipsc->rNumericArgs(25);
917 9 : mat->Resistance = s_ipsc->rNumericArgs(26);
918 9 : if (mat->Resistance <= 0.0) mat->Resistance = 0.158; // equivalent to single pane of 1/4" inch standard glass
919 : // Assumes thermal emissivity is the same as thermal absorptance
920 9 : mat->AbsorpThermalFront = mat->TAR.IR.Ft.Tra;
921 9 : mat->AbsorpThermalBack = mat->TAR.IR.Bk.Tra;
922 9 : mat->TransThermal = mat->TAR.IR.Ft.Tra;
923 :
924 9 : mat->windowOpticalData = static_cast<Window::OpticalDataModel>(getEnumValue(Window::opticalDataModelNamesUC, s_ipsc->cAlphaArgs(2)));
925 :
926 : // IF(dataMaterial.Material(MaterNum)%GlassSpectralDataPtr == 0 .AND. Util::SameString(s_ipsc->cAlphaArgs(2),'Spectral')) THEN
927 : // ErrorsFound = .TRUE.
928 : // CALL ShowSevereError(state, TRIM(s_ipsc->cCurrentModuleObject)//'="'//Trim(dataMaterial.Material(MaterNum)%Name)// &
929 : // '" has '//TRIM(cAlphaFieldNames(2))//' = Spectral but has no matching MaterialProperty:GlazingSpectralData set')
930 : // if (s_ipsc->lAlphaFieldBlanks(3)) THEN
931 : // CALL ShowContinueError(state, '...'//TRIM(cAlphaFieldNames(3))//' is blank.')
932 : // ELSE
933 : // CALL ShowContinueError(state, '...'//TRIM(cAlphaFieldNames(3))//'="'//TRIM(s_ipsc->cAlphaArgs(3))// &
934 : // '" not found as item in MaterialProperty:GlazingSpectralData objects.')
935 : // END IF
936 : // END IF
937 :
938 9 : if (mat->windowOpticalData != Window::OpticalDataModel::SpectralAverage) {
939 0 : ErrorsFound = true;
940 0 : ShowSevereInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2), "Must be \"SpectralAverage\".");
941 : }
942 :
943 : } // W5GlsMatEQL loop
944 :
945 : // Window gas materials (for gaps with a single gas)
946 :
947 273 : s_ipsc->cCurrentModuleObject = "WindowMaterial:Gas";
948 273 : s_mat->NumW5Gases = s_ip->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
949 309 : for (int Loop = 1; Loop <= s_mat->NumW5Gases; ++Loop) {
950 :
951 : // Call Input Get routine to retrieve material data
952 72 : s_ip->getObjectItem(state,
953 36 : s_ipsc->cCurrentModuleObject,
954 : Loop,
955 36 : s_ipsc->cAlphaArgs,
956 : NumAlphas,
957 36 : s_ipsc->rNumericArgs,
958 : NumNums,
959 : IOStat,
960 36 : s_ipsc->lNumericFieldBlanks,
961 36 : s_ipsc->lAlphaFieldBlanks,
962 36 : s_ipsc->cAlphaFieldNames,
963 36 : s_ipsc->cNumericFieldNames);
964 :
965 36 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
966 :
967 36 : if (s_mat->materialMap.find(s_ipsc->cAlphaArgs(1)) != s_mat->materialMap.end()) {
968 0 : ShowSevereDuplicateName(state, eoh);
969 0 : ErrorsFound = true;
970 0 : continue;
971 : }
972 :
973 36 : auto *matGas = new MaterialGasMix;
974 36 : matGas->group = Group::Gas;
975 36 : matGas->Name = s_ipsc->cAlphaArgs(1);
976 :
977 36 : s_mat->materials.push_back(matGas);
978 36 : matGas->Num = s_mat->materials.isize();
979 36 : s_mat->materialMap.insert_or_assign(matGas->Name, matGas->Num);
980 :
981 36 : matGas->numGases = 1;
982 36 : matGas->gasFracts[0] = 1.0;
983 :
984 : // Load the material derived type from the input data.
985 :
986 36 : matGas->gases[0].type = static_cast<GasType>(getEnumValue(gasTypeNamesUC, Util::makeUPPER(s_ipsc->cAlphaArgs(2))));
987 36 : matGas->Roughness = SurfaceRoughness::MediumRough;
988 :
989 36 : matGas->Thickness = s_ipsc->rNumericArgs(1);
990 36 : matGas->ROnly = true;
991 :
992 36 : gasType = matGas->gases[0].type;
993 36 : if (gasType != GasType::Custom) {
994 36 : matGas->gases[0] = gases[(int)gasType];
995 : }
996 :
997 : // Custom gas
998 :
999 36 : if (gasType == GasType::Custom) {
1000 0 : matGas->gases[0].con.c0 = s_ipsc->rNumericArgs(2);
1001 0 : matGas->gases[0].con.c1 = s_ipsc->rNumericArgs(3);
1002 0 : matGas->gases[0].con.c2 = s_ipsc->rNumericArgs(4);
1003 0 : matGas->gases[0].vis.c0 = s_ipsc->rNumericArgs(5);
1004 0 : matGas->gases[0].vis.c1 = s_ipsc->rNumericArgs(6);
1005 0 : matGas->gases[0].vis.c2 = s_ipsc->rNumericArgs(7);
1006 0 : matGas->gases[0].cp.c0 = s_ipsc->rNumericArgs(8);
1007 0 : matGas->gases[0].cp.c1 = s_ipsc->rNumericArgs(9);
1008 0 : matGas->gases[0].cp.c2 = s_ipsc->rNumericArgs(10);
1009 0 : matGas->gases[0].wght = s_ipsc->rNumericArgs(11);
1010 0 : matGas->gases[0].specHeatRatio = s_ipsc->rNumericArgs(12);
1011 :
1012 : // Check for errors in custom gas properties
1013 : // IF(dataMaterial.Material(MaterNum)%GasCon(1,1) <= 0.0) THEN
1014 : // ErrorsFound = .TRUE.
1015 : // CALL ShowSevereError(state, 'Conductivity Coefficient A for custom window gas='&
1016 : // //TRIM(s_ipsc->cAlphaArgs(1))//' should be > 0.')
1017 : // END IF
1018 :
1019 0 : if (matGas->gases[0].vis.c0 <= 0.0) {
1020 0 : ErrorsFound = true;
1021 0 : ShowSevereCustom(state, eoh, format("{} not > 0.0", s_ipsc->cNumericFieldNames(5)));
1022 : }
1023 0 : if (matGas->gases[0].cp.c0 <= 0.0) {
1024 0 : ErrorsFound = true;
1025 0 : ShowSevereCustom(state, eoh, format("{} not > 0.0", s_ipsc->cNumericFieldNames(8)));
1026 : }
1027 0 : if (matGas->gases[0].wght <= 0.0) {
1028 0 : ErrorsFound = true;
1029 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value.");
1030 0 : ShowContinueError(state, s_ipsc->cNumericFieldNames(11) + " not > 0.0");
1031 : }
1032 : }
1033 :
1034 : // Nominal resistance of gap at room temperature
1035 36 : if (!ErrorsFound) {
1036 36 : DenomRGas = (matGas->gases[0].con.c0 + matGas->gases[0].con.c1 * 300.0 + matGas->gases[0].con.c2 * 90000.0);
1037 36 : if (DenomRGas > 0.0) {
1038 36 : matGas->NominalR = matGas->Thickness / DenomRGas;
1039 : } else {
1040 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value.");
1041 0 : ShowContinueError(state,
1042 0 : format("Nominal resistance of gap at room temperature calculated at a negative Conductivity=[{:.3R}].", DenomRGas));
1043 0 : ErrorsFound = true;
1044 : }
1045 : }
1046 : }
1047 :
1048 : // Window gap materials (for gaps with a single gas for EquivalentLayer)
1049 :
1050 273 : s_ipsc->cCurrentModuleObject = "WindowMaterial:Gap:EquivalentLayer";
1051 273 : s_mat->NumEQLGaps = s_ip->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
1052 285 : for (int Loop = 1; Loop <= s_mat->NumEQLGaps; ++Loop) {
1053 :
1054 : // Call Input Get routine to retrieve material data
1055 24 : s_ip->getObjectItem(state,
1056 12 : s_ipsc->cCurrentModuleObject,
1057 : Loop,
1058 12 : s_ipsc->cAlphaArgs,
1059 : NumAlphas,
1060 12 : s_ipsc->rNumericArgs,
1061 : NumNums,
1062 : IOStat,
1063 12 : s_ipsc->lNumericFieldBlanks,
1064 12 : s_ipsc->lAlphaFieldBlanks,
1065 12 : s_ipsc->cAlphaFieldNames,
1066 12 : s_ipsc->cNumericFieldNames);
1067 :
1068 12 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
1069 :
1070 12 : if (s_mat->materialMap.find(s_ipsc->cAlphaArgs(1)) != s_mat->materialMap.end()) {
1071 0 : ShowSevereDuplicateName(state, eoh);
1072 0 : ErrorsFound = true;
1073 0 : continue;
1074 : }
1075 :
1076 12 : auto *matGas = new MaterialGasMix;
1077 12 : matGas->group = Group::WindowGapEQL;
1078 12 : matGas->Name = s_ipsc->cAlphaArgs(1);
1079 :
1080 12 : s_mat->materials.push_back(matGas);
1081 12 : matGas->Num = s_mat->materials.isize();
1082 12 : s_mat->materialMap.insert_or_assign(matGas->Name, matGas->Num);
1083 :
1084 12 : matGas->numGases = 1;
1085 12 : matGas->gasFracts[0] = 1.0;
1086 :
1087 : // Load the material derived type from the input data.
1088 :
1089 12 : matGas->gases[0].type = static_cast<GasType>(getEnumValue(gasTypeNamesUC, Util::makeUPPER(s_ipsc->cAlphaArgs(2)))); // Error check?
1090 :
1091 12 : matGas->Roughness = SurfaceRoughness::MediumRough;
1092 :
1093 12 : matGas->Thickness = s_ipsc->rNumericArgs(1);
1094 12 : matGas->ROnly = true;
1095 :
1096 12 : gasType = matGas->gases[0].type;
1097 12 : if (gasType != GasType::Custom) {
1098 12 : matGas->gases[0] = gases[(int)gasType];
1099 : }
1100 :
1101 12 : if (!s_ipsc->lAlphaFieldBlanks(2)) {
1102 : // Get gap vent type
1103 12 : matGas->gapVentType = static_cast<GapVentType>(getEnumValue(gapVentTypeNamesUC, Util::makeUPPER(s_ipsc->cAlphaArgs(3))));
1104 : }
1105 :
1106 12 : if (gasType == GasType::Custom) {
1107 0 : for (ICoeff = 1; ICoeff <= 3; ++ICoeff) {
1108 0 : matGas->gases[0].con.c0 = s_ipsc->rNumericArgs(2);
1109 0 : matGas->gases[0].con.c1 = s_ipsc->rNumericArgs(3);
1110 0 : matGas->gases[0].con.c2 = s_ipsc->rNumericArgs(4);
1111 0 : matGas->gases[0].vis.c0 = s_ipsc->rNumericArgs(5);
1112 0 : matGas->gases[0].vis.c1 = s_ipsc->rNumericArgs(6);
1113 0 : matGas->gases[0].vis.c2 = s_ipsc->rNumericArgs(7);
1114 0 : matGas->gases[0].cp.c0 = s_ipsc->rNumericArgs(8);
1115 0 : matGas->gases[0].cp.c1 = s_ipsc->rNumericArgs(9);
1116 0 : matGas->gases[0].cp.c2 = s_ipsc->rNumericArgs(10);
1117 : }
1118 0 : matGas->gases[0].wght = s_ipsc->rNumericArgs(11);
1119 0 : matGas->gases[0].specHeatRatio = s_ipsc->rNumericArgs(12);
1120 :
1121 0 : if (matGas->gases[0].vis.c0 <= 0.0) {
1122 0 : ErrorsFound = true;
1123 0 : ShowSevereError(state, format("{}=\"{}\", Illegal value.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
1124 0 : ShowContinueError(state, format("{} not > 0.0", s_ipsc->cNumericFieldNames(5)));
1125 : }
1126 0 : if (matGas->gases[0].cp.c0 <= 0.0) {
1127 0 : ErrorsFound = true;
1128 0 : ShowSevereError(state, format("{}=\"{}\", Illegal value.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
1129 0 : ShowContinueError(state, format("{} not > 0.0", s_ipsc->cNumericFieldNames(8)));
1130 : }
1131 0 : if (matGas->gases[0].wght <= 0.0) {
1132 0 : ErrorsFound = true;
1133 0 : ShowSevereError(state, format("{}=\"{}\", Illegal value.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
1134 0 : ShowContinueError(state, format("{} not > 0.0", s_ipsc->cNumericFieldNames(11)));
1135 : }
1136 : }
1137 :
1138 : // Nominal resistance of gap at room temperature
1139 12 : if (!ErrorsFound) {
1140 12 : DenomRGas = (matGas->gases[0].con.c0 + matGas->gases[0].con.c1 * 300.0 + matGas->gases[0].con.c2 * 90000.0);
1141 12 : if (DenomRGas > 0.0) {
1142 12 : matGas->NominalR = matGas->Thickness / DenomRGas;
1143 : } else {
1144 0 : ShowSevereError(state, format("{}=\"{}\", Illegal value.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
1145 0 : ShowContinueError(state,
1146 0 : format("Nominal resistance of gap at room temperature calculated at a negative Conductivity=[{:.3R}].", DenomRGas));
1147 0 : ErrorsFound = true;
1148 : }
1149 : }
1150 : } // for (Loop : W5MatEQL)
1151 :
1152 : // Window gas mixtures (for gaps with two or more gases)
1153 :
1154 273 : s_ipsc->cCurrentModuleObject = "WindowMaterial:GasMixture";
1155 273 : s_mat->NumW5GasMixtures = s_ip->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
1156 273 : for (int Loop = 1; Loop <= s_mat->NumW5GasMixtures; ++Loop) {
1157 :
1158 : // Call Input Get routine to retrieve material data
1159 0 : s_ip->getObjectItem(state,
1160 0 : s_ipsc->cCurrentModuleObject,
1161 : Loop,
1162 0 : s_ipsc->cAlphaArgs,
1163 : NumAlphas,
1164 0 : s_ipsc->rNumericArgs,
1165 : NumNums,
1166 : IOStat,
1167 0 : s_ipsc->lNumericFieldBlanks,
1168 0 : s_ipsc->lAlphaFieldBlanks,
1169 0 : s_ipsc->cAlphaFieldNames,
1170 0 : s_ipsc->cNumericFieldNames);
1171 0 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
1172 :
1173 0 : if (s_mat->materialMap.find(s_ipsc->cAlphaArgs(1)) != s_mat->materialMap.end()) {
1174 0 : ShowSevereDuplicateName(state, eoh);
1175 0 : ErrorsFound = true;
1176 0 : continue;
1177 : }
1178 :
1179 0 : auto *matGas = new MaterialGasMix;
1180 0 : matGas->group = Group::GasMixture;
1181 0 : matGas->Name = s_ipsc->cAlphaArgs(1);
1182 :
1183 0 : s_mat->materials.push_back(matGas);
1184 0 : matGas->Num = s_mat->materials.isize();
1185 0 : s_mat->materialMap.insert_or_assign(matGas->Name, matGas->Num);
1186 :
1187 0 : matGas->gases[0].type = matGas->gases[1].type = matGas->gases[2].type = matGas->gases[3].type = matGas->gases[4].type = GasType::Invalid;
1188 :
1189 : // Load the material derived type from the input data.
1190 :
1191 0 : NumGases = s_ipsc->rNumericArgs(2);
1192 0 : matGas->numGases = NumGases;
1193 0 : for (NumGas = 0; NumGas < NumGases; ++NumGas) {
1194 0 : auto &gas = matGas->gases[NumGas];
1195 0 : gas.type = static_cast<GasType>(getEnumValue(gasTypeNamesUC, Util::makeUPPER(s_ipsc->cAlphaArgs(2 + NumGas))));
1196 0 : if (gas.type == GasType::Invalid) {
1197 0 : ShowSevereError(state, format("{}=\"{}\", Illegal value.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1 + NumGas)));
1198 : // Error check?
1199 0 : ErrorsFound = true;
1200 : }
1201 : }
1202 :
1203 0 : matGas->Roughness = SurfaceRoughness::MediumRough; // Unused
1204 :
1205 0 : matGas->Thickness = s_ipsc->rNumericArgs(1);
1206 0 : if (matGas->Thickness <= 0.0) {
1207 0 : ShowSevereError(state, format("{}=\"{}\", Illegal value.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
1208 0 : ShowContinueError(state, s_ipsc->cNumericFieldNames(1) + " must be greater than 0.");
1209 : }
1210 0 : matGas->ROnly = true;
1211 :
1212 0 : for (NumGas = 0; NumGas < NumGases; ++NumGas) {
1213 0 : gasType = matGas->gases[NumGas].type;
1214 0 : if (gasType != GasType::Custom) {
1215 0 : matGas->gasFracts[NumGas] = s_ipsc->rNumericArgs(3 + NumGas);
1216 0 : matGas->gases[NumGas] = gases[(int)gasType];
1217 : }
1218 : }
1219 :
1220 : // Nominal resistance of gap at room temperature (based on first gas in mixture)
1221 0 : matGas->NominalR = matGas->Thickness / (matGas->gases[0].con.c0 + matGas->gases[0].con.c1 * 300.0 + matGas->gases[0].con.c2 * 90000.0);
1222 : }
1223 :
1224 : // Window Shade Materials
1225 :
1226 273 : s_ipsc->cCurrentModuleObject = "WindowMaterial:Shade";
1227 273 : s_mat->NumShades = s_ip->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
1228 275 : for (int Loop = 1; Loop <= s_mat->NumShades; ++Loop) {
1229 :
1230 : // Call Input Get routine to retrieve material data
1231 4 : s_ip->getObjectItem(state,
1232 2 : s_ipsc->cCurrentModuleObject,
1233 : Loop,
1234 2 : s_ipsc->cAlphaArgs,
1235 : NumAlphas,
1236 2 : s_ipsc->rNumericArgs,
1237 : NumNums,
1238 : IOStat,
1239 2 : s_ipsc->lNumericFieldBlanks,
1240 2 : s_ipsc->lAlphaFieldBlanks,
1241 2 : s_ipsc->cAlphaFieldNames,
1242 2 : s_ipsc->cNumericFieldNames);
1243 :
1244 2 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
1245 :
1246 2 : if (s_mat->materialMap.find(s_ipsc->cAlphaArgs(1)) != s_mat->materialMap.end()) {
1247 0 : ShowSevereDuplicateName(state, eoh);
1248 0 : ErrorsFound = true;
1249 0 : continue;
1250 : }
1251 :
1252 2 : auto *mat = new MaterialShade;
1253 2 : mat->Name = s_ipsc->cAlphaArgs(1);
1254 :
1255 2 : s_mat->materials.push_back(mat);
1256 2 : mat->Num = s_mat->materials.isize();
1257 2 : s_mat->materialMap.insert_or_assign(mat->Name, mat->Num);
1258 :
1259 2 : mat->Roughness = SurfaceRoughness::MediumRough;
1260 2 : mat->Trans = s_ipsc->rNumericArgs(1);
1261 2 : mat->ReflectShade = s_ipsc->rNumericArgs(2);
1262 2 : mat->TransVis = s_ipsc->rNumericArgs(3);
1263 2 : mat->ReflectShadeVis = s_ipsc->rNumericArgs(4);
1264 2 : mat->AbsorpThermal = s_ipsc->rNumericArgs(5);
1265 2 : mat->AbsorpThermalInput = s_ipsc->rNumericArgs(5);
1266 2 : mat->TransThermal = s_ipsc->rNumericArgs(6);
1267 2 : mat->Thickness = s_ipsc->rNumericArgs(7);
1268 2 : mat->Conductivity = s_ipsc->rNumericArgs(8);
1269 2 : mat->AbsorpSolar = max(0.0, 1.0 - mat->Trans - mat->ReflectShade);
1270 2 : mat->AbsorpSolarInput = mat->AbsorpSolar;
1271 2 : mat->toGlassDist = s_ipsc->rNumericArgs(9);
1272 2 : mat->topOpeningMult = s_ipsc->rNumericArgs(10);
1273 2 : mat->bottomOpeningMult = s_ipsc->rNumericArgs(11);
1274 2 : mat->leftOpeningMult = s_ipsc->rNumericArgs(12);
1275 2 : mat->rightOpeningMult = s_ipsc->rNumericArgs(13);
1276 2 : mat->airFlowPermeability = s_ipsc->rNumericArgs(14);
1277 2 : mat->ROnly = true;
1278 :
1279 2 : if (mat->Conductivity > 0.0) {
1280 2 : mat->NominalR = mat->Thickness / mat->Conductivity;
1281 : } else {
1282 0 : mat->NominalR = 1.0;
1283 : }
1284 :
1285 2 : if (s_ipsc->rNumericArgs(1) + s_ipsc->rNumericArgs(2) >= 1.0) {
1286 0 : ErrorsFound = true;
1287 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination.");
1288 0 : ShowContinueError(state, s_ipsc->cNumericFieldNames(1) + " + " + s_ipsc->cNumericFieldNames(2) + " not < 1.0");
1289 : }
1290 :
1291 2 : if (s_ipsc->rNumericArgs(3) + s_ipsc->rNumericArgs(4) >= 1.0) {
1292 0 : ErrorsFound = true;
1293 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination.");
1294 0 : ShowContinueError(state, s_ipsc->cNumericFieldNames(3) + " + " + s_ipsc->cNumericFieldNames(4) + " not < 1.0");
1295 : }
1296 :
1297 2 : if (s_ipsc->rNumericArgs(5) + s_ipsc->rNumericArgs(6) >= 1.0) {
1298 0 : ErrorsFound = true;
1299 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination.");
1300 0 : ShowContinueError(state, s_ipsc->cNumericFieldNames(5) + " + " + s_ipsc->cNumericFieldNames(6) + " not < 1.0");
1301 : }
1302 : }
1303 :
1304 : // Window Shade Materials
1305 :
1306 273 : s_ipsc->cCurrentModuleObject = "WindowMaterial:Shade:EquivalentLayer";
1307 273 : s_mat->NumEQLShades = s_ip->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
1308 273 : for (int Loop = 1; Loop <= s_mat->NumEQLShades; ++Loop) {
1309 :
1310 0 : s_ipsc->rNumericArgs = 0;
1311 :
1312 : // Call Input Get routine to retrieve material data
1313 0 : s_ip->getObjectItem(state,
1314 0 : s_ipsc->cCurrentModuleObject,
1315 : Loop,
1316 0 : s_ipsc->cAlphaArgs,
1317 : NumAlphas,
1318 0 : s_ipsc->rNumericArgs,
1319 : NumNums,
1320 : IOStat,
1321 0 : s_ipsc->lNumericFieldBlanks,
1322 0 : s_ipsc->lAlphaFieldBlanks,
1323 0 : s_ipsc->cAlphaFieldNames,
1324 0 : s_ipsc->cNumericFieldNames);
1325 :
1326 0 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
1327 :
1328 0 : if (s_mat->materialMap.find(s_ipsc->cAlphaArgs(1)) != s_mat->materialMap.end()) {
1329 0 : ShowSevereDuplicateName(state, eoh);
1330 0 : ErrorsFound = true;
1331 0 : continue;
1332 : }
1333 :
1334 0 : auto *mat = new MaterialShadeEQL;
1335 0 : mat->group = Group::ShadeEQL;
1336 0 : mat->Name = s_ipsc->cAlphaArgs(1);
1337 :
1338 0 : s_mat->materials.push_back(mat);
1339 0 : mat->Num = s_mat->materials.isize();
1340 0 : s_mat->materialMap.insert_or_assign(mat->Name, mat->Num);
1341 :
1342 0 : mat->Roughness = SurfaceRoughness::MediumRough;
1343 0 : mat->ROnly = true;
1344 :
1345 : // Front side and back side have the same beam-Beam Transmittance
1346 0 : mat->TAR.Sol.Ft.Bm[0].BmTra = s_ipsc->rNumericArgs(1);
1347 0 : mat->TAR.Sol.Bk.Bm[0].BmTra = s_ipsc->rNumericArgs(1);
1348 0 : mat->TAR.Sol.Ft.Bm[0].DfTra = s_ipsc->rNumericArgs(2);
1349 0 : mat->TAR.Sol.Bk.Bm[0].DfTra = s_ipsc->rNumericArgs(3);
1350 0 : mat->TAR.Sol.Ft.Bm[0].DfRef = s_ipsc->rNumericArgs(4);
1351 0 : mat->TAR.Sol.Bk.Bm[0].DfRef = s_ipsc->rNumericArgs(5);
1352 0 : mat->TAR.Vis.Ft.Bm[0].BmTra = s_ipsc->rNumericArgs(6);
1353 0 : mat->TAR.Vis.Ft.Bm[0].DfTra = s_ipsc->rNumericArgs(7);
1354 0 : mat->TAR.Vis.Ft.Bm[0].DfRef = s_ipsc->rNumericArgs(8);
1355 0 : mat->TAR.IR.Ft.Tra = mat->TAR.IR.Bk.Tra = s_ipsc->rNumericArgs(9);
1356 0 : mat->TAR.IR.Ft.Emi = s_ipsc->rNumericArgs(10);
1357 0 : mat->TAR.IR.Bk.Emi = s_ipsc->rNumericArgs(11);
1358 : // Assumes thermal emissivity is the same as thermal absorptance
1359 0 : mat->AbsorpThermalFront = mat->TAR.IR.Ft.Emi;
1360 0 : mat->AbsorpThermalBack = mat->TAR.IR.Bk.Emi;
1361 0 : mat->TransThermal = mat->TAR.IR.Ft.Tra;
1362 :
1363 0 : if (s_ipsc->rNumericArgs(1) + s_ipsc->rNumericArgs(2) + s_ipsc->rNumericArgs(4) >= 1.0) {
1364 0 : ErrorsFound = true;
1365 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination.");
1366 0 : ShowContinueError(
1367 0 : state, s_ipsc->cNumericFieldNames(1) + " + " + s_ipsc->cNumericFieldNames(2) + " + " + s_ipsc->cNumericFieldNames(4) + "not < 1.0");
1368 : }
1369 0 : if (s_ipsc->rNumericArgs(1) + s_ipsc->rNumericArgs(3) + s_ipsc->rNumericArgs(5) >= 1.0) {
1370 0 : ErrorsFound = true;
1371 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination.");
1372 0 : ShowContinueError(
1373 0 : state, s_ipsc->cNumericFieldNames(1) + " + " + s_ipsc->cNumericFieldNames(3) + " + " + s_ipsc->cNumericFieldNames(5) + "not < 1.0");
1374 : }
1375 0 : if (s_ipsc->rNumericArgs(6) + s_ipsc->rNumericArgs(7) + s_ipsc->rNumericArgs(8) >= 1.0) {
1376 0 : ErrorsFound = true;
1377 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination.");
1378 0 : ShowContinueError(
1379 0 : state, s_ipsc->cNumericFieldNames(6) + " + " + s_ipsc->cNumericFieldNames(7) + " + " + s_ipsc->cNumericFieldNames(8) + "not < 1.0");
1380 : }
1381 0 : if (s_ipsc->rNumericArgs(9) + s_ipsc->rNumericArgs(10) >= 1.0) {
1382 0 : ErrorsFound = true;
1383 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination.");
1384 0 : ShowContinueError(state, s_ipsc->cNumericFieldNames(9) + " + " + s_ipsc->cNumericFieldNames(10) + " not < 1.0");
1385 : }
1386 0 : if (s_ipsc->rNumericArgs(9) + s_ipsc->rNumericArgs(11) >= 1.0) {
1387 0 : ErrorsFound = true;
1388 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination.");
1389 0 : ShowContinueError(state, s_ipsc->cNumericFieldNames(9) + " + " + s_ipsc->cNumericFieldNames(11) + " not < 1.0");
1390 : }
1391 :
1392 : } // TotShadesEQL loop
1393 :
1394 : // Window drape materials
1395 :
1396 273 : s_ipsc->cCurrentModuleObject = "WindowMaterial:Drape:EquivalentLayer";
1397 273 : s_mat->NumEQLDrapes = s_ip->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
1398 273 : for (int Loop = 1; Loop <= s_mat->NumEQLDrapes; ++Loop) {
1399 :
1400 0 : s_ipsc->rNumericArgs = 0;
1401 :
1402 : // Call Input Get routine to retrieve material data
1403 0 : s_ip->getObjectItem(state,
1404 0 : s_ipsc->cCurrentModuleObject,
1405 : Loop,
1406 0 : s_ipsc->cAlphaArgs,
1407 : NumAlphas,
1408 0 : s_ipsc->rNumericArgs,
1409 : NumNums,
1410 : IOStat,
1411 0 : s_ipsc->lNumericFieldBlanks,
1412 0 : s_ipsc->lAlphaFieldBlanks,
1413 0 : s_ipsc->cAlphaFieldNames,
1414 0 : s_ipsc->cNumericFieldNames);
1415 :
1416 0 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
1417 :
1418 0 : if (s_mat->materialMap.find(s_ipsc->cAlphaArgs(1)) != s_mat->materialMap.end()) {
1419 0 : ShowSevereDuplicateName(state, eoh);
1420 0 : ErrorsFound = true;
1421 0 : continue;
1422 : }
1423 :
1424 0 : auto *mat = new MaterialDrapeEQL;
1425 0 : mat->group = Group::DrapeEQL;
1426 0 : mat->Name = s_ipsc->cAlphaArgs(1);
1427 :
1428 0 : s_mat->materials.push_back(mat);
1429 0 : mat->Num = s_mat->materials.isize();
1430 0 : s_mat->materialMap.insert_or_assign(mat->Name, mat->Num);
1431 :
1432 0 : mat->Roughness = SurfaceRoughness::MediumRough;
1433 0 : mat->ROnly = true;
1434 :
1435 : // Front side and back side have the same properties
1436 0 : mat->TAR.Sol.Ft.Bm[0].BmTra = s_ipsc->rNumericArgs(1);
1437 0 : mat->TAR.Sol.Bk.Bm[0].BmTra = s_ipsc->rNumericArgs(1);
1438 :
1439 0 : mat->TAR.Sol.Ft.Bm[0].DfTra = s_ipsc->rNumericArgs(2);
1440 0 : mat->TAR.Sol.Bk.Bm[0].DfTra = s_ipsc->rNumericArgs(3);
1441 :
1442 0 : mat->TAR.Sol.Ft.Bm[0].DfRef = s_ipsc->rNumericArgs(4);
1443 0 : mat->TAR.Sol.Bk.Bm[0].DfRef = s_ipsc->rNumericArgs(5);
1444 0 : mat->TAR.Vis.Ft.Bm[0].BmTra = s_ipsc->rNumericArgs(6);
1445 0 : mat->TAR.Vis.Ft.Bm[0].DfTra = s_ipsc->rNumericArgs(7);
1446 0 : mat->TAR.Vis.Ft.Bm[0].DfRef = s_ipsc->rNumericArgs(8);
1447 0 : mat->TAR.IR.Ft.Tra = mat->TAR.IR.Bk.Tra = s_ipsc->rNumericArgs(9);
1448 0 : mat->TAR.IR.Ft.Emi = s_ipsc->rNumericArgs(10);
1449 0 : mat->TAR.IR.Bk.Emi = s_ipsc->rNumericArgs(11);
1450 : // Assumes thermal emissivity is the same as thermal absorptance
1451 0 : mat->AbsorpThermalFront = mat->TAR.IR.Ft.Emi;
1452 0 : mat->AbsorpThermalBack = mat->TAR.IR.Bk.Emi;
1453 0 : mat->TransThermal = mat->TAR.IR.Ft.Tra;
1454 :
1455 0 : if (!s_ipsc->lNumericFieldBlanks(12) && !s_ipsc->lNumericFieldBlanks(13)) {
1456 0 : if (s_ipsc->rNumericArgs(12) != 0.0 && s_ipsc->rNumericArgs(13) != 0.0) {
1457 0 : mat->pleatedWidth = s_ipsc->rNumericArgs(12);
1458 0 : mat->pleatedLength = s_ipsc->rNumericArgs(13);
1459 0 : mat->isPleated = true;
1460 : }
1461 : } else {
1462 0 : mat->isPleated = false;
1463 : }
1464 0 : if (s_ipsc->rNumericArgs(1) + s_ipsc->rNumericArgs(2) + s_ipsc->rNumericArgs(4) >= 1.0) {
1465 0 : ErrorsFound = true;
1466 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination.");
1467 0 : ShowContinueError(
1468 0 : state, s_ipsc->cNumericFieldNames(1) + " + " + s_ipsc->cNumericFieldNames(2) + " + " + s_ipsc->cNumericFieldNames(4) + "not < 1.0");
1469 : }
1470 0 : if (s_ipsc->rNumericArgs(6) + s_ipsc->rNumericArgs(7) + s_ipsc->rNumericArgs(8) >= 1.0) {
1471 0 : ErrorsFound = true;
1472 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination.");
1473 0 : ShowContinueError(
1474 0 : state, s_ipsc->cNumericFieldNames(4) + " + " + s_ipsc->cNumericFieldNames(5) + " + " + s_ipsc->cNumericFieldNames(6) + "not < 1.0");
1475 : }
1476 0 : if (s_ipsc->rNumericArgs(9) + s_ipsc->rNumericArgs(10) > 1.0) {
1477 0 : ErrorsFound = true;
1478 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination.");
1479 0 : ShowContinueError(state, s_ipsc->cNumericFieldNames(9) + " + " + s_ipsc->cNumericFieldNames(10) + " not < 1.0");
1480 : }
1481 :
1482 : } // TotDrapesEQL loop
1483 :
1484 : // Window Screen Materials
1485 :
1486 273 : s_ipsc->cCurrentModuleObject = "WindowMaterial:Screen";
1487 273 : s_mat->NumScreens = s_ip->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
1488 273 : for (int Loop = 1; Loop <= s_mat->NumScreens; ++Loop) {
1489 :
1490 : // Call GetObjectItem routine to retrieve material data
1491 0 : s_ip->getObjectItem(state,
1492 0 : s_ipsc->cCurrentModuleObject,
1493 : Loop,
1494 0 : s_ipsc->cAlphaArgs,
1495 : NumAlphas,
1496 0 : s_ipsc->rNumericArgs,
1497 : NumNums,
1498 : IOStat,
1499 0 : s_ipsc->lNumericFieldBlanks,
1500 0 : s_ipsc->lAlphaFieldBlanks,
1501 0 : s_ipsc->cAlphaFieldNames,
1502 0 : s_ipsc->cNumericFieldNames);
1503 :
1504 0 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
1505 :
1506 0 : if (s_mat->materialMap.find(s_ipsc->cAlphaArgs(1)) != s_mat->materialMap.end()) {
1507 0 : ShowSevereDuplicateName(state, eoh);
1508 0 : ErrorsFound = true;
1509 0 : continue;
1510 : }
1511 :
1512 0 : auto *matScreen = new MaterialScreen;
1513 0 : matScreen->Name = s_ipsc->cAlphaArgs(1);
1514 :
1515 0 : s_mat->materials.push_back(matScreen);
1516 0 : matScreen->Num = s_mat->materials.isize();
1517 0 : s_mat->materialMap.insert_or_assign(matScreen->Name, matScreen->Num);
1518 :
1519 : // Load the material derived type from the input data.
1520 :
1521 0 : matScreen->bmRefModel =
1522 0 : static_cast<ScreenBeamReflectanceModel>(getEnumValue(screenBeamReflectanceModelNamesUC, Util::makeUPPER(s_ipsc->cAlphaArgs(2))));
1523 0 : if (matScreen->bmRefModel == ScreenBeamReflectanceModel::Invalid) {
1524 0 : ShowSevereError(state, format("{}=\"{}\", Illegal value.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
1525 0 : ShowContinueError(state,
1526 0 : format("{}=\"{}\", must be one of DoNotModel, ModelAsDirectBeam or ModelAsDiffuse.",
1527 0 : s_ipsc->cAlphaFieldNames(2),
1528 0 : s_ipsc->cAlphaArgs(2)));
1529 0 : ErrorsFound = true;
1530 : }
1531 0 : matScreen->Roughness = SurfaceRoughness::MediumRough;
1532 0 : matScreen->ShadeRef = s_ipsc->rNumericArgs(1);
1533 0 : if (matScreen->ShadeRef < 0.0 || matScreen->ShadeRef > 1.0) {
1534 0 : ErrorsFound = true;
1535 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value.");
1536 0 : ShowContinueError(state, s_ipsc->cNumericFieldNames(1) + " must be >= 0 and <= 1");
1537 : }
1538 0 : matScreen->ShadeRefVis = s_ipsc->rNumericArgs(2);
1539 0 : if (matScreen->ShadeRefVis < 0.0 || matScreen->ShadeRefVis > 1.0) {
1540 0 : ErrorsFound = true;
1541 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value.");
1542 0 : ShowContinueError(state, s_ipsc->cNumericFieldNames(2) + " must be >= 0 and <= 1 for material " + matScreen->Name + '.');
1543 : }
1544 0 : matScreen->AbsorpThermal = s_ipsc->rNumericArgs(3);
1545 0 : matScreen->AbsorpThermalInput = s_ipsc->rNumericArgs(3);
1546 0 : if (matScreen->AbsorpThermal < 0.0 || matScreen->AbsorpThermal > 1.0) {
1547 0 : ErrorsFound = true;
1548 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value.");
1549 0 : ShowContinueError(state, s_ipsc->cNumericFieldNames(3) + " must be >= 0 and <= 1");
1550 : }
1551 0 : matScreen->Conductivity = s_ipsc->rNumericArgs(4);
1552 0 : matScreen->Thickness = s_ipsc->rNumericArgs(6); // thickness = diameter
1553 :
1554 0 : if (s_ipsc->rNumericArgs(5) > 0.0) {
1555 : // Screens(ScNum)%ScreenDiameterToSpacingRatio = s_ipsc->rNumericArgs(6)/s_ipsc->rNumericArgs(5) or
1556 : // 1-SQRT(dataMaterial.Material(MaterNum)%Trans
1557 0 : if (s_ipsc->rNumericArgs(6) / s_ipsc->rNumericArgs(5) >= 1.0) {
1558 0 : ErrorsFound = true;
1559 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination.");
1560 0 : ShowContinueError(state, s_ipsc->cNumericFieldNames(6) + " must be less than " + s_ipsc->cNumericFieldNames(5));
1561 : } else {
1562 : // Calculate direct normal transmittance (open area fraction)
1563 0 : matScreen->Trans = pow_2(1.0 - s_ipsc->rNumericArgs(6) / s_ipsc->rNumericArgs(5));
1564 : }
1565 : } else {
1566 0 : ErrorsFound = true;
1567 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value.");
1568 0 : ShowContinueError(state, s_ipsc->cNumericFieldNames(5) + " must be > 0.");
1569 0 : s_ipsc->rNumericArgs(5) = 0.000000001;
1570 : }
1571 :
1572 0 : if (s_ipsc->rNumericArgs(6) <= 0.0) {
1573 0 : ErrorsFound = true;
1574 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value.");
1575 0 : ShowContinueError(state, s_ipsc->cNumericFieldNames(6) + " must be > 0.");
1576 : }
1577 :
1578 : // Modify reflectance to account for the open area in the screen assembly
1579 0 : matScreen->ShadeRef *= (1.0 - matScreen->Trans);
1580 0 : matScreen->ShadeRefVis *= (1.0 - matScreen->Trans);
1581 :
1582 0 : matScreen->toGlassDist = s_ipsc->rNumericArgs(7);
1583 0 : if (matScreen->toGlassDist < 0.001 || matScreen->toGlassDist > 1.0) {
1584 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value.");
1585 0 : ShowContinueError(state, s_ipsc->cNumericFieldNames(7) + " must be greater than or equal to 0.001 and less than or equal to 1.");
1586 : }
1587 :
1588 0 : matScreen->topOpeningMult = s_ipsc->rNumericArgs(8);
1589 0 : if (matScreen->topOpeningMult < 0.0 || matScreen->topOpeningMult > 1.0) {
1590 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value.");
1591 0 : ShowContinueError(state, s_ipsc->cNumericFieldNames(8) + " must be greater than or equal to 0 and less than or equal to 1.");
1592 : }
1593 :
1594 0 : matScreen->bottomOpeningMult = s_ipsc->rNumericArgs(9);
1595 0 : if (matScreen->bottomOpeningMult < 0.0 || matScreen->bottomOpeningMult > 1.0) {
1596 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value.");
1597 0 : ShowContinueError(state, s_ipsc->cNumericFieldNames(9) + " must be greater than or equal to 0 and less than or equal to 1.");
1598 : }
1599 :
1600 0 : matScreen->leftOpeningMult = s_ipsc->rNumericArgs(10);
1601 0 : if (matScreen->leftOpeningMult < 0.0 || matScreen->leftOpeningMult > 1.0) {
1602 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value.");
1603 0 : ShowContinueError(state, s_ipsc->cNumericFieldNames(10) + " must be greater than or equal to 0 and less than or equal to 1.");
1604 : }
1605 :
1606 0 : matScreen->rightOpeningMult = s_ipsc->rNumericArgs(11);
1607 0 : if (matScreen->rightOpeningMult < 0.0 || matScreen->rightOpeningMult > 1.0) {
1608 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value.");
1609 0 : ShowContinueError(state, s_ipsc->cNumericFieldNames(11) + " must be greater than or equal to 0 and less than or equal to 1.");
1610 : }
1611 :
1612 0 : matScreen->mapDegResolution = s_ipsc->rNumericArgs(12);
1613 0 : if (matScreen->mapDegResolution < 0 || matScreen->mapDegResolution > 5 || matScreen->mapDegResolution == 4) {
1614 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value.");
1615 0 : ShowContinueError(state, s_ipsc->cNumericFieldNames(12) + " must be 0, 1, 2, 3, or 5.");
1616 0 : ErrorsFound = true;
1617 : }
1618 :
1619 : // Default air flow permeability to open area fraction
1620 0 : matScreen->airFlowPermeability = matScreen->Trans;
1621 0 : matScreen->TransThermal = matScreen->Trans;
1622 0 : matScreen->TransVis = matScreen->Trans;
1623 :
1624 0 : matScreen->ROnly = true;
1625 :
1626 : // Calculate absorptance accounting for the open area in the screen assembly (used only in CreateShadedWindowConstruction)
1627 0 : matScreen->AbsorpSolar = max(0.0, 1.0 - matScreen->Trans - matScreen->ShadeRef);
1628 0 : matScreen->AbsorpSolarInput = matScreen->AbsorpSolar;
1629 0 : matScreen->AbsorpVisible = max(0.0, 1.0 - matScreen->TransVis - matScreen->ShadeRefVis);
1630 0 : matScreen->AbsorpVisibleInput = matScreen->AbsorpVisible;
1631 0 : matScreen->AbsorpThermal *= (1.0 - matScreen->Trans);
1632 0 : matScreen->AbsorpThermalInput = matScreen->AbsorpThermal;
1633 :
1634 0 : if (matScreen->Conductivity > 0.0) {
1635 0 : matScreen->NominalR = (1.0 - matScreen->Trans) * matScreen->Thickness / matScreen->Conductivity;
1636 : } else {
1637 0 : matScreen->NominalR = 1.0;
1638 0 : ShowWarningError(
1639 : state,
1640 0 : "Conductivity for material=\"" + matScreen->Name +
1641 : "\" must be greater than 0 for calculating Nominal R-value, Nominal R is defaulted to 1 and the simulation continues.");
1642 : }
1643 :
1644 0 : if (matScreen->Trans + matScreen->ShadeRef >= 1.0) {
1645 0 : ErrorsFound = true;
1646 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination.");
1647 0 : ShowContinueError(state, "Calculated solar transmittance + solar reflectance not < 1.0");
1648 0 : ShowContinueError(state, "See Engineering Reference for calculation procedure for solar transmittance.");
1649 : }
1650 :
1651 0 : if (matScreen->TransVis + matScreen->ShadeRefVis >= 1.0) {
1652 0 : ErrorsFound = true;
1653 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination.");
1654 0 : ShowContinueError(state, "Calculated visible transmittance + visible reflectance not < 1.0");
1655 0 : ShowContinueError(state, "See Engineering Reference for calculation procedure for visible solar transmittance.");
1656 : }
1657 :
1658 0 : if (matScreen->TransThermal + matScreen->AbsorpThermal >= 1.0) {
1659 0 : ErrorsFound = true;
1660 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination.");
1661 0 : ShowSevereError(state, "Thermal hemispherical emissivity plus open area fraction (1-diameter/spacing)**2 not < 1.0");
1662 : }
1663 : }
1664 :
1665 273 : s_ipsc->cCurrentModuleObject = "WindowMaterial:Screen:EquivalentLayer";
1666 273 : s_mat->NumEQLScreens = s_ip->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
1667 273 : for (int Loop = 1; Loop <= s_mat->NumEQLScreens; ++Loop) {
1668 :
1669 0 : s_ipsc->rNumericArgs = 0;
1670 :
1671 : // Call GetObjectItem routine to retrieve material data
1672 0 : s_ip->getObjectItem(state,
1673 0 : s_ipsc->cCurrentModuleObject,
1674 : Loop,
1675 0 : s_ipsc->cAlphaArgs,
1676 : NumAlphas,
1677 0 : s_ipsc->rNumericArgs,
1678 : NumNums,
1679 : IOStat,
1680 0 : s_ipsc->lNumericFieldBlanks,
1681 0 : s_ipsc->lAlphaFieldBlanks,
1682 0 : s_ipsc->cAlphaFieldNames,
1683 0 : s_ipsc->cNumericFieldNames);
1684 :
1685 0 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
1686 :
1687 0 : if (s_mat->materialMap.find(s_ipsc->cAlphaArgs(1)) != s_mat->materialMap.end()) {
1688 0 : ShowSevereDuplicateName(state, eoh);
1689 0 : ErrorsFound = true;
1690 0 : continue;
1691 : }
1692 :
1693 0 : auto *matScreen = new MaterialScreenEQL;
1694 0 : matScreen->group = Group::ScreenEQL;
1695 0 : matScreen->Name = s_ipsc->cAlphaArgs(1);
1696 :
1697 0 : s_mat->materials.push_back(matScreen);
1698 0 : matScreen->Num = s_mat->materials.isize();
1699 0 : s_mat->materialMap.insert_or_assign(matScreen->Name, matScreen->Num);
1700 :
1701 : // Load the material derived type from the input data.
1702 : // WindowMaterial:Screen:EquivalentLayer,
1703 0 : matScreen->Roughness = SurfaceRoughness::MediumRough;
1704 0 : matScreen->ROnly = true;
1705 0 : matScreen->TAR.Sol.Ft.Bm[0].BmTra = s_ipsc->rNumericArgs(1);
1706 0 : matScreen->TAR.Sol.Bk.Bm[0].BmTra = s_ipsc->rNumericArgs(1);
1707 0 : matScreen->TAR.Sol.Ft.Bm[0].DfTra = s_ipsc->rNumericArgs(2);
1708 0 : matScreen->TAR.Sol.Bk.Bm[0].DfTra = s_ipsc->rNumericArgs(2);
1709 0 : matScreen->TAR.Sol.Ft.Bm[0].DfRef = s_ipsc->rNumericArgs(3);
1710 0 : matScreen->TAR.Sol.Bk.Bm[0].DfRef = s_ipsc->rNumericArgs(3);
1711 0 : matScreen->TAR.Vis.Ft.Bm[0].BmTra = s_ipsc->rNumericArgs(4);
1712 0 : matScreen->TAR.Vis.Ft.Bm[0].DfTra = s_ipsc->rNumericArgs(5);
1713 0 : matScreen->TAR.Vis.Ft.Df.Ref = s_ipsc->rNumericArgs(6);
1714 0 : matScreen->TAR.IR.Ft.Tra = matScreen->TAR.IR.Bk.Tra = s_ipsc->rNumericArgs(7);
1715 0 : matScreen->TAR.IR.Ft.Emi = s_ipsc->rNumericArgs(8);
1716 0 : matScreen->TAR.IR.Bk.Emi = s_ipsc->rNumericArgs(8);
1717 :
1718 : // Assumes thermal emissivity is the same as thermal absorptance
1719 0 : matScreen->AbsorpThermalFront = matScreen->TAR.IR.Ft.Emi;
1720 0 : matScreen->AbsorpThermalBack = matScreen->TAR.IR.Bk.Emi;
1721 0 : matScreen->TransThermal = matScreen->TAR.IR.Ft.Tra;
1722 :
1723 0 : if (s_ipsc->rNumericArgs(3) < 0.0 || s_ipsc->rNumericArgs(3) > 1.0) {
1724 0 : ErrorsFound = true;
1725 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value.");
1726 0 : ShowContinueError(state, s_ipsc->cNumericFieldNames(3) + " must be >= 0 and <= 1");
1727 : }
1728 :
1729 0 : if (s_ipsc->rNumericArgs(6) < 0.0 || s_ipsc->rNumericArgs(6) > 1.0) {
1730 0 : ErrorsFound = true;
1731 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value.");
1732 0 : ShowContinueError(state, s_ipsc->cNumericFieldNames(6) + " must be >= 0 and <= 1 for material " + matScreen->Name + '.');
1733 : }
1734 :
1735 0 : if (!s_ipsc->lNumericFieldBlanks(9)) {
1736 0 : if (s_ipsc->rNumericArgs(9) > 0.00001) {
1737 0 : matScreen->wireSpacing = s_ipsc->rNumericArgs(9); // screen wire spacing
1738 : } else {
1739 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value.");
1740 0 : ShowContinueError(state, s_ipsc->cNumericFieldNames(9) + " must be > 0.");
1741 0 : ShowContinueError(state, "...Setting screen wire spacing to a default value of 0.025m and simulation continues.");
1742 0 : matScreen->wireSpacing = 0.025;
1743 : }
1744 : }
1745 :
1746 0 : if (!s_ipsc->lNumericFieldBlanks(10)) {
1747 0 : if (s_ipsc->rNumericArgs(10) > 0.00001 && s_ipsc->rNumericArgs(10) < matScreen->wireSpacing) {
1748 0 : matScreen->wireDiameter = s_ipsc->rNumericArgs(10); // screen wire spacing
1749 : } else {
1750 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value.");
1751 0 : ShowContinueError(state, s_ipsc->cNumericFieldNames(10) + " must be > 0.");
1752 0 : ShowContinueError(state, "...Setting screen wire diameter to a default value of 0.005m and simulation continues.");
1753 0 : matScreen->wireDiameter = 0.005;
1754 : }
1755 : }
1756 :
1757 0 : if (matScreen->wireSpacing > 0.0) {
1758 0 : if (matScreen->wireDiameter / matScreen->wireSpacing >= 1.0) {
1759 0 : ErrorsFound = true;
1760 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination.");
1761 0 : ShowContinueError(state, s_ipsc->cNumericFieldNames(10) + " must be less than " + s_ipsc->cNumericFieldNames(9));
1762 : } else {
1763 : // Calculate direct normal transmittance (open area fraction)
1764 0 : Openness = pow_2(1.0 - matScreen->wireDiameter / matScreen->wireSpacing);
1765 0 : if ((matScreen->TAR.Sol.Ft.Bm[0].BmTra - Openness) / Openness > 0.01) {
1766 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", screen openness specified.");
1767 0 : ShowContinueError(state, s_ipsc->cNumericFieldNames(1) + " is > 1.0% of the value calculated from input fields:");
1768 0 : ShowContinueError(state, s_ipsc->cNumericFieldNames(9) + " and " + (s_ipsc->cNumericFieldNames(10)));
1769 0 : ShowContinueError(state, " using the formula (1-diameter/spacing)**2");
1770 0 : ShowContinueError(state, " ...the screen diameter is recalculated from the material openness specified ");
1771 0 : ShowContinueError(state, " ...and wire spacing using the formula = wire spacing * (1.0 - SQRT(Opennes))");
1772 0 : matScreen->wireDiameter = matScreen->wireSpacing * (1.0 - std::sqrt(matScreen->TAR.Sol.Ft.Bm[0].BmTra));
1773 0 : ShowContinueError(state, format(" ...Recalculated {}={:.4R} m", s_ipsc->cNumericFieldNames(10), matScreen->wireDiameter));
1774 : }
1775 : }
1776 : }
1777 :
1778 0 : if (matScreen->TAR.Sol.Ft.Bm[0].BmTra + matScreen->TAR.Sol.Ft.Bm[0].DfRef >= 1.0) {
1779 0 : ErrorsFound = true;
1780 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination.");
1781 0 : ShowContinueError(state, "Calculated solar transmittance + solar reflectance not < 1.0");
1782 0 : ShowContinueError(state, "See Engineering Reference for calculation procedure for solar transmittance.");
1783 : }
1784 :
1785 0 : if (matScreen->TAR.Vis.Ft.Bm[0].BmTra + matScreen->TAR.Vis.Ft.Df.Ref >= 1.0) {
1786 0 : ErrorsFound = true;
1787 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination.");
1788 0 : ShowContinueError(state, "Calculated visible transmittance + visible reflectance not < 1.0");
1789 0 : ShowContinueError(state, "See Engineering Reference for calculation procedure for visible solar transmittance.");
1790 : }
1791 0 : if (matScreen->TransThermal + matScreen->AbsorpThermal >= 1.0) {
1792 0 : ErrorsFound = true;
1793 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination.");
1794 0 : ShowSevereError(state, "Thermal hemispherical emissivity plus open area fraction (1-diameter/spacing)**2 not < 1.0");
1795 : }
1796 :
1797 : } // TotScreensEQL loop
1798 :
1799 273 : s_ipsc->cCurrentModuleObject = "WindowMaterial:Blind";
1800 273 : s_mat->NumBlinds = s_ip->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
1801 276 : for (int Loop = 1; Loop <= s_mat->NumBlinds; ++Loop) {
1802 :
1803 : // Call Input Get routine to retrieve material data
1804 6 : s_ip->getObjectItem(state,
1805 3 : s_ipsc->cCurrentModuleObject,
1806 : Loop,
1807 3 : s_ipsc->cAlphaArgs,
1808 : NumAlphas,
1809 3 : s_ipsc->rNumericArgs,
1810 : NumNums,
1811 : IOStat,
1812 3 : s_ipsc->lNumericFieldBlanks,
1813 3 : s_ipsc->lAlphaFieldBlanks,
1814 3 : s_ipsc->cAlphaFieldNames,
1815 3 : s_ipsc->cNumericFieldNames);
1816 :
1817 3 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
1818 :
1819 3 : if (s_mat->materialMap.find(s_ipsc->cAlphaArgs(1)) != s_mat->materialMap.end()) {
1820 0 : ShowSevereDuplicateName(state, eoh);
1821 0 : ErrorsFound = true;
1822 0 : continue;
1823 : }
1824 :
1825 3 : auto *matBlind = new MaterialBlind;
1826 3 : matBlind->Name = s_ipsc->cAlphaArgs(1);
1827 :
1828 3 : s_mat->materials.push_back(matBlind);
1829 3 : matBlind->Num = s_mat->materials.isize();
1830 3 : s_mat->materialMap.insert_or_assign(matBlind->Name, matBlind->Num);
1831 :
1832 3 : matBlind->Roughness = SurfaceRoughness::Rough;
1833 3 : matBlind->ROnly = true;
1834 :
1835 3 : matBlind->SlatOrientation =
1836 3 : static_cast<DataWindowEquivalentLayer::Orientation>(getEnumValue(DataWindowEquivalentLayer::orientationNamesUC, s_ipsc->cAlphaArgs(2)));
1837 :
1838 3 : matBlind->SlatWidth = s_ipsc->rNumericArgs(1);
1839 3 : matBlind->SlatSeparation = s_ipsc->rNumericArgs(2);
1840 3 : matBlind->SlatThickness = s_ipsc->rNumericArgs(3);
1841 3 : matBlind->SlatAngle = s_ipsc->rNumericArgs(4);
1842 3 : matBlind->SlatConductivity = s_ipsc->rNumericArgs(5);
1843 :
1844 3 : matBlind->slatTAR.Sol.Ft.Bm[0].DfTra = s_ipsc->rNumericArgs(6);
1845 3 : matBlind->slatTAR.Sol.Ft.Bm[0].DfRef = s_ipsc->rNumericArgs(7);
1846 3 : matBlind->slatTAR.Sol.Bk.Bm[0].DfRef = s_ipsc->rNumericArgs(8);
1847 3 : matBlind->slatTAR.Sol.Ft.Df.Tra = s_ipsc->rNumericArgs(9);
1848 3 : matBlind->slatTAR.Sol.Ft.Df.Ref = s_ipsc->rNumericArgs(10);
1849 3 : matBlind->slatTAR.Sol.Bk.Df.Ref = s_ipsc->rNumericArgs(11);
1850 3 : matBlind->slatTAR.Vis.Ft.Bm[0].DfTra = s_ipsc->rNumericArgs(12);
1851 3 : matBlind->slatTAR.Vis.Ft.Bm[0].DfRef = s_ipsc->rNumericArgs(13);
1852 3 : matBlind->slatTAR.Vis.Bk.Bm[0].DfRef = s_ipsc->rNumericArgs(14);
1853 3 : matBlind->slatTAR.Vis.Ft.Df.Tra = s_ipsc->rNumericArgs(15);
1854 3 : matBlind->slatTAR.Vis.Ft.Df.Ref = s_ipsc->rNumericArgs(16);
1855 3 : matBlind->slatTAR.Vis.Bk.Df.Ref = s_ipsc->rNumericArgs(17);
1856 3 : matBlind->slatTAR.IR.Ft.Tra = matBlind->slatTAR.IR.Bk.Tra = s_ipsc->rNumericArgs(18);
1857 3 : matBlind->slatTAR.IR.Ft.Emi = s_ipsc->rNumericArgs(19);
1858 3 : matBlind->slatTAR.IR.Bk.Emi = s_ipsc->rNumericArgs(20);
1859 3 : matBlind->toGlassDist = s_ipsc->rNumericArgs(21);
1860 3 : matBlind->topOpeningMult = s_ipsc->rNumericArgs(22);
1861 3 : matBlind->bottomOpeningMult = s_ipsc->rNumericArgs(23);
1862 3 : matBlind->leftOpeningMult = s_ipsc->rNumericArgs(24);
1863 3 : matBlind->rightOpeningMult = s_ipsc->rNumericArgs(25);
1864 3 : matBlind->MinSlatAngle = s_ipsc->rNumericArgs(26);
1865 3 : matBlind->MaxSlatAngle = s_ipsc->rNumericArgs(27);
1866 :
1867 : // TH 2/11/2010. For CR 8010
1868 : // By default all blinds have fixed slat angle, new blinds with variable slat angle are created if
1869 : // they are used with window shading controls that adjust slat angles like ScheduledSlatAngle or BlockBeamSolar
1870 3 : matBlind->SlatAngleType = DataWindowEquivalentLayer::AngleType::Fixed;
1871 :
1872 3 : if (matBlind->SlatWidth < matBlind->SlatSeparation) {
1873 0 : ShowWarningError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Slat Angles/Widths");
1874 0 : ShowContinueError(state,
1875 0 : format("{} [{:.2R}] is less than {} [{:.2R}].",
1876 0 : s_ipsc->cNumericFieldNames(1),
1877 0 : matBlind->SlatWidth,
1878 0 : s_ipsc->cNumericFieldNames(2),
1879 0 : matBlind->SlatSeparation));
1880 0 : ShowContinueError(state, "This will allow direct beam to be transmitted when Slat angle = 0.");
1881 : }
1882 :
1883 3 : if ((s_ipsc->rNumericArgs(6) + s_ipsc->rNumericArgs(7) >= 1.0)) {
1884 0 : ErrorsFound = true;
1885 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination.");
1886 0 : ShowContinueError(state, s_ipsc->cNumericFieldNames(6) + " + " + s_ipsc->cNumericFieldNames(7) + " not < 1.0");
1887 : }
1888 3 : if ((s_ipsc->rNumericArgs(6) + s_ipsc->rNumericArgs(8) >= 1.0)) {
1889 0 : ErrorsFound = true;
1890 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination.");
1891 0 : ShowContinueError(state, s_ipsc->cNumericFieldNames(6) + " + " + s_ipsc->cNumericFieldNames(8) + " not < 1.0");
1892 : }
1893 :
1894 3 : if ((s_ipsc->rNumericArgs(9) + s_ipsc->rNumericArgs(10) >= 1.0)) {
1895 0 : ErrorsFound = true;
1896 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination.");
1897 0 : ShowContinueError(state, s_ipsc->cNumericFieldNames(9) + " + " + s_ipsc->cNumericFieldNames(10) + " not < 1.0");
1898 : }
1899 3 : if ((s_ipsc->rNumericArgs(9) + s_ipsc->rNumericArgs(11) >= 1.0)) {
1900 0 : ErrorsFound = true;
1901 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination.");
1902 0 : ShowContinueError(state, s_ipsc->cNumericFieldNames(9) + " + " + s_ipsc->cNumericFieldNames(11) + " not < 1.0");
1903 : }
1904 :
1905 3 : if ((s_ipsc->rNumericArgs(12) + s_ipsc->rNumericArgs(13) >= 1.0) || (s_ipsc->rNumericArgs(12) + s_ipsc->rNumericArgs(14) >= 1.0)) {
1906 0 : ErrorsFound = true;
1907 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination.");
1908 0 : ShowContinueError(state, s_ipsc->cNumericFieldNames(12) + " + " + s_ipsc->cNumericFieldNames(13) + " not < 1.0 OR");
1909 0 : ShowContinueError(state, s_ipsc->cNumericFieldNames(12) + " + " + s_ipsc->cNumericFieldNames(14) + " not < 1.0");
1910 : }
1911 :
1912 3 : if ((s_ipsc->rNumericArgs(12) + s_ipsc->rNumericArgs(13) >= 1.0)) {
1913 0 : ErrorsFound = true;
1914 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination.");
1915 0 : ShowContinueError(state, s_ipsc->cNumericFieldNames(12) + " + " + s_ipsc->cNumericFieldNames(13) + " not < 1.0");
1916 : }
1917 3 : if ((s_ipsc->rNumericArgs(12) + s_ipsc->rNumericArgs(14) >= 1.0)) {
1918 0 : ErrorsFound = true;
1919 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination.");
1920 0 : ShowContinueError(state, s_ipsc->cNumericFieldNames(12) + " + " + s_ipsc->cNumericFieldNames(14) + " not < 1.0");
1921 : }
1922 :
1923 3 : if ((s_ipsc->rNumericArgs(15) + s_ipsc->rNumericArgs(16) >= 1.0)) {
1924 0 : ErrorsFound = true;
1925 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination.");
1926 0 : ShowContinueError(state, s_ipsc->cNumericFieldNames(15) + " + " + s_ipsc->cNumericFieldNames(16) + " not < 1.0");
1927 : }
1928 3 : if ((s_ipsc->rNumericArgs(15) + s_ipsc->rNumericArgs(17) >= 1.0)) {
1929 0 : ErrorsFound = true;
1930 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination.");
1931 0 : ShowContinueError(state, s_ipsc->cNumericFieldNames(15) + " + " + s_ipsc->cNumericFieldNames(17) + " not < 1.0");
1932 : }
1933 :
1934 : // Require that beam and diffuse properties be the same
1935 3 : if (std::abs(s_ipsc->rNumericArgs(9) - s_ipsc->rNumericArgs(6)) > 1.e-5) {
1936 0 : ErrorsFound = true;
1937 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination.");
1938 0 : ShowContinueError(state, s_ipsc->cNumericFieldNames(6) + " must equal " + s_ipsc->cNumericFieldNames(9));
1939 : }
1940 :
1941 3 : if (std::abs(s_ipsc->rNumericArgs(10) - s_ipsc->rNumericArgs(7)) > 1.e-5) {
1942 0 : ErrorsFound = true;
1943 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination.");
1944 0 : ShowContinueError(state, s_ipsc->cNumericFieldNames(7) + " must equal " + s_ipsc->cNumericFieldNames(10));
1945 : }
1946 :
1947 3 : if (std::abs(s_ipsc->rNumericArgs(11) - s_ipsc->rNumericArgs(8)) > 1.e-5) {
1948 0 : ErrorsFound = true;
1949 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination.");
1950 0 : ShowContinueError(state, s_ipsc->cNumericFieldNames(8) + " must equal " + s_ipsc->cNumericFieldNames(11));
1951 : }
1952 :
1953 3 : if (std::abs(s_ipsc->rNumericArgs(15) - s_ipsc->rNumericArgs(12)) > 1.e-5) {
1954 0 : ErrorsFound = true;
1955 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination.");
1956 0 : ShowContinueError(state, s_ipsc->cNumericFieldNames(12) + " must equal " + s_ipsc->cNumericFieldNames(15));
1957 : }
1958 :
1959 3 : if (std::abs(s_ipsc->rNumericArgs(16) - s_ipsc->rNumericArgs(13)) > 1.e-5) {
1960 0 : ErrorsFound = true;
1961 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination.");
1962 0 : ShowContinueError(state, s_ipsc->cNumericFieldNames(13) + " must equal " + s_ipsc->cNumericFieldNames(16));
1963 : }
1964 :
1965 3 : if (std::abs(s_ipsc->rNumericArgs(17) - s_ipsc->rNumericArgs(14)) > 1.e-5) {
1966 0 : ErrorsFound = true;
1967 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination.");
1968 0 : ShowContinueError(state, s_ipsc->cNumericFieldNames(14) + " must equal " + s_ipsc->cNumericFieldNames(17));
1969 : }
1970 :
1971 3 : if ((s_ipsc->rNumericArgs(18) + s_ipsc->rNumericArgs(19) >= 1.0)) {
1972 0 : ErrorsFound = true;
1973 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination.");
1974 0 : ShowContinueError(state, s_ipsc->cNumericFieldNames(18) + " + " + s_ipsc->cNumericFieldNames(19) + " not < 1.0");
1975 : }
1976 3 : if ((s_ipsc->rNumericArgs(18) + s_ipsc->rNumericArgs(20) >= 1.0)) {
1977 0 : ErrorsFound = true;
1978 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination.");
1979 0 : ShowContinueError(state, s_ipsc->cNumericFieldNames(18) + " + " + s_ipsc->cNumericFieldNames(20) + " not < 1.0");
1980 : }
1981 :
1982 3 : if (matBlind->toGlassDist < 0.5 * matBlind->SlatWidth) {
1983 0 : ErrorsFound = true;
1984 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination.");
1985 0 : ShowContinueError(state, s_ipsc->cNumericFieldNames(21) + " is less than half of the " + s_ipsc->cNumericFieldNames(1));
1986 : }
1987 :
1988 : // Minimum and maximum slat angles allowed by slat geometry
1989 3 : if (matBlind->SlatWidth > matBlind->SlatSeparation) {
1990 3 : MinSlatAngGeom = std::asin(matBlind->SlatThickness / (matBlind->SlatThickness + matBlind->SlatSeparation)) / Constant::DegToRad;
1991 : } else {
1992 0 : MinSlatAngGeom = 0.0;
1993 : }
1994 3 : MaxSlatAngGeom = 180.0 - MinSlatAngGeom;
1995 :
1996 : // Error if input slat angle not in range allowed by slat geometry
1997 3 : if ((matBlind->SlatSeparation + matBlind->SlatThickness) < matBlind->SlatWidth) {
1998 3 : if (matBlind->SlatAngle < MinSlatAngGeom) {
1999 0 : ErrorsFound = true;
2000 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination.");
2001 0 : ShowContinueError(state,
2002 0 : format("{}=[{:.1R}], is less than smallest allowed by slat dimensions and spacing, [{:.1R}] deg.",
2003 0 : s_ipsc->cNumericFieldNames(4),
2004 0 : matBlind->SlatAngle,
2005 : MinSlatAngGeom));
2006 3 : } else if (matBlind->SlatAngle > MaxSlatAngGeom) {
2007 0 : ErrorsFound = true;
2008 0 : ShowSevereError(state, s_ipsc->cCurrentModuleObject + "=\"" + s_ipsc->cAlphaArgs(1) + "\", Illegal value combination.");
2009 0 : ShowContinueError(state,
2010 0 : format("{}=[{:.1R}], is greater than largest allowed by slat dimensions and spacing, [{:.1R}] deg.",
2011 0 : s_ipsc->cNumericFieldNames(4),
2012 0 : matBlind->SlatAngle,
2013 : MinSlatAngGeom));
2014 : }
2015 : }
2016 :
2017 : // By default all Blinds are "fixed" slats. Only with Shading Control is one considered variable and this check
2018 : // is now done when that happens. 9.3.2009 LKL
2019 :
2020 : // IF(Blind(Loop)%SlatAngleType == VariableSlats) THEN
2021 : // ! Error if maximum slat angle less than minimum
2022 : // IF(Blind(Loop)%MaxSlatAngle < Blind(Loop)%MinSlatAngle) THEN
2023 : // ErrorsFound = .TRUE.
2024 : // CALL ShowSevereError(state, TRIM(s_ipsc->cCurrentModuleObject)//'="'//TRIM(s_ipsc->cAlphaArgs(1))//'", Illegal value
2025 : // combination.') CALL ShowContinueError(state,
2026 : // TRIM(cNumericFieldNames(26))//'=['//TRIM(RoundSigDigits(Blind(Loop)%MinSlatAngle,1))// &
2027 : // '], is greater than '//TRIM(cNumericFieldNames(27))//'=['// &
2028 : // TRIM(RoundSigDigits(Blind(Loop)%MaxSlatAngle,1))//'] deg.')
2029 : // END IF
2030 : // ! Error if input slat angle not in input min/max range
2031 : // IF(Blind(Loop)%MaxSlatAngle > Blind(Loop)%MinSlatAngle .AND. (Blind(Loop)%SlatAngle < Blind(Loop)%MinSlatAngle &
2032 : // .OR. Blind(Loop)%SlatAngle > Blind(Loop)%MaxSlatAngle)) THEN
2033 : // ErrorsFound = .TRUE.
2034 : // CALL ShowSevereError(state, TRIM(s_ipsc->cCurrentModuleObject)//'="'//TRIM(s_ipsc->cAlphaArgs(1))//'", Illegal value
2035 : // combination.') CALL ShowContinueError(state, TRIM(cNumericFieldNames(4))//'=['//TRIM(RoundSigDigits(Blind(Loop)%SlatAngle,1))//
2036 : // &
2037 : // '] is outside of the input min/max range, min=['//TRIM(RoundSigDigits(Blind(Loop)%MinSlatAngle,1))// &
2038 : // '], max=['//TRIM(RoundSigDigits(Blind(Loop)%MaxSlatAngle,1))//'] deg.')
2039 : // END IF
2040 : // ! Error if input minimum slat angle is less than that allowed by slat geometry
2041 : // IF(Blind(Loop)%MinSlatAngle < MinSlatAngGeom) THEN
2042 : // CALL ShowSevereError(state, TRIM(s_ipsc->cCurrentModuleObject)//'="'//TRIM(s_ipsc->cAlphaArgs(1))//'", Illegal value
2043 : // combination.') CALL ShowContinueError(state,
2044 : // TRIM(cNumericFieldNames(26))//'=['//TRIM(RoundSigDigits(Blind(Loop)%MinSlatAngle,1))// &
2045 : // '] is less than the smallest allowed by slat dimensions and spacing, min=['// &
2046 : // TRIM(RoundSigDigits(MinSlatAngGeom,1))//'] deg.')
2047 : // CALL ShowContinueError(state, 'Minimum Slat Angle will be set to '//TRIM(RoundSigDigits(MinSlatAngGeom,1))//' deg.')
2048 : // Blind(Loop)%MinSlatAngle = MinSlatAngGeom
2049 : // END IF
2050 : // ! Error if input maximum slat angle is greater than that allowed by slat geometry
2051 : // IF(Blind(Loop)%MaxSlatAngle > MaxSlatAngGeom) THEN
2052 : // CALL ShowWarningError(state, TRIM(s_ipsc->cCurrentModuleObject)//'="'//TRIM(s_ipsc->cAlphaArgs(1))//'", Illegal value
2053 : // combination.') CALL ShowContinueError(state,
2054 : // TRIM(cNumericFieldNames(27))//'=['//TRIM(RoundSigDigits(Blind(Loop)%MaxSlatAngle,1))// &
2055 : // '] is greater than the largest allowed by slat dimensions and spacing, ['// &
2056 : // TRIM(RoundSigDigits(MaxSlatAngGeom,1))//'] deg.')
2057 : // CALL ShowContinueError(state, 'Maximum Slat Angle will be set to '//TRIM(RoundSigDigits(MaxSlatAngGeom,1))//' deg.')
2058 : // Blind(Loop)%MaxSlatAngle = MaxSlatAngGeom
2059 : // END IF
2060 : // END IF ! End of check if slat angle is variable
2061 : }
2062 :
2063 : // Window Blind Materials for EquivalentLayer Model
2064 :
2065 273 : s_ipsc->cCurrentModuleObject = "WindowMaterial:Blind:EquivalentLayer";
2066 273 : s_mat->NumEQLBlinds = s_ip->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
2067 278 : for (int Loop = 1; Loop <= s_mat->NumEQLBlinds; ++Loop) {
2068 :
2069 : // Call Input Get routine to retrieve material data
2070 10 : s_ip->getObjectItem(state,
2071 5 : s_ipsc->cCurrentModuleObject,
2072 : Loop,
2073 5 : s_ipsc->cAlphaArgs,
2074 : NumAlphas,
2075 5 : s_ipsc->rNumericArgs,
2076 : NumNums,
2077 : IOStat,
2078 5 : s_ipsc->lNumericFieldBlanks,
2079 5 : s_ipsc->lAlphaFieldBlanks,
2080 5 : s_ipsc->cAlphaFieldNames,
2081 5 : s_ipsc->cNumericFieldNames);
2082 :
2083 5 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
2084 :
2085 5 : if (s_mat->materialMap.find(s_ipsc->cAlphaArgs(1)) != s_mat->materialMap.end()) {
2086 0 : ShowSevereDuplicateName(state, eoh);
2087 0 : ErrorsFound = true;
2088 0 : continue;
2089 : }
2090 :
2091 5 : auto *mat = new MaterialBlindEQL;
2092 5 : mat->group = Group::BlindEQL;
2093 5 : mat->Name = s_ipsc->cAlphaArgs(1);
2094 :
2095 5 : s_mat->materials.push_back(mat);
2096 5 : mat->Num = s_mat->materials.isize();
2097 5 : s_mat->materialMap.insert_or_assign(mat->Name, mat->Num);
2098 :
2099 5 : mat->Roughness = SurfaceRoughness::Rough;
2100 5 : mat->ROnly = true;
2101 :
2102 5 : mat->SlatOrientation =
2103 5 : static_cast<DataWindowEquivalentLayer::Orientation>(getEnumValue(DataWindowEquivalentLayer::orientationNamesUC, s_ipsc->cAlphaArgs(2)));
2104 :
2105 5 : mat->SlatWidth = s_ipsc->rNumericArgs(1);
2106 5 : mat->SlatSeparation = s_ipsc->rNumericArgs(2);
2107 5 : mat->SlatCrown = s_ipsc->rNumericArgs(3);
2108 5 : mat->SlatAngle = s_ipsc->rNumericArgs(4);
2109 :
2110 5 : mat->TAR.Sol.Ft.Bm[0].DfTra = s_ipsc->rNumericArgs(5);
2111 5 : mat->TAR.Sol.Bk.Bm[0].DfTra = s_ipsc->rNumericArgs(6);
2112 5 : mat->TAR.Sol.Ft.Bm[0].DfRef = s_ipsc->rNumericArgs(7);
2113 5 : mat->TAR.Sol.Bk.Bm[0].DfRef = s_ipsc->rNumericArgs(8);
2114 :
2115 9 : if (!s_ipsc->lNumericFieldBlanks(9) && !s_ipsc->lNumericFieldBlanks(10) && !s_ipsc->lNumericFieldBlanks(11) &&
2116 4 : !s_ipsc->lNumericFieldBlanks(12)) {
2117 4 : mat->TAR.Vis.Ft.Bm[0].DfTra = s_ipsc->rNumericArgs(9);
2118 4 : mat->TAR.Vis.Bk.Bm[0].DfTra = s_ipsc->rNumericArgs(10);
2119 4 : mat->TAR.Vis.Ft.Bm[0].DfRef = s_ipsc->rNumericArgs(11);
2120 4 : mat->TAR.Vis.Bk.Bm[0].DfRef = s_ipsc->rNumericArgs(12);
2121 : }
2122 5 : if (!s_ipsc->lNumericFieldBlanks(13) && !s_ipsc->lNumericFieldBlanks(14) && !s_ipsc->lNumericFieldBlanks(15)) {
2123 5 : mat->TAR.Sol.Ft.Df.Tra = s_ipsc->rNumericArgs(13);
2124 5 : mat->TAR.Sol.Ft.Df.Ref = s_ipsc->rNumericArgs(14);
2125 5 : mat->TAR.Sol.Bk.Df.Ref = s_ipsc->rNumericArgs(15);
2126 : }
2127 5 : if (!s_ipsc->lNumericFieldBlanks(16) && !s_ipsc->lNumericFieldBlanks(17) && !s_ipsc->lNumericFieldBlanks(18)) {
2128 4 : mat->TAR.Vis.Ft.Df.Tra = s_ipsc->rNumericArgs(13);
2129 4 : mat->TAR.Vis.Ft.Df.Ref = s_ipsc->rNumericArgs(14);
2130 4 : mat->TAR.Vis.Bk.Df.Ref = s_ipsc->rNumericArgs(15);
2131 : }
2132 5 : if (!s_ipsc->lNumericFieldBlanks(19)) {
2133 4 : mat->TAR.IR.Ft.Tra = mat->TAR.IR.Bk.Tra = s_ipsc->rNumericArgs(19);
2134 : }
2135 5 : if (!s_ipsc->lNumericFieldBlanks(20)) {
2136 5 : mat->TAR.IR.Ft.Emi = s_ipsc->rNumericArgs(20);
2137 : }
2138 5 : if (!s_ipsc->lNumericFieldBlanks(21)) {
2139 5 : mat->TAR.IR.Bk.Emi = s_ipsc->rNumericArgs(21);
2140 : }
2141 : // Assumes thermal emissivity is the same as thermal absorptance
2142 5 : mat->AbsorpThermalFront = mat->TAR.IR.Ft.Emi;
2143 5 : mat->AbsorpThermalBack = mat->TAR.IR.Bk.Emi;
2144 5 : mat->TransThermal = mat->TAR.IR.Ft.Tra;
2145 :
2146 : // By default all blinds have fixed slat angle,
2147 : // they are used with window shading controls that adjust slat angles like
2148 : // MaximizeSolar or BlockBeamSolar
2149 5 : mat->slatAngleType = SlatAngleType::FixedSlatAngle;
2150 5 : if (!s_ipsc->lAlphaFieldBlanks(3)) {
2151 5 : mat->slatAngleType = static_cast<SlatAngleType>(getEnumValue(slatAngleTypeNamesUC, Util::makeUPPER(s_ipsc->cAlphaArgs(3))));
2152 : }
2153 5 : if (mat->SlatWidth < mat->SlatSeparation) {
2154 0 : ShowWarningError(state, format("{}=\"{}\", Slat Seperation/Width", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
2155 0 : ShowContinueError(state,
2156 0 : format("{} [{:.2R}] is less than {} [{:.2R}].",
2157 0 : s_ipsc->cNumericFieldNames(1),
2158 0 : mat->SlatWidth,
2159 0 : s_ipsc->cNumericFieldNames(2),
2160 0 : mat->SlatSeparation));
2161 0 : ShowContinueError(state, "This will allow direct beam to be transmitted when Slat angle = 0.");
2162 : }
2163 5 : if (mat->SlatSeparation < 0.001) {
2164 0 : ShowWarningError(state, format("{}=\"{}\", Slat Seperation", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
2165 0 : ShowContinueError(state, format("{} [{:.2R}]. Slate spacing must be > 0.0", s_ipsc->cNumericFieldNames(2), mat->SlatSeparation));
2166 0 : ShowContinueError(state,
2167 : "...Setting slate spacing to default value of 0.025 m and "
2168 : "simulation continues.");
2169 0 : mat->SlatSeparation = 0.025;
2170 : }
2171 5 : if (mat->SlatWidth < 0.001 || mat->SlatWidth >= 2.0 * mat->SlatSeparation) {
2172 0 : ShowWarningError(state, format("{}=\"{}\", Slat Width", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
2173 0 : ShowContinueError(state,
2174 0 : format("{} [{:.2R}]. Slat width range is 0 < Width <= 2*Spacing", s_ipsc->cNumericFieldNames(1), mat->SlatWidth));
2175 0 : ShowContinueError(state, "...Setting slate width equal to slate spacing and simulation continues.");
2176 0 : mat->SlatWidth = mat->SlatSeparation;
2177 : }
2178 5 : if (mat->SlatCrown < 0.0 || mat->SlatCrown >= 0.5 * mat->SlatWidth) {
2179 0 : ShowWarningError(state, format("{}=\"{}\", Slat Crown", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
2180 0 : ShowContinueError(state,
2181 0 : format("{} [{:.2R}]. Slat crwon range is 0 <= crown < 0.5*Width", s_ipsc->cNumericFieldNames(3), mat->SlatCrown));
2182 0 : ShowContinueError(state, "...Setting slate crown to 0.0 and simulation continues.");
2183 0 : mat->SlatCrown = 0.0;
2184 : }
2185 5 : if (mat->SlatAngle < -90.0 || mat->SlatAngle > 90.0) {
2186 0 : ShowWarningError(state, format("{}=\"{}\", Slat Angle", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
2187 0 : ShowContinueError(state, format("{} [{:.2R}]. Slat angle range is -90.0 <= Angle < 90.0", s_ipsc->cNumericFieldNames(4), mat->SlatAngle));
2188 0 : ShowContinueError(state, "...Setting slate angle to 0.0 and simulation continues.");
2189 0 : mat->SlatAngle = 0.0;
2190 : }
2191 :
2192 5 : if ((s_ipsc->rNumericArgs(5) + s_ipsc->rNumericArgs(7) >= 1.0)) {
2193 0 : ErrorsFound = true;
2194 0 : ShowSevereError(state, format("{}=\"{}\", Illegal value combination.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
2195 0 : ShowContinueError(state, format("{} + {} not < 1.0", s_ipsc->cNumericFieldNames(5), s_ipsc->cNumericFieldNames(7)));
2196 : }
2197 5 : if ((s_ipsc->rNumericArgs(6) + s_ipsc->rNumericArgs(8) >= 1.0)) {
2198 0 : ErrorsFound = true;
2199 0 : ShowSevereError(state, format("{}=\"{}\", Illegal value combination.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
2200 0 : ShowContinueError(state, format("{} + {} not < 1.0", s_ipsc->cNumericFieldNames(6), s_ipsc->cNumericFieldNames(8)));
2201 : }
2202 5 : if ((s_ipsc->rNumericArgs(9) + s_ipsc->rNumericArgs(11) >= 1.0)) {
2203 0 : ErrorsFound = true;
2204 0 : ShowSevereError(state, format("{}=\"{}\", Illegal value combination.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
2205 0 : ShowContinueError(state, format("{} + {} not < 1.0", s_ipsc->cNumericFieldNames(9), s_ipsc->cNumericFieldNames(11)));
2206 : }
2207 5 : if ((s_ipsc->rNumericArgs(10) + s_ipsc->rNumericArgs(12) >= 1.0)) {
2208 0 : ErrorsFound = true;
2209 0 : ShowSevereError(state, format("{}=\"{}\", Illegal value combination.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
2210 0 : ShowContinueError(state, format("{} + {} not < 1.0", s_ipsc->cNumericFieldNames(10), s_ipsc->cNumericFieldNames(12)));
2211 : }
2212 :
2213 : } // TotBlindsEQL loop
2214 :
2215 : // EcoRoof Materials
2216 : // PSU 2006
2217 273 : s_ipsc->cCurrentModuleObject = "Material:RoofVegetation";
2218 273 : s_mat->NumEcoRoofs = s_ip->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
2219 275 : for (int Loop = 1; Loop <= s_mat->NumEcoRoofs; ++Loop) {
2220 : // Call Input Get Routine to retrieve material data from ecoroof
2221 :
2222 4 : s_ip->getObjectItem(state,
2223 2 : s_ipsc->cCurrentModuleObject,
2224 : Loop,
2225 2 : s_ipsc->cAlphaArgs,
2226 : NumAlphas,
2227 2 : s_ipsc->rNumericArgs,
2228 : NumNums,
2229 : IOStat,
2230 2 : s_ipsc->lNumericFieldBlanks,
2231 2 : s_ipsc->lAlphaFieldBlanks,
2232 2 : s_ipsc->cAlphaFieldNames,
2233 2 : s_ipsc->cNumericFieldNames);
2234 :
2235 2 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
2236 :
2237 2 : if (s_mat->materialMap.find(s_ipsc->cAlphaArgs(1)) != s_mat->materialMap.end()) {
2238 0 : ShowSevereDuplicateName(state, eoh);
2239 0 : ErrorsFound = true;
2240 0 : continue;
2241 : }
2242 :
2243 : // this part is similar to the regular material
2244 : // Load the material derived type from the input data.
2245 2 : auto *mat = new MaterialEcoRoof;
2246 2 : mat->group = Group::EcoRoof;
2247 2 : mat->Name = s_ipsc->cAlphaArgs(1);
2248 :
2249 2 : s_mat->materials.push_back(mat);
2250 2 : mat->Num = s_mat->materials.isize();
2251 2 : s_mat->materialMap.insert_or_assign(mat->Name, mat->Num);
2252 :
2253 2 : mat->HeightOfPlants = s_ipsc->rNumericArgs(1);
2254 2 : mat->LAI = s_ipsc->rNumericArgs(2);
2255 2 : mat->Lreflectivity = s_ipsc->rNumericArgs(3); // Albedo
2256 2 : mat->LEmissitivity = s_ipsc->rNumericArgs(4);
2257 2 : mat->RStomata = s_ipsc->rNumericArgs(5);
2258 :
2259 : // need to treat the A2 with is just the name of the soil(it is
2260 : // not important)
2261 2 : mat->Roughness = static_cast<SurfaceRoughness>(getEnumValue(surfaceRoughnessNamesUC, Util::makeUPPER(s_ipsc->cAlphaArgs(3))));
2262 :
2263 2 : if (s_ipsc->lAlphaFieldBlanks(4)) {
2264 0 : mat->calcMethod = EcoRoofCalcMethod::SchaapGenuchten;
2265 : } else {
2266 2 : mat->calcMethod = static_cast<EcoRoofCalcMethod>(getEnumValue(ecoRoofCalcMethodNamesUC, s_ipsc->cAlphaArgs(4)));
2267 : }
2268 :
2269 2 : mat->Thickness = s_ipsc->rNumericArgs(6);
2270 2 : mat->Conductivity = s_ipsc->rNumericArgs(7);
2271 2 : mat->Density = s_ipsc->rNumericArgs(8);
2272 2 : mat->SpecHeat = s_ipsc->rNumericArgs(9);
2273 2 : mat->AbsorpThermal = s_ipsc->rNumericArgs(10); // emissivity
2274 2 : mat->AbsorpSolar = s_ipsc->rNumericArgs(11); // (1 - Albedo)
2275 2 : mat->AbsorpVisible = s_ipsc->rNumericArgs(12);
2276 2 : mat->Porosity = s_ipsc->rNumericArgs(13);
2277 2 : mat->MinMoisture = s_ipsc->rNumericArgs(14);
2278 2 : mat->InitMoisture = s_ipsc->rNumericArgs(15);
2279 :
2280 2 : if (mat->Conductivity > 0.0) {
2281 2 : mat->Resistance = mat->NominalR = mat->Thickness / mat->Conductivity;
2282 : } else {
2283 0 : ShowSevereError(state, format("{}=\"{}\" is not defined correctly.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
2284 0 : ShowContinueError(state, format("{} is <=0.", s_ipsc->cNumericFieldNames(7)));
2285 0 : ErrorsFound = true;
2286 : }
2287 :
2288 2 : if (mat->InitMoisture > mat->Porosity) {
2289 1 : ShowWarningError(state, format("{}=\"{}\", Illegal value combination.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
2290 2 : ShowContinueError(
2291 2 : state, format("{} is greater than {}. It must be less or equal.", s_ipsc->cNumericFieldNames(15), s_ipsc->cNumericFieldNames(13)));
2292 1 : ShowContinueError(state, format("{} = {:.3T}.", s_ipsc->cNumericFieldNames(13), mat->Porosity));
2293 1 : ShowContinueError(state, format("{} = {:.3T}.", s_ipsc->cNumericFieldNames(15), mat->InitMoisture));
2294 2 : ShowContinueError(state,
2295 2 : format("{} is reset to the maximum (saturation) value = {:.3T}.", s_ipsc->cNumericFieldNames(15), mat->Porosity));
2296 2 : ShowContinueError(state, "Simulation continues.");
2297 1 : mat->InitMoisture = mat->Porosity;
2298 : }
2299 : }
2300 :
2301 : // Thermochromic glazing group
2302 : // get the number of WindowMaterial:GlazingGroup:Thermochromic objects in the idf file
2303 273 : s_ipsc->cCurrentModuleObject = "WindowMaterial:GlazingGroup:Thermochromic";
2304 273 : s_mat->NumTCGlazings = s_ip->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
2305 :
2306 273 : for (int Loop = 1; Loop <= s_mat->NumTCGlazings; ++Loop) {
2307 : // Get each TCGlazings from the input processor
2308 0 : s_ip->getObjectItem(state,
2309 0 : s_ipsc->cCurrentModuleObject,
2310 : Loop,
2311 0 : s_ipsc->cAlphaArgs,
2312 : NumAlphas,
2313 0 : s_ipsc->rNumericArgs,
2314 : NumNums,
2315 : IOStat,
2316 0 : s_ipsc->lNumericFieldBlanks,
2317 0 : s_ipsc->lAlphaFieldBlanks,
2318 0 : s_ipsc->cAlphaFieldNames,
2319 0 : s_ipsc->cNumericFieldNames);
2320 :
2321 0 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
2322 0 : std::string nameUC = Util::makeUPPER(s_ipsc->cAlphaArgs(1));
2323 :
2324 0 : if (s_mat->materialMap.find(nameUC) != s_mat->materialMap.end()) {
2325 0 : ShowSevereDuplicateName(state, eoh);
2326 0 : ErrorsFound = true;
2327 0 : continue;
2328 : }
2329 :
2330 0 : auto *mat = new MaterialGlassTC;
2331 0 : mat->Name = s_ipsc->cAlphaArgs(1);
2332 0 : s_mat->materials.push_back(mat);
2333 0 : mat->Num = s_mat->materials.isize();
2334 0 : s_mat->materialMap.insert_or_assign(nameUC, mat->Num);
2335 :
2336 0 : if (NumNums + 1 != NumAlphas) {
2337 0 : ShowSevereCustom(
2338 0 : state, eoh, format("Check number of {} compared to number of {}", s_ipsc->cAlphaFieldNames(2), s_ipsc->cNumericFieldNames(1)));
2339 0 : ErrorsFound = true;
2340 0 : continue;
2341 : }
2342 :
2343 : // Allocate arrays
2344 0 : mat->numMatRefs = NumNums;
2345 0 : mat->matRefs.allocate(mat->numMatRefs);
2346 :
2347 0 : for (int iMatRef = 1; iMatRef <= mat->numMatRefs; ++iMatRef) {
2348 0 : auto &matRef = mat->matRefs(iMatRef);
2349 0 : matRef.specTemp = s_ipsc->rNumericArgs(iMatRef);
2350 : // Find this glass definition
2351 0 : matRef.matNum = Material::GetMaterialNum(state, s_ipsc->cAlphaArgs(1 + iMatRef));
2352 0 : if (matRef.matNum == 0) {
2353 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(1 + iMatRef), s_ipsc->cAlphaArgs(1 + iMatRef));
2354 0 : ErrorsFound = true;
2355 0 : continue;
2356 : }
2357 :
2358 : // TC glazing
2359 0 : auto *matGlass = s_mat->materials(matRef.matNum);
2360 : // test that named material is of the right type
2361 0 : if (matGlass->group != Group::Glass) {
2362 0 : ShowSevereCustom(
2363 : state,
2364 : eoh,
2365 0 : format("{} = {}, Material is not a window glazing ", s_ipsc->cAlphaFieldNames(1 + iMatRef), s_ipsc->cAlphaArgs(1 + iMatRef)));
2366 0 : ErrorsFound = true;
2367 0 : continue;
2368 : }
2369 :
2370 0 : dynamic_cast<MaterialGlass *>(matGlass)->TCParentMatNum = mat->Num;
2371 : }
2372 0 : }
2373 :
2374 273 : s_ipsc->cCurrentModuleObject = "WindowMaterial:SimpleGlazingSystem";
2375 273 : s_mat->NumSimpleWindows = s_ip->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
2376 296 : for (int Loop = 1; Loop <= s_mat->NumSimpleWindows; ++Loop) {
2377 :
2378 46 : s_ip->getObjectItem(state,
2379 23 : s_ipsc->cCurrentModuleObject,
2380 : Loop,
2381 23 : s_ipsc->cAlphaArgs,
2382 : NumAlphas,
2383 23 : s_ipsc->rNumericArgs,
2384 : NumNums,
2385 : IOStat,
2386 23 : s_ipsc->lNumericFieldBlanks,
2387 23 : s_ipsc->lAlphaFieldBlanks,
2388 23 : s_ipsc->cAlphaFieldNames,
2389 23 : s_ipsc->cNumericFieldNames);
2390 :
2391 23 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
2392 :
2393 23 : if (s_mat->materialMap.find(s_ipsc->cAlphaArgs(1)) != s_mat->materialMap.end()) {
2394 0 : ShowSevereDuplicateName(state, eoh);
2395 0 : ErrorsFound = true;
2396 0 : continue;
2397 : }
2398 :
2399 23 : auto *mat = new MaterialGlass;
2400 23 : mat->group = Group::GlassSimple;
2401 23 : mat->Name = s_ipsc->cAlphaArgs(1);
2402 :
2403 23 : s_mat->materials.push_back(mat);
2404 23 : mat->Num = s_mat->materials.isize();
2405 23 : s_mat->materialMap.insert_or_assign(mat->Name, mat->Num);
2406 :
2407 23 : mat->SimpleWindowUfactor = s_ipsc->rNumericArgs(1);
2408 23 : mat->SimpleWindowSHGC = s_ipsc->rNumericArgs(2);
2409 23 : if (!s_ipsc->lNumericFieldBlanks(3)) {
2410 13 : mat->SimpleWindowVisTran = s_ipsc->rNumericArgs(3);
2411 13 : mat->SimpleWindowVTinputByUser = true;
2412 : }
2413 :
2414 23 : mat->SetupSimpleWindowGlazingSystem(state);
2415 : }
2416 :
2417 : // Reading WindowMaterial:Gap, this will also read the
2418 : // WindowMaterial:DeflectionState and WindowMaterial:SupportPillar
2419 : // objects if necessary
2420 273 : s_ipsc->cCurrentModuleObject = "WindowMaterial:Gap";
2421 273 : s_mat->NumW7Gaps = s_ip->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
2422 : // ALLOCATE(DeflectionState(W7DeflectionStates))
2423 274 : for (int Loop = 1; Loop <= s_mat->NumW7Gaps; ++Loop) {
2424 2 : s_ip->getObjectItem(state,
2425 1 : s_ipsc->cCurrentModuleObject,
2426 : Loop,
2427 1 : s_ipsc->cAlphaArgs,
2428 : NumAlphas,
2429 1 : s_ipsc->rNumericArgs,
2430 : NumNums,
2431 : IOStat,
2432 1 : s_ipsc->lNumericFieldBlanks,
2433 1 : s_ipsc->lAlphaFieldBlanks,
2434 1 : s_ipsc->cAlphaFieldNames,
2435 1 : s_ipsc->cNumericFieldNames);
2436 :
2437 1 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
2438 :
2439 1 : if (s_mat->materialMap.find(s_ipsc->cAlphaArgs(1)) != s_mat->materialMap.end()) {
2440 0 : ShowSevereDuplicateName(state, eoh);
2441 0 : ErrorsFound = true;
2442 0 : continue;
2443 : }
2444 :
2445 1 : auto *mat = new Material::MaterialComplexWindowGap;
2446 1 : mat->Name = s_ipsc->cAlphaArgs(1);
2447 :
2448 1 : s_mat->materials.push_back(mat);
2449 1 : mat->Num = s_mat->materials.isize();
2450 1 : s_mat->materialMap.insert_or_assign(mat->Name, mat->Num);
2451 :
2452 1 : mat->group = Material::Group::ComplexWindowGap;
2453 1 : mat->Roughness = Material::SurfaceRoughness::Rough;
2454 1 : mat->ROnly = true;
2455 :
2456 1 : mat->Thickness = s_ipsc->rNumericArgs(1);
2457 1 : if (s_ipsc->rNumericArgs(1) <= 0.0) {
2458 0 : ErrorsFound = true;
2459 0 : ShowSevereCustom(state, eoh, format("{} must be > 0, entered {:.2R}", s_ipsc->cNumericFieldNames(1), s_ipsc->rNumericArgs(1)));
2460 : }
2461 :
2462 1 : mat->Pressure = s_ipsc->rNumericArgs(2);
2463 1 : if (s_ipsc->rNumericArgs(2) <= 0.0) {
2464 0 : ErrorsFound = true;
2465 0 : ShowSevereCustom(state, eoh, format("{} must be > 0, entered {:.2R}", s_ipsc->cNumericFieldNames(2), s_ipsc->rNumericArgs(2)));
2466 : }
2467 :
2468 1 : if (!s_ipsc->lAlphaFieldBlanks(2)) {
2469 1 : int matGasNum = GetMaterialNum(state, s_ipsc->cAlphaArgs(2));
2470 1 : if (matGasNum == 0) {
2471 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2));
2472 0 : ErrorsFound = true;
2473 0 : continue;
2474 : }
2475 :
2476 : // Copy all relevant fields from referenced gas mixture
2477 1 : auto const *matGasMix = dynamic_cast<MaterialGasMix const *>(s_mat->materials(matGasNum));
2478 1 : mat->numGases = matGasMix->numGases;
2479 1 : mat->gasFracts = matGasMix->gasFracts;
2480 1 : mat->gases = matGasMix->gases;
2481 1 : mat->gapVentType = matGasMix->gapVentType;
2482 : }
2483 :
2484 : // Find referenced DeflectionState object and copy field from it
2485 1 : if (!s_ipsc->lAlphaFieldBlanks(3)) {
2486 0 : auto const itInstances = s_ip->epJSON.find("WindowGap:DeflectionState");
2487 0 : if (itInstances == s_ip->epJSON.end()) {
2488 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3));
2489 0 : ErrorsFound = true;
2490 0 : continue;
2491 : }
2492 :
2493 0 : auto const &instances2 = itInstances.value();
2494 0 : auto itObj = instances2.begin();
2495 : // Can't use find here because epJSON keys are not upper-cased
2496 0 : for (; itObj != instances2.end(); ++itObj) {
2497 0 : if (Util::makeUPPER(itObj.key()) == s_ipsc->cAlphaArgs(3)) break;
2498 : }
2499 :
2500 0 : if (itObj == instances2.end()) {
2501 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3));
2502 0 : ErrorsFound = true;
2503 0 : continue;
2504 : }
2505 :
2506 0 : auto const &obj = itObj.value();
2507 0 : auto const &objSchemaProps = s_ip->getObjectSchemaProps(state, "WindowGap:DeflectionState");
2508 0 : mat->deflectedThickness = s_ip->getRealFieldValue(obj, objSchemaProps, "deflected_thickness");
2509 : }
2510 :
2511 : // Find referenced
2512 1 : if (!s_ipsc->lAlphaFieldBlanks(4)) {
2513 0 : auto const itInstances = s_ip->epJSON.find("WindowGap:SupportPillar");
2514 0 : if (itInstances == s_ip->epJSON.end()) {
2515 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(4), s_ipsc->cAlphaArgs(4));
2516 0 : ErrorsFound = true;
2517 0 : continue;
2518 : }
2519 :
2520 0 : auto const &instances3 = itInstances.value();
2521 :
2522 0 : auto itObj = instances3.begin();
2523 : // Can't use find here because epJSON keys are not upper-cased
2524 0 : for (; itObj != instances3.end(); ++itObj) {
2525 0 : if (Util::makeUPPER(itObj.key()) == s_ipsc->cAlphaArgs(4)) break;
2526 : }
2527 :
2528 0 : if (itObj == instances3.end()) {
2529 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(4), s_ipsc->cAlphaArgs(4));
2530 0 : ErrorsFound = true;
2531 0 : continue;
2532 : }
2533 :
2534 0 : auto const &obj = itObj.value();
2535 0 : auto const &objSchemaProps = s_ip->getObjectSchemaProps(state, "WindowGap:SupportPillar");
2536 0 : mat->pillarSpacing = s_ip->getRealFieldValue(obj, objSchemaProps, "spacing");
2537 0 : mat->pillarRadius = s_ip->getRealFieldValue(obj, objSchemaProps, "radius");
2538 : }
2539 : }
2540 :
2541 : // Reading WindowMaterial:ComplexShade
2542 273 : s_ipsc->cCurrentModuleObject = "WindowMaterial:ComplexShade";
2543 273 : int TotComplexShades = s_ip->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
2544 276 : for (int Loop = 1; Loop <= TotComplexShades; ++Loop) {
2545 6 : s_ip->getObjectItem(state,
2546 3 : s_ipsc->cCurrentModuleObject,
2547 : Loop,
2548 3 : s_ipsc->cAlphaArgs,
2549 : NumAlphas,
2550 3 : s_ipsc->rNumericArgs,
2551 : NumNums,
2552 : IOStat,
2553 3 : s_ipsc->lNumericFieldBlanks,
2554 3 : s_ipsc->lAlphaFieldBlanks,
2555 3 : s_ipsc->cAlphaFieldNames,
2556 3 : s_ipsc->cNumericFieldNames);
2557 :
2558 3 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
2559 :
2560 3 : if (s_mat->materialMap.find(s_ipsc->cAlphaArgs(1)) != s_mat->materialMap.end()) {
2561 0 : ShowSevereDuplicateName(state, eoh);
2562 0 : ErrorsFound = true;
2563 0 : continue;
2564 : }
2565 :
2566 3 : auto *mat = new Material::MaterialComplexShade;
2567 3 : mat->Name = s_ipsc->cAlphaArgs(1);
2568 :
2569 3 : s_mat->materials.push_back(mat);
2570 3 : mat->Num = s_mat->materials.isize();
2571 3 : s_mat->materialMap.insert_or_assign(mat->Name, mat->Num);
2572 :
2573 3 : mat->Roughness = Material::SurfaceRoughness::Rough;
2574 3 : mat->ROnly = true;
2575 :
2576 3 : mat->LayerType = static_cast<TARCOGParams::TARCOGLayerType>(getEnumValue(TARCOGParams::layerTypeNamesUC, s_ipsc->cAlphaArgs(2)));
2577 :
2578 3 : mat->Thickness = s_ipsc->rNumericArgs(1);
2579 3 : mat->Conductivity = s_ipsc->rNumericArgs(2);
2580 3 : mat->TransThermal = s_ipsc->rNumericArgs(3);
2581 3 : mat->FrontEmissivity = s_ipsc->rNumericArgs(4);
2582 3 : mat->BackEmissivity = s_ipsc->rNumericArgs(5);
2583 :
2584 : // Simon: in heat balance radiation exchange routines AbsorpThermal is used
2585 : // and program will crash if value is not assigned. Not sure if this is correct
2586 : // or some additional calculation is necessary. Simon TODO
2587 3 : mat->AbsorpThermal = s_ipsc->rNumericArgs(5);
2588 3 : mat->AbsorpThermalFront = s_ipsc->rNumericArgs(4);
2589 3 : mat->AbsorpThermalBack = s_ipsc->rNumericArgs(5);
2590 :
2591 3 : mat->topOpeningMult = s_ipsc->rNumericArgs(6);
2592 3 : mat->bottomOpeningMult = s_ipsc->rNumericArgs(7);
2593 3 : mat->leftOpeningMult = s_ipsc->rNumericArgs(8);
2594 3 : mat->rightOpeningMult = s_ipsc->rNumericArgs(9);
2595 3 : mat->frontOpeningMult = s_ipsc->rNumericArgs(10);
2596 :
2597 3 : mat->SlatWidth = s_ipsc->rNumericArgs(11);
2598 3 : mat->SlatSpacing = s_ipsc->rNumericArgs(12);
2599 3 : mat->SlatThickness = s_ipsc->rNumericArgs(13);
2600 3 : mat->SlatAngle = s_ipsc->rNumericArgs(14);
2601 3 : mat->SlatConductivity = s_ipsc->rNumericArgs(15);
2602 3 : mat->SlatCurve = s_ipsc->rNumericArgs(16);
2603 :
2604 3 : if (s_ipsc->rNumericArgs(1) <= 0.0) {
2605 0 : ErrorsFound = true;
2606 0 : ShowSevereCustom(state, eoh, format("{} must be > 0, entered value = {:.2R}", s_ipsc->cNumericFieldNames(1), s_ipsc->rNumericArgs(1)));
2607 : }
2608 :
2609 3 : if (s_ipsc->rNumericArgs(2) <= 0.0) {
2610 0 : ErrorsFound = true;
2611 0 : ShowSevereCustom(state, eoh, format("{} must be > 0, entered value = {:.2R}", s_ipsc->cNumericFieldNames(2), s_ipsc->rNumericArgs(2)));
2612 : }
2613 :
2614 3 : if ((s_ipsc->rNumericArgs(3) < 0.0) || (s_ipsc->rNumericArgs(3) > 1.0)) {
2615 0 : ErrorsFound = true;
2616 0 : ShowSevereCustom(
2617 0 : state, eoh, format("{} value must be >= 0 and <= 1, entered value = {:.2R}", s_ipsc->cNumericFieldNames(3), s_ipsc->rNumericArgs(3)));
2618 : }
2619 :
2620 3 : if ((s_ipsc->rNumericArgs(4) <= 0.0) || (s_ipsc->rNumericArgs(4) > 1.0)) {
2621 0 : ErrorsFound = true;
2622 0 : ShowSevereCustom(
2623 0 : state, eoh, format("{} value must be >= 0 and <= 1, entered value = {:.2R}", s_ipsc->cNumericFieldNames(4), s_ipsc->rNumericArgs(4)));
2624 : }
2625 :
2626 3 : if ((s_ipsc->rNumericArgs(5) <= 0.0) || (s_ipsc->rNumericArgs(5) > 1.0)) {
2627 0 : ErrorsFound = true;
2628 0 : ShowSevereCustom(
2629 0 : state, eoh, format("{} value must be >= 0 and <= 1, entered value = {:.2R}", s_ipsc->cNumericFieldNames(5), s_ipsc->rNumericArgs(5)));
2630 : }
2631 :
2632 3 : if ((s_ipsc->rNumericArgs(6) < 0.0) || (s_ipsc->rNumericArgs(6) > 1.0)) {
2633 0 : ErrorsFound = true;
2634 0 : ShowSevereCustom(
2635 0 : state, eoh, format("{} must be >= 0 or <= 1, entered value = {:.2R}", s_ipsc->cNumericFieldNames(6), s_ipsc->rNumericArgs(6)));
2636 : }
2637 :
2638 3 : if ((s_ipsc->rNumericArgs(7) < 0.0) || (s_ipsc->rNumericArgs(7) > 1.0)) {
2639 0 : ErrorsFound = true;
2640 0 : ShowSevereCustom(state, eoh, format("{} must be >=0 or <=1, entered {:.2R}", s_ipsc->cNumericFieldNames(7), s_ipsc->rNumericArgs(7)));
2641 : }
2642 :
2643 3 : if ((s_ipsc->rNumericArgs(8) < 0.0) || (s_ipsc->rNumericArgs(8) > 1.0)) {
2644 0 : ErrorsFound = true;
2645 0 : ShowSevereCustom(
2646 0 : state, eoh, format("{} must be >=0 or <=1, entered value = {:.2R}", s_ipsc->cNumericFieldNames(8), s_ipsc->rNumericArgs(8)));
2647 : }
2648 :
2649 3 : if ((s_ipsc->rNumericArgs(9) < 0.0) || (s_ipsc->rNumericArgs(9) > 1.0)) {
2650 0 : ErrorsFound = true;
2651 0 : ShowSevereCustom(
2652 0 : state, eoh, format("{} must be >=0 or <=1, entered value = {:.2R}", s_ipsc->cNumericFieldNames(9), s_ipsc->rNumericArgs(9)));
2653 : }
2654 :
2655 3 : if ((s_ipsc->rNumericArgs(10) < 0.0) || (s_ipsc->rNumericArgs(10) > 1.0)) {
2656 0 : ErrorsFound = true;
2657 0 : ShowSevereCustom(
2658 0 : state, eoh, format("{} must be >=0 or <=1, entered value = {:.2R}", s_ipsc->cNumericFieldNames(10), s_ipsc->rNumericArgs(10)));
2659 : }
2660 :
2661 3 : if ((mat->LayerType == TARCOGParams::TARCOGLayerType::VENETBLIND_HORIZ) ||
2662 1 : (mat->LayerType == TARCOGParams::TARCOGLayerType::VENETBLIND_VERT)) {
2663 2 : if (s_ipsc->rNumericArgs(11) <= 0.0) {
2664 0 : ErrorsFound = true;
2665 0 : ShowSevereCustom(
2666 0 : state, eoh, format("{} must be >0, entered value = {:.2R}", s_ipsc->cNumericFieldNames(11), s_ipsc->rNumericArgs(11)));
2667 : }
2668 :
2669 2 : if (s_ipsc->rNumericArgs(12) <= 0.0) {
2670 0 : ErrorsFound = true;
2671 0 : ShowSevereCustom(
2672 0 : state, eoh, format("{} must be >0, entered value = {:.2R}", s_ipsc->cNumericFieldNames(12), s_ipsc->rNumericArgs(12)));
2673 : }
2674 :
2675 2 : if (s_ipsc->rNumericArgs(13) <= 0.0) {
2676 0 : ErrorsFound = true;
2677 0 : ShowSevereCustom(
2678 0 : state, eoh, format("{} must be >0, entered value = {:.2R}", s_ipsc->cNumericFieldNames(13), s_ipsc->rNumericArgs(13)));
2679 : }
2680 :
2681 2 : if ((s_ipsc->rNumericArgs(14) < -90.0) || (s_ipsc->rNumericArgs(14) > 90.0)) {
2682 0 : ErrorsFound = true;
2683 0 : ShowSevereCustom(
2684 : state,
2685 : eoh,
2686 0 : format("{} must be >=-90 and <=90, entered value = {:.2R}", s_ipsc->cNumericFieldNames(14), s_ipsc->rNumericArgs(14)));
2687 : }
2688 :
2689 2 : if (s_ipsc->rNumericArgs(15) <= 0.0) {
2690 0 : ErrorsFound = true;
2691 0 : ShowSevereCustom(
2692 0 : state, eoh, format("{} must be >0, entered value = {:.2R}", s_ipsc->cNumericFieldNames(15), s_ipsc->rNumericArgs(15)));
2693 : }
2694 :
2695 4 : if ((s_ipsc->rNumericArgs(16) < 0.0) ||
2696 2 : ((s_ipsc->rNumericArgs(16) > 0.0) && (s_ipsc->rNumericArgs(16) < (s_ipsc->rNumericArgs(11) / 2)))) {
2697 0 : ErrorsFound = true;
2698 0 : ShowSevereCustom(state,
2699 : eoh,
2700 0 : format("{} must be = 0 or greater than SlatWidth/2, entered value = {:.2R}",
2701 0 : s_ipsc->cNumericFieldNames(16),
2702 0 : s_ipsc->rNumericArgs(16)));
2703 : }
2704 : }
2705 :
2706 3 : if (ErrorsFound) ShowFatalError(state, "Error in complex fenestration material input.");
2707 : }
2708 :
2709 273 : bool DoReport = false;
2710 :
2711 819 : ScanForReports(state, "Constructions", DoReport, "Materials");
2712 :
2713 273 : if (DoReport) {
2714 :
2715 2 : print(state.files.eio,
2716 : "! <Material Details>,Material Name,ThermalResistance {{m2-K/w}},Roughness,Thickness {{m}},Conductivity "
2717 : "{{w/m-K}},Density {{kg/m3}},Specific Heat "
2718 : "{{J/kg-K}},Absorptance:Thermal,Absorptance:Solar,Absorptance:Visible\n");
2719 :
2720 2 : print(state.files.eio, "! <Material:Air>,Material Name,ThermalResistance {{m2-K/w}}\n");
2721 :
2722 : // Formats
2723 2 : constexpr std::string_view Format_701(" Material Details,{},{:.4R},{},{:.4R},{:.3R},{:.3R},{:.3R},{:.4R},{:.4R},{:.4R}\n");
2724 2 : constexpr std::string_view Format_702(" Material:Air,{},{:.4R}\n");
2725 :
2726 48 : for (auto const *mat : s_mat->materials) {
2727 :
2728 46 : switch (mat->group) {
2729 4 : case Group::AirGap: {
2730 4 : print(state.files.eio, Format_702, mat->Name, mat->Resistance);
2731 4 : } break;
2732 42 : default: {
2733 42 : print(state.files.eio,
2734 : Format_701,
2735 42 : mat->Name,
2736 42 : mat->Resistance,
2737 42 : surfaceRoughnessNames[(int)mat->Roughness],
2738 42 : mat->Thickness,
2739 42 : mat->Conductivity,
2740 42 : mat->Density,
2741 42 : mat->SpecHeat,
2742 42 : mat->AbsorpThermal,
2743 42 : mat->AbsorpSolar,
2744 42 : mat->AbsorpVisible);
2745 42 : } break;
2746 : }
2747 : }
2748 : }
2749 :
2750 : // FORMATS.
2751 :
2752 273 : if (state.dataGlobal->AnyEnergyManagementSystemInModel) { // setup surface property EMS actuators
2753 :
2754 136 : for (auto *mat : s_mat->materials) {
2755 110 : if (mat->group != Group::Regular) continue;
2756 :
2757 98 : SetupEMSActuator(state,
2758 : "Material",
2759 : mat->Name,
2760 : "Surface Property Solar Absorptance",
2761 : "[ ]",
2762 98 : mat->AbsorpSolarEMSOverrideOn,
2763 98 : mat->AbsorpSolarEMSOverride);
2764 98 : SetupEMSActuator(state,
2765 : "Material",
2766 : mat->Name,
2767 : "Surface Property Thermal Absorptance",
2768 : "[ ]",
2769 98 : mat->AbsorpThermalEMSOverrideOn,
2770 98 : mat->AbsorpThermalEMSOverride);
2771 98 : SetupEMSActuator(state,
2772 : "Material",
2773 : mat->Name,
2774 : "Surface Property Visible Absorptance",
2775 : "[ ]",
2776 98 : mat->AbsorpVisibleEMSOverrideOn,
2777 98 : mat->AbsorpVisibleEMSOverride);
2778 : }
2779 : }
2780 :
2781 273 : GetVariableAbsorptanceInput(state, ErrorsFound); // Read variable thermal and solar absorptance add-on data
2782 273 : }
2783 :
2784 280 : void GetVariableAbsorptanceInput(EnergyPlusData &state, bool &errorsFound)
2785 : {
2786 280 : constexpr std::string_view routineName = "GetVariableAbsorptanceInput";
2787 :
2788 : int IOStat; // IO Status when calling get input subroutine
2789 : int numAlphas;
2790 : int numNumbers;
2791 :
2792 280 : auto &s_ip = state.dataInputProcessing->inputProcessor;
2793 280 : auto &s_ipsc = state.dataIPShortCut;
2794 280 : auto &s_mat = state.dataMaterial;
2795 :
2796 280 : s_ipsc->cCurrentModuleObject = "MaterialProperty:VariableAbsorptance";
2797 280 : int numVariAbs = s_ip->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
2798 280 : s_mat->AnyVariableAbsorptance = (numVariAbs > 0);
2799 284 : for (int i = 1; i <= numVariAbs; ++i) {
2800 : // Call Input Get routine to retrieve material data
2801 18 : s_ip->getObjectItem(state,
2802 9 : s_ipsc->cCurrentModuleObject,
2803 : i,
2804 9 : s_ipsc->cAlphaArgs,
2805 : numAlphas,
2806 9 : s_ipsc->rNumericArgs,
2807 : numNumbers,
2808 : IOStat,
2809 9 : s_ipsc->lNumericFieldBlanks,
2810 9 : s_ipsc->lAlphaFieldBlanks,
2811 9 : s_ipsc->cAlphaFieldNames,
2812 9 : s_ipsc->cNumericFieldNames);
2813 :
2814 9 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
2815 :
2816 : // Load the material derived type from the input data.
2817 9 : int matNum = Material::GetMaterialNum(state, s_ipsc->cAlphaArgs(2));
2818 9 : if (matNum == 0) {
2819 1 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2));
2820 1 : errorsFound = true;
2821 5 : return;
2822 : }
2823 :
2824 8 : auto *mat = s_mat->materials(matNum);
2825 :
2826 8 : if (mat->group != Group::Regular) {
2827 2 : ShowSevereError(
2828 : state,
2829 2 : format("{}: Reference Material is not appropriate type for Thermal/Solar Absorptance properties, material={}, must have regular "
2830 : "properties (Thermal/Solar Absorptance)",
2831 1 : s_ipsc->cCurrentModuleObject,
2832 1 : mat->Name));
2833 1 : errorsFound = true;
2834 1 : continue;
2835 : }
2836 :
2837 7 : mat->absorpVarCtrlSignal = VariableAbsCtrlSignal::SurfaceTemperature; // default value
2838 7 : mat->absorpVarCtrlSignal = static_cast<VariableAbsCtrlSignal>(getEnumValue(variableAbsCtrlSignalNamesUC, s_ipsc->cAlphaArgs(3)));
2839 :
2840 7 : mat->absorpThermalVarCurve = Curve::GetCurve(state, s_ipsc->cAlphaArgs(4));
2841 7 : mat->absorpThermalVarSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(5));
2842 7 : mat->absorpSolarVarCurve = Curve::GetCurve(state, s_ipsc->cAlphaArgs(6));
2843 7 : mat->absorpSolarVarSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(7));
2844 7 : if (mat->absorpVarCtrlSignal == VariableAbsCtrlSignal::Scheduled) {
2845 3 : if ((mat->absorpThermalVarSched == nullptr) && (mat->absorpSolarVarSched == nullptr)) {
2846 2 : ShowSevereError(
2847 : state,
2848 3 : format("{}: Control signal \"Scheduled\" is chosen but both thermal and solar absorptance schedules are undefined, for object {}",
2849 1 : s_ipsc->cCurrentModuleObject,
2850 1 : s_ipsc->cAlphaArgs(1)));
2851 1 : errorsFound = true;
2852 1 : return;
2853 : }
2854 2 : if ((mat->absorpThermalVarCurve != nullptr) || (mat->absorpSolarVarCurve != nullptr)) {
2855 2 : ShowWarningError(state,
2856 3 : format("{}: Control signal \"Scheduled\" is chosen. Thermal or solar absorptance function name is going to be "
2857 : "ignored, for object {}",
2858 1 : s_ipsc->cCurrentModuleObject,
2859 1 : s_ipsc->cAlphaArgs(1)));
2860 1 : errorsFound = true;
2861 1 : return;
2862 : }
2863 :
2864 : } else { // controlled by performance table or curve
2865 4 : if ((mat->absorpThermalVarCurve == nullptr) && (mat->absorpSolarVarCurve == nullptr)) {
2866 2 : ShowSevereError(state,
2867 3 : format("{}: Non-schedule control signal is chosen but both thermal and solar absorptance table or curve are "
2868 : "undefined, for object {}",
2869 1 : s_ipsc->cCurrentModuleObject,
2870 1 : s_ipsc->cAlphaArgs(1)));
2871 1 : errorsFound = true;
2872 1 : return;
2873 : }
2874 3 : if ((mat->absorpThermalVarSched != nullptr) || (mat->absorpSolarVarSched != nullptr)) {
2875 2 : ShowWarningError(state,
2876 3 : format("{}: Non-schedule control signal is chosen. Thermal or solar absorptance schedule name is going to be "
2877 : "ignored, for object {}",
2878 1 : s_ipsc->cCurrentModuleObject,
2879 1 : s_ipsc->cAlphaArgs(1)));
2880 1 : errorsFound = true;
2881 1 : return;
2882 : }
2883 : }
2884 : }
2885 : } // GetVariableAbsorptanceInput()
2886 :
2887 126 : void GetWindowGlassSpectralData(EnergyPlusData &state, bool &ErrorsFound) // set to true if errors found in input
2888 : {
2889 :
2890 : // SUBROUTINE INFORMATION:
2891 : // AUTHOR Fred Winkelmann
2892 : // DATE WRITTEN May 2000
2893 :
2894 : // PURPOSE OF THIS SUBROUTINE:
2895 : // Gets spectral data (transmittance, front reflectance, and back
2896 : // reflectance at normal incidence vs. wavelength) for glass
2897 :
2898 : // SUBROUTINE PARAMETER DEFINITIONS:
2899 126 : constexpr std::string_view routineName = "GetWindowGlassSpectralData";
2900 :
2901 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2902 : int IOStat; // IO Status when calling get input subroutine
2903 : int NumAlphas; // Number of spectral data alpha names being passed
2904 : int NumNums; // Number of spectral data properties being passed
2905 : Real64 Lam; // Wavelength (microns)
2906 : Real64 Tau; // Transmittance, front reflectance, back reflectance
2907 : Real64 RhoF;
2908 : Real64 RhoB;
2909 :
2910 126 : auto &s_ip = state.dataInputProcessing->inputProcessor;
2911 126 : auto &s_ipsc = state.dataIPShortCut;
2912 126 : auto &s_mat = state.dataMaterial;
2913 :
2914 126 : constexpr int MaxSpectralDataElements = 800; // Maximum number in Spectral Data arrays.
2915 :
2916 126 : s_ipsc->cCurrentModuleObject = "MaterialProperty:GlazingSpectralData";
2917 126 : s_mat->NumSpectralData = s_ip->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
2918 :
2919 126 : if (s_mat->NumSpectralData == 0) return;
2920 :
2921 2 : s_mat->SpectralData.allocate(s_mat->NumSpectralData);
2922 :
2923 4 : for (int Loop = 1; Loop <= s_mat->NumSpectralData; ++Loop) {
2924 :
2925 : // Call Input Get routine to retrieve spectral data
2926 : // Name is followed by up to 450 sets of normal-incidence measured values of
2927 : // [wavelength (microns), transmittance, front reflectance, back reflectance] for
2928 : // wavelengths covering the short-wave solar spectrum (from about 0.25 to 2.5 microns)
2929 4 : s_ip->getObjectItem(state,
2930 2 : s_ipsc->cCurrentModuleObject,
2931 : Loop,
2932 2 : s_ipsc->cAlphaArgs,
2933 : NumAlphas,
2934 2 : s_ipsc->rNumericArgs,
2935 : NumNums,
2936 : IOStat,
2937 2 : s_ipsc->lNumericFieldBlanks,
2938 2 : s_ipsc->lAlphaFieldBlanks,
2939 2 : s_ipsc->cAlphaFieldNames,
2940 2 : s_ipsc->cNumericFieldNames);
2941 :
2942 2 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
2943 :
2944 2 : auto &specData = s_mat->SpectralData(Loop);
2945 : // Load the spectral data derived type from the input data.
2946 2 : specData.Name = s_ipsc->cAlphaArgs(1);
2947 2 : int TotLam = NumNums / 4;
2948 2 : if (mod(NumNums, 4) != 0) {
2949 0 : ShowWarningCustom(
2950 : state,
2951 : eoh,
2952 0 : format("{} of items in data set is not a multiple of 4 (Wavelength,Trans,ReflFront,ReflBack), remainder items set to 0.0", NumNums));
2953 0 : ErrorsFound = true;
2954 0 : continue;
2955 : }
2956 :
2957 2 : if (TotLam > MaxSpectralDataElements) {
2958 0 : ShowSevereCustom(state, eoh, format("More than {} entries in set ({})", MaxSpectralDataElements, NumNums));
2959 0 : ErrorsFound = true;
2960 0 : continue;
2961 : }
2962 :
2963 2 : specData.NumOfWavelengths = TotLam;
2964 2 : specData.WaveLength.allocate(TotLam); // Wavelength (microns)
2965 2 : specData.Trans.allocate(TotLam); // Transmittance at normal incidence
2966 2 : specData.ReflFront.allocate(TotLam); // Front reflectance at normal incidence
2967 2 : specData.ReflBack.allocate(TotLam); // Back reflectance at normal incidence
2968 :
2969 536 : for (int LamNum = 1; LamNum <= TotLam; ++LamNum) {
2970 534 : specData.WaveLength(LamNum) = s_ipsc->rNumericArgs(4 * LamNum - 3);
2971 534 : specData.Trans(LamNum) = s_ipsc->rNumericArgs(4 * LamNum - 2);
2972 : // Following is needed since angular calculation in subr TransAndReflAtPhi
2973 : // fails for Trans = 0.0
2974 534 : if (specData.Trans(LamNum) < 0.001) specData.Trans(LamNum) = 0.001;
2975 534 : specData.ReflFront(LamNum) = s_ipsc->rNumericArgs(4 * LamNum - 1);
2976 534 : specData.ReflBack(LamNum) = s_ipsc->rNumericArgs(4 * LamNum);
2977 : }
2978 :
2979 : // Check integrity of the spectral data
2980 536 : for (int LamNum = 1; LamNum <= TotLam; ++LamNum) {
2981 534 : Lam = specData.WaveLength(LamNum);
2982 534 : Tau = specData.Trans(LamNum);
2983 534 : RhoF = specData.ReflFront(LamNum);
2984 534 : RhoB = specData.ReflBack(LamNum);
2985 534 : if (LamNum < TotLam && specData.WaveLength(LamNum + 1) <= Lam) {
2986 0 : ErrorsFound = true;
2987 0 : ShowSevereError(state, format("{}{}=\"{}\" invalid set.", routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
2988 0 : ShowContinueError(state,
2989 0 : format("... Wavelengths not in increasing order. at wavelength#={}, value=[{:.4T}], next is [{:.4T}].",
2990 : LamNum,
2991 : Lam,
2992 : specData.WaveLength(LamNum + 1)));
2993 : }
2994 :
2995 534 : if (Lam < 0.1 || Lam > 4.0) {
2996 0 : ErrorsFound = true;
2997 0 : ShowSevereError(state, format("{}{}=\"{}\" invalid value.", routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
2998 0 : ShowContinueError(state,
2999 0 : format("... A wavelength is not in the range 0.1 to 4.0 microns; at wavelength#={}, value=[{:.4T}].", LamNum, Lam));
3000 : }
3001 :
3002 : // TH 2/15/2011. CR 8343
3003 : // IGDB (International Glazing Database) does not meet the above strict restrictions.
3004 : // Relax rules to allow directly use of spectral data from IGDB
3005 534 : if (Tau > 1.01) {
3006 0 : ErrorsFound = true;
3007 0 : ShowSevereError(state, format("{}: {}=\"{}\" invalid value.", routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
3008 0 : ShowContinueError(state, format("... A transmittance is > 1.0; at wavelength#={}, value=[{:.4T}].", LamNum, Tau));
3009 : }
3010 :
3011 534 : if (RhoF < 0.0 || RhoF > 1.02 || RhoB < 0.0 || RhoB > 1.02) {
3012 0 : ErrorsFound = true;
3013 0 : ShowSevereError(state, format("{}: {}=\"{}\" invalid value.", routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
3014 0 : ShowContinueError(state, format("... A reflectance is < 0.0 or > 1.0; at wavelength#={}, RhoF value=[{:.4T}].", LamNum, RhoF));
3015 0 : ShowContinueError(state, format("... A reflectance is < 0.0 or > 1.0; at wavelength#={}, RhoB value=[{:.4T}].", LamNum, RhoB));
3016 : }
3017 :
3018 534 : if ((Tau + RhoF) > 1.03 || (Tau + RhoB) > 1.03) {
3019 0 : ErrorsFound = true;
3020 0 : ShowSevereError(state, format("{}: {}=\"{}\" invalid value.", routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
3021 0 : ShowContinueError(state,
3022 0 : format("... Transmittance + reflectance) > 1.0 for an entry; at wavelength#={}",
3023 0 : format("{}, value(Tau+RhoF)=[{:.4T}], value(Tau+RhoB)=[{:.4T}].", LamNum, (Tau + RhoF), (Tau + RhoB))));
3024 : }
3025 : }
3026 : }
3027 : } // GetWindowGlassSpectralData()
3028 :
3029 26 : void MaterialGlass::SetupSimpleWindowGlazingSystem(EnergyPlusData &state)
3030 : {
3031 :
3032 : // SUBROUTINE INFORMATION:
3033 : // AUTHOR B. Griffith
3034 : // DATE WRITTEN January 2009
3035 :
3036 : // PURPOSE OF THIS SUBROUTINE:
3037 : // Convert simple window performance indices into all the properties needed to
3038 : // describe a single, equivalent glass layer
3039 :
3040 : // METHODOLOGY EMPLOYED:
3041 : // The simple window indices are converted to a single materal layer using a "block model"
3042 :
3043 : // REFERENCES:
3044 : // draft paper by Arasteh, Kohler, and Griffith
3045 :
3046 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
3047 26 : Real64 Riw(0.0); // thermal resistance of interior film coefficient under winter conditions (m2-K/W)
3048 26 : Real64 Row(0.0); // theraml resistance of exterior film coefficient under winter conditions (m2-K/W)
3049 26 : Real64 Rlw(0.0); // thermal resistance of block model layer (m2-K/W)
3050 26 : Real64 Ris(0.0); // thermal resistance of interior film coefficient under summer conditions (m2-K/W)
3051 26 : Real64 Ros(0.0); // theraml resistance of exterior film coefficient under summer conditions (m2-K/W)
3052 26 : Real64 InflowFraction(0.0); // inward flowing fraction for SHGC, intermediate value non dimensional
3053 26 : Real64 SolarAbsorb(0.0); // solar aborptance
3054 26 : bool ErrorsFound(false);
3055 26 : Real64 TsolLowSide(0.0); // intermediate solar transmission for interpolating
3056 26 : Real64 TsolHiSide(0.0); // intermediate solar transmission for interpolating
3057 26 : Real64 DeltaSHGCandTsol(0.0); // intermediate difference
3058 26 : Real64 RLowSide(0.0);
3059 26 : Real64 RHiSide(0.0);
3060 :
3061 : // first fill out defaults
3062 26 : this->GlassSpectralDataPtr = 0;
3063 26 : this->SolarDiffusing = false;
3064 26 : this->Roughness = Material::SurfaceRoughness::VerySmooth;
3065 26 : this->TransThermal = 0.0;
3066 26 : this->AbsorpThermalBack = 0.84;
3067 26 : this->AbsorpThermalFront = 0.84;
3068 26 : this->AbsorpThermal = this->AbsorpThermalBack;
3069 :
3070 : // step 1. Determine U-factor without film coefficients
3071 : // Simple window model has its own correlation for film coefficients (m2-K/W) under Winter conditions as function of U-factor
3072 26 : if (this->SimpleWindowUfactor < 5.85) {
3073 22 : Riw = 1.0 / (0.359073 * std::log(this->SimpleWindowUfactor) + 6.949915);
3074 : } else {
3075 4 : Riw = 1.0 / (1.788041 * this->SimpleWindowUfactor - 2.886625);
3076 : }
3077 26 : Row = 1.0 / (0.025342 * this->SimpleWindowUfactor + 29.163853);
3078 :
3079 : // determine 1/U without film coefficients
3080 26 : Rlw = (1.0 / this->SimpleWindowUfactor) - Riw - Row;
3081 26 : if (Rlw <= 0.0) { // U factor of film coefficients is better than user input.
3082 0 : Rlw = max(Rlw, 0.001);
3083 0 : ShowWarningError(state,
3084 0 : format("WindowMaterial:SimpleGlazingSystem: {} has U-factor higher than that provided by surface film resistances, "
3085 : "Check value of U-factor",
3086 0 : this->Name));
3087 : }
3088 :
3089 : // Step 2. determine layer thickness.
3090 :
3091 26 : if ((1.0 / Rlw) > 7.0) {
3092 15 : this->Thickness = 0.002;
3093 : } else {
3094 11 : this->Thickness = 0.05914 - (0.00714 / Rlw);
3095 : }
3096 :
3097 : // Step 3. determine effective conductivity
3098 :
3099 26 : this->Conductivity = this->Thickness / Rlw;
3100 26 : if (this->Conductivity > 0.0) {
3101 26 : this->NominalR = this->Resistance = Rlw;
3102 : } else {
3103 0 : ErrorsFound = true;
3104 0 : ShowSevereError(state,
3105 0 : format("WindowMaterial:SimpleGlazingSystem: {} has Conductivity <= 0.0, must be >0.0, Check value of U-factor", this->Name));
3106 : }
3107 :
3108 : // step 4. determine solar transmission (revised to 10-1-2009 version from LBNL.)
3109 :
3110 26 : if (this->SimpleWindowUfactor > 4.5) {
3111 :
3112 12 : if (this->SimpleWindowSHGC < 0.7206) {
3113 :
3114 5 : this->Trans = 0.939998 * pow_2(this->SimpleWindowSHGC) + 0.20332 * this->SimpleWindowSHGC;
3115 : } else { // >= 0.7206
3116 7 : this->Trans = 1.30415 * this->SimpleWindowSHGC - 0.30515;
3117 : }
3118 :
3119 14 : } else if (this->SimpleWindowUfactor < 3.4) {
3120 :
3121 14 : if (this->SimpleWindowSHGC <= 0.15) {
3122 0 : this->Trans = 0.41040 * this->SimpleWindowSHGC;
3123 : } else { // > 0.15
3124 14 : this->Trans = 0.085775 * pow_2(this->SimpleWindowSHGC) + 0.963954 * this->SimpleWindowSHGC - 0.084958;
3125 : }
3126 : } else { // interpolate. 3.4 <= Ufactor <= 4.5
3127 :
3128 0 : if (this->SimpleWindowSHGC < 0.7206) {
3129 0 : TsolHiSide = 0.939998 * pow_2(this->SimpleWindowSHGC) + 0.20332 * this->SimpleWindowSHGC;
3130 : } else { // >= 0.7206
3131 0 : TsolHiSide = 1.30415 * this->SimpleWindowSHGC - 0.30515;
3132 : }
3133 :
3134 0 : if (this->SimpleWindowSHGC <= 0.15) {
3135 0 : TsolLowSide = 0.41040 * this->SimpleWindowSHGC;
3136 : } else { // > 0.15
3137 0 : TsolLowSide = 0.085775 * pow_2(this->SimpleWindowSHGC) + 0.963954 * this->SimpleWindowSHGC - 0.084958;
3138 : }
3139 :
3140 0 : this->Trans = ((this->SimpleWindowUfactor - 3.4) / (4.5 - 3.4)) * (TsolHiSide - TsolLowSide) + TsolLowSide;
3141 : }
3142 26 : if (this->Trans < 0.0) this->Trans = 0.0;
3143 :
3144 : // step 5. determine solar reflectances
3145 :
3146 26 : DeltaSHGCandTsol = this->SimpleWindowSHGC - this->Trans;
3147 :
3148 26 : if (this->SimpleWindowUfactor > 4.5) {
3149 :
3150 12 : Ris = 1.0 / (29.436546 * pow_3(DeltaSHGCandTsol) - 21.943415 * pow_2(DeltaSHGCandTsol) + 9.945872 * DeltaSHGCandTsol + 7.426151);
3151 12 : Ros = 1.0 / (2.225824 * DeltaSHGCandTsol + 20.577080);
3152 14 : } else if (this->SimpleWindowUfactor < 3.4) {
3153 :
3154 14 : Ris = 1.0 / (199.8208128 * pow_3(DeltaSHGCandTsol) - 90.639733 * pow_2(DeltaSHGCandTsol) + 19.737055 * DeltaSHGCandTsol + 6.766575);
3155 14 : Ros = 1.0 / (5.763355 * DeltaSHGCandTsol + 20.541528);
3156 : } else { // interpolate. 3.4 <= Ufactor <= 4.5
3157 : // inside first
3158 0 : RLowSide = 1.0 / (199.8208128 * pow_3(DeltaSHGCandTsol) - 90.639733 * pow_2(DeltaSHGCandTsol) + 19.737055 * DeltaSHGCandTsol + 6.766575);
3159 0 : RHiSide = 1.0 / (29.436546 * pow_3(DeltaSHGCandTsol) - 21.943415 * pow_2(DeltaSHGCandTsol) + 9.945872 * DeltaSHGCandTsol + 7.426151);
3160 0 : Ris = ((this->SimpleWindowUfactor - 3.4) / (4.5 - 3.4)) * (RLowSide - RHiSide) + RLowSide;
3161 : // then outside
3162 0 : RLowSide = 1.0 / (5.763355 * DeltaSHGCandTsol + 20.541528);
3163 0 : RHiSide = 1.0 / (2.225824 * DeltaSHGCandTsol + 20.577080);
3164 0 : Ros = ((this->SimpleWindowUfactor - 3.4) / (4.5 - 3.4)) * (RLowSide - RHiSide) + RLowSide;
3165 : }
3166 :
3167 26 : InflowFraction = (Ros + 0.5 * Rlw) / (Ros + Rlw + Ris);
3168 :
3169 26 : SolarAbsorb = (this->SimpleWindowSHGC - this->Trans) / InflowFraction;
3170 26 : this->ReflectSolBeamBack = 1.0 - this->Trans - SolarAbsorb;
3171 26 : this->ReflectSolBeamFront = this->ReflectSolBeamBack;
3172 :
3173 : // step 6. determine visible properties.
3174 26 : if (this->SimpleWindowVTinputByUser) {
3175 13 : this->TransVis = this->SimpleWindowVisTran;
3176 13 : this->ReflectVisBeamBack = -0.7409 * pow_3(this->TransVis) + 1.6531 * pow_2(this->TransVis) - 1.2299 * this->TransVis + 0.4545;
3177 13 : if (this->TransVis + this->ReflectVisBeamBack >= 1.0) {
3178 8 : this->ReflectVisBeamBack = 0.999 - this->TransVis;
3179 : }
3180 :
3181 13 : this->ReflectVisBeamFront = -0.0622 * pow_3(this->TransVis) + 0.4277 * pow_2(this->TransVis) - 0.4169 * this->TransVis + 0.2399;
3182 13 : if (this->TransVis + this->ReflectVisBeamFront >= 1.0) {
3183 8 : this->ReflectVisBeamFront = 0.999 - this->TransVis;
3184 : }
3185 : } else {
3186 13 : this->TransVis = this->Trans;
3187 13 : this->ReflectVisBeamBack = this->ReflectSolBeamBack;
3188 13 : this->ReflectVisBeamFront = this->ReflectSolBeamFront;
3189 : }
3190 :
3191 : // step 7. The dependence on incident angle is in subroutine TransAndReflAtPhi
3192 :
3193 : // step 8. Hemispherical terms are averaged using standard method
3194 :
3195 26 : if (ErrorsFound) {
3196 0 : ShowFatalError(state, "Program halted because of input problem(s) in WindowMaterial:SimpleGlazingSystem");
3197 : }
3198 26 : } // MaterialGlass::SetupSimpleWindowGlazingSystem()
3199 :
3200 0 : void CalcScreenTransmittance([[maybe_unused]] EnergyPlusData &state,
3201 : MaterialScreen const *screen,
3202 : Real64 phi, // Sun altitude relative to surface outward normal (radians, 0 to Pi)
3203 : Real64 theta, // Optional sun azimuth relative to surface outward normal (radians, 0 to Pi)
3204 : ScreenBmTransAbsRef &tar)
3205 : {
3206 :
3207 : // FUNCTION INFORMATION:
3208 : // AUTHOR Richard Raustad
3209 : // DATE WRITTEN May 2006
3210 : // MODIFIED na
3211 : // RE-ENGINEERED na
3212 :
3213 : // PURPOSE OF THIS FUNCTION:
3214 : // Calculate transmittance of window screen given azimuth and altitude angle
3215 : // of sun and surface orientation.
3216 :
3217 : // METHODOLOGY EMPLOYED:
3218 : // Window screen solar beam transmittance varies as the sun moves across the sky
3219 : // due to the geometry of the screen material and the angle of incidence
3220 : // of the solar beam. Azimuth and altitude angle are calculated with respect
3221 : // to the surface outward normal. Solar beam reflectance and absorptance are also
3222 : // accounted for.
3223 :
3224 0 : Real64 constexpr Small(1.E-9); // Small Number used to approximate zero
3225 :
3226 : Real64 Tdirect; // Beam solar transmitted through screen (dependent on sun angle)
3227 : Real64 Tscattered; // Beam solar reflected through screen (dependent on sun angle)
3228 : Real64 TscatteredVis; // Visible beam solar reflected through screen (dependent on sun angle)
3229 :
3230 0 : assert(phi >= 0.0 && phi <= Constant::Pi);
3231 0 : assert(theta >= 0.0 && theta <= Constant::Pi);
3232 :
3233 0 : Real64 sinPhi = std::sin(phi);
3234 0 : Real64 cosPhi = std::cos(phi);
3235 0 : Real64 tanPhi = sinPhi / cosPhi;
3236 0 : Real64 cosTheta = std::cos(theta);
3237 :
3238 0 : bool sunInFront = (phi < Constant::PiOvr2) && (theta < Constant::PiOvr2); // Sun is in front of screen
3239 :
3240 : // ratio of screen material diameter to screen material spacing
3241 0 : Real64 Gamma = screen->diameterToSpacingRatio;
3242 :
3243 : // ************************************************************************************************
3244 : // * calculate transmittance of totally absorbing screen material (beam passing through open area)*
3245 : // ************************************************************************************************
3246 :
3247 : // Now we need to normalize phi and theta to the 0 to Pi/2 range using reflection.
3248 0 : if (phi > Constant::PiOvr2) phi = Constant::Pi - phi;
3249 0 : if (theta > Constant::PiOvr2) theta = Constant::Pi - theta;
3250 :
3251 : // calculate compliment of relative solar azimuth
3252 0 : Real64 Beta = Constant::PiOvr2 - theta;
3253 :
3254 : // Catch all divide by zero instances
3255 : Real64 TransYDir;
3256 : Real64 TransXDir;
3257 0 : if (Beta > Small && std::abs(phi - Constant::PiOvr2) > Small) {
3258 0 : Real64 AlphaDblPrime = std::atan(tanPhi / cosTheta);
3259 0 : TransYDir = 1.0 - Gamma * (std::cos(AlphaDblPrime) + std::sin(AlphaDblPrime) * tanPhi * std::sqrt(1.0 + pow_2(1.0 / std::tan(Beta))));
3260 0 : TransYDir = max(0.0, TransYDir);
3261 : } else {
3262 0 : TransYDir = 0.0;
3263 : }
3264 :
3265 0 : Real64 COSMu = std::sqrt(pow_2(cosPhi) * pow_2(cosTheta) + pow_2(sinPhi));
3266 0 : if (COSMu <= Small) {
3267 0 : TransXDir = 1.0 - Gamma;
3268 : } else {
3269 0 : Real64 Epsilon = std::acos(cosPhi * cosTheta / COSMu);
3270 0 : Real64 Eta = Constant::PiOvr2 - Epsilon;
3271 0 : if (std::cos(Epsilon) != 0.0 && Eta != 0.0) {
3272 0 : Real64 MuPrime = std::atan(std::tan(std::acos(COSMu)) / std::cos(Epsilon));
3273 0 : TransXDir =
3274 0 : 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))));
3275 0 : TransXDir = max(0.0, TransXDir);
3276 0 : } else {
3277 0 : TransXDir = 0.0;
3278 : }
3279 : }
3280 0 : Tdirect = max(0.0, TransXDir * TransYDir);
3281 :
3282 : // *******************************************************************************
3283 : // * calculate transmittance of scattered beam due to reflecting screen material *
3284 : // *******************************************************************************
3285 :
3286 0 : Real64 ReflCyl = screen->CylinderRef;
3287 0 : Real64 ReflCylVis = screen->CylinderRefVis;
3288 :
3289 0 : if ((Constant::PiOvr2 - theta) < Small || (Constant::PiOvr2 - phi) < Small) {
3290 0 : Tscattered = 0.0;
3291 0 : TscatteredVis = 0.0;
3292 : } else {
3293 : // DeltaMax and Delta are in degrees
3294 0 : Real64 DeltaMax = 89.7 - (10.0 * Gamma / 0.16);
3295 0 : Real64 Delta = std::sqrt(pow_2(theta / Constant::DegToRad) + pow_2(phi / Constant::DegToRad));
3296 :
3297 : // Use empirical model to determine maximum (peak) scattering
3298 0 : Real64 Tscattermax = 0.0229 * Gamma + 0.2971 * ReflCyl - 0.03624 * pow_2(Gamma) + 0.04763 * pow_2(ReflCyl) - 0.44416 * Gamma * ReflCyl;
3299 : Real64 TscattermaxVis =
3300 0 : 0.0229 * Gamma + 0.2971 * ReflCylVis - 0.03624 * pow_2(Gamma) + 0.04763 * pow_2(ReflCylVis) - 0.44416 * Gamma * ReflCylVis;
3301 :
3302 : // Vary slope of interior and exterior surface of scattering model
3303 0 : Real64 ExponentInterior = -pow_2(Delta - DeltaMax) / 600.0;
3304 0 : Real64 ExponentExterior = -std::pow(std::abs(Delta - DeltaMax), 2.5) / 600.0;
3305 :
3306 : // Determine ratio of scattering at 0,0 incident angle to maximum (peak) scattering
3307 0 : Real64 PeakToPlateauRatio = 1.0 / (0.2 * (1 - Gamma) * ReflCyl);
3308 0 : Real64 PeakToPlateauRatioVis = 1.0 / (0.2 * (1 - Gamma) * ReflCylVis);
3309 :
3310 : // Apply offset for plateau and use exterior exponential function to simulate actual scattering as a function of solar angles
3311 0 : if (Delta > DeltaMax) {
3312 0 : Tscattered = 0.2 * (1.0 - Gamma) * ReflCyl * Tscattermax * (1.0 + (PeakToPlateauRatio - 1.0) * std::exp(ExponentExterior));
3313 0 : TscatteredVis = 0.2 * (1.0 - Gamma) * ReflCylVis * TscattermaxVis * (1.0 + (PeakToPlateauRatioVis - 1.0) * std::exp(ExponentExterior));
3314 : // Trim off offset if solar angle (delta) is greater than maximum (peak) scattering angle
3315 0 : Tscattered -= (0.2 * (1.0 - Gamma) * ReflCyl * Tscattermax) * max(0.0, (Delta - DeltaMax) / (90.0 - DeltaMax));
3316 0 : TscatteredVis -= (0.2 * (1.0 - Gamma) * ReflCylVis * TscattermaxVis) * max(0.0, (Delta - DeltaMax) / (90.0 - DeltaMax));
3317 : } else {
3318 0 : Tscattered = 0.2 * (1.0 - Gamma) * ReflCyl * Tscattermax * (1.0 + (PeakToPlateauRatio - 1.0) * std::exp(ExponentInterior));
3319 0 : TscatteredVis = 0.2 * (1.0 - Gamma) * ReflCylVis * TscattermaxVis * (1.0 + (PeakToPlateauRatioVis - 1.0) * std::exp(ExponentInterior));
3320 : }
3321 : }
3322 :
3323 0 : if (screen->bmRefModel == Material::ScreenBeamReflectanceModel::DoNotModel) {
3324 0 : if (sunInFront) {
3325 0 : tar.BmTrans = Tdirect;
3326 0 : tar.BmTransVis = Tdirect;
3327 0 : tar.BmTransBack = 0.0;
3328 : } else {
3329 0 : tar.BmTrans = 0.0;
3330 0 : tar.BmTransVis = 0.0;
3331 0 : tar.BmTransBack = Tdirect;
3332 : }
3333 0 : Tscattered = 0.0;
3334 0 : TscatteredVis = 0.0;
3335 0 : } else if (screen->bmRefModel == Material::ScreenBeamReflectanceModel::DirectBeam) {
3336 0 : if (sunInFront) {
3337 0 : tar.BmTrans = Tdirect + Tscattered;
3338 0 : tar.BmTransVis = Tdirect + TscatteredVis;
3339 0 : tar.BmTransBack = 0.0;
3340 : } else {
3341 0 : tar.BmTrans = 0.0;
3342 0 : tar.BmTransVis = 0.0;
3343 0 : tar.BmTransBack = Tdirect + Tscattered;
3344 : }
3345 0 : Tscattered = 0.0;
3346 0 : TscatteredVis = 0.0;
3347 0 : } else if (screen->bmRefModel == Material::ScreenBeamReflectanceModel::Diffuse) {
3348 0 : if (sunInFront) {
3349 0 : tar.BmTrans = Tdirect;
3350 0 : tar.BmTransVis = Tdirect;
3351 0 : tar.BmTransBack = 0.0;
3352 : } else {
3353 0 : tar.BmTrans = 0.0;
3354 0 : tar.BmTransVis = 0.0;
3355 0 : tar.BmTransBack = Tdirect;
3356 : }
3357 0 : Tscattered = max(0.0, Tscattered);
3358 0 : TscatteredVis = max(0.0, TscatteredVis);
3359 : }
3360 :
3361 0 : if (sunInFront) {
3362 0 : tar.DfTrans = Tscattered;
3363 0 : tar.DfTransVis = TscatteredVis;
3364 0 : tar.DfTransBack = 0.0;
3365 0 : tar.RefSolFront = max(0.0, ReflCyl * (1.0 - Tdirect) - Tscattered);
3366 0 : tar.RefVisFront = max(0.0, ReflCylVis * (1.0 - Tdirect) - TscatteredVis);
3367 0 : tar.AbsSolFront = max(0.0, (1.0 - Tdirect) * (1.0 - ReflCyl));
3368 0 : tar.RefSolBack = 0.0;
3369 0 : tar.RefVisBack = 0.0;
3370 0 : tar.AbsSolBack = 0.0;
3371 : } else {
3372 0 : tar.DfTrans = 0.0;
3373 0 : tar.DfTransVis = 0.0;
3374 0 : tar.DfTransBack = Tscattered;
3375 0 : tar.RefSolFront = 0.0;
3376 0 : tar.RefVisFront = 0.0;
3377 0 : tar.AbsSolFront = 0.0;
3378 0 : tar.RefSolBack = max(0.0, ReflCyl * (1.0 - Tdirect) - Tscattered);
3379 0 : tar.RefVisBack = max(0.0, ReflCylVis * (1.0 - Tdirect) - TscatteredVis);
3380 0 : tar.AbsSolBack = max(0.0, (1.0 - Tdirect) * (1.0 - ReflCyl));
3381 : }
3382 0 : } // CalcScreenTransmittance()
3383 :
3384 0 : void GetRelativePhiTheta(Real64 phiWin, Real64 thetaWin, Vector3<Real64> const &solcos, Real64 &phi, Real64 &theta)
3385 : {
3386 0 : phi = std::abs(std::acos(solcos.z) - phiWin);
3387 0 : theta = std::abs(std::atan2(solcos.x, solcos.y) - thetaWin);
3388 :
3389 0 : NormalizePhiTheta(phi, theta);
3390 0 : } // GetRelativePhiTheta()
3391 :
3392 : // Use reflection around Pi to normalize to the range 0 to Pi
3393 0 : void NormalizePhiTheta(Real64 &phi, Real64 &theta)
3394 : {
3395 :
3396 0 : while (phi > 2 * Constant::Pi)
3397 0 : phi -= 2 * Constant::Pi;
3398 0 : if (phi > Constant::Pi) phi = 2 * Constant::Pi - phi;
3399 :
3400 0 : while (theta > 2 * Constant::Pi)
3401 0 : theta -= 2 * Constant::Pi;
3402 0 : if (theta > Constant::Pi) theta = 2 * Constant::Pi - theta;
3403 0 : } // NormalizePhiTheta()
3404 :
3405 0 : void GetPhiThetaIndices(Real64 phi, Real64 theta, Real64 dPhi, Real64 dTheta, int &iPhi1, int &iPhi2, int &iTheta1, int &iTheta2)
3406 : {
3407 0 : iPhi1 = int(phi / dPhi);
3408 0 : iPhi2 = (iPhi1 == maxIPhi - 1) ? iPhi1 : iPhi1 + 1;
3409 0 : iTheta1 = int(theta / dTheta);
3410 0 : iTheta2 = (iTheta1 == maxITheta - 1) ? iTheta1 : iTheta1 + 1;
3411 0 : } // GetPhiThetaIndices()
3412 :
3413 53578 : Real64 MaterialBlind::BeamBeamTrans(Real64 const ProfAng, // Solar profile angle (rad)
3414 : Real64 const SlatAng // Slat angle (rad)
3415 : ) const
3416 : {
3417 :
3418 : // FUNCTION INFORMATION:
3419 : // AUTHOR Fred Winkelmann
3420 : // DATE WRITTEN Jan 2002
3421 : // MODIFIED na
3422 : // RE-ENGINEERED na
3423 :
3424 : // PURPOSE OF THIS SUBROUTINE:
3425 : // Calculates beam-to-beam transmittance of a window blind
3426 :
3427 : // METHODOLOGY EMPLOYED:
3428 : // Based on solar profile angle and slat geometry
3429 :
3430 53578 : Real64 CosProfAng = std::cos(ProfAng); // Cosine of profile angle
3431 53578 : Real64 gamma = SlatAng - ProfAng;
3432 53578 : Real64 wbar = this->SlatSeparation;
3433 53578 : if (CosProfAng != 0.0) wbar = this->SlatWidth * std::cos(gamma) / CosProfAng;
3434 53578 : Real64 BeamBeamTrans = max(0.0, 1.0 - std::abs(wbar / this->SlatSeparation));
3435 :
3436 53578 : if (BeamBeamTrans > 0.0) {
3437 :
3438 : // Correction factor that accounts for finite thickness of slats. It is used to modify the
3439 : // blind transmittance to account for reflection and absorption by the slat edges.
3440 : // fEdge is ratio of area subtended by edge of slat to area between tops of adjacent slats.
3441 :
3442 17018 : Real64 fEdge = 0.0; // Slat edge correction factor
3443 17018 : Real64 fEdge1 = 0.0;
3444 17018 : if (std::abs(std::sin(gamma)) > 0.01) {
3445 17018 : if ((SlatAng > 0.0 && SlatAng <= Constant::PiOvr2 && ProfAng <= SlatAng) ||
3446 8448 : (SlatAng > Constant::PiOvr2 && SlatAng <= Constant::Pi && ProfAng > -(Constant::Pi - SlatAng)))
3447 17018 : fEdge1 = this->SlatThickness * std::abs(std::sin(gamma)) /
3448 17018 : ((this->SlatSeparation + this->SlatThickness / std::abs(std::sin(SlatAng))) * CosProfAng);
3449 17018 : fEdge = min(1.0, std::abs(fEdge1));
3450 : }
3451 17018 : BeamBeamTrans *= (1.0 - fEdge);
3452 : }
3453 :
3454 53578 : return BeamBeamTrans;
3455 :
3456 : } // MaterialBlind::BeamBeamTrans()
3457 :
3458 2 : void GetProfIndices(Real64 profAng, int &idxLo, int &idxHi)
3459 : {
3460 2 : idxLo = int((profAng + Constant::PiOvr2) / dProfAng) + 1;
3461 2 : idxHi = std::min(MaxProfAngs, idxLo + 1);
3462 2 : }
3463 :
3464 10 : void GetSlatIndicesInterpFac(Real64 slatAng, int &idxLo, int &idxHi, Real64 &interpFac)
3465 : {
3466 10 : idxLo = int(slatAng / dSlatAng);
3467 10 : idxHi = std::min(MaxSlatAngs, idxLo + 1);
3468 10 : interpFac = (slatAng - (idxLo * dSlatAng)) / dSlatAng;
3469 10 : }
3470 :
3471 : } // namespace EnergyPlus::Material
|