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