Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2025, The Board of Trustees of the University of Illinois,
2 : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
3 : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
4 : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
5 : // contributors. All rights reserved.
6 : //
7 : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
8 : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
9 : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
10 : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
11 : // derivative works, and perform publicly and display publicly, and to permit others to do so.
12 : //
13 : // Redistribution and use in source and binary forms, with or without modification, are permitted
14 : // provided that the following conditions are met:
15 : //
16 : // (1) Redistributions of source code must retain the above copyright notice, this list of
17 : // conditions and the following disclaimer.
18 : //
19 : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
20 : // conditions and the following disclaimer in the documentation and/or other materials
21 : // provided with the distribution.
22 : //
23 : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
24 : // the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
25 : // used to endorse or promote products derived from this software without specific prior
26 : // written permission.
27 : //
28 : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
29 : // without changes from the version obtained under this License, or (ii) Licensee makes a
30 : // reference solely to the software portion of its product, Licensee must refer to the
31 : // software as "EnergyPlus version X" software, where "X" is the version number Licensee
32 : // obtained under this License and may not use a different name for the software. Except as
33 : // specifically required in this Section (4), Licensee shall not use in a company name, a
34 : // product name, in advertising, publicity, or other promotional activities any name, trade
35 : // name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
36 : // similar designation, without the U.S. Department of Energy's prior written consent.
37 : //
38 : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
39 : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
40 : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
41 : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
42 : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
43 : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
44 : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
45 : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
46 : // POSSIBILITY OF SUCH DAMAGE.
47 :
48 : // C++ Headers
49 : #include <algorithm>
50 : #include <cmath>
51 : #include <string>
52 :
53 : // ObjexxFCL Headers
54 : #include <ObjexxFCL/Array.functions.hh>
55 : #include <ObjexxFCL/Array1S.hh>
56 : #include <ObjexxFCL/ArrayS.functions.hh>
57 : #include <ObjexxFCL/Fmath.hh>
58 : #include <ObjexxFCL/string.functions.hh>
59 :
60 : // EnergyPlus Headers
61 : #include <EnergyPlus/Construction.hh>
62 : #include <EnergyPlus/CurveManager.hh>
63 : #include <EnergyPlus/Data/EnergyPlusData.hh>
64 : #include <EnergyPlus/DataBSDFWindow.hh>
65 : #include <EnergyPlus/DataContaminantBalance.hh>
66 : #include <EnergyPlus/DataHVACGlobals.hh>
67 : #include <EnergyPlus/DataHeatBalFanSys.hh>
68 : #include <EnergyPlus/DataHeatBalSurface.hh>
69 : #include <EnergyPlus/DataHeatBalance.hh>
70 : #include <EnergyPlus/DataIPShortCuts.hh>
71 : #include <EnergyPlus/DataReportingFlags.hh>
72 : #include <EnergyPlus/DataStringGlobals.hh>
73 : #include <EnergyPlus/DataSurfaces.hh>
74 : #include <EnergyPlus/DataSystemVariables.hh>
75 : #include <EnergyPlus/DataZoneEnergyDemands.hh>
76 : #include <EnergyPlus/DaylightingDevices.hh>
77 : #include <EnergyPlus/DaylightingManager.hh>
78 : #include <EnergyPlus/DisplayRoutines.hh>
79 : #include <EnergyPlus/EMSManager.hh>
80 : #include <EnergyPlus/EconomicTariff.hh>
81 : #include <EnergyPlus/FileSystem.hh>
82 : #include <EnergyPlus/GlobalNames.hh>
83 : #include <EnergyPlus/HVACSizingSimulationManager.hh>
84 : #include <EnergyPlus/HVACSystemRootFindingAlgorithm.hh>
85 : #include <EnergyPlus/HeatBalanceIntRadExchange.hh>
86 : #include <EnergyPlus/HeatBalanceManager.hh>
87 : #include <EnergyPlus/HeatBalanceSurfaceManager.hh>
88 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
89 : #include <EnergyPlus/InternalHeatGains.hh>
90 : #include <EnergyPlus/Material.hh>
91 : #include <EnergyPlus/MatrixDataManager.hh>
92 : #include <EnergyPlus/NodeInputManager.hh>
93 : #include <EnergyPlus/OutAirNodeManager.hh>
94 : #include <EnergyPlus/OutputProcessor.hh>
95 : #include <EnergyPlus/OutputReportTabular.hh>
96 : #include <EnergyPlus/PhaseChangeModeling/HysteresisModel.hh>
97 : #include <EnergyPlus/PluginManager.hh>
98 : #include <EnergyPlus/ScheduleManager.hh>
99 : #include <EnergyPlus/SolarShading.hh>
100 : #include <EnergyPlus/StringUtilities.hh>
101 : #include <EnergyPlus/SurfaceGeometry.hh>
102 : #include <EnergyPlus/SurfaceOctree.hh>
103 : #include <EnergyPlus/TARCOGGassesParams.hh>
104 : #include <EnergyPlus/TARCOGParams.hh>
105 : #include <EnergyPlus/UtilityRoutines.hh>
106 : #include <EnergyPlus/WindowComplexManager.hh>
107 : #include <EnergyPlus/WindowEquivalentLayer.hh>
108 : #include <EnergyPlus/WindowManager.hh>
109 : #include <EnergyPlus/ZoneTempPredictorCorrector.hh>
110 :
111 : namespace EnergyPlus {
112 :
113 : namespace HeatBalanceManager {
114 :
115 : // Module containing the heat balance simulation routines
116 : // calculation (initialization) routines
117 :
118 : // MODULE INFORMATION:
119 : // AUTHOR Richard J. Liesen
120 : // DATE WRITTEN February 1998
121 : // MODIFIED November 1998, FW
122 : // MODIFIED April 1999, LKL
123 : // MODIFIED Dec 2006 DJS of PSU for ecoroof
124 : // Added Dec 2008 TH for thermochromic windows:
125 : // new subroutine CreateTCConstructions called by GetHeatBalanceInput
126 :
127 : // PURPOSE OF THIS MODULE:
128 : // To encapsulate the data and algorithms required to
129 : // manage the heat balance simulation on the building.
130 :
131 : // REFERENCES:
132 : // The heat balance method is outlined in the "Tarp Algorithms Manual"
133 : // The methods are also summarized in many BSO Theses and papers.
134 :
135 : // OTHER NOTES:
136 : // This module was created from IBLAST subroutines
137 :
138 : Array1D_string const PassFail(2, {"Fail", "Pass"});
139 :
140 249946 : void ManageHeatBalance(EnergyPlusData &state)
141 : {
142 :
143 : // SUBROUTINE INFORMATION:
144 : // AUTHOR Rick Strand
145 : // DATE WRITTEN January 1997
146 : // MODIFIED February 1998 Richard Liesen
147 :
148 : // PURPOSE OF THIS SUBROUTINE:
149 : // This subroutine manages the heat balance method of calculating
150 : // building thermal loads. It is called from the SimulationManager
151 : // at the time step level. This driver manages the calls to all of
152 : // the other modules, drivers, and simulation algorithms.
153 :
154 : // METHODOLOGY EMPLOYED:
155 : // The order of this routine was taken from HeatBalanceModule with routine
156 : // and Data Structuring
157 :
158 : // REFERENCES:
159 : // Legacy code from (I)BLAST, subroutine SIMZGD.
160 :
161 : // Using/Aliasing
162 : using namespace HeatBalanceSurfaceManager;
163 : using EMSManager::ManageEMS;
164 : using EMSManager::UpdateEMSTrendVariables;
165 :
166 : // Get the heat balance input at the beginning of the simulation only
167 249946 : if (state.dataHeatBalMgr->ManageHeatBalanceGetInputFlag) {
168 103 : GetHeatBalanceInput(state); // Obtains heat balance related parameters from input file
169 103 : if (state.dataGlobal->DoingSizing) state.dataHeatBal->doSpaceHeatBalance = state.dataHeatBal->doSpaceHeatBalanceSizing;
170 :
171 : // Surface octree setup
172 : // The surface octree holds live references to surfaces so it must be updated
173 : // if in the future surfaces are altered after this point
174 103 : if (state.dataSurface->TotSurfaces >= Dayltg::octreeCrossover) { // Octree can be active
175 0 : if (state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Daylighting:Controls") > 0) { // Daylighting is active
176 0 : state.dataHeatBalMgr->surfaceOctree.init(state.dataSurface->Surface); // Set up surface octree
177 : }
178 : }
179 :
180 850 : for (auto &surface : state.dataSurface->Surface)
181 747 : surface.set_computed_geometry(); // Set up extra surface geometry info for PierceSurface
182 :
183 103 : state.dataHeatBalMgr->ManageHeatBalanceGetInputFlag = false;
184 : }
185 :
186 : bool anyRan;
187 :
188 249946 : ManageEMS(state,
189 : EMSManager::EMSCallFrom::BeginZoneTimestepBeforeInitHeatBalance,
190 : anyRan,
191 499892 : ObjexxFCL::Optional_int_const()); // EMS calling point
192 :
193 : // These Inits will still have to be looked at as the routines are re-engineered further
194 :
195 249946 : InitHeatBalance(state); // Initialize all heat balance related parameters
196 249946 : ManageEMS(
197 499892 : state, EMSManager::EMSCallFrom::BeginZoneTimestepAfterInitHeatBalance, anyRan, ObjexxFCL::Optional_int_const()); // EMS calling point
198 :
199 : // Solve the zone heat balance by first calling the Surface Heat Balance Manager
200 : // and then the Air Heat Balance Manager is called by the Surface Heat Balance
201 : // Manager. The order of execution is still important and the zone cannot
202 : // go through any record keeping before the HVAC system has run because there
203 : // may be a radiant system in the building which will require iteration between
204 : // the HVAC system (called from the Air Heat Balance) and the zone (simulated
205 : // in the Surface Heat Balance Manager). In the future, this may be improved.
206 249946 : ManageSurfaceHeatBalance(state);
207 249945 : ManageEMS(state, EMSManager::EMSCallFrom::EndZoneTimestepBeforeZoneReporting, anyRan, ObjexxFCL::Optional_int_const()); // EMS calling point
208 249945 : RecKeepHeatBalance(state); // Do any heat balance related record keeping
209 :
210 : // This call has been moved to the FanSystemModule and does effect the output file
211 : // You do get a shift in the Air Handling System Summary for the building electric loads
212 : // IF ((.NOT.WarmupFlag).AND.(DayOfSim.GT.0)) CALL RCKEEP ! Do fan system accounting (to be moved later)
213 :
214 249945 : ReportHeatBalance(state); // Manage heat balance reporting until the new reporting is in place
215 :
216 249945 : ManageEMS(state, EMSManager::EMSCallFrom::EndZoneTimestepAfterZoneReporting, anyRan, ObjexxFCL::Optional_int_const()); // EMS calling point
217 :
218 249945 : UpdateEMSTrendVariables(state);
219 249945 : EnergyPlus::PluginManagement::PluginManager::updatePluginValues(state);
220 :
221 249945 : if (state.dataGlobal->WarmupFlag && state.dataGlobal->EndDayFlag) {
222 :
223 1817 : CheckWarmupConvergence(state);
224 1817 : if (!state.dataGlobal->WarmupFlag) {
225 216 : state.dataGlobal->DayOfSim = 0; // Reset DayOfSim if Warmup converged
226 216 : state.dataGlobal->DayOfSimChr = "0";
227 :
228 216 : ManageEMS(state, EMSManager::EMSCallFrom::BeginNewEnvironmentAfterWarmUp, anyRan, ObjexxFCL::Optional_int_const()); // calling point
229 : }
230 : }
231 :
232 249945 : if (!state.dataGlobal->WarmupFlag && state.dataGlobal->EndDayFlag && state.dataGlobal->DayOfSim == 1 && !state.dataGlobal->DoingSizing) {
233 134 : ReportWarmupConvergence(state);
234 : }
235 249945 : }
236 :
237 : // Get Input Section of the Module
238 : //******************************************************************************
239 :
240 116 : void GetHeatBalanceInput(EnergyPlusData &state)
241 : {
242 :
243 : // SUBROUTINE INFORMATION:
244 : // AUTHOR Rick Strand
245 : // DATE WRITTEN September 1997
246 : // MODIFIED February 1998 Richard Liesen
247 : // November 1998 FW
248 :
249 : // PURPOSE OF THIS SUBROUTINE:
250 : // This subroutine is the main driver for initializations within the
251 : // heat balance.
252 :
253 : // Using/Aliasing
254 : using InternalHeatGains::ManageInternalHeatGains;
255 :
256 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
257 116 : bool ErrorsFound(false); // If errors detected in input
258 :
259 116 : GetProjectControlData(state, ErrorsFound);
260 :
261 116 : GetSiteAtmosphereData(state, ErrorsFound);
262 :
263 116 : Material::GetWindowGlassSpectralData(state, ErrorsFound);
264 :
265 116 : Material::GetMaterialData(state, ErrorsFound); // Read materials from input file/transfer from legacy data structure
266 :
267 116 : Material::GetHysteresisData(state, ErrorsFound);
268 :
269 116 : GetFrameAndDividerData(state);
270 :
271 116 : GetConstructData(state, ErrorsFound); // Read constructs from input file/transfer from legacy data structure
272 :
273 116 : GetBuildingData(state, ErrorsFound); // Read building data from input file
274 :
275 116 : DataSurfaces::GetVariableAbsorptanceSurfaceList(state);
276 :
277 116 : GetIncidentSolarMultiplier(state, ErrorsFound);
278 :
279 : // Added SV 6/26/2013 to load scheduled surface gains
280 116 : GetScheduledSurfaceGains(state, ErrorsFound);
281 :
282 116 : if (state.dataSurface->UseRepresentativeSurfaceCalculations) {
283 0 : print(state.files.eio, "{}\n", "! <Representative Surface Assignment>,Surface Name,Representative Surface Name");
284 0 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
285 0 : int RepSurfNum = state.dataSurface->Surface(SurfNum).RepresentativeCalcSurfNum;
286 0 : if (SurfNum != RepSurfNum) {
287 0 : print(state.files.eio,
288 : " Representative Surface Assignment,{},{}\n",
289 0 : state.dataSurface->Surface(SurfNum).Name,
290 0 : state.dataSurface->Surface(RepSurfNum).Name);
291 : }
292 : }
293 : }
294 :
295 : // Added TH 1/9/2009 to create thermochromic window constructions
296 116 : CreateTCConstructions(state, ErrorsFound);
297 :
298 116 : if (state.dataSurface->TotSurfaces > 0 && state.dataGlobal->NumOfZones == 0) {
299 0 : bool ValidSimulationWithNoZones = CheckValidSimulationObjects(state);
300 0 : if (!ValidSimulationWithNoZones) {
301 0 : ShowSevereError(state, "GetHeatBalanceInput: There are surfaces in input but no zones found. Invalid simulation.");
302 0 : ErrorsFound = true;
303 : }
304 : }
305 :
306 116 : CheckUsedConstructions(state, ErrorsFound);
307 :
308 116 : if (ErrorsFound) {
309 0 : ShowFatalError(state, "Errors found in Building Input, Program Stopped");
310 : }
311 :
312 : // Set up enclosures before processing internal gains input
313 116 : HeatBalanceIntRadExchange::InitSolarViewFactors(state);
314 :
315 : // following is done to "get internal heat gains" input so that lights are gotten before
316 : // daylighting input
317 116 : ManageInternalHeatGains(state, true);
318 :
319 : // following is done so that people are gotten before for thermal comfort calculations
320 : // Setup Kiva instances
321 116 : if (state.dataHeatBal->AnyKiva) {
322 0 : state.dataSurfaceGeometry->kivaManager.setupKivaInstances(state);
323 : }
324 116 : }
325 :
326 116 : void CheckUsedConstructions(EnergyPlusData &state, [[maybe_unused]] bool &ErrorsFound)
327 : {
328 :
329 : // SUBROUTINE INFORMATION:
330 : // AUTHOR Linda Lawrie
331 : // DATE WRITTEN August 2011
332 :
333 : // PURPOSE OF THIS SUBROUTINE:
334 : // Counts or details unused constructions.
335 :
336 : // SUBROUTINE PARAMETER DEFINITIONS:
337 116 : int constexpr NumConstrObjects(6);
338 : Array1D_string const ConstrObjects(NumConstrObjects,
339 : {"Pipe:Indoor",
340 : "Pipe:Outdoor",
341 : "Pipe:Underground",
342 : "GroundHeatExchanger:Surface",
343 : "DaylightingDevice:Tubular",
344 116 : "EnergyManagementSystem:ConstructionIndexVariable"});
345 :
346 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
347 : int NumAlphas;
348 : int NumNumbers;
349 : int Status;
350 : int CNum;
351 :
352 : // Needs to account for Pipe:HeatTransfer/indoor, etc constructions.
353 812 : for (int ONum = 1; ONum <= NumConstrObjects; ++ONum) {
354 696 : int NumObjects = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, ConstrObjects(ONum));
355 700 : for (int Loop = 1; Loop <= NumObjects; ++Loop) {
356 8 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
357 4 : ConstrObjects(ONum),
358 : Loop,
359 4 : state.dataIPShortCut->cAlphaArgs,
360 : NumAlphas,
361 4 : state.dataIPShortCut->rNumericArgs,
362 : NumNumbers,
363 : Status);
364 4 : if (ONum == 5) {
365 0 : CNum = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(4), state.dataConstruction->Construct);
366 : } else {
367 4 : CNum = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(2), state.dataConstruction->Construct);
368 : }
369 4 : if (CNum == 0) continue;
370 4 : state.dataConstruction->Construct(CNum).IsUsed = true;
371 4 : if (ONum == 4 || ONum == 6) {
372 : // GroundHeatExchanger:Surface or EnergyManagementSystem:ConstructionIndexVariable
373 : // Include all EMS constructions since they can potentially be used by a CTF surface
374 4 : if (!state.dataConstruction->Construct(CNum).TypeIsWindow) {
375 0 : state.dataConstruction->Construct(CNum).IsUsedCTF = true;
376 : }
377 : }
378 : }
379 : }
380 232 : int Unused = state.dataHeatBal->TotConstructs - std::count_if(state.dataConstruction->Construct.begin(),
381 116 : state.dataConstruction->Construct.end(),
382 343 : [](Construction::ConstructionProps const &e) { return e.IsUsed; });
383 116 : if (Unused > 0) {
384 5 : if (!state.dataGlobal->DisplayExtraWarnings) {
385 5 : ShowWarningError(state, format("CheckUsedConstructions: There are {} nominally unused constructions in input.", Unused));
386 15 : ShowContinueError(state, "For explicit details on each unused construction, use Output:Diagnostics,DisplayExtraWarnings;");
387 : } else {
388 0 : ShowWarningError(state, format("CheckUsedConstructions: There are {} nominally unused constructions in input.", Unused));
389 0 : ShowContinueError(state, "Each Unused construction is shown.");
390 0 : for (int Loop = 1; Loop <= state.dataHeatBal->TotConstructs; ++Loop) {
391 0 : if (state.dataConstruction->Construct(Loop).IsUsed) continue;
392 0 : ShowMessage(state, format("Construction={}", state.dataConstruction->Construct(Loop).Name));
393 : }
394 : }
395 : }
396 116 : }
397 :
398 0 : bool CheckValidSimulationObjects(EnergyPlusData &state)
399 : {
400 :
401 : // FUNCTION INFORMATION:
402 : // AUTHOR Linda Lawrie
403 : // DATE WRITTEN July 2008
404 :
405 : // PURPOSE OF THIS FUNCTION:
406 : // If an input file presents with surfaces but no zones, there are certain objects
407 : // that must be present for the simulation to be valid. This check was necessitated by
408 : // an input file that was entirely detached shading surfaces but no zones (and nothing else).
409 : // Other objects include Solar Collectors, PV arrays.
410 :
411 : // METHODOLOGY EMPLOYED:
412 : // Check for specific objects that must be present for such a simulation to be valid.
413 :
414 : // Return value
415 : bool ValidSimulation; // True is other objects appear to make this a valid simulation.
416 :
417 0 : ValidSimulation = false;
418 0 : if (state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "SolarCollector:FlatPlate:Water") > 0) {
419 0 : ValidSimulation = true;
420 0 : } else if (state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Generator:Photovoltaic") > 0) {
421 0 : ValidSimulation = true;
422 0 : } else if (state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Generator:InternalCombustionEngine") > 0) {
423 0 : ValidSimulation = true;
424 0 : } else if (state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Generator:CombustionTurbine") > 0) {
425 0 : ValidSimulation = true;
426 0 : } else if (state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Generator:FuelCell") > 0) {
427 0 : ValidSimulation = true;
428 0 : } else if (state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Generator:MicroCHP") > 0) {
429 0 : ValidSimulation = true;
430 0 : } else if (state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Generator:MicroTurbine") > 0) {
431 0 : ValidSimulation = true;
432 0 : } else if (state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Generator:WindTurbine") > 0) {
433 0 : ValidSimulation = true;
434 : }
435 :
436 0 : return ValidSimulation;
437 : }
438 :
439 122 : void SetPreConstructionInputParameters(EnergyPlusData &state)
440 : {
441 : // SUBROUTINE INFORMATION:
442 : // AUTHOR Edwin Lee
443 : // DATE WRITTEN October 2014
444 :
445 : // PURPOSE OF THIS SUBROUTINE:
446 : // This subroutine sets parameters that need to be established before any heat balance inputs are read
447 :
448 : int NumAlpha;
449 : int NumNumber;
450 : int IOStat;
451 :
452 : // Get all the construction objects to determine the max layers and use this as the value for DataHeatBalance::MaxSolidWinLayers
453 : // The variable MaxSolidWinLayers is initialized to zero to immediately catch any issues with timing of this routine
454 :
455 : // start by setting this to 5; it will satisfy the regular window constructions (Construction) and the Window5 files
456 : // (Construction:WindowDataFile)
457 122 : state.dataHeatBal->MaxSolidWinLayers = 7;
458 :
459 : // Construction:ComplexFenestrationState have a limit of 10 layers, so set it up to 10 if they are present
460 122 : if (state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Construction:ComplexFenestrationState") > 0) {
461 1 : state.dataHeatBal->MaxSolidWinLayers = max(state.dataHeatBal->MaxSolidWinLayers, 10);
462 : }
463 :
464 : // then process the rest of the relevant constructions
465 122 : std::string constructName("Construction:WindowEquivalentLayer");
466 122 : int numConstructions(state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, constructName));
467 128 : for (int constructionNum = 1; constructionNum <= numConstructions; ++constructionNum) {
468 12 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
469 : constructName,
470 : constructionNum,
471 6 : state.dataIPShortCut->cAlphaArgs,
472 : NumAlpha,
473 6 : state.dataIPShortCut->rNumericArgs,
474 : NumNumber,
475 : IOStat,
476 6 : state.dataIPShortCut->lNumericFieldBlanks,
477 6 : state.dataIPShortCut->lAlphaFieldBlanks,
478 6 : state.dataIPShortCut->cAlphaFieldNames,
479 6 : state.dataIPShortCut->cNumericFieldNames);
480 6 : int numLayersInThisConstruct(NumAlpha - 1);
481 6 : state.dataHeatBal->MaxSolidWinLayers = max(state.dataHeatBal->MaxSolidWinLayers, numLayersInThisConstruct);
482 : }
483 :
484 : // construction types being ignored as they are opaque: Construction:CfactorUndergroundWall, Construction:FfactorGroundFloor,
485 122 : }
486 :
487 204 : void GetProjectControlData(EnergyPlusData &state, bool &ErrorsFound) // Set to true if errors detected during getting data
488 : {
489 :
490 : // SUBROUTINE INFORMATION:
491 : // AUTHOR Linda Lawrie
492 : // DATE WRITTEN October 2004
493 :
494 : // PURPOSE OF THIS SUBROUTINE:
495 : // This subroutine gets the project control data before the rest of the building data (such as
496 : // materials) is obtained.
497 :
498 : // REFERENCES:
499 : // This routine gets the following objects:
500 : // BUILDING
501 : // INSIDE CONVECTION ALGORITHM
502 : // OUTSIDE CONVECTION ALGORITHM
503 : // SOLUTION ALGORITHM
504 : // ASHRAE Handbook of Fundamentals, Chap 16, for the setting of Site Atmospheric defaults based
505 : // on terrain.
506 : // ZoneAirHeatBalanceAlgorithm, Added by L. Gu, 12/09
507 : // ZoneAirContaminantBalance, Added by L. Gu, 06/10
508 :
509 : // Using/Aliasing
510 204 : auto &HVACSystemRootFinding = state.dataRootFinder->HVACSystemRootFinding;
511 :
512 : // SUBROUTINE PARAMETER DEFINITIONS:
513 : static constexpr std::string_view RoutineName("GetProjectControlData: ");
514 : static constexpr std::string_view routineName = "GetProjectControlData";
515 :
516 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
517 204 : Array1D_string AlphaName(4);
518 204 : Array1D<Real64> BuildingNumbers(5);
519 : int NumAlpha;
520 : int NumNumber;
521 : int IOStat;
522 : std::string::size_type TMP;
523 :
524 : // Assign the values to the building data
525 :
526 204 : state.dataHeatBalMgr->CurrentModuleObject = "Building";
527 204 : int NumObjects = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, state.dataHeatBalMgr->CurrentModuleObject);
528 :
529 204 : if (NumObjects > 0) {
530 612 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
531 204 : state.dataHeatBalMgr->CurrentModuleObject,
532 : 1,
533 : AlphaName,
534 : NumAlpha,
535 : BuildingNumbers,
536 : NumNumber,
537 : IOStat,
538 204 : state.dataIPShortCut->lNumericFieldBlanks,
539 204 : state.dataIPShortCut->lAlphaFieldBlanks,
540 204 : state.dataIPShortCut->cAlphaFieldNames,
541 204 : state.dataIPShortCut->cNumericFieldNames);
542 : // Building Name (remove certain characters)
543 204 : state.dataHeatBal->BuildingName = AlphaName(1);
544 204 : TMP = index(state.dataHeatBal->BuildingName, char(1));
545 204 : while (TMP != std::string::npos) {
546 0 : state.dataHeatBal->BuildingName[TMP] = ',';
547 0 : TMP = index(state.dataHeatBal->BuildingName, char(1));
548 : }
549 204 : TMP = index(state.dataHeatBal->BuildingName, char(2));
550 204 : while (TMP != std::string::npos) {
551 0 : state.dataHeatBal->BuildingName[TMP] = '!';
552 0 : TMP = index(state.dataHeatBal->BuildingName, char(2));
553 : }
554 204 : TMP = index(state.dataHeatBal->BuildingName, char(3));
555 204 : while (TMP != std::string::npos) {
556 0 : state.dataHeatBal->BuildingName[TMP] = '\\';
557 0 : TMP = index(state.dataHeatBal->BuildingName, char(3));
558 : }
559 : // Building Azimuth (no validation)
560 204 : state.dataHeatBal->BuildingAzimuth = mod(BuildingNumbers(1), 360.0);
561 : // Terrain
562 204 : if (AlphaName(2) == "COUNTRY" || AlphaName(2) == "1") {
563 2 : state.dataEnvrn->SiteWindExp = 0.14;
564 2 : state.dataEnvrn->SiteWindBLHeight = 270.0;
565 2 : AlphaName(2) = "Country";
566 202 : } else if (AlphaName(2) == "SUBURBS" || AlphaName(2) == "2" || AlphaName(2) == "SUBURB") {
567 185 : state.dataEnvrn->SiteWindExp = 0.22;
568 185 : state.dataEnvrn->SiteWindBLHeight = 370.0;
569 185 : AlphaName(2) = "Suburbs";
570 17 : } else if (AlphaName(2) == "CITY" || AlphaName(2) == "3") {
571 17 : state.dataEnvrn->SiteWindExp = 0.33;
572 17 : state.dataEnvrn->SiteWindBLHeight = 460.0;
573 17 : AlphaName(2) = "City";
574 0 : } else if (AlphaName(2) == "OCEAN") {
575 0 : state.dataEnvrn->SiteWindExp = 0.10;
576 0 : state.dataEnvrn->SiteWindBLHeight = 210.0;
577 0 : AlphaName(2) = "Ocean";
578 0 : } else if (AlphaName(2) == "URBAN") {
579 0 : state.dataEnvrn->SiteWindExp = 0.22;
580 0 : state.dataEnvrn->SiteWindBLHeight = 370.0;
581 0 : AlphaName(2) = "Urban";
582 : } else {
583 0 : ShowSevereError(state,
584 0 : format("{}{}: {} invalid={}",
585 : RoutineName,
586 0 : state.dataHeatBalMgr->CurrentModuleObject,
587 0 : state.dataIPShortCut->cAlphaFieldNames(2),
588 : AlphaName(2)));
589 0 : state.dataEnvrn->SiteWindExp = 0.14;
590 0 : state.dataEnvrn->SiteWindBLHeight = 270.0;
591 0 : AlphaName(2) = AlphaName(2) + "-invalid";
592 0 : ErrorsFound = true;
593 : }
594 : // Loads Convergence Tolerance Value
595 204 : state.dataHeatBal->LoadsConvergTol = BuildingNumbers(2);
596 204 : if (state.dataHeatBal->LoadsConvergTol <= 0.0) {
597 0 : ShowSevereError(state,
598 0 : format("{}{}: {} value invalid, [{:.3R}]",
599 : RoutineName,
600 0 : state.dataHeatBalMgr->CurrentModuleObject,
601 0 : state.dataIPShortCut->cNumericFieldNames(2),
602 0 : state.dataHeatBal->LoadsConvergTol));
603 0 : ErrorsFound = true;
604 : }
605 : // Temperature Convergence Tolerance Value
606 204 : state.dataHeatBal->TempConvergTol = BuildingNumbers(3);
607 204 : if (state.dataHeatBal->TempConvergTol <= 0.0) {
608 0 : ShowSevereError(state,
609 0 : format("{}{}: {} value invalid, [{:.3R}]",
610 : RoutineName,
611 0 : state.dataHeatBalMgr->CurrentModuleObject,
612 0 : state.dataIPShortCut->cNumericFieldNames(3),
613 0 : state.dataHeatBal->TempConvergTol));
614 0 : ErrorsFound = true;
615 : }
616 : // Solar Distribution
617 204 : if (has_prefix(AlphaName(3), "MIN") || AlphaName(3) == "-1" || state.dataSysVars->lMinimalShadowing) {
618 42 : state.dataHeatBal->SolarDistribution = DataHeatBalance::Shadowing::Minimal;
619 42 : AlphaName(3) = "MinimalShadowing";
620 42 : state.dataSurface->CalcSolRefl = false;
621 162 : } else if (AlphaName(3) == "FULLEXTERIOR" || AlphaName(3) == "0") {
622 133 : state.dataHeatBal->SolarDistribution = DataHeatBalance::Shadowing::FullExterior;
623 133 : AlphaName(3) = "FullExterior";
624 133 : state.dataSurface->CalcSolRefl = false;
625 29 : } else if (AlphaName(3) == "FULLINTERIORANDEXTERIOR" || AlphaName(3) == "1") {
626 29 : state.dataHeatBal->SolarDistribution = DataHeatBalance::Shadowing::FullInteriorExterior;
627 29 : AlphaName(3) = "FullInteriorAndExterior";
628 29 : state.dataSurface->CalcSolRefl = false;
629 0 : } else if (AlphaName(3) == "FULLEXTERIORWITHREFLECTIONS") {
630 0 : state.dataHeatBal->SolarDistribution = DataHeatBalance::Shadowing::FullExterior;
631 0 : AlphaName(3) = "FullExteriorWithReflectionsFromExteriorSurfaces";
632 0 : state.dataSurface->CalcSolRefl = true;
633 0 : } else if (AlphaName(3) == "FULLINTERIORANDEXTERIORWITHREFLECTIONS") {
634 0 : state.dataHeatBal->SolarDistribution = DataHeatBalance::Shadowing::FullInteriorExterior;
635 0 : AlphaName(3) = "FullInteriorAndExteriorWithReflectionsFromExteriorSurfaces";
636 0 : state.dataSurface->CalcSolRefl = true;
637 : } else {
638 0 : ShowSevereError(state,
639 0 : format("{}{}: {} invalid={}",
640 : RoutineName,
641 0 : state.dataHeatBalMgr->CurrentModuleObject,
642 0 : state.dataIPShortCut->cAlphaFieldNames(3),
643 : AlphaName(3)));
644 0 : ErrorsFound = true;
645 0 : AlphaName(3) = AlphaName(3) + "-invalid";
646 : }
647 : // Maximum Number of Warmup Days
648 204 : if (!state.dataIPShortCut->lNumericFieldBlanks(4)) {
649 175 : state.dataHeatBal->MaxNumberOfWarmupDays = BuildingNumbers(4);
650 175 : if (state.dataHeatBal->MaxNumberOfWarmupDays <= 0) {
651 0 : ShowSevereError(state,
652 0 : format("{}{}: {} invalid, [{}], {} will be used",
653 : RoutineName,
654 0 : state.dataHeatBalMgr->CurrentModuleObject,
655 0 : state.dataIPShortCut->cNumericFieldNames(4),
656 0 : state.dataHeatBal->MaxNumberOfWarmupDays,
657 : DataHeatBalance::DefaultMaxNumberOfWarmupDays));
658 0 : state.dataHeatBal->MaxNumberOfWarmupDays = DataHeatBalance::DefaultMaxNumberOfWarmupDays;
659 : }
660 : } else {
661 29 : state.dataHeatBal->MaxNumberOfWarmupDays = DataHeatBalance::DefaultMaxNumberOfWarmupDays;
662 : }
663 : // Minimum Number of Warmup Days
664 204 : if (!state.dataIPShortCut->lNumericFieldBlanks(5)) {
665 188 : state.dataHeatBal->MinNumberOfWarmupDays = BuildingNumbers(5);
666 188 : if (state.dataHeatBal->MinNumberOfWarmupDays <= 0) {
667 0 : ShowWarningError(state,
668 0 : format("{}{}: {} invalid, [{}], {} will be used",
669 : RoutineName,
670 0 : state.dataHeatBalMgr->CurrentModuleObject,
671 0 : state.dataIPShortCut->cNumericFieldNames(5),
672 0 : state.dataHeatBal->MinNumberOfWarmupDays,
673 : DataHeatBalance::DefaultMinNumberOfWarmupDays));
674 0 : state.dataHeatBal->MinNumberOfWarmupDays = DataHeatBalance::DefaultMinNumberOfWarmupDays;
675 : }
676 : } else {
677 16 : state.dataHeatBal->MinNumberOfWarmupDays = DataHeatBalance::DefaultMinNumberOfWarmupDays;
678 : }
679 204 : if (state.dataHeatBal->MinNumberOfWarmupDays > state.dataHeatBal->MaxNumberOfWarmupDays) {
680 0 : ShowWarningError(state,
681 0 : format("{}{}: {} [{}] is greater than {} [{}], {} will be used.",
682 : RoutineName,
683 0 : state.dataHeatBalMgr->CurrentModuleObject,
684 0 : state.dataIPShortCut->cNumericFieldNames(5),
685 0 : state.dataHeatBal->MinNumberOfWarmupDays,
686 0 : state.dataIPShortCut->cNumericFieldNames(4),
687 0 : state.dataHeatBal->MaxNumberOfWarmupDays,
688 0 : state.dataHeatBal->MinNumberOfWarmupDays));
689 0 : state.dataHeatBal->MaxNumberOfWarmupDays = state.dataHeatBal->MinNumberOfWarmupDays;
690 : }
691 :
692 : } else {
693 0 : ShowSevereError(state, format("{} A {} Object must be entered.", RoutineName, state.dataHeatBalMgr->CurrentModuleObject));
694 0 : ErrorsFound = true;
695 0 : state.dataHeatBal->BuildingName = "NOT ENTERED";
696 0 : AlphaName(2) = "NOT ENTERED";
697 0 : AlphaName(3) = "NOT ENTERED";
698 0 : state.dataHeatBal->MaxNumberOfWarmupDays = DataHeatBalance::DefaultMaxNumberOfWarmupDays;
699 0 : state.dataHeatBal->MinNumberOfWarmupDays = DataHeatBalance::DefaultMinNumberOfWarmupDays;
700 : }
701 :
702 204 : constexpr const char *Format_720(" Building Information,{},{:.3R},{},{:.5R},{:.5R},{},{},{}\n");
703 204 : constexpr const char *Format_721("! <Building Information>, Building Name,North Axis {{deg}},Terrain, Loads Convergence Tolerance "
704 : "Value,Temperature Convergence Tolerance Value, Solar Distribution,Maximum Number of Warmup Days,Minimum "
705 : "Number of Warmup Days\n");
706 : // Write Building Information to the initialization output file
707 204 : print(state.files.eio, Format_721);
708 204 : print(state.files.eio,
709 : Format_720,
710 204 : state.dataHeatBal->BuildingName,
711 204 : state.dataHeatBal->BuildingAzimuth,
712 : AlphaName(2),
713 204 : state.dataHeatBal->LoadsConvergTol,
714 204 : state.dataHeatBal->TempConvergTol,
715 : AlphaName(3),
716 204 : state.dataHeatBal->MaxNumberOfWarmupDays,
717 204 : state.dataHeatBal->MinNumberOfWarmupDays);
718 : // Above should be validated...
719 :
720 204 : state.dataHeatBalMgr->CurrentModuleObject = "SurfaceConvectionAlgorithm:Inside";
721 204 : NumObjects = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, state.dataHeatBalMgr->CurrentModuleObject);
722 204 : if (NumObjects > 0) {
723 231 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
724 77 : state.dataHeatBalMgr->CurrentModuleObject,
725 : 1,
726 : AlphaName,
727 : NumAlpha,
728 : BuildingNumbers,
729 : NumNumber,
730 : IOStat,
731 77 : state.dataIPShortCut->lNumericFieldBlanks,
732 77 : state.dataIPShortCut->lAlphaFieldBlanks,
733 77 : state.dataIPShortCut->cAlphaFieldNames,
734 77 : state.dataIPShortCut->cNumericFieldNames);
735 :
736 77 : Convect::HcInt hcIn = static_cast<Convect::HcInt>(getEnumValue(Convect::HcIntNamesUC, AlphaName(1)));
737 :
738 77 : if (hcIn == Convect::HcInt::TrombeWall) {
739 0 : ShowSevereError(state,
740 : "GetInsideConvectionAlgorithm: TrombeWall has been used as a global definition. This is a zone oriented value. "
741 : "Will be illegal in the future.");
742 77 : } else if (hcIn != Convect::HcInt::ASHRAESimple && hcIn != Convect::HcInt::ASHRAETARP && hcIn != Convect::HcInt::CeilingDiffuser &&
743 0 : hcIn != Convect::HcInt::AdaptiveConvectionAlgorithm && hcIn != Convect::HcInt::ASTMC1340) {
744 0 : ShowWarningError(state,
745 0 : format("GetInsideConvectionAlgorithm: Invalid value for {}, defaulting to TARP, invalid value={}",
746 0 : state.dataHeatBalMgr->CurrentModuleObject,
747 : AlphaName(1)));
748 0 : hcIn = Convect::HcInt::ASHRAETARP;
749 : }
750 77 : state.dataHeatBal->DefaultIntConvAlgo = hcIn;
751 : } else {
752 : // default value, if not specified
753 127 : state.dataHeatBal->DefaultIntConvAlgo = Convect::HcInt::ASHRAETARP;
754 : }
755 204 : constexpr const char *Format_722("! <Inside Convection Algorithm>, Algorithm {{Simple | TARP | CeilingDiffuser | "
756 : "AdaptiveConvectionAlgorithm}}\nInside Convection Algorithm,{}\n");
757 204 : print(state.files.eio, Format_722, Convect::HcIntNames[static_cast<int>(state.dataHeatBal->DefaultIntConvAlgo)]);
758 :
759 : // Get only the first (if more were input)
760 204 : state.dataHeatBalMgr->CurrentModuleObject = "SurfaceConvectionAlgorithm:Outside";
761 204 : NumObjects = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, state.dataHeatBalMgr->CurrentModuleObject);
762 204 : if (NumObjects > 0) {
763 136 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
764 : "SurfaceConvectionAlgorithm:Outside",
765 : 1,
766 : AlphaName,
767 : NumAlpha,
768 : BuildingNumbers,
769 : NumNumber,
770 : IOStat,
771 68 : state.dataIPShortCut->lNumericFieldBlanks,
772 68 : state.dataIPShortCut->lAlphaFieldBlanks,
773 68 : state.dataIPShortCut->cAlphaFieldNames,
774 68 : state.dataIPShortCut->cNumericFieldNames);
775 :
776 68 : Convect::HcExt hcOut = static_cast<Convect::HcExt>(getEnumValue(Convect::HcExtNamesUC, AlphaName(1)));
777 :
778 68 : if (hcOut != Convect::HcExt::ASHRAESimple && hcOut != Convect::HcExt::ASHRAETARP && hcOut != Convect::HcExt::MoWiTTHcOutside &&
779 0 : hcOut != Convect::HcExt::DOE2HcOutside && hcOut != Convect::HcExt::AdaptiveConvectionAlgorithm) {
780 0 : ShowWarningError(state,
781 0 : format("GetOutsideConvectionAlgorithm: Invalid value for {}, defaulting to DOE-2, invalid value={}",
782 0 : state.dataHeatBalMgr->CurrentModuleObject,
783 : AlphaName(1)));
784 0 : hcOut = Convect::HcExt::DOE2HcOutside;
785 : }
786 68 : state.dataHeatBal->DefaultExtConvAlgo = hcOut;
787 : } else {
788 : // default value, if not specified
789 136 : state.dataHeatBal->DefaultExtConvAlgo = Convect::HcExt::DOE2HcOutside;
790 : }
791 :
792 204 : constexpr const char *Format_723("! <Outside Convection Algorithm>, Algorithm {{SimpleCombined | TARP | MoWitt | DOE-2 | "
793 : "AdaptiveConvectionAlgorithm}}\nOutside Convection Algorithm,{}\n");
794 204 : print(state.files.eio, Format_723, Convect::HcExtNames[static_cast<int>(state.dataHeatBal->DefaultExtConvAlgo)]);
795 :
796 204 : state.dataHeatBalMgr->CurrentModuleObject = "HeatBalanceAlgorithm";
797 204 : NumObjects = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, state.dataHeatBalMgr->CurrentModuleObject);
798 204 : if (NumObjects > 0) {
799 219 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
800 73 : state.dataHeatBalMgr->CurrentModuleObject,
801 : 1,
802 : AlphaName,
803 : NumAlpha,
804 : BuildingNumbers,
805 : NumNumber,
806 : IOStat,
807 73 : state.dataIPShortCut->lNumericFieldBlanks,
808 73 : state.dataIPShortCut->lAlphaFieldBlanks,
809 73 : state.dataIPShortCut->cAlphaFieldNames,
810 73 : state.dataIPShortCut->cNumericFieldNames);
811 :
812 : {
813 73 : std::string const &SELECT_CASE_var = AlphaName(1);
814 : // The default is CTF
815 73 : if (SELECT_CASE_var == "CONDUCTIONTRANSFERFUNCTION") {
816 67 : state.dataHeatBal->OverallHeatTransferSolutionAlgo = DataSurfaces::HeatTransferModel::CTF;
817 67 : state.dataHeatBal->AnyCTF = true;
818 :
819 6 : } else if (SELECT_CASE_var == "MOISTUREPENETRATIONDEPTHCONDUCTIONTRANSFERFUNCTION") {
820 2 : state.dataHeatBal->OverallHeatTransferSolutionAlgo = DataSurfaces::HeatTransferModel::EMPD;
821 2 : state.dataHeatBal->AnyEMPD = true;
822 2 : state.dataHeatBal->AllCTF = false;
823 4 : } else if (SELECT_CASE_var == "CONDUCTIONFINITEDIFFERENCE") {
824 3 : state.dataHeatBal->OverallHeatTransferSolutionAlgo = DataSurfaces::HeatTransferModel::CondFD;
825 3 : state.dataHeatBal->AnyCondFD = true;
826 3 : state.dataHeatBal->AllCTF = false;
827 3 : if (state.dataGlobal->TimeStepsInHour < 20) {
828 2 : ShowSevereError(
829 : state,
830 3 : format("GetSolutionAlgorithm: {} {} is Conduction Finite Difference but Number of TimeSteps in Hour < 20, Value is {}.",
831 1 : state.dataHeatBalMgr->CurrentModuleObject,
832 1 : state.dataIPShortCut->cAlphaFieldNames(1),
833 1 : state.dataGlobal->TimeStepsInHour));
834 3 : ShowContinueError(state,
835 : "...Suggested minimum number of time steps in hour for Conduction Finite Difference solutions is 20. "
836 : "Errors or inaccurate calculations may occur.");
837 : }
838 :
839 1 : } else if (SELECT_CASE_var == "COMBINEDHEATANDMOISTUREFINITEELEMENT") {
840 1 : state.dataHeatBal->OverallHeatTransferSolutionAlgo = DataSurfaces::HeatTransferModel::HAMT;
841 1 : state.dataHeatBal->AnyHAMT = true;
842 1 : state.dataHeatBal->AllCTF = false;
843 1 : if (state.dataGlobal->TimeStepsInHour < 20) {
844 2 : ShowSevereError(state,
845 3 : format("GetSolutionAlgorithm: {} {} is Combined Heat and Moisture Finite Element but Number of TimeSteps in "
846 : "Hour < 20, Value is {}.",
847 1 : state.dataHeatBalMgr->CurrentModuleObject,
848 1 : state.dataIPShortCut->cAlphaFieldNames(1),
849 1 : state.dataGlobal->TimeStepsInHour));
850 2 : ShowContinueError(state,
851 : "...Suggested minimum number of time steps in hour for Combined Heat and Moisture Finite Element solutions "
852 : "is 20. Errors or inaccurate calculations may occur.");
853 3 : ShowContinueError(state,
854 : "...If the simulation crashes, look at material properties (esp porosity), use timestep=60, or less layers "
855 : "in your constructions.");
856 : }
857 :
858 : } else {
859 0 : state.dataHeatBal->OverallHeatTransferSolutionAlgo = DataSurfaces::HeatTransferModel::CTF;
860 0 : state.dataHeatBal->AnyCTF = true;
861 : }
862 : }
863 :
864 73 : if (NumNumber > 0) {
865 7 : state.dataHeatBalSurf->MaxSurfaceTempLimit = BuildingNumbers(1);
866 7 : state.dataHeatBalSurf->MaxSurfaceTempLimitBeforeFatal = state.dataHeatBalSurf->MaxSurfaceTempLimit * 2.5;
867 7 : if (state.dataHeatBalSurf->MaxSurfaceTempLimit < DataHeatBalSurface::MinSurfaceTempLimit) {
868 7 : } else if (state.dataHeatBalSurf->MaxSurfaceTempLimit < 0.0) {
869 0 : state.dataHeatBalSurf->MaxSurfaceTempLimit = DataHeatBalSurface::DefaultSurfaceTempLimit;
870 0 : state.dataHeatBalSurf->MaxSurfaceTempLimitBeforeFatal = state.dataHeatBalSurf->MaxSurfaceTempLimit * 2.5;
871 : }
872 : }
873 :
874 73 : if (!state.dataIPShortCut->lNumericFieldBlanks(2)) {
875 1 : state.dataHeatBal->LowHConvLimit = BuildingNumbers(2);
876 : }
877 73 : if (!state.dataIPShortCut->lNumericFieldBlanks(3)) {
878 1 : state.dataHeatBal->HighHConvLimit = BuildingNumbers(3);
879 : }
880 :
881 : } else {
882 131 : state.dataHeatBal->OverallHeatTransferSolutionAlgo = DataSurfaces::HeatTransferModel::CTF;
883 131 : state.dataHeatBal->AnyCTF = true;
884 131 : state.dataHeatBalSurf->MaxSurfaceTempLimit = DataHeatBalSurface::DefaultSurfaceTempLimit;
885 131 : state.dataHeatBalSurf->MaxSurfaceTempLimitBeforeFatal = state.dataHeatBalSurf->MaxSurfaceTempLimit * 2.5;
886 : }
887 :
888 : // algorithm input checks now deferred until surface properties are read in,
889 : // moved to SurfaceGeometry.cc routine GetSurfaceHeatTransferAlgorithmOverrides
890 :
891 204 : constexpr const char *Format_724("! <Sky Radiance Distribution>, Value {{Anisotropic}}\nSky Radiance Distribution,Anisotropic\n");
892 204 : print(state.files.eio, Format_724);
893 :
894 204 : state.dataHeatBalMgr->CurrentModuleObject = "Compliance:Building";
895 204 : NumObjects = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, state.dataHeatBalMgr->CurrentModuleObject);
896 :
897 204 : if (NumObjects > 0) {
898 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
899 0 : state.dataHeatBalMgr->CurrentModuleObject,
900 : 1,
901 : AlphaName,
902 : NumAlpha,
903 : BuildingNumbers,
904 : NumNumber,
905 : IOStat,
906 0 : state.dataIPShortCut->lNumericFieldBlanks,
907 0 : state.dataIPShortCut->lAlphaFieldBlanks,
908 0 : state.dataIPShortCut->cAlphaFieldNames,
909 0 : state.dataIPShortCut->cNumericFieldNames);
910 : // Building Rotation for Appendix G
911 0 : state.dataHeatBal->BuildingRotationAppendixG = mod(BuildingNumbers(1), 360.0);
912 : }
913 :
914 : // A new object is added by L. Gu, 12/09
915 204 : state.dataHeatBalMgr->CurrentModuleObject = "ZoneAirHeatBalanceAlgorithm";
916 204 : NumObjects = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, state.dataHeatBalMgr->CurrentModuleObject);
917 204 : if (NumObjects > 0) {
918 69 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
919 23 : state.dataHeatBalMgr->CurrentModuleObject,
920 : 1,
921 : AlphaName,
922 : NumAlpha,
923 : BuildingNumbers,
924 : NumNumber,
925 : IOStat,
926 23 : state.dataIPShortCut->lNumericFieldBlanks,
927 23 : state.dataIPShortCut->lAlphaFieldBlanks,
928 23 : state.dataIPShortCut->cAlphaFieldNames,
929 23 : state.dataIPShortCut->cNumericFieldNames);
930 23 : if (NumAlpha > 0) {
931 : {
932 23 : std::string const &SELECT_CASE_var = AlphaName(1);
933 23 : if (SELECT_CASE_var == "THIRDORDERBACKWARDDIFFERENCE") {
934 9 : state.dataHeatBal->ZoneAirSolutionAlgo = DataHeatBalance::SolutionAlgo::ThirdOrder;
935 9 : AlphaName(1) = "ThirdOrderBackwardDifference";
936 14 : } else if (SELECT_CASE_var == "ANALYTICALSOLUTION") {
937 14 : state.dataHeatBal->ZoneAirSolutionAlgo = DataHeatBalance::SolutionAlgo::AnalyticalSolution;
938 14 : AlphaName(1) = "AnalyticalSolution";
939 0 : } else if (SELECT_CASE_var == "EULERMETHOD") {
940 0 : state.dataHeatBal->ZoneAirSolutionAlgo = DataHeatBalance::SolutionAlgo::EulerMethod;
941 0 : AlphaName(1) = "EulerMethod";
942 : } else {
943 0 : state.dataHeatBal->ZoneAirSolutionAlgo = DataHeatBalance::SolutionAlgo::ThirdOrder;
944 0 : AlphaName(1) = "ThirdOrderBackwardDifference";
945 0 : ShowWarningError(state,
946 0 : format("{}: Invalid input of {}. The default choice is assigned = {}",
947 0 : state.dataHeatBalMgr->CurrentModuleObject,
948 0 : state.dataIPShortCut->cAlphaFieldNames(1),
949 : AlphaName(1)));
950 0 : ShowContinueError(state, "Valid choices are: ThirdOrderBackwardDifference, AnalyticalSolution, or EulerMethod.");
951 : }
952 : }
953 : }
954 23 : if (!state.dataIPShortCut->lAlphaFieldBlanks(2)) {
955 8 : state.dataHeatBal->doSpaceHeatBalanceSizing = static_cast<bool>(getYesNoValue(AlphaName(2)));
956 : }
957 23 : if (!state.dataIPShortCut->lAlphaFieldBlanks(3)) {
958 9 : state.dataHeatBal->doSpaceHeatBalanceSimulation = static_cast<bool>(getYesNoValue(AlphaName(3)));
959 : }
960 : } else {
961 181 : state.dataHeatBal->ZoneAirSolutionAlgo = DataHeatBalance::SolutionAlgo::ThirdOrder;
962 181 : AlphaName(1) = "ThirdOrderBackwardDifference";
963 : }
964 204 : if (state.dataHeatBal->OverrideZoneAirSolutionAlgo) {
965 0 : state.dataHeatBal->ZoneAirSolutionAlgo = DataHeatBalance::SolutionAlgo::EulerMethod;
966 0 : AlphaName(1) = "EulerMethod";
967 : }
968 :
969 : // Write Solution Algorithm to the initialization output file for User Verification
970 204 : constexpr const char *Format_726("! <Zone Air Solution Algorithm>, Algorithm {{ThirdOrderBackwardDifference | AnalyticalSolution | "
971 : "EulerMethod}}, Space Heat Balance Sizing, Space Heat Balance Simulation\n");
972 204 : print(state.files.eio, Format_726);
973 204 : constexpr const char *Format_727(" Zone Air Solution Algorithm, {}, {}, {}\n");
974 204 : print(state.files.eio,
975 : Format_727,
976 : AlphaName(1),
977 204 : state.dataHeatBal->doSpaceHeatBalanceSizing ? "Yes" : "No",
978 204 : state.dataHeatBal->doSpaceHeatBalanceSimulation ? "Yes" : "No");
979 :
980 : // A new object is added by L. Gu, 06/10
981 204 : state.dataHeatBalMgr->CurrentModuleObject = "ZoneAirContaminantBalance";
982 204 : NumObjects = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, state.dataHeatBalMgr->CurrentModuleObject);
983 204 : if (NumObjects > 0) {
984 3 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
985 1 : state.dataHeatBalMgr->CurrentModuleObject,
986 : 1,
987 : AlphaName,
988 : NumAlpha,
989 : BuildingNumbers,
990 : NumNumber,
991 : IOStat,
992 1 : state.dataIPShortCut->lNumericFieldBlanks,
993 1 : state.dataIPShortCut->lAlphaFieldBlanks,
994 1 : state.dataIPShortCut->cAlphaFieldNames,
995 1 : state.dataIPShortCut->cNumericFieldNames);
996 :
997 1 : ErrorObjectHeader eoh{routineName, state.dataHeatBalMgr->CurrentModuleObject, state.dataHeatBalMgr->CurrentModuleObject};
998 :
999 1 : if (NumAlpha > 0) {
1000 : { // Why an extra nested scope here?
1001 1 : std::string const &SELECT_CASE_var = AlphaName(1);
1002 1 : if (SELECT_CASE_var == "YES") {
1003 0 : state.dataContaminantBalance->Contaminant.CO2Simulation = true;
1004 0 : state.dataContaminantBalance->Contaminant.SimulateContaminants = true;
1005 1 : } else if (SELECT_CASE_var == "NO") {
1006 1 : state.dataContaminantBalance->Contaminant.CO2Simulation = false;
1007 : } else {
1008 0 : state.dataContaminantBalance->Contaminant.CO2Simulation = false;
1009 0 : AlphaName(1) = "NO";
1010 0 : ShowWarningError(state,
1011 0 : format("{}: Invalid input of {}. The default choice is assigned = NO",
1012 0 : state.dataHeatBalMgr->CurrentModuleObject,
1013 0 : state.dataIPShortCut->cAlphaFieldNames(1)));
1014 : }
1015 : }
1016 : }
1017 :
1018 1 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
1019 0 : if (state.dataIPShortCut->lAlphaFieldBlanks(2)) {
1020 0 : ShowSevereEmptyField(state, eoh, state.dataIPShortCut->cAlphaFieldNames(2));
1021 0 : ErrorsFound = true;
1022 0 : } else if ((state.dataContaminantBalance->Contaminant.CO2OutdoorSched = Sched::GetSchedule(state, AlphaName(2))) == nullptr) {
1023 0 : ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(2), AlphaName(2));
1024 0 : ErrorsFound = true;
1025 : }
1026 : }
1027 :
1028 1 : if (NumAlpha > 2) {
1029 : {
1030 0 : std::string const &SELECT_CASE_var = AlphaName(3);
1031 0 : if (SELECT_CASE_var == "YES") {
1032 0 : state.dataContaminantBalance->Contaminant.GenericContamSimulation = true;
1033 0 : if (!state.dataContaminantBalance->Contaminant.CO2Simulation)
1034 0 : state.dataContaminantBalance->Contaminant.SimulateContaminants = true;
1035 0 : } else if (SELECT_CASE_var == "NO") {
1036 0 : state.dataContaminantBalance->Contaminant.GenericContamSimulation = false;
1037 : } else {
1038 0 : state.dataContaminantBalance->Contaminant.GenericContamSimulation = false;
1039 0 : AlphaName(3) = "NO";
1040 0 : ShowWarningError(state,
1041 0 : format("{}: Invalid input of {}. The default choice is assigned = NO",
1042 0 : state.dataHeatBalMgr->CurrentModuleObject,
1043 0 : state.dataIPShortCut->cAlphaFieldNames(3)));
1044 : }
1045 : }
1046 :
1047 0 : if (NumAlpha == 3 && state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
1048 0 : ShowSevereError(state,
1049 0 : format("{}, {} is required and not given.",
1050 0 : state.dataHeatBalMgr->CurrentModuleObject,
1051 0 : state.dataIPShortCut->cAlphaFieldNames(4)));
1052 0 : ErrorsFound = true;
1053 0 : } else if (NumAlpha > 3 && state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
1054 0 : if ((state.dataContaminantBalance->Contaminant.genericOutdoorSched = Sched::GetSchedule(state, AlphaName(4))) == nullptr) {
1055 0 : ShowSevereError(state,
1056 0 : format("{}, {} not found: {}",
1057 0 : state.dataHeatBalMgr->CurrentModuleObject,
1058 0 : state.dataIPShortCut->cAlphaFieldNames(4),
1059 : AlphaName(4)));
1060 0 : ErrorsFound = true;
1061 : }
1062 : }
1063 : }
1064 : } else {
1065 203 : state.dataContaminantBalance->Contaminant.SimulateContaminants = false;
1066 203 : state.dataContaminantBalance->Contaminant.CO2Simulation = false;
1067 203 : state.dataContaminantBalance->Contaminant.GenericContamSimulation = false;
1068 203 : AlphaName(1) = "NO";
1069 203 : AlphaName(3) = "NO";
1070 : }
1071 :
1072 204 : Window::initWindowModel(state);
1073 :
1074 204 : constexpr const char *Format_728("! <Zone Air Carbon Dioxide Balance Simulation>, Simulation {{Yes/No}}, Carbon Dioxide Concentration\n");
1075 204 : print(state.files.eio, Format_728);
1076 204 : constexpr const char *Format_730(" Zone Air Carbon Dioxide Balance Simulation, {},{}\n");
1077 204 : if (state.dataContaminantBalance->Contaminant.SimulateContaminants && state.dataContaminantBalance->Contaminant.CO2Simulation) {
1078 0 : print(state.files.eio, Format_730, "Yes", AlphaName(1));
1079 : } else {
1080 204 : print(state.files.eio, Format_730, "No", "N/A");
1081 : }
1082 :
1083 204 : constexpr const char *Format_729(
1084 : "! <Zone Air Generic Contaminant Balance Simulation>, Simulation {{Yes/No}}, Generic Contaminant Concentration\n");
1085 204 : constexpr const char *Format_731(" Zone Air Generic Contaminant Balance Simulation, {},{}\n");
1086 204 : print(state.files.eio, Format_729);
1087 204 : if (state.dataContaminantBalance->Contaminant.SimulateContaminants && state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
1088 0 : print(state.files.eio, Format_731, "Yes", AlphaName(3));
1089 : } else {
1090 204 : print(state.files.eio, Format_731, "No", "N/A");
1091 : }
1092 :
1093 : // A new object is added by B. Nigusse, 02/14
1094 204 : state.dataHeatBalMgr->CurrentModuleObject = "ZoneAirMassFlowConservation";
1095 204 : NumObjects = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, state.dataHeatBalMgr->CurrentModuleObject);
1096 204 : state.dataHeatBal->ZoneAirMassFlow.EnforceZoneMassBalance = false;
1097 :
1098 204 : if (NumObjects > 0) {
1099 39 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1100 13 : state.dataHeatBalMgr->CurrentModuleObject,
1101 : 1,
1102 : AlphaName,
1103 : NumAlpha,
1104 : BuildingNumbers,
1105 : NumNumber,
1106 : IOStat,
1107 13 : state.dataIPShortCut->lNumericFieldBlanks,
1108 13 : state.dataIPShortCut->lAlphaFieldBlanks,
1109 13 : state.dataIPShortCut->cAlphaFieldNames,
1110 13 : state.dataIPShortCut->cNumericFieldNames);
1111 13 : if (NumAlpha > 0) {
1112 : {
1113 13 : int FlowTypeNum = getEnumValue(DataHeatBalance::AdjustmentTypeNamesUC, Util::makeUPPER(AlphaName(1)));
1114 13 : state.dataHeatBal->ZoneAirMassFlow.ZoneFlowAdjustment = static_cast<DataHeatBalance::AdjustmentType>(FlowTypeNum);
1115 13 : AlphaName(1) = DataHeatBalance::AdjustmentTypeNamesCC[FlowTypeNum];
1116 13 : DataHeatBalance::AdjustmentType ZoneFlowAdjustment = state.dataHeatBal->ZoneAirMassFlow.ZoneFlowAdjustment;
1117 13 : if ((ZoneFlowAdjustment == DataHeatBalance::AdjustmentType::AdjustMixingOnly) ||
1118 7 : (ZoneFlowAdjustment == DataHeatBalance::AdjustmentType::AdjustReturnOnly) ||
1119 6 : (ZoneFlowAdjustment == DataHeatBalance::AdjustmentType::AdjustMixingThenReturn) ||
1120 : (ZoneFlowAdjustment == DataHeatBalance::AdjustmentType::AdjustReturnThenMixing)) {
1121 8 : state.dataHeatBal->ZoneAirMassFlow.EnforceZoneMassBalance = true;
1122 : }
1123 13 : if (state.dataHeatBal->ZoneAirMassFlow.ZoneFlowAdjustment == DataHeatBalance::AdjustmentType::Invalid) {
1124 0 : state.dataHeatBal->ZoneAirMassFlow.ZoneFlowAdjustment = DataHeatBalance::AdjustmentType::NoAdjustReturnAndMixing;
1125 0 : AlphaName(1) = "None";
1126 0 : ShowWarningError(state,
1127 0 : format("{}: Invalid input of {}. The default choice is assigned = None",
1128 0 : state.dataHeatBalMgr->CurrentModuleObject,
1129 0 : state.dataIPShortCut->cAlphaFieldNames(1)));
1130 : }
1131 : }
1132 13 : if (state.dataHeatBal->ZoneAirMassFlow.ZoneFlowAdjustment != DataHeatBalance::AdjustmentType::NoAdjustReturnAndMixing)
1133 8 : state.dataHeatBal->ZoneAirMassFlow.AdjustZoneMixingFlow = true;
1134 : }
1135 13 : if (NumAlpha > 1) {
1136 : {
1137 13 : int FlowTypeNum = getEnumValue(DataHeatBalance::InfiltrationFlowTypeNamesUC, Util::makeUPPER(AlphaName(2)));
1138 13 : state.dataHeatBal->ZoneAirMassFlow.InfiltrationTreatment = static_cast<DataHeatBalance::InfiltrationFlow>(FlowTypeNum);
1139 13 : AlphaName(2) = DataHeatBalance::InfiltrationFlowTypeNamesCC[FlowTypeNum];
1140 25 : if (state.dataHeatBal->ZoneAirMassFlow.InfiltrationTreatment == DataHeatBalance::InfiltrationFlow::Add ||
1141 12 : state.dataHeatBal->ZoneAirMassFlow.InfiltrationTreatment == DataHeatBalance::InfiltrationFlow::Adjust) {
1142 8 : state.dataHeatBal->ZoneAirMassFlow.EnforceZoneMassBalance = true;
1143 5 : } else if (state.dataHeatBal->ZoneAirMassFlow.InfiltrationTreatment == DataHeatBalance::InfiltrationFlow::Invalid) {
1144 0 : state.dataHeatBal->ZoneAirMassFlow.InfiltrationTreatment = DataHeatBalance::InfiltrationFlow::Add;
1145 0 : state.dataHeatBal->ZoneAirMassFlow.EnforceZoneMassBalance = true;
1146 0 : AlphaName(2) = "AddInfiltrationFlow";
1147 0 : ShowWarningError(state,
1148 0 : format("{}: Invalid input of {}. The default choice is assigned = AddInfiltrationFlow",
1149 0 : state.dataHeatBalMgr->CurrentModuleObject,
1150 0 : state.dataIPShortCut->cAlphaFieldNames(2)));
1151 : }
1152 : }
1153 : } else {
1154 0 : state.dataHeatBal->ZoneAirMassFlow.InfiltrationTreatment = DataHeatBalance::InfiltrationFlow::Add;
1155 0 : state.dataHeatBal->ZoneAirMassFlow.EnforceZoneMassBalance = true;
1156 0 : AlphaName(2) = "AddInfiltrationFlow";
1157 : }
1158 13 : if (state.dataHeatBal->ZoneAirMassFlow.InfiltrationTreatment == DataHeatBalance::InfiltrationFlow::No) {
1159 5 : AlphaName(3) = "N/A";
1160 : } else {
1161 8 : if (NumAlpha > 2) {
1162 : {
1163 8 : int FlowTypeNum = getEnumValue(DataHeatBalance::InfiltrationZoneTypeNamesUC, Util::makeUPPER(AlphaName(3)));
1164 8 : state.dataHeatBal->ZoneAirMassFlow.InfiltrationForZones = static_cast<DataHeatBalance::InfiltrationZoneType>(FlowTypeNum);
1165 8 : AlphaName(3) = DataHeatBalance::InfiltrationZoneTypeNamesCC[FlowTypeNum];
1166 8 : if (state.dataHeatBal->ZoneAirMassFlow.InfiltrationForZones == DataHeatBalance::InfiltrationZoneType::Invalid) {
1167 0 : state.dataHeatBal->ZoneAirMassFlow.InfiltrationForZones = DataHeatBalance::InfiltrationZoneType::MixingSourceZonesOnly;
1168 0 : AlphaName(3) = "MixingSourceZonesOnly";
1169 0 : ShowWarningError(state,
1170 0 : format("{}: Invalid input of {}. The default choice is assigned = MixingSourceZonesOnly",
1171 0 : state.dataHeatBalMgr->CurrentModuleObject,
1172 0 : state.dataIPShortCut->cAlphaFieldNames(3)));
1173 : }
1174 : }
1175 : } else {
1176 0 : state.dataHeatBal->ZoneAirMassFlow.InfiltrationForZones = DataHeatBalance::InfiltrationZoneType::MixingSourceZonesOnly;
1177 0 : AlphaName(3) = "MixingSourceZonesOnly";
1178 : }
1179 : }
1180 : } else {
1181 191 : state.dataHeatBal->ZoneAirMassFlow.EnforceZoneMassBalance = false;
1182 : }
1183 204 : if (state.dataHeatBal->ZoneAirMassFlow.InfiltrationTreatment != DataHeatBalance::InfiltrationFlow::No)
1184 8 : state.dataHeatBal->ZoneAirMassFlow.AdjustZoneInfiltrationFlow = true;
1185 :
1186 204 : constexpr const char *Format_732(
1187 : "! <Zone Air Mass Flow Balance Simulation>, Enforce Mass Balance, Adjust Zone Mixing and Return {{AdjustMixingOnly | AdjustReturnOnly | "
1188 : "AdjustMixingThenReturn | AdjustReturnThenMixing | None}}, Adjust Zone Infiltration "
1189 : "{{AddInfiltration | AdjustInfiltration | None}}, Infiltration Zones {{MixingSourceZonesOnly | AllZones}}\n");
1190 204 : constexpr const char *Format_733(" Zone Air Mass Flow Balance Simulation, {},{},{},{}\n");
1191 :
1192 204 : print(state.files.eio, Format_732);
1193 204 : if (state.dataHeatBal->ZoneAirMassFlow.EnforceZoneMassBalance) {
1194 9 : print(state.files.eio, Format_733, "Yes", AlphaName(1), AlphaName(2), AlphaName(3));
1195 : } else {
1196 195 : print(state.files.eio, Format_733, "No", "N/A", "N/A", "N/A");
1197 : }
1198 :
1199 : // A new object is added by L. Gu, 4/17
1200 204 : state.dataHeatBalMgr->CurrentModuleObject = "HVACSystemRootFindingAlgorithm";
1201 204 : NumObjects = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, state.dataHeatBalMgr->CurrentModuleObject);
1202 204 : if (NumObjects > 0) {
1203 6 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1204 2 : state.dataHeatBalMgr->CurrentModuleObject,
1205 : 1,
1206 : AlphaName,
1207 : NumAlpha,
1208 : BuildingNumbers,
1209 : NumNumber,
1210 : IOStat,
1211 2 : state.dataIPShortCut->lNumericFieldBlanks,
1212 2 : state.dataIPShortCut->lAlphaFieldBlanks,
1213 2 : state.dataIPShortCut->cAlphaFieldNames,
1214 2 : state.dataIPShortCut->cNumericFieldNames);
1215 2 : ErrorObjectHeader eoh{routineName, state.dataHeatBalMgr->CurrentModuleObject, AlphaName(1)};
1216 2 : if (NumAlpha > 0) {
1217 2 : HVACSystemRootFinding.Algorithm = AlphaName(1);
1218 2 : HVACSystemRootFinding.HVACSystemRootSolverMethod =
1219 2 : static_cast<HVACSystemRootSolverAlgorithm>(getEnumValue(HVACSystemRootSolverAlgorithmUC, Util::makeUPPER(AlphaName(1))));
1220 2 : if (HVACSystemRootFinding.HVACSystemRootSolverMethod == HVACSystemRootSolverAlgorithm::Invalid) {
1221 0 : HVACSystemRootFinding.HVACSystemRootSolverMethod = HVACSystemRootSolverAlgorithm::RegulaFalsi;
1222 0 : ShowWarningInvalidKey(
1223 0 : state, eoh, state.dataIPShortCut->cAlphaFieldNames(1), AlphaName(1), "Invalid input. The default choice is assigned.");
1224 0 : ShowContinueError(
1225 : state, "Valid choices are: RegulaFalsi, Bisection, BisectionThenRegulaFalsi, RegulaFalsiThenBisection, or Alternation.");
1226 : }
1227 : }
1228 2 : if (NumNumber > 0) {
1229 1 : HVACSystemRootFinding.NumOfIter = BuildingNumbers(1);
1230 : }
1231 : } else {
1232 202 : HVACSystemRootFinding.Algorithm = "RegulaFalsi";
1233 202 : HVACSystemRootFinding.HVACSystemRootSolverMethod = HVACSystemRootSolverAlgorithm::RegulaFalsi;
1234 : }
1235 :
1236 : // Write Solution Algorithm to the initialization output file for User Verification
1237 204 : constexpr const char *Format_734(
1238 : "! <HVACSystemRootFindingAlgorithm>, Value {{RegulaFalsi | Bisection | BisectionThenRegulaFalsi | RegulaFalsiThenBisection}}\n");
1239 204 : constexpr const char *Format_735(" HVACSystemRootFindingAlgorithm, {}\n");
1240 204 : print(state.files.eio, Format_734);
1241 204 : print(state.files.eio, Format_735, HVACSystemRootFinding.Algorithm);
1242 204 : }
1243 :
1244 116 : void GetSiteAtmosphereData(EnergyPlusData &state, bool &ErrorsFound)
1245 : {
1246 :
1247 : // SUBROUTINE INFORMATION:
1248 : // AUTHOR Peter Graham Ellis
1249 : // DATE WRITTEN January 2006
1250 :
1251 : // PURPOSE OF THIS SUBROUTINE:
1252 : // Reads the input data for the SITE ATMOSPHERIC VARIATION object.
1253 :
1254 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1255 116 : Array1D_string AlphArray(1); // Character string data
1256 116 : Array1D<Real64> NumArray(3); // Numeric data
1257 :
1258 : // Formats
1259 116 : constexpr const char *Format_720("Environment:Site Atmospheric Variation,{:.3R},{:.3R},{:.6R}\n");
1260 :
1261 116 : state.dataHeatBalMgr->CurrentModuleObject = "Site:HeightVariation";
1262 116 : int NumObjects = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, state.dataHeatBalMgr->CurrentModuleObject);
1263 :
1264 116 : if (NumObjects == 1) {
1265 : int NumAlphas; // Number of elements in the alpha array
1266 : int NumNums; // Number of elements in the numeric array
1267 : int IOStat; // IO Status when calling get input subroutine
1268 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1269 0 : state.dataHeatBalMgr->CurrentModuleObject,
1270 : 1,
1271 : AlphArray,
1272 : NumAlphas,
1273 : NumArray,
1274 : NumNums,
1275 : IOStat,
1276 0 : state.dataIPShortCut->lNumericFieldBlanks,
1277 0 : state.dataIPShortCut->lAlphaFieldBlanks,
1278 0 : state.dataIPShortCut->cAlphaFieldNames,
1279 0 : state.dataIPShortCut->cNumericFieldNames);
1280 :
1281 0 : if (NumNums > 0) state.dataEnvrn->SiteWindExp = NumArray(1);
1282 0 : if (NumNums > 1) state.dataEnvrn->SiteWindBLHeight = NumArray(2);
1283 0 : if (NumNums > 2) state.dataEnvrn->SiteTempGradient = NumArray(3);
1284 :
1285 116 : } else if (NumObjects > 1) {
1286 0 : ShowSevereError(state, format("Too many {} objects, only 1 allowed.", state.dataHeatBalMgr->CurrentModuleObject));
1287 0 : ErrorsFound = true;
1288 : } else { // None entered
1289 : // IDD defaults would have this:
1290 : // Building object defaults use Terrain to set SiteWindExp and SiteWindBLHeight but would
1291 : // be overridden by a Site Atmospheric Variation Object.
1292 : // SiteWindExp = 0.22
1293 : // SiteWindBLHeight = 370.0
1294 116 : state.dataEnvrn->SiteTempGradient = 0.0065;
1295 : }
1296 :
1297 : // Write to the initialization output file
1298 116 : print(state.files.eio,
1299 : "! <Environment:Site Atmospheric Variation>,Wind Speed Profile Exponent {{}},Wind Speed Profile Boundary "
1300 : "Layer Thickness {{m}},Air Temperature Gradient Coefficient {{K/m}}\n");
1301 :
1302 116 : print(state.files.eio, Format_720, state.dataEnvrn->SiteWindExp, state.dataEnvrn->SiteWindBLHeight, state.dataEnvrn->SiteTempGradient);
1303 116 : }
1304 :
1305 245 : void GetConstructData(EnergyPlusData &state, bool &ErrorsFound) // If errors found in input
1306 : {
1307 :
1308 : // SUBROUTINE INFORMATION:
1309 : // AUTHOR Richard Liesen
1310 : // DATE WRITTEN September 1997
1311 : // MODIFIED January 2003, FCW: accommodate between-glass shading device
1312 : // July 2009, TH: added constructions defined with F and C factors
1313 :
1314 : // PURPOSE OF THIS SUBROUTINE:
1315 : // This file reads the input through the input processor for Constructions.
1316 : // Data read in this routine is stored in a derived type (Construct)
1317 : // defined in the DataHeatBalance module.
1318 : // This subroutine only sets those parameters which must be obtained
1319 : // from the input file--all other portions of the Construct derived
1320 : // type are set during the initializations.
1321 :
1322 : // Using/Aliasing
1323 : using namespace DataStringGlobals;
1324 :
1325 : static constexpr std::string_view routineName = "GetConstructData";
1326 :
1327 : // If UniqueConstructionNames size, then input has already been gotten
1328 245 : if (state.dataHeatBalMgr->UniqueConstructNames.size()) return;
1329 :
1330 : int ConstructNumAlpha; // Number of construction alpha names being passed
1331 : int DummyNumProp; // dummy variable for properties being passed
1332 : int IOStat; // IO Status when calling get input subroutine
1333 245 : Array1D_string ConstructAlphas({0, Construction::MaxLayersInConstruct}); // Construction Alpha names defined
1334 245 : Array1D<Real64> DummyProps(5); // Temporary array to transfer construction properties
1335 : int TotRegConstructs; // Number of "regular" constructions (no embedded sources or sinks and
1336 :
1337 : int TotFfactorConstructs; // Number of slabs-on-grade or underground floor constructions defined with F factors
1338 : int TotCfactorConstructs; // Number of underground wall constructions defined with C factors
1339 :
1340 : // int TotSourceConstructs; // Number of constructions with embedded sources or sinks
1341 : int TotWindow5Constructs; // Number of constructions from Window5 data file
1342 : bool ConstructionFound; // True if input window construction name is found in the
1343 : // Window5 data file
1344 : bool EOFonW5File; // True if EOF encountered reading Window5 data file
1345 :
1346 245 : Array1D_string WConstructNames;
1347 :
1348 245 : auto &s_ipsc = state.dataIPShortCut;
1349 245 : auto &s_mat = state.dataMaterial;
1350 :
1351 : // Get the Total number of Constructions from the input
1352 245 : TotRegConstructs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Construction");
1353 245 : int totAirBoundaryConstructs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Construction:AirBoundary");
1354 :
1355 245 : TotFfactorConstructs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Construction:FfactorGroundFloor");
1356 245 : TotCfactorConstructs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Construction:CfactorUndergroundWall");
1357 :
1358 245 : if (TotFfactorConstructs > 0) {
1359 0 : state.dataHeatBal->NoFfactorConstructionsUsed = false;
1360 : }
1361 :
1362 245 : if (TotCfactorConstructs > 0) {
1363 0 : state.dataHeatBal->NoCfactorConstructionsUsed = false;
1364 : }
1365 :
1366 490 : state.dataBSDFWindow->TotComplexFenStates =
1367 245 : state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Construction:ComplexFenestrationState");
1368 245 : TotWindow5Constructs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Construction:WindowDataFile");
1369 490 : state.dataWindowEquivLayer->TotWinEquivLayerConstructs =
1370 245 : state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Construction:WindowEquivalentLayer");
1371 :
1372 245 : WConstructNames.allocate(TotWindow5Constructs);
1373 :
1374 980 : state.dataHeatBal->TotConstructs = TotRegConstructs + TotFfactorConstructs + TotCfactorConstructs + totAirBoundaryConstructs +
1375 245 : state.dataBSDFWindow->TotComplexFenStates + state.dataWindowEquivLayer->TotWinEquivLayerConstructs;
1376 :
1377 245 : state.dataHeatBal->NominalRforNominalUCalculation.dimension(state.dataHeatBal->TotConstructs, 0.0);
1378 245 : state.dataHeatBal->NominalU.dimension(state.dataHeatBal->TotConstructs, 0.0);
1379 245 : state.dataHeatBal->NominalUBeforeAdjusted.dimension(state.dataHeatBal->TotConstructs, 0.0);
1380 245 : state.dataHeatBal->CoeffAdjRatio.dimension(state.dataHeatBal->TotConstructs, 1.0);
1381 :
1382 : // Allocate the array to the number of constructions/initialize selected variables
1383 245 : state.dataConstruction->Construct.allocate(state.dataHeatBal->TotConstructs);
1384 245 : state.dataHeatBalMgr->UniqueConstructNames.reserve(state.dataHeatBal->TotConstructs);
1385 : // Note: If TotWindow5Constructs > 0, additional constructions are created in
1386 : // subr. SearchWindow5DataFile corresponding to those found on the data file.
1387 1040 : for (auto &e : state.dataConstruction->Construct) {
1388 : // Initialize CTF and History terms
1389 795 : e.NumCTFTerms = 0;
1390 795 : e.NumHistories = 0;
1391 :
1392 : // Initialize some heat source/sink variables
1393 795 : e.SourceSinkPresent = false; // "default" is no source or sink present
1394 795 : e.SolutionDimensions = 1; // "default" is 1-D heat transfer
1395 795 : e.SourceAfterLayer = 0; // this has no meaning if a source/sink is not present
1396 795 : e.TempAfterLayer = 0; // this has no meaning if a source/sink is not present
1397 795 : e.ThicknessPerpend = 0.0; // this has no meaning if a source/sink is not present
1398 :
1399 795 : e.W5FrameDivider = 0;
1400 795 : e.FromWindow5DataFile = false;
1401 :
1402 : // these Construct arrays dimensioned based on MaxSolidWinLayers
1403 795 : e.setArraysBasedOnMaxSolidWinLayers(state);
1404 : }
1405 :
1406 245 : int ConstrNum = 0;
1407 :
1408 245 : s_ipsc->cCurrentModuleObject = "Construction";
1409 1019 : for (int Loop = 1; Loop <= TotRegConstructs; ++Loop) { // Loop through all constructs in the input...
1410 :
1411 : // Get the object names for each construction from the input processor
1412 2322 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1413 774 : s_ipsc->cCurrentModuleObject,
1414 : Loop,
1415 : ConstructAlphas,
1416 : ConstructNumAlpha,
1417 : DummyProps,
1418 : DummyNumProp,
1419 : IOStat,
1420 774 : s_ipsc->lNumericFieldBlanks,
1421 774 : s_ipsc->lAlphaFieldBlanks,
1422 774 : s_ipsc->cAlphaFieldNames,
1423 774 : s_ipsc->cNumericFieldNames);
1424 :
1425 774 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, ConstructAlphas(1)};
1426 :
1427 1548 : if (GlobalNames::VerifyUniqueInterObjectName(state,
1428 774 : state.dataHeatBalMgr->UniqueConstructNames,
1429 774 : ConstructAlphas(0),
1430 774 : state.dataHeatBalMgr->CurrentModuleObject,
1431 774 : state.dataIPShortCut->cAlphaFieldNames(1),
1432 : ErrorsFound)) {
1433 0 : continue;
1434 : }
1435 :
1436 774 : ++ConstrNum;
1437 774 : auto &thisConstruct = state.dataConstruction->Construct(ConstrNum);
1438 : // Assign Construction name to the Derived Type using the zeroth position of the array
1439 774 : thisConstruct.Name = ConstructAlphas(0);
1440 :
1441 : // Set the total number of layers for the construction
1442 774 : thisConstruct.TotLayers = ConstructNumAlpha - 1;
1443 :
1444 : // Loop through all of the layers of the construct to match the material names.
1445 : // The loop index is the number minus 1
1446 :
1447 2167 : for (int GlassLayer = 0, Layer = 1; Layer <= ConstructNumAlpha - 1; ++Layer) {
1448 :
1449 : // Find the material in the list of materials
1450 1393 : thisConstruct.LayerPoint(Layer) = Material::GetMaterialNum(state, ConstructAlphas(Layer));
1451 :
1452 1393 : if (thisConstruct.LayerPoint(Layer) == 0) {
1453 15 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(Layer), ConstructAlphas(Layer));
1454 15 : ErrorsFound = true;
1455 15 : continue;
1456 : }
1457 :
1458 1378 : auto const *mat = s_mat->materials(thisConstruct.LayerPoint(Layer));
1459 1378 : if (mat->group == Material::Group::Glass) {
1460 135 : ++GlassLayer;
1461 1243 : } else if (mat->group == Material::Group::GlassEQL || mat->group == Material::Group::ShadeEQL ||
1462 1243 : mat->group == Material::Group::DrapeEQL || mat->group == Material::Group::BlindEQL ||
1463 1243 : mat->group == Material::Group::ScreenEQL || mat->group == Material::Group::WindowGapEQL) {
1464 0 : ShowSevereError(state, format("Invalid material layer type in window {} = {}", s_ipsc->cCurrentModuleObject, thisConstruct.Name));
1465 0 : ShowContinueError(
1466 : state,
1467 0 : format("Equivalent Layer material type = {} is allowed only in Construction:WindowEquivalentLayer window object.",
1468 : ConstructAlphas(Layer)));
1469 0 : ErrorsFound = true;
1470 0 : continue;
1471 1243 : } else if (mat->group == Material::Group::GlassTCParent) {
1472 0 : ++GlassLayer;
1473 : // reset layer pointer to the first glazing in the TC GlazingGroup
1474 0 : auto const *matGlassTC = dynamic_cast<Material::MaterialGlassTC const *>(mat);
1475 0 : assert(matGlassTC != nullptr);
1476 :
1477 0 : thisConstruct.LayerPoint(Layer) = matGlassTC->matRefs(1).matNum;
1478 0 : thisConstruct.isTCWindow = true;
1479 0 : thisConstruct.isTCMaster = true;
1480 0 : thisConstruct.TCMasterConstrNum = ConstrNum;
1481 0 : thisConstruct.TCMasterMatNum = matGlassTC->Num;
1482 0 : thisConstruct.TCGlassNum = GlassLayer; // the TC glass layer ID
1483 0 : thisConstruct.TCLayerNum = Layer;
1484 0 : thisConstruct.TypeIsWindow = true;
1485 : }
1486 :
1487 1378 : state.dataHeatBal->NominalRforNominalUCalculation(ConstrNum) += mat->NominalR;
1488 1378 : if (mat->group == Material::Group::Regular && !mat->ROnly) {
1489 958 : state.dataHeatBal->NoRegularMaterialsUsed = false;
1490 : }
1491 :
1492 : } // ...end of the Layer DO loop
1493 :
1494 : } // ...end of Regular Construction DO loop
1495 :
1496 245 : TotRegConstructs = ConstrNum;
1497 :
1498 : // Added TH 7/2009 for underground walls and floors constructions
1499 245 : if (TotFfactorConstructs + TotCfactorConstructs >= 1) {
1500 0 : CreateFCfactorConstructions(state, ConstrNum, ErrorsFound);
1501 0 : if (ErrorsFound) {
1502 0 : ShowSevereError(state, "Errors found in creating the constructions defined with Ffactor or Cfactor method");
1503 : }
1504 0 : TotRegConstructs += TotFfactorConstructs + TotCfactorConstructs;
1505 : }
1506 :
1507 245 : if (totAirBoundaryConstructs >= 1) {
1508 11 : CreateAirBoundaryConstructions(state, ConstrNum, ErrorsFound);
1509 11 : if (ErrorsFound) {
1510 3 : ShowSevereError(state, "Errors found in creating the constructions defined with Construction:AirBoundary.");
1511 : }
1512 11 : TotRegConstructs += totAirBoundaryConstructs;
1513 : }
1514 :
1515 : // Added BG 6/2010 for complex fenestration
1516 245 : if (state.dataBSDFWindow->TotComplexFenStates > 0) {
1517 1 : SetupComplexFenestrationStateInput(state, ConstrNum, ErrorsFound);
1518 1 : if (ErrorsFound) {
1519 0 : ShowSevereError(state, "Errors found in processing complex fenestration input");
1520 : }
1521 1 : TotRegConstructs += state.dataBSDFWindow->TotComplexFenStates;
1522 : }
1523 :
1524 245 : state.dataHeatBalMgr->CurrentModuleObject = "ConstructionProperty:InternalHeatSource";
1525 :
1526 245 : auto instances = state.dataInputProcessing->inputProcessor->epJSON.find(state.dataHeatBalMgr->CurrentModuleObject);
1527 245 : if (instances != state.dataInputProcessing->inputProcessor->epJSON.end()) {
1528 6 : state.dataHeatBal->AnyInternalHeatSourceInInput = true;
1529 6 : auto &instancesValue = instances.value();
1530 15 : for (auto instance = instancesValue.begin(); instance != instancesValue.end(); ++instance) {
1531 9 : auto const &fields = instance.value();
1532 9 : std::string const thisObjectName = Util::makeUPPER(instance.key());
1533 :
1534 18 : std::string construction_name = Util::makeUPPER(fields.at("construction_name").get<std::string>());
1535 18 : int source_after_layer_number = fields.at("thermal_source_present_after_layer_number").get<int>();
1536 18 : int calculation_after_layer_number = fields.at("temperature_calculation_requested_after_layer_number").get<int>();
1537 9 : int ctf_dimensions = fields.at("dimensions_for_the_ctf_calculation").get<int>();
1538 9 : if ((ctf_dimensions < 1) || (ctf_dimensions > 2)) {
1539 0 : ShowWarningError(state, "ConstructionProperty:InternalHeatSource must be either 1- or 2-D. Reset to 1-D solution.");
1540 0 : ShowContinueError(state, format("Construction={} is affected.", construction_name));
1541 0 : ctf_dimensions = 1;
1542 : }
1543 9 : Real64 tube_spacing = fields.at("tube_spacing").get<Real64>();
1544 9 : Real64 calculation_position = 0.0;
1545 9 : auto const twoDimTempCalcPos = fields.find("two_dimensional_temperature_calculation_position");
1546 9 : if (twoDimTempCalcPos != fields.end()) {
1547 8 : calculation_position = twoDimTempCalcPos.value().get<Real64>();
1548 : }
1549 :
1550 : // Find the construction
1551 9 : int construction_index = Util::FindItemInList(construction_name, state.dataConstruction->Construct);
1552 :
1553 9 : if (construction_index == 0) {
1554 0 : ShowSevereError(state,
1555 0 : format("Did not find matching construction for {} {}, missing construction = {}",
1556 0 : state.dataHeatBalMgr->CurrentModuleObject,
1557 : thisObjectName,
1558 : construction_name));
1559 0 : ErrorsFound = true;
1560 0 : continue;
1561 : }
1562 :
1563 9 : state.dataInputProcessing->inputProcessor->markObjectAsUsed(state.dataHeatBalMgr->CurrentModuleObject, instance.key());
1564 :
1565 9 : auto &thisConstruct = state.dataConstruction->Construct(construction_index);
1566 :
1567 : // May need some additional validation of the construction here
1568 9 : if (thisConstruct.SourceSinkPresent) {
1569 : // Emulate old behavior by disallowing two sources in a single material
1570 0 : ShowSevereError(
1571 : state,
1572 0 : format("Construction {} has more than one internal heat source referencing it, which is not allowed", construction_name));
1573 0 : ErrorsFound = true;
1574 0 : continue;
1575 : }
1576 :
1577 9 : thisConstruct.SourceSinkPresent = true;
1578 9 : thisConstruct.SourceAfterLayer = source_after_layer_number;
1579 9 : thisConstruct.TempAfterLayer = calculation_after_layer_number;
1580 9 : thisConstruct.SolutionDimensions = ctf_dimensions;
1581 9 : thisConstruct.ThicknessPerpend = thisConstruct.setThicknessPerpendicular(state, tube_spacing);
1582 9 : thisConstruct.userTemperatureLocationPerpendicular =
1583 9 : thisConstruct.setUserTemperatureLocationPerpendicular(state, calculation_position);
1584 :
1585 : // Set the total number of layers for the construction
1586 9 : if ((thisConstruct.SourceAfterLayer >= thisConstruct.TotLayers) || (thisConstruct.SourceAfterLayer <= 0)) {
1587 0 : ShowWarningError(state, format("Construction {} must have a source that is between two layers", thisConstruct.Name));
1588 0 : ShowContinueError(state, "The source after layer parameter has been set to one less than the number of layers.");
1589 0 : thisConstruct.SourceAfterLayer = thisConstruct.TotLayers - 1;
1590 : }
1591 9 : if ((thisConstruct.TempAfterLayer >= thisConstruct.TotLayers) || (thisConstruct.TempAfterLayer <= 0)) {
1592 0 : ShowWarningError(state,
1593 0 : format("Construction {} must have a temperature calculation that is between two layers", thisConstruct.Name));
1594 0 : ShowContinueError(state, "The temperature calculation after layer parameter has been set to one less than the number of layers.");
1595 0 : thisConstruct.TempAfterLayer = thisConstruct.TotLayers - 1;
1596 : }
1597 9 : }
1598 : }
1599 :
1600 245 : state.dataHeatBal->TotConstructs = TotRegConstructs;
1601 :
1602 256 : if (state.dataHeatBal->TotConstructs > 0 && (state.dataHeatBal->NoRegularMaterialsUsed && state.dataHeatBal->NoCfactorConstructionsUsed &&
1603 11 : state.dataHeatBal->NoFfactorConstructionsUsed)) {
1604 22 : ShowWarningError(state, "This building has no thermal mass which can cause an unstable solution.");
1605 33 : ShowContinueError(state, "Use Material object for all opaque material definitions except very light insulation layers.");
1606 : }
1607 :
1608 245 : ConstrNum = 0;
1609 245 : state.dataHeatBalMgr->CurrentModuleObject = "Construction:WindowEquivalentLayer";
1610 253 : for (int Loop = 1; Loop <= state.dataWindowEquivLayer->TotWinEquivLayerConstructs;
1611 : ++Loop) { // Loop through all constructs with Window EquivalentLayer ...
1612 :
1613 : // Get the object names for each construction from the input processor
1614 24 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1615 8 : state.dataHeatBalMgr->CurrentModuleObject,
1616 : Loop,
1617 : ConstructAlphas,
1618 : ConstructNumAlpha,
1619 : DummyProps,
1620 : DummyNumProp,
1621 : IOStat,
1622 8 : state.dataIPShortCut->lNumericFieldBlanks,
1623 8 : state.dataIPShortCut->lAlphaFieldBlanks,
1624 8 : state.dataIPShortCut->cAlphaFieldNames,
1625 8 : state.dataIPShortCut->cNumericFieldNames);
1626 16 : if (GlobalNames::VerifyUniqueInterObjectName(state,
1627 8 : state.dataHeatBalMgr->UniqueConstructNames,
1628 8 : ConstructAlphas(0),
1629 8 : state.dataHeatBalMgr->CurrentModuleObject,
1630 8 : state.dataIPShortCut->cAlphaFieldNames(1),
1631 : ErrorsFound)) {
1632 0 : continue;
1633 : }
1634 :
1635 8 : ++ConstrNum;
1636 8 : auto const &thisConstruct = state.dataConstruction->Construct(ConstrNum);
1637 : // Assign Construction name to the Derived Type using the zeroth position of the array
1638 8 : state.dataConstruction->Construct(TotRegConstructs + ConstrNum).Name = ConstructAlphas(0);
1639 :
1640 : // Set the total number of layers for the construction
1641 8 : state.dataConstruction->Construct(TotRegConstructs + ConstrNum).TotLayers = ConstructNumAlpha - 1;
1642 8 : if (state.dataConstruction->Construct(TotRegConstructs + ConstrNum).TotLayers < 1) {
1643 0 : ShowSevereError(state,
1644 0 : format("Construction {} must have at least a single layer",
1645 0 : state.dataConstruction->Construct(TotRegConstructs + ConstrNum).Name));
1646 0 : ErrorsFound = true;
1647 : }
1648 :
1649 : // Loop through all of the layers of the construct to match the material names.
1650 : // The loop index is the number minus 1
1651 38 : for (int Layer = 1; Layer <= ConstructNumAlpha - 1; ++Layer) {
1652 :
1653 : // Find the material in the list of materials
1654 30 : state.dataConstruction->Construct(TotRegConstructs + ConstrNum).LayerPoint(Layer) =
1655 30 : Material::GetMaterialNum(state, ConstructAlphas(Layer));
1656 :
1657 30 : if (state.dataConstruction->Construct(TotRegConstructs + ConstrNum).LayerPoint(Layer) == 0) {
1658 0 : ShowSevereError(state,
1659 0 : format("Did not find matching material for {} {}, missing material = {}",
1660 0 : state.dataHeatBalMgr->CurrentModuleObject,
1661 0 : thisConstruct.Name,
1662 : ConstructAlphas(Layer)));
1663 0 : ErrorsFound = true;
1664 : } else {
1665 30 : auto const *mat = s_mat->materials(state.dataConstruction->Construct(TotRegConstructs + ConstrNum).LayerPoint(Layer));
1666 30 : if (!((mat->group == Material::Group::GlassEQL) || (mat->group == Material::Group::ShadeEQL) ||
1667 16 : (mat->group == Material::Group::DrapeEQL) || (mat->group == Material::Group::BlindEQL) ||
1668 12 : (mat->group == Material::Group::ScreenEQL) || (mat->group == Material::Group::WindowGapEQL))) {
1669 2 : ShowSevereError(state,
1670 2 : format("Invalid material layer type in window {} = {}",
1671 1 : state.dataHeatBalMgr->CurrentModuleObject,
1672 1 : state.dataConstruction->Construct(TotRegConstructs + ConstrNum).Name));
1673 2 : ShowContinueError(state,
1674 2 : format("...Window layer = {} is not allowed in Construction:WindowEquivalentLayer window object.",
1675 : ConstructAlphas(Layer)));
1676 2 : ShowContinueError(state, "Only materials of type Material:*:EquivalentLayer are allowed");
1677 1 : ErrorsFound = true;
1678 : }
1679 :
1680 30 : if (ConstructNumAlpha <= 2) {
1681 :
1682 : } else {
1683 29 : auto const *mat = s_mat->materials(state.dataConstruction->Construct(TotRegConstructs + ConstrNum).LayerPoint(Layer));
1684 29 : state.dataHeatBal->NominalRforNominalUCalculation(TotRegConstructs + ConstrNum) += mat->NominalR;
1685 : }
1686 : }
1687 :
1688 : } // Layer loop
1689 8 : state.dataConstruction->Construct(TotRegConstructs + ConstrNum).EQLConsPtr = ConstrNum;
1690 8 : state.dataConstruction->Construct(TotRegConstructs + ConstrNum).WindowTypeEQL = true;
1691 : } // TotWinEquivLayerConstructs loop
1692 :
1693 245 : state.dataWindowEquivLayer->TotWinEquivLayerConstructs = ConstrNum;
1694 245 : TotRegConstructs += state.dataWindowEquivLayer->TotWinEquivLayerConstructs;
1695 245 : state.dataHeatBal->TotConstructs = TotRegConstructs;
1696 : //-------------------------------------------------------------------------------
1697 245 : ConstrNum = 0;
1698 :
1699 245 : state.dataHeatBalMgr->CurrentModuleObject = "Construction:WindowDataFile";
1700 245 : for (int Loop = 1; Loop <= TotWindow5Constructs; ++Loop) { // Loop through all Window5 constructions. These constructions come
1701 : // from the Window5 data file and can be referenced only by windows
1702 :
1703 : // Get the object names for each construction from the input processor
1704 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1705 0 : state.dataHeatBalMgr->CurrentModuleObject,
1706 : Loop,
1707 : ConstructAlphas,
1708 : ConstructNumAlpha,
1709 : DummyProps,
1710 : DummyNumProp,
1711 : IOStat,
1712 0 : state.dataIPShortCut->lNumericFieldBlanks,
1713 0 : state.dataIPShortCut->lAlphaFieldBlanks,
1714 0 : state.dataIPShortCut->cAlphaFieldNames,
1715 0 : state.dataIPShortCut->cNumericFieldNames);
1716 :
1717 0 : ++ConstrNum;
1718 0 : WConstructNames(ConstrNum) = ConstructAlphas(0);
1719 :
1720 : // Obtain the data
1721 0 : if (DummyNumProp != 0) {
1722 0 : ShowSevereError(state, format("Construction From Window5 Data File: there should be no numerical inputs for {}", ConstructAlphas(0)));
1723 0 : ErrorsFound = true;
1724 0 : continue;
1725 : }
1726 :
1727 : // See if this construction is in the W5DataFile produced by the WINDOW 5 program;
1728 : // if so, ConstructionFound will be set to true and the Material objects
1729 : // associated with the construction will be created in subr. SearchWindow5DataFile.
1730 : // (If the matching construction on the Window5 data file has two glazing systems, a
1731 : // second construction and its associated materials will be created in subr.
1732 : // SearchWindow5DataFile and TotConstructs WILL BE INCREMENTED BY 1 in that routine.
1733 : // A FrameAndDivider object will also be created if window on data file has a
1734 : // frame or divider.)
1735 :
1736 0 : fs::path window5DataFilePath;
1737 0 : if (ConstructAlphas(1) == "") {
1738 0 : window5DataFilePath = state.dataStrGlobals->CurrentWorkingFolder / "Window5DataFile.dat";
1739 : } else {
1740 0 : window5DataFilePath = ConstructAlphas(1);
1741 : }
1742 0 : DisplayString(state, "Searching Window5 data file for Construction=" + ConstructAlphas(0));
1743 :
1744 0 : SearchWindow5DataFile(state, window5DataFilePath, ConstructAlphas(0), ConstructionFound, EOFonW5File, ErrorsFound);
1745 :
1746 0 : if (EOFonW5File || !ConstructionFound) {
1747 0 : DisplayString(state, "--Construction not found");
1748 0 : ErrorsFound = true;
1749 0 : ShowSevereError(state, format("No match on WINDOW5 data file for Construction={}, or error in data file.", ConstructAlphas(0)));
1750 0 : ShowContinueError(state, format("...Looking on file={}", window5DataFilePath)); // TODO: call getAbsolutePath maybe?
1751 0 : continue;
1752 : }
1753 :
1754 0 : } // ...end of Window5 Constructions DO loop
1755 :
1756 245 : WConstructNames.deallocate();
1757 :
1758 : // set some (default) properties of the Construction Derived Type
1759 1040 : for (int ConstrNum = 1; ConstrNum <= state.dataHeatBal->TotConstructs; ++ConstrNum) {
1760 :
1761 795 : auto &thisConstruct = state.dataConstruction->Construct(ConstrNum);
1762 : // For air boundaries, skip TypeIsAirBoundary
1763 795 : if (thisConstruct.TypeIsAirBoundary) continue;
1764 783 : if (state.dataHeatBal->NominalRforNominalUCalculation(ConstrNum) != 0.0) {
1765 779 : state.dataHeatBal->NominalU(ConstrNum) = 1.0 / state.dataHeatBal->NominalRforNominalUCalculation(ConstrNum);
1766 : } else {
1767 4 : if (!thisConstruct.WindowTypeEQL) {
1768 3 : ShowSevereError(state, format("Nominal U is zero, for construction={}", thisConstruct.Name));
1769 3 : ErrorsFound = true;
1770 : }
1771 : }
1772 :
1773 783 : DataHeatBalance::CheckAndSetConstructionProperties(state, ConstrNum, ErrorsFound);
1774 :
1775 : } // End of ConstrNum DO loop
1776 245 : }
1777 :
1778 125 : void GetBuildingData(EnergyPlusData &state, bool &ErrorsFound) // If errors found in input
1779 : {
1780 :
1781 : // SUBROUTINE INFORMATION:
1782 : // AUTHOR Linda K. Lawrie
1783 : // DATE WRITTEN November 1997
1784 : // MODIFIED October 1998, FW; May 1999 FW; Oct 2004 LKL
1785 :
1786 : // PURPOSE OF THIS SUBROUTINE:
1787 : // This routine calls other routines to get the Zone, and Surface data
1788 : // from the input file.
1789 :
1790 : // METHODOLOGY EMPLOYED:
1791 : // The GetObjectItem routines are employed to retrieve the data.
1792 :
1793 125 : SolarShading::GetShadowingInput(state);
1794 :
1795 125 : GetZoneData(state, ErrorsFound); // Read Zone data from input file
1796 :
1797 125 : SurfaceGeometry::SetupZoneGeometry(state, ErrorsFound);
1798 125 : }
1799 :
1800 451 : void GetZoneData(EnergyPlusData &state, bool &ErrorsFound) // If errors found in input
1801 : {
1802 :
1803 : // SUBROUTINE INFORMATION:
1804 : // AUTHOR Linda K. Lawrie
1805 : // DATE WRITTEN November 1997
1806 : // MODIFIED PGE: Added ZONE LIST and ZONE GROUP objects, Nov 2003
1807 : // RJH: Added init of DElight member of ZoneDaylight object, Jan 2004
1808 : // JG: Added Part of Total Floor Area field March 2006
1809 :
1810 : // PURPOSE OF THIS SUBROUTINE:
1811 : // This subroutine gets the zone data for each zone in the input file.
1812 :
1813 : // METHODOLOGY EMPLOYED:
1814 : // The GetObjectItem routines are employed to retrieve the data.
1815 :
1816 : // REFERENCES:
1817 : // IDD Definition for Zone object
1818 :
1819 : // SUBROUTINE PARAMETER DEFINITIONS:
1820 451 : constexpr const char *RoutineName("GetZoneData: ");
1821 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1822 : int NumAlphas;
1823 : int NumNumbers;
1824 : int IOStatus;
1825 : std::string::size_type TMP;
1826 : int ZoneNum;
1827 451 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
1828 451 : cCurrentModuleObject = "Zone";
1829 451 : state.dataGlobal->NumOfZones = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
1830 :
1831 451 : state.dataHeatBal->Zone.allocate(state.dataGlobal->NumOfZones);
1832 451 : state.dataDayltg->ZoneDaylight.allocate(state.dataGlobal->NumOfZones);
1833 : // always allocate as the data structure is needed in output variable Zone Heat Index, Zone Humidity Index
1834 451 : state.dataHeatBal->Resilience.allocate(state.dataGlobal->NumOfZones);
1835 :
1836 451 : int ZoneLoop = 0;
1837 :
1838 1147 : for (int Loop = 1; Loop <= state.dataGlobal->NumOfZones; ++Loop) {
1839 :
1840 696 : state.dataIPShortCut->rNumericArgs = 0.0; // Zero out just in case
1841 1392 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1842 : cCurrentModuleObject,
1843 : Loop,
1844 696 : state.dataIPShortCut->cAlphaArgs,
1845 : NumAlphas,
1846 696 : state.dataIPShortCut->rNumericArgs,
1847 : NumNumbers,
1848 : IOStatus,
1849 696 : state.dataIPShortCut->lNumericFieldBlanks,
1850 696 : state.dataIPShortCut->lAlphaFieldBlanks,
1851 696 : state.dataIPShortCut->cAlphaFieldNames,
1852 696 : state.dataIPShortCut->cNumericFieldNames);
1853 696 : TMP = index(state.dataIPShortCut->cAlphaArgs(1), char(1));
1854 696 : while (TMP != std::string::npos) {
1855 0 : state.dataIPShortCut->cAlphaArgs(1)[TMP] = ',';
1856 0 : TMP = index(state.dataIPShortCut->cAlphaArgs(1), char(1));
1857 : }
1858 696 : TMP = index(state.dataIPShortCut->cAlphaArgs(1), char(2));
1859 696 : while (TMP != std::string::npos) {
1860 0 : state.dataIPShortCut->cAlphaArgs(1)[TMP] = '!';
1861 0 : TMP = index(state.dataIPShortCut->cAlphaArgs(1), char(2));
1862 : }
1863 :
1864 696 : if (Util::IsNameEmpty(state, state.dataIPShortCut->cAlphaArgs(1), state.dataHeatBalMgr->CurrentModuleObject, ErrorsFound)) continue;
1865 :
1866 696 : ++ZoneLoop;
1867 2088 : ProcessZoneData(state,
1868 : cCurrentModuleObject,
1869 : ZoneLoop,
1870 696 : state.dataIPShortCut->cAlphaArgs,
1871 : NumAlphas,
1872 696 : state.dataIPShortCut->rNumericArgs,
1873 : NumNumbers,
1874 696 : state.dataIPShortCut->lNumericFieldBlanks,
1875 696 : state.dataIPShortCut->lAlphaFieldBlanks,
1876 696 : state.dataIPShortCut->cAlphaFieldNames,
1877 696 : state.dataIPShortCut->cNumericFieldNames,
1878 : ErrorsFound);
1879 :
1880 : } // Loop
1881 :
1882 1147 : for (int Loop = 1; Loop <= state.dataGlobal->NumOfZones; ++Loop) {
1883 : // Check to see if "nominally" controlled -- Zone Name appears in Zone Equip Configuration
1884 : // relies on zone name being the "name" of the Zone Controlled Equip Configuration
1885 2088 : if (state.dataInputProcessing->inputProcessor->getObjectItemNum(
1886 1392 : state, "ZoneHVAC:EquipmentConnections", "zone_name", state.dataHeatBal->Zone(Loop).Name) > 0) {
1887 320 : state.dataHeatBal->Zone(Loop).isNominalControlled = true;
1888 : } else {
1889 376 : state.dataHeatBal->Zone(Loop).isNominalControlled = false;
1890 : }
1891 : }
1892 :
1893 : // Get ZONE LIST objects
1894 451 : cCurrentModuleObject = "ZoneList";
1895 451 : state.dataHeatBal->NumOfZoneLists = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
1896 :
1897 451 : if (state.dataHeatBal->NumOfZoneLists > 0) {
1898 :
1899 18 : state.dataHeatBal->ZoneList.allocate(state.dataHeatBal->NumOfZoneLists);
1900 :
1901 40 : for (int ListNum = 1; ListNum <= state.dataHeatBal->NumOfZoneLists; ++ListNum) {
1902 44 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1903 : cCurrentModuleObject,
1904 : ListNum,
1905 22 : state.dataIPShortCut->cAlphaArgs,
1906 : NumAlphas,
1907 22 : state.dataIPShortCut->rNumericArgs,
1908 : NumNumbers,
1909 : IOStatus,
1910 22 : state.dataIPShortCut->lNumericFieldBlanks,
1911 22 : state.dataIPShortCut->lAlphaFieldBlanks,
1912 22 : state.dataIPShortCut->cAlphaFieldNames,
1913 22 : state.dataIPShortCut->cNumericFieldNames);
1914 :
1915 22 : state.dataHeatBal->ZoneList(ListNum).Name = state.dataIPShortCut->cAlphaArgs(1);
1916 22 : if (Util::FindItemInList(state.dataHeatBal->ZoneList(ListNum).Name, state.dataHeatBal->Zone) > 0) {
1917 0 : ShowWarningError(
1918 : state,
1919 0 : format(
1920 0 : "{}{}=\"{}\": is a duplicate of a zone name.", RoutineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
1921 0 : ShowContinueError(state, "This could be a problem in places where either a Zone Name or a Zone List can be used.");
1922 : }
1923 :
1924 : // List of zones
1925 22 : state.dataHeatBal->ZoneList(ListNum).NumOfZones = NumAlphas - 1;
1926 :
1927 22 : if (state.dataHeatBal->ZoneList(ListNum).NumOfZones < 1) {
1928 0 : ShowSevereError(
1929 0 : state, format("{}{}=\"{}\": No zones specified.", RoutineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
1930 0 : ErrorsFound = true;
1931 : } else {
1932 22 : state.dataHeatBal->ZoneList(ListNum).Zone.allocate(state.dataHeatBal->ZoneList(ListNum).NumOfZones);
1933 22 : state.dataHeatBal->ZoneList(ListNum).Zone = 0;
1934 :
1935 89 : for (ZoneNum = 1; ZoneNum <= state.dataHeatBal->ZoneList(ListNum).NumOfZones; ++ZoneNum) {
1936 67 : std::string ZoneName = state.dataIPShortCut->cAlphaArgs(ZoneNum + 1);
1937 67 : state.dataHeatBal->ZoneList(ListNum).MaxZoneNameLength =
1938 67 : max(state.dataHeatBal->ZoneList(ListNum).MaxZoneNameLength, len(ZoneName));
1939 67 : state.dataHeatBal->ZoneList(ListNum).Zone(ZoneNum) = Util::FindItemInList(ZoneName, state.dataHeatBal->Zone);
1940 67 : if (state.dataHeatBal->ZoneList(ListNum).Zone(ZoneNum) == 0) {
1941 0 : ShowSevereError(state,
1942 0 : format("{}{}=\"{}\": {} {} not found.",
1943 : RoutineName,
1944 : cCurrentModuleObject,
1945 0 : state.dataIPShortCut->cAlphaArgs(1),
1946 0 : state.dataIPShortCut->cAlphaFieldNames(ZoneNum + 1),
1947 : ZoneName));
1948 0 : ErrorsFound = true;
1949 : }
1950 :
1951 : // Check for duplicate zones
1952 238 : for (int Loop = 1; Loop <= ZoneNum - 1; ++Loop) {
1953 171 : if (state.dataHeatBal->ZoneList(ListNum).Zone(ZoneNum) == state.dataHeatBal->ZoneList(ListNum).Zone(Loop)) {
1954 0 : ShowSevereError(state,
1955 0 : format("{}{}=\"{}\": {} {} appears more than once in list.",
1956 : RoutineName,
1957 : cCurrentModuleObject,
1958 0 : state.dataIPShortCut->cAlphaArgs(1),
1959 0 : state.dataIPShortCut->cAlphaFieldNames(ZoneNum + 1),
1960 : ZoneName));
1961 0 : ErrorsFound = true;
1962 : }
1963 : } // Loop
1964 67 : } // ZoneNum
1965 : }
1966 :
1967 : } // ListNum
1968 : }
1969 :
1970 : // Get ZONE GROUP objects
1971 451 : cCurrentModuleObject = "ZoneGroup";
1972 451 : state.dataHeatBal->NumOfZoneGroups = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
1973 :
1974 451 : if (state.dataHeatBal->NumOfZoneGroups > 0) {
1975 11 : state.dataHeatBal->ZoneGroup.allocate(state.dataHeatBal->NumOfZoneGroups);
1976 :
1977 22 : for (int GroupNum = 1; GroupNum <= state.dataHeatBal->NumOfZoneGroups; ++GroupNum) {
1978 22 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1979 : cCurrentModuleObject,
1980 : GroupNum,
1981 11 : state.dataIPShortCut->cAlphaArgs,
1982 : NumAlphas,
1983 11 : state.dataIPShortCut->rNumericArgs,
1984 : NumNumbers,
1985 : IOStatus,
1986 11 : state.dataIPShortCut->lNumericFieldBlanks,
1987 11 : state.dataIPShortCut->lAlphaFieldBlanks,
1988 11 : state.dataIPShortCut->cAlphaFieldNames,
1989 11 : state.dataIPShortCut->cNumericFieldNames);
1990 :
1991 11 : state.dataHeatBal->ZoneGroup(GroupNum).Name = state.dataIPShortCut->cAlphaArgs(1);
1992 :
1993 : // Multiplier - checked already by IDD rules
1994 11 : state.dataHeatBal->ZoneGroup(GroupNum).Multiplier = state.dataIPShortCut->rNumericArgs(1);
1995 :
1996 : // Zone list
1997 11 : int ListNum = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(2), state.dataHeatBal->ZoneList);
1998 11 : state.dataHeatBal->ZoneGroup(GroupNum).ZoneList = ListNum;
1999 :
2000 11 : if (ListNum == 0) {
2001 0 : ShowSevereError(state,
2002 0 : format("{}{}=\"{}\": {} named {} not found.",
2003 : RoutineName,
2004 : cCurrentModuleObject,
2005 0 : state.dataIPShortCut->cAlphaArgs(1),
2006 0 : state.dataIPShortCut->cAlphaFieldNames(2),
2007 0 : state.dataIPShortCut->cAlphaArgs(2)));
2008 0 : ErrorsFound = true;
2009 : } else {
2010 : // Check to make sure list is not in use by another ZONE GROUP
2011 11 : for (int Loop = 1; Loop <= GroupNum - 1; ++Loop) {
2012 0 : if (state.dataHeatBal->ZoneGroup(GroupNum).ZoneList == state.dataHeatBal->ZoneGroup(Loop).ZoneList) {
2013 0 : ShowSevereError(state,
2014 0 : format("{}{}=\"{}\": {} already used by {} named {}.",
2015 : RoutineName,
2016 : cCurrentModuleObject,
2017 0 : state.dataIPShortCut->cAlphaArgs(1),
2018 0 : state.dataIPShortCut->cAlphaFieldNames(2),
2019 : cCurrentModuleObject,
2020 0 : state.dataHeatBal->ZoneGroup(Loop).Name));
2021 0 : ErrorsFound = true;
2022 : }
2023 : } // Loop
2024 :
2025 : // Set group multiplier for each zone in the list
2026 22 : for (int Loop = 1; Loop <= state.dataHeatBal->ZoneList(ListNum).NumOfZones; ++Loop) {
2027 11 : ZoneNum = state.dataHeatBal->ZoneList(ListNum).Zone(Loop);
2028 :
2029 11 : if (ZoneNum > 0) {
2030 : // Check to make sure group multiplier was not already set by another ZONE GROUP
2031 11 : if (state.dataHeatBal->Zone(ZoneNum).ListGroup == 0) {
2032 11 : state.dataHeatBal->Zone(ZoneNum).ListMultiplier = state.dataHeatBal->ZoneGroup(GroupNum).Multiplier;
2033 11 : state.dataHeatBal->Zone(ZoneNum).ListGroup = ListNum;
2034 : } else {
2035 0 : ShowSevereError(state,
2036 0 : format("{}{}=\"{}\": Zone {} in ZoneList already exists in ZoneList of another ZoneGroup.",
2037 : RoutineName,
2038 : cCurrentModuleObject,
2039 0 : state.dataIPShortCut->cAlphaArgs(1),
2040 0 : state.dataHeatBal->Zone(ZoneNum).Name));
2041 0 : ShowContinueError(
2042 : state,
2043 0 : format("Previous ZoneList={}", state.dataHeatBal->ZoneList(state.dataHeatBal->Zone(ZoneNum).ListGroup).Name));
2044 0 : ErrorsFound = true;
2045 : }
2046 : }
2047 : } // Loop
2048 : }
2049 :
2050 : } // GroupNum
2051 : }
2052 :
2053 451 : GetZoneLocalEnvData(state, ErrorsFound);
2054 :
2055 : // allocate the array the holds the predefined report data
2056 451 : state.dataHeatBal->ZonePreDefRep.allocate(state.dataGlobal->NumOfZones);
2057 :
2058 : // Now get Space data after Zones are set up, because Space is optional, Zones are not
2059 451 : GetSpaceData(state, ErrorsFound);
2060 451 : }
2061 :
2062 122 : void GetIncidentSolarMultiplier(EnergyPlusData &state, bool &ErrorsFound)
2063 : {
2064 : static constexpr std::string_view RoutineName("GetIncidentSolarMultiplier: ");
2065 : static constexpr std::string_view routineName = "GetIncidentSolarMultiplier";
2066 :
2067 122 : auto &s_mat = state.dataMaterial;
2068 122 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
2069 122 : cCurrentModuleObject = "SurfaceProperty:IncidentSolarMultiplier";
2070 :
2071 122 : state.dataSurface->TotSurfIncSolMultiplier = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
2072 :
2073 122 : if (state.dataSurface->TotSurfIncSolMultiplier <= 0) return;
2074 :
2075 6 : if (!allocated(state.dataSurface->SurfIncSolMultiplier)) {
2076 : // could be extended to interior surfaces later
2077 2 : state.dataSurface->SurfIncSolMultiplier.allocate(state.dataSurface->TotSurfaces);
2078 : }
2079 :
2080 : int NumAlpha;
2081 : int NumNumeric;
2082 : int IOStat;
2083 12 : for (int Loop = 1; Loop <= state.dataSurface->TotSurfIncSolMultiplier; ++Loop) {
2084 12 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
2085 : cCurrentModuleObject,
2086 : Loop,
2087 6 : state.dataIPShortCut->cAlphaArgs,
2088 : NumAlpha,
2089 6 : state.dataIPShortCut->rNumericArgs,
2090 : NumNumeric,
2091 : IOStat,
2092 6 : state.dataIPShortCut->lNumericFieldBlanks,
2093 6 : state.dataIPShortCut->lAlphaFieldBlanks,
2094 6 : state.dataIPShortCut->cAlphaFieldNames,
2095 6 : state.dataIPShortCut->cNumericFieldNames);
2096 :
2097 6 : ErrorObjectHeader eoh{routineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)};
2098 :
2099 : // Assign surface number
2100 6 : int SurfNum = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(1), state.dataSurface->Surface);
2101 6 : if (SurfNum == 0) {
2102 0 : ShowSevereError(state,
2103 0 : format("{}{}=\"{}, object. Illegal value for {} has been found.",
2104 : RoutineName,
2105 : cCurrentModuleObject,
2106 0 : state.dataIPShortCut->cAlphaArgs(1),
2107 0 : state.dataIPShortCut->cAlphaFieldNames(1)));
2108 0 : ShowContinueError(
2109 : state,
2110 0 : format("{} entered value = \"{}\" no corresponding surface (ref BuildingSurface:Detailed) has been found in the input file.",
2111 0 : state.dataIPShortCut->cAlphaFieldNames(1),
2112 0 : state.dataIPShortCut->cAlphaArgs(1)));
2113 0 : ErrorsFound = true;
2114 4 : continue;
2115 : }
2116 6 : auto &Surf = state.dataSurface->Surface(SurfNum);
2117 6 : if (Surf.Class != DataSurfaces::SurfaceClass::Window) {
2118 2 : ShowSevereError(state, "IncidentSolarMultiplier defined for non-window surfaces");
2119 1 : ErrorsFound = true;
2120 1 : continue;
2121 : }
2122 5 : if (Surf.ExtBoundCond != DataSurfaces::ExternalEnvironment) {
2123 2 : ShowSevereError(state, "IncidentSolarMultiplier defined for interior surfaces");
2124 1 : ErrorsFound = true;
2125 1 : continue;
2126 : }
2127 4 : int ConstrNum = Surf.Construction;
2128 4 : auto const &Constr = state.dataConstruction->Construct(ConstrNum);
2129 4 : auto const *mat = s_mat->materials(Constr.LayerPoint(Constr.TotLayers));
2130 4 : bool withNoncompatibleShades =
2131 4 : (mat->group == Material::Group::Shade || mat->group == Material::Group::Blind || mat->group == Material::Group::Screen ||
2132 3 : mat->group == Material::Group::GlassEQL || mat->group == Material::Group::WindowGapEQL || mat->group == Material::Group::ShadeEQL ||
2133 11 : mat->group == Material::Group::DrapeEQL || mat->group == Material::Group::ScreenEQL || mat->group == Material::Group::BlindEQL ||
2134 3 : Surf.HasShadeControl);
2135 4 : if (withNoncompatibleShades) {
2136 4 : ShowSevereError(state, "Non-compatible shades defined alongside SurfaceProperty:IncidentSolarMultiplier for the same window");
2137 2 : ErrorsFound = true;
2138 2 : continue;
2139 : }
2140 :
2141 2 : Surf.hasIncSolMultiplier = true;
2142 2 : auto &SurfIncSolMult = state.dataSurface->SurfIncSolMultiplier(SurfNum);
2143 2 : SurfIncSolMult.Name = state.dataIPShortCut->cAlphaArgs(1);
2144 2 : SurfIncSolMult.SurfaceIdx = SurfNum;
2145 2 : SurfIncSolMult.Scaler = state.dataIPShortCut->rNumericArgs(1);
2146 :
2147 2 : if (state.dataIPShortCut->lAlphaFieldBlanks(2)) {
2148 2 : } else if ((SurfIncSolMult.sched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(2))) == nullptr) {
2149 1 : ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(2), state.dataIPShortCut->cAlphaArgs(2));
2150 : }
2151 : } // for (Loop)
2152 : } // GetIncidentSolarMultiplier()
2153 :
2154 451 : void GetZoneLocalEnvData(EnergyPlusData &state, bool &ErrorsFound) // Error flag indicator (true if errors found)
2155 : {
2156 : // SUBROUTINE INFORMATION:
2157 : // AUTHOR X LUO
2158 : // DATE WRITTEN July 2017
2159 :
2160 : // PURPOSE OF THIS SUBROUTINE:
2161 : // load input data for Outdoor Air Node for zones
2162 :
2163 : // Using/Aliasing
2164 : using DataLoopNode::ObjectIsParent;
2165 : using NodeInputManager::GetOnlySingleNode;
2166 : using OutAirNodeManager::CheckOutAirNodeNumber;
2167 :
2168 : //-----------------------------------------------------------------------
2169 : // ZoneProperty:LocalEnvironment
2170 : //-----------------------------------------------------------------------
2171 451 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
2172 451 : cCurrentModuleObject = "ZoneProperty:LocalEnvironment";
2173 451 : int TotZoneEnv = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
2174 :
2175 451 : if (TotZoneEnv > 0) {
2176 : int NumAlpha;
2177 : int NumNumeric;
2178 : int IOStat;
2179 1 : constexpr const char *RoutineName("GetZoneLocalEnvData: ");
2180 : // Check if IDD definition is correct
2181 1 : state.dataGlobal->AnyLocalEnvironmentsInModel = true;
2182 :
2183 1 : if (!allocated(state.dataHeatBal->ZoneLocalEnvironment)) {
2184 1 : state.dataHeatBal->ZoneLocalEnvironment.allocate(TotZoneEnv);
2185 : }
2186 :
2187 2 : for (int Loop = 1; Loop <= TotZoneEnv; ++Loop) {
2188 2 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
2189 : cCurrentModuleObject,
2190 : Loop,
2191 1 : state.dataIPShortCut->cAlphaArgs,
2192 : NumAlpha,
2193 1 : state.dataIPShortCut->rNumericArgs,
2194 : NumNumeric,
2195 : IOStat,
2196 1 : state.dataIPShortCut->lNumericFieldBlanks,
2197 1 : state.dataIPShortCut->lAlphaFieldBlanks,
2198 1 : state.dataIPShortCut->cAlphaFieldNames,
2199 1 : state.dataIPShortCut->cNumericFieldNames);
2200 :
2201 1 : state.dataHeatBal->ZoneLocalEnvironment(Loop).Name = state.dataIPShortCut->cAlphaArgs(1);
2202 :
2203 : // Assign zone number
2204 1 : int ZoneNum = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(2), state.dataHeatBal->Zone);
2205 1 : if (ZoneNum == 0) {
2206 0 : ShowSevereError(state,
2207 0 : format("{}{}=\"{}, object. Illegal value for {} has been found.",
2208 : RoutineName,
2209 : cCurrentModuleObject,
2210 0 : state.dataIPShortCut->cAlphaArgs(1),
2211 0 : state.dataIPShortCut->cAlphaFieldNames(2)));
2212 0 : ShowContinueError(state,
2213 0 : format("{} entered value = \"{}\" no corresponding zone has been found in the input file.",
2214 0 : state.dataIPShortCut->cAlphaFieldNames(2),
2215 0 : state.dataIPShortCut->cAlphaArgs(2)));
2216 0 : ErrorsFound = true;
2217 : } else {
2218 1 : state.dataHeatBal->ZoneLocalEnvironment(Loop).ZonePtr = ZoneNum;
2219 : }
2220 :
2221 : // Assign outdoor air node number;
2222 1 : int NodeNum = GetOnlySingleNode(state,
2223 1 : state.dataIPShortCut->cAlphaArgs(3),
2224 : ErrorsFound,
2225 : DataLoopNode::ConnectionObjectType::ZonePropertyLocalEnvironment,
2226 1 : state.dataIPShortCut->cAlphaArgs(1),
2227 : DataLoopNode::NodeFluidType::Air,
2228 : DataLoopNode::ConnectionType::Inlet,
2229 : NodeInputManager::CompFluidStream::Primary,
2230 : ObjectIsParent);
2231 1 : if (NodeNum == 0 && CheckOutAirNodeNumber(state, NodeNum)) {
2232 0 : ShowSevereError(state,
2233 0 : format("{}{}=\"{}, object. Illegal value for {} has been found.",
2234 : RoutineName,
2235 : cCurrentModuleObject,
2236 0 : state.dataIPShortCut->cAlphaArgs(1),
2237 0 : state.dataIPShortCut->cAlphaFieldNames(3)));
2238 0 : ShowContinueError(state,
2239 0 : format("{} entered value = \"{}\" no corresponding schedule has been found in the input file.",
2240 0 : state.dataIPShortCut->cAlphaFieldNames(3),
2241 0 : state.dataIPShortCut->cAlphaArgs(3)));
2242 0 : ErrorsFound = true;
2243 : } else {
2244 1 : state.dataHeatBal->ZoneLocalEnvironment(Loop).OutdoorAirNodePtr = NodeNum;
2245 : }
2246 : }
2247 : }
2248 : // Link zone properties to zone object
2249 1147 : for (int ZoneLoop = 1; ZoneLoop <= state.dataGlobal->NumOfZones; ++ZoneLoop) {
2250 697 : for (int Loop = 1; Loop <= TotZoneEnv; ++Loop) {
2251 1 : if (state.dataHeatBal->ZoneLocalEnvironment(Loop).ZonePtr == ZoneLoop) {
2252 1 : if (state.dataHeatBal->ZoneLocalEnvironment(Loop).OutdoorAirNodePtr != 0) {
2253 1 : state.dataHeatBal->Zone(ZoneLoop).LinkedOutAirNode = state.dataHeatBal->ZoneLocalEnvironment(Loop).OutdoorAirNodePtr;
2254 : }
2255 : }
2256 : }
2257 : }
2258 451 : }
2259 :
2260 699 : void ProcessZoneData(EnergyPlusData &state,
2261 : std::string const &cCurrentModuleObject,
2262 : int const ZoneLoop,
2263 : Array1D_string const &cAlphaArgs,
2264 : int const NumAlphas,
2265 : Array1D<Real64> const &rNumericArgs,
2266 : int const NumNumbers,
2267 : [[maybe_unused]] Array1D_bool const &lNumericFieldBlanks, // Unused
2268 : Array1D_bool const &lAlphaFieldBlanks,
2269 : Array1D_string const &cAlphaFieldNames,
2270 : [[maybe_unused]] Array1D_string const &cNumericFieldNames, // Unused
2271 : bool &ErrorsFound // If errors found in input
2272 : )
2273 : {
2274 :
2275 : // SUBROUTINE INFORMATION:
2276 : // AUTHOR Linda K. Lawrie
2277 : // DATE WRITTEN November 1997
2278 : // MODIFIED PGE: Added ZONE LIST and ZONE GROUP objects, Nov 2003
2279 : // RJH: Added init of DElight member of ZoneDaylight object, Jan 2004
2280 : // JG: Added Part of Total Floor Area field March 2006
2281 : // RE-ENGINEERED MJW: Split out processing zone input to facilitate unit testing, Nov 2014
2282 :
2283 : // PURPOSE OF THIS SUBROUTINE:
2284 : // This subroutine gets the zone data for each zone in the input file.
2285 :
2286 699 : constexpr const char *RoutineName("ProcessZoneData: ");
2287 :
2288 699 : state.dataHeatBal->Zone(ZoneLoop).Name = cAlphaArgs(1);
2289 699 : if (NumNumbers >= 1) state.dataHeatBal->Zone(ZoneLoop).RelNorth = rNumericArgs(1);
2290 699 : if (NumNumbers >= 2) state.dataHeatBal->Zone(ZoneLoop).OriginX = rNumericArgs(2);
2291 699 : if (NumNumbers >= 3) state.dataHeatBal->Zone(ZoneLoop).OriginY = rNumericArgs(3);
2292 699 : if (NumNumbers >= 4) state.dataHeatBal->Zone(ZoneLoop).OriginZ = rNumericArgs(4);
2293 699 : if (NumNumbers >= 5) state.dataHeatBal->Zone(ZoneLoop).OfType = rNumericArgs(5);
2294 699 : state.dataHeatBal->Zone(ZoneLoop).OfType = DataHeatBalance::StandardZone;
2295 699 : if (NumNumbers >= 6) state.dataHeatBal->Zone(ZoneLoop).Multiplier = rNumericArgs(6);
2296 699 : if (NumNumbers >= 7) state.dataHeatBal->Zone(ZoneLoop).CeilingHeight = rNumericArgs(7);
2297 699 : if (NumNumbers >= 8) state.dataHeatBal->Zone(ZoneLoop).Volume = rNumericArgs(8);
2298 699 : if (NumNumbers >= 9) state.dataHeatBal->Zone(ZoneLoop).UserEnteredFloorArea = rNumericArgs(9);
2299 :
2300 699 : if (NumAlphas > 1 && !state.dataIPShortCut->lAlphaFieldBlanks(2)) {
2301 15 : Convect::HcInt hcIn = static_cast<Convect::HcInt>(getEnumValue(Convect::HcIntNamesUC, cAlphaArgs(2)));
2302 :
2303 15 : if (hcIn != Convect::HcInt::ASHRAESimple && hcIn != Convect::HcInt::ASHRAETARP && hcIn != Convect::HcInt::CeilingDiffuser &&
2304 2 : hcIn != Convect::HcInt::TrombeWall && hcIn != Convect::HcInt::AdaptiveConvectionAlgorithm && hcIn != Convect::HcInt::ASTMC1340) {
2305 :
2306 1 : ShowSevereError(state, format("{}{}=\"{}\".", RoutineName, cCurrentModuleObject, state.dataHeatBal->Zone(ZoneLoop).Name));
2307 1 : ShowContinueError(state, format("Invalid value for {}=\"{}\".", cAlphaFieldNames(2), cAlphaArgs(2)));
2308 1 : ErrorsFound = true;
2309 : }
2310 15 : state.dataHeatBal->Zone(ZoneLoop).IntConvAlgo = hcIn;
2311 : } else {
2312 : // No zone specific algorithm specified, use default Inside Convection Algorithm
2313 684 : state.dataHeatBal->Zone(ZoneLoop).IntConvAlgo = state.dataHeatBal->DefaultIntConvAlgo;
2314 : }
2315 :
2316 699 : if (NumAlphas > 2 && !state.dataIPShortCut->lAlphaFieldBlanks(3)) {
2317 :
2318 1 : Convect::HcExt hcOut = static_cast<Convect::HcExt>(getEnumValue(Convect::HcExtNamesUC, cAlphaArgs(3)));
2319 :
2320 1 : if (hcOut != Convect::HcExt::ASHRAESimple && hcOut != Convect::HcExt::ASHRAETARP && hcOut != Convect::HcExt::MoWiTTHcOutside &&
2321 0 : hcOut != Convect::HcExt::DOE2HcOutside && hcOut != Convect::HcExt::AdaptiveConvectionAlgorithm) {
2322 :
2323 0 : ShowSevereError(state, format("{}{}=\"{}\".", RoutineName, cCurrentModuleObject, state.dataHeatBal->Zone(ZoneLoop).Name));
2324 0 : ShowContinueError(state, format("Invalid value for {}=\"{}\".", cAlphaFieldNames(3), cAlphaArgs(3)));
2325 0 : ErrorsFound = true;
2326 : }
2327 1 : state.dataHeatBal->Zone(ZoneLoop).ExtConvAlgo = hcOut;
2328 :
2329 : } else {
2330 : // No zone specific algorithm specified, use default Outside Convection Algorithm
2331 698 : state.dataHeatBal->Zone(ZoneLoop).ExtConvAlgo = state.dataHeatBal->DefaultExtConvAlgo;
2332 : }
2333 :
2334 : // Process the input field: Part of Total Floor Area
2335 : // The default value is YES and so only NO needs to be handled
2336 699 : if (NumAlphas > 3) {
2337 76 : if (Util::SameString("No", cAlphaArgs(4))) {
2338 9 : state.dataHeatBal->Zone(ZoneLoop).isPartOfTotalArea = false;
2339 67 : } else if (Util::SameString("Yes", cAlphaArgs(4)) || lAlphaFieldBlanks(4)) {
2340 67 : state.dataHeatBal->Zone(ZoneLoop).isPartOfTotalArea = true;
2341 : } else {
2342 0 : ShowSevereError(state, format("{}{}=\"{}\".", RoutineName, cCurrentModuleObject, state.dataHeatBal->Zone(ZoneLoop).Name));
2343 0 : ShowContinueError(state, format("Invalid value for {}=\"{}\".", cAlphaFieldNames(4), cAlphaArgs(4)));
2344 0 : ErrorsFound = true;
2345 : }
2346 : }
2347 :
2348 : // Zone outdoor environmental variables, used for zone infiltration/ventilation
2349 1398 : SetupOutputVariable(state,
2350 : "Zone Outdoor Air Drybulb Temperature",
2351 : Constant::Units::C,
2352 699 : state.dataHeatBal->Zone(ZoneLoop).OutDryBulbTemp,
2353 : OutputProcessor::TimeStepType::Zone,
2354 : OutputProcessor::StoreType::Average,
2355 699 : state.dataHeatBal->Zone(ZoneLoop).Name);
2356 1398 : SetupOutputVariable(state,
2357 : "Zone Outdoor Air Wetbulb Temperature",
2358 : Constant::Units::C,
2359 699 : state.dataHeatBal->Zone(ZoneLoop).OutWetBulbTemp,
2360 : OutputProcessor::TimeStepType::Zone,
2361 : OutputProcessor::StoreType::Average,
2362 699 : state.dataHeatBal->Zone(ZoneLoop).Name);
2363 1398 : SetupOutputVariable(state,
2364 : "Zone Outdoor Air Wind Speed",
2365 : Constant::Units::m_s,
2366 699 : state.dataHeatBal->Zone(ZoneLoop).WindSpeed,
2367 : OutputProcessor::TimeStepType::Zone,
2368 : OutputProcessor::StoreType::Average,
2369 699 : state.dataHeatBal->Zone(ZoneLoop).Name);
2370 1398 : SetupOutputVariable(state,
2371 : "Zone Outdoor Air Wind Direction",
2372 : Constant::Units::deg,
2373 699 : state.dataHeatBal->Zone(ZoneLoop).WindDir,
2374 : OutputProcessor::TimeStepType::Zone,
2375 : OutputProcessor::StoreType::Average,
2376 699 : state.dataHeatBal->Zone(ZoneLoop).Name);
2377 699 : }
2378 :
2379 451 : void GetSpaceData(EnergyPlusData &state, bool &ErrorsFound) // If errors found in input
2380 : {
2381 451 : constexpr const char *RoutineName("GetSpaceData: ");
2382 451 : std::string cCurrentModuleObject = "Space";
2383 451 : auto &ip = state.dataInputProcessing->inputProcessor;
2384 451 : auto const instances = ip->epJSON.find(cCurrentModuleObject);
2385 451 : if (instances != ip->epJSON.end()) {
2386 34 : auto const &objectSchemaProps = ip->getObjectSchemaProps(state, cCurrentModuleObject);
2387 34 : auto &instancesValue = instances.value();
2388 34 : int numSpaces = instancesValue.size();
2389 34 : int spaceNum = 0;
2390 : // Allow for one additional Space per zone if some surfaces do not have a Space assigned in input
2391 34 : state.dataHeatBal->space.allocate(size_t(numSpaces + state.dataGlobal->NumOfZones));
2392 : // Allow for one additional "General" space type for auto-generated spaces
2393 34 : state.dataHeatBal->spaceTypes.allocate(size_t(numSpaces + 1));
2394 :
2395 146 : for (auto instance = instancesValue.begin(); instance != instancesValue.end(); ++instance) {
2396 112 : ++spaceNum;
2397 112 : auto const &objectFields = instance.value();
2398 112 : auto &thisSpace = state.dataHeatBal->space(spaceNum);
2399 112 : thisSpace.Name = Util::makeUPPER(instance.key());
2400 112 : ip->markObjectAsUsed(cCurrentModuleObject, instance.key());
2401 224 : std::string zoneName = ip->getAlphaFieldValue(objectFields, objectSchemaProps, "zone_name");
2402 224 : thisSpace.CeilingHeight = ip->getRealFieldValue(objectFields, objectSchemaProps, "ceiling_height");
2403 224 : thisSpace.Volume = ip->getRealFieldValue(objectFields, objectSchemaProps, "volume");
2404 224 : thisSpace.userEnteredFloorArea = ip->getRealFieldValue(objectFields, objectSchemaProps, "floor_area");
2405 112 : int zoneNum = Util::FindItemInList(zoneName, state.dataHeatBal->Zone);
2406 112 : if (zoneNum > 0) {
2407 112 : thisSpace.zoneNum = zoneNum;
2408 112 : state.dataHeatBal->Zone(zoneNum).spaceIndexes.emplace_back(spaceNum);
2409 112 : ++state.dataHeatBal->Zone(zoneNum).numSpaces;
2410 : } else {
2411 0 : ShowSevereError(state, format("{}{}={}", RoutineName, cCurrentModuleObject, thisSpace.Name));
2412 0 : ShowContinueError(state, format("Zone Name ={}not found.", zoneName));
2413 0 : ErrorsFound = true;
2414 : }
2415 224 : thisSpace.spaceType = ip->getAlphaFieldValue(objectFields, objectSchemaProps, "space_type");
2416 112 : bool spaceTypeFound = false;
2417 113 : for (int spaceTypePtr = 1; spaceTypePtr <= state.dataGlobal->numSpaceTypes; ++spaceTypePtr) {
2418 78 : if (Util::SameString(thisSpace.spaceType, state.dataHeatBal->spaceTypes(spaceTypePtr))) {
2419 77 : thisSpace.spaceTypeNum = spaceTypePtr;
2420 77 : spaceTypeFound = true;
2421 77 : break;
2422 : }
2423 : }
2424 112 : if (!spaceTypeFound) {
2425 35 : ++state.dataGlobal->numSpaceTypes;
2426 35 : state.dataHeatBal->spaceTypes(state.dataGlobal->numSpaceTypes) = thisSpace.spaceType;
2427 35 : thisSpace.spaceTypeNum = state.dataGlobal->numSpaceTypes;
2428 : }
2429 :
2430 112 : auto extensibles = objectFields.find("tags");
2431 112 : auto const &extensionSchemaProps = objectSchemaProps["tags"]["items"]["properties"];
2432 112 : if (extensibles != objectFields.end()) {
2433 1 : auto &extensiblesArray = extensibles.value();
2434 3 : for (auto &extensibleInstance : extensiblesArray) {
2435 6 : thisSpace.tags.emplace_back(ip->getAlphaFieldValue(extensibleInstance, extensionSchemaProps, "tag"));
2436 : }
2437 : }
2438 112 : }
2439 34 : state.dataGlobal->numSpaces = spaceNum;
2440 : } else {
2441 : // If no Spaces are defined, then allow for one Space per zone, and one spaceType
2442 417 : state.dataHeatBal->space.allocate(state.dataGlobal->NumOfZones);
2443 417 : state.dataHeatBal->spaceTypes.allocate(1);
2444 : }
2445 :
2446 451 : cCurrentModuleObject = "SpaceList";
2447 451 : auto const instances2 = ip->epJSON.find(cCurrentModuleObject);
2448 451 : if (instances2 != ip->epJSON.end()) {
2449 8 : auto const &objectSchemaProps = ip->getObjectSchemaProps(state, cCurrentModuleObject);
2450 8 : auto &instancesValue = instances2.value();
2451 8 : int numSpaceLists = instancesValue.size();
2452 8 : int spaceListNum = 0;
2453 8 : state.dataHeatBal->spaceList.allocate(numSpaceLists);
2454 16 : for (auto instance = instancesValue.begin(); instance != instancesValue.end(); ++instance) {
2455 8 : ++spaceListNum;
2456 8 : auto const &objectFields = instance.value();
2457 8 : auto &thisSpaceList = state.dataHeatBal->spaceList(spaceListNum);
2458 8 : thisSpaceList.Name = Util::makeUPPER(instance.key());
2459 8 : ip->markObjectAsUsed(cCurrentModuleObject, instance.key());
2460 :
2461 8 : if (Util::FindItemInList(thisSpaceList.Name, state.dataHeatBal->Zone) > 0) {
2462 0 : ShowSevereError(state,
2463 0 : format("{}{}=\"{}\": is a duplicate of a zone name.", RoutineName, cCurrentModuleObject, thisSpaceList.Name));
2464 0 : ErrorsFound = true;
2465 : }
2466 8 : if (Util::FindItemInList(thisSpaceList.Name, state.dataHeatBal->space) > 0) {
2467 0 : ShowSevereError(state,
2468 0 : format("{}{}=\"{}\": is a duplicate of a space name.", RoutineName, cCurrentModuleObject, thisSpaceList.Name));
2469 0 : ErrorsFound = true;
2470 : }
2471 :
2472 : // List of spaces
2473 8 : thisSpaceList.numListSpaces = 0;
2474 8 : auto extensibles = objectFields.find("spaces");
2475 8 : auto const &extensionSchemaProps = objectSchemaProps["spaces"]["items"]["properties"];
2476 8 : if (extensibles != objectFields.end()) {
2477 8 : auto &extensiblesArray = extensibles.value();
2478 24 : for (auto &extensibleInstance : extensiblesArray) {
2479 32 : std::string thisSpaceName = ip->getAlphaFieldValue(extensibleInstance, extensionSchemaProps, "space_name");
2480 16 : int thisSpaceNum = Util::FindItemInList(thisSpaceName, state.dataHeatBal->space);
2481 16 : if (thisSpaceNum > 0) {
2482 16 : thisSpaceList.spaces.emplace_back(thisSpaceNum);
2483 16 : ++thisSpaceList.numListSpaces;
2484 : } else {
2485 0 : ShowSevereError(state, format("{}{}={}", RoutineName, cCurrentModuleObject, thisSpaceList.Name));
2486 0 : ShowContinueError(state, format("Space Name={} not found.", thisSpaceName));
2487 0 : ErrorsFound = true;
2488 : }
2489 16 : thisSpaceList.maxSpaceNameLength = max(thisSpaceList.maxSpaceNameLength, len(thisSpaceName));
2490 : // Check for duplicate spaces
2491 24 : for (int loop = 1; loop <= int(thisSpaceList.spaces.size()) - 1; ++loop) {
2492 8 : if (thisSpaceNum == thisSpaceList.spaces(loop)) {
2493 0 : ShowSevereError(state,
2494 0 : format("{}{}=\"{}\": Space Name {} appears more than once in list.",
2495 : RoutineName,
2496 : cCurrentModuleObject,
2497 0 : thisSpaceList.Name,
2498 : thisSpaceName));
2499 0 : ErrorsFound = true;
2500 : }
2501 : }
2502 16 : }
2503 : }
2504 : }
2505 : }
2506 :
2507 : // Make sure every zone has at least one space
2508 1147 : for (int zoneNum = 1; zoneNum <= state.dataGlobal->NumOfZones; ++zoneNum) {
2509 696 : auto &thisZone = state.dataHeatBal->Zone(zoneNum);
2510 696 : if (thisZone.spaceIndexes.empty()) {
2511 616 : ++state.dataGlobal->numSpaces;
2512 616 : state.dataHeatBal->space(state.dataGlobal->numSpaces).zoneNum = zoneNum;
2513 616 : state.dataHeatBal->space(state.dataGlobal->numSpaces).Name = thisZone.Name;
2514 616 : state.dataHeatBal->space(state.dataGlobal->numSpaces).spaceType = "GENERAL";
2515 616 : state.dataHeatBal->space(state.dataGlobal->numSpaces).spaceTypeNum = GetGeneralSpaceTypeNum(state);
2516 : // Add to zone's list of spaces
2517 616 : thisZone.spaceIndexes.emplace_back(state.dataGlobal->numSpaces);
2518 616 : ++state.dataHeatBal->Zone(zoneNum).numSpaces;
2519 : }
2520 : }
2521 451 : }
2522 :
2523 616 : int GetGeneralSpaceTypeNum(EnergyPlusData &state)
2524 : {
2525 : // If "General" exists as a space type return the index
2526 616 : bool generalSpaceTypeExists = false;
2527 616 : int generalSpaceTypeNum = 0;
2528 616 : for (int spaceTypePtr = 1; spaceTypePtr <= state.dataGlobal->numSpaceTypes; ++spaceTypePtr) {
2529 217 : if (Util::SameString(state.dataHeatBal->spaceTypes(spaceTypePtr), "GENERAL")) {
2530 217 : generalSpaceTypeNum = spaceTypePtr;
2531 217 : generalSpaceTypeExists = true;
2532 217 : break;
2533 : }
2534 : }
2535 : // Add General space type if it doesn't exist yet
2536 616 : if (!generalSpaceTypeExists) {
2537 399 : ++state.dataGlobal->numSpaceTypes;
2538 399 : state.dataHeatBal->spaceTypes(state.dataGlobal->numSpaceTypes) = "GENERAL";
2539 399 : generalSpaceTypeNum = state.dataGlobal->numSpaceTypes;
2540 : }
2541 616 : return generalSpaceTypeNum;
2542 : }
2543 : // End of Get Input subroutines for the HB Module
2544 : //******************************************************************************
2545 :
2546 : // Beginning Initialization Section of the Module
2547 : //******************************************************************************
2548 :
2549 249956 : void InitHeatBalance(EnergyPlusData &state)
2550 : {
2551 :
2552 : // SUBROUTINE INFORMATION:
2553 : // AUTHOR Rick Strand
2554 : // DATE WRITTEN April 1997
2555 :
2556 : // PURPOSE OF THIS SUBROUTINE:
2557 : // This subroutine is the main driver for initializations within the
2558 : // heat balance.
2559 :
2560 : // METHODOLOGY EMPLOYED:
2561 : // Uses the status flags to trigger initialization events. Some of the files
2562 : // have been moved to other heat balance managers. More of these initializations
2563 : // will have to continue to be re-structured.
2564 :
2565 : // Using/Aliasing
2566 : using namespace Window;
2567 : using namespace SolarShading;
2568 : using Dayltg::InitDaylightingDevices;
2569 : using OutAirNodeManager::SetOutAirNodes;
2570 : using WindowEquivalentLayer::InitEquivalentLayerWindowCalculations;
2571 :
2572 249956 : if (state.dataGlobal->BeginSimFlag) {
2573 108 : AllocateHeatBalArrays(state); // Allocate the Module Arrays
2574 108 : if (state.dataHeatBal->AnyCTF || state.dataHeatBal->AnyEMPD) {
2575 105 : DisplayString(state, "Initializing Response Factors");
2576 105 : InitConductionTransferFunctions(state); // Initialize the response factors
2577 : }
2578 108 : HeatBalanceSurfaceManager::InitSurfacePropertyViewFactors(state);
2579 108 : DisplayString(state, "Initializing Window Optical Properties");
2580 108 : InitEquivalentLayerWindowCalculations(state); // Initialize the EQL window optical properties
2581 : // InitGlassOpticalCalculations(); // Initialize the window optical properties
2582 108 : Window::InitWindowOpticalCalculations(state);
2583 108 : InitDaylightingDevices(state); // Initialize any daylighting devices
2584 108 : DisplayString(state, "Initializing Solar Calculations");
2585 108 : InitSolarCalculations(state); // Initialize the shadowing calculations
2586 : }
2587 :
2588 249956 : if (state.dataGlobal->BeginEnvrnFlag) {
2589 483 : state.dataHeatBalMgr->MaxHeatLoadPrevDay = 0.0;
2590 483 : state.dataHeatBalMgr->MaxCoolLoadPrevDay = 0.0;
2591 483 : state.dataHeatBalMgr->MaxTempPrevDay = 0.0;
2592 483 : state.dataHeatBalMgr->MinTempPrevDay = 0.0;
2593 483 : state.dataHeatBalMgr->MaxHeatLoadZone = -9999.0;
2594 483 : state.dataHeatBalMgr->MaxCoolLoadZone = -9999.0;
2595 483 : state.dataHeatBalMgr->MaxTempZone = -9999.0;
2596 483 : state.dataHeatBalMgr->MinTempZone = 1000.0;
2597 483 : state.dataHeatBalMgr->TempZone = -9999.0;
2598 483 : state.dataHeatBalMgr->LoadZone = -9999.0;
2599 483 : state.dataHeatBalMgr->TempZonePrevDay = 1000.0;
2600 483 : state.dataHeatBalMgr->LoadZonePrevDay = -9999.0;
2601 483 : state.dataHeatBalMgr->TempZoneSecPrevDay = -9999.0;
2602 483 : state.dataHeatBalMgr->WarmupTempDiff = 0.0;
2603 483 : state.dataHeatBalMgr->WarmupLoadDiff = 0.0;
2604 483 : state.dataHeatBalMgr->TempZoneRpt = 0.0;
2605 483 : state.dataHeatBalMgr->LoadZoneRpt = 0.0;
2606 483 : state.dataHeatBalMgr->MaxLoadZoneRpt = 0.0;
2607 483 : state.dataHeatBalMgr->CountWarmupDayPoints = 0;
2608 :
2609 4701 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; SurfNum++) {
2610 8436 : std::fill(
2611 4218 : state.dataSurface->SurfaceWindow(SurfNum).thetaFace.begin(), state.dataSurface->SurfaceWindow(SurfNum).thetaFace.end(), 296.15);
2612 4218 : state.dataSurface->SurfWinEffInsSurfTemp(SurfNum) = 23.0;
2613 : }
2614 : }
2615 :
2616 249956 : if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
2617 116073 : HeatBalanceSurfaceManager::InitEMSControlledConstructions(state);
2618 116073 : HeatBalanceSurfaceManager::InitEMSControlledSurfaceProperties(state);
2619 : }
2620 :
2621 : // Init storm window pointers
2622 249956 : if (state.dataSurface->TotStormWin > 0) {
2623 0 : if (state.dataGlobal->BeginDayFlag) {
2624 0 : SetStormWindowControl(state);
2625 0 : state.dataHeatBalMgr->ChangeSet = false;
2626 0 : } else if (!state.dataHeatBalMgr->ChangeSet) {
2627 0 : state.dataHeatBal->StormWinChangeThisDay = false;
2628 0 : for (int StormWinNum = 1; StormWinNum <= state.dataSurface->TotStormWin; ++StormWinNum) {
2629 0 : int SurfNum = state.dataSurface->StormWindow(StormWinNum).BaseWindowNum;
2630 0 : state.dataSurface->SurfWinStormWinFlagPrevDay(SurfNum) = state.dataSurface->SurfWinStormWinFlag(SurfNum);
2631 : }
2632 0 : state.dataHeatBalMgr->ChangeSet = true;
2633 : }
2634 0 : for (int zoneNum = 1; zoneNum <= state.dataGlobal->NumOfZones; ++zoneNum) {
2635 0 : for (int spaceNum : state.dataHeatBal->Zone(zoneNum).spaceIndexes) {
2636 0 : auto const &thisSpace = state.dataHeatBal->space(spaceNum);
2637 0 : int const firstSurfWin = thisSpace.WindowSurfaceFirst;
2638 0 : int const lastSurfWin = thisSpace.WindowSurfaceLast;
2639 0 : for (int SurfNum = firstSurfWin; SurfNum <= lastSurfWin; ++SurfNum) {
2640 0 : if (state.dataSurface->SurfWinStormWinFlag(SurfNum) == 1 &&
2641 0 : state.dataSurface->SurfWinWindowModelType(SurfNum) == DataSurfaces::WindowModel::Detailed) {
2642 0 : state.dataSurface->SurfActiveConstruction(SurfNum) = state.dataSurface->SurfWinStormWinConstr(SurfNum);
2643 : } else {
2644 0 : state.dataSurface->SurfActiveConstruction(SurfNum) = state.dataSurface->Surface(SurfNum).Construction;
2645 : }
2646 : }
2647 : }
2648 : }
2649 : }
2650 :
2651 249956 : if (state.dataGlobal->BeginSimFlag && state.dataGlobal->DoWeathSim && state.dataSysVars->ReportExtShadingSunlitFrac) {
2652 1 : OpenShadingFile(state);
2653 : }
2654 :
2655 249956 : if (state.dataGlobal->BeginDayFlag) {
2656 2299 : if (!state.dataGlobal->WarmupFlag) {
2657 217 : if (state.dataGlobal->DayOfSim == 1) {
2658 216 : state.dataHeatBalMgr->MaxHeatLoadZone = -9999.0;
2659 216 : state.dataHeatBalMgr->MaxCoolLoadZone = -9999.0;
2660 216 : state.dataHeatBalMgr->MaxTempZone = -9999.0;
2661 216 : state.dataHeatBalMgr->MinTempZone = 1000.0;
2662 : }
2663 : }
2664 2299 : if (!state.dataSysVars->DetailedSolarTimestepIntegration) {
2665 2283 : PerformSolarCalculations(state);
2666 : }
2667 : }
2668 :
2669 249956 : if (state.dataSysVars->DetailedSolarTimestepIntegration) { // always redo solar calcs
2670 1356 : PerformSolarCalculations(state);
2671 : }
2672 :
2673 249957 : if (state.dataGlobal->BeginDayFlag && !state.dataGlobal->WarmupFlag && state.dataGlobal->KindOfSim == Constant::KindOfSim::RunPeriodWeather &&
2674 1 : state.dataSysVars->ReportExtShadingSunlitFrac) {
2675 25 : for (int iHour = 1; iHour <= Constant::iHoursInDay; ++iHour) { // Do for all hours.
2676 72 : for (int TS = 1; TS <= state.dataGlobal->TimeStepsInHour; ++TS) {
2677 48 : constexpr const char *ShdFracFmt1(" {:02}/{:02} {:02}:{:02},");
2678 48 : if (TS == state.dataGlobal->TimeStepsInHour) {
2679 24 : print(state.files.shade, ShdFracFmt1, state.dataEnvrn->Month, state.dataEnvrn->DayOfMonth, iHour, 0);
2680 : } else {
2681 24 : print(state.files.shade,
2682 : ShdFracFmt1,
2683 24 : state.dataEnvrn->Month,
2684 24 : state.dataEnvrn->DayOfMonth,
2685 0 : iHour - 1,
2686 48 : (60 / state.dataGlobal->TimeStepsInHour) * TS);
2687 : }
2688 144 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
2689 96 : constexpr const char *ShdFracFmt2("{:10.8F},");
2690 96 : print(state.files.shade, ShdFracFmt2, state.dataHeatBal->SurfSunlitFrac(iHour, TS, SurfNum));
2691 : }
2692 48 : print(state.files.shade, "\n");
2693 : }
2694 : }
2695 : }
2696 :
2697 : // Initialize zone outdoor environmental variables
2698 : // Bulk Initialization for Temperatures & WindSpeed
2699 : // using the zone, modify the zone Dry/Wet BulbTemps
2700 249956 : DataHeatBalance::SetZoneOutBulbTempAt(state);
2701 249956 : DataHeatBalance::CheckZoneOutBulbTempAt(state);
2702 :
2703 : // set zone level wind dir to global value
2704 249956 : DataHeatBalance::SetZoneWindSpeedAt(state);
2705 249956 : DataHeatBalance::SetZoneWindDirAt(state);
2706 :
2707 : // Set zone data to linked air node value if defined.
2708 249956 : if (state.dataGlobal->AnyLocalEnvironmentsInModel) {
2709 2 : SetOutAirNodes(state);
2710 4 : for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
2711 2 : if (state.dataHeatBal->Zone(ZoneNum).LinkedOutAirNode > 0) {
2712 2 : if (state.dataLoopNodes->Node(state.dataHeatBal->Zone(ZoneNum).LinkedOutAirNode).outAirDryBulbSched != nullptr) {
2713 1 : state.dataHeatBal->Zone(ZoneNum).OutDryBulbTemp =
2714 1 : state.dataLoopNodes->Node(state.dataHeatBal->Zone(ZoneNum).LinkedOutAirNode).outAirDryBulbSched->getCurrentVal();
2715 : } else {
2716 1 : state.dataHeatBal->Zone(ZoneNum).OutDryBulbTemp =
2717 1 : state.dataLoopNodes->Node(state.dataHeatBal->Zone(ZoneNum).LinkedOutAirNode).OutAirDryBulb;
2718 : }
2719 2 : if (state.dataLoopNodes->Node(state.dataHeatBal->Zone(ZoneNum).LinkedOutAirNode).outAirWetBulbSched != nullptr) {
2720 1 : state.dataHeatBal->Zone(ZoneNum).OutWetBulbTemp =
2721 1 : state.dataLoopNodes->Node(state.dataHeatBal->Zone(ZoneNum).LinkedOutAirNode).outAirWetBulbSched->getCurrentVal();
2722 : } else {
2723 1 : state.dataHeatBal->Zone(ZoneNum).OutWetBulbTemp =
2724 1 : state.dataLoopNodes->Node(state.dataHeatBal->Zone(ZoneNum).LinkedOutAirNode).OutAirWetBulb;
2725 : }
2726 2 : if (state.dataLoopNodes->Node(state.dataHeatBal->Zone(ZoneNum).LinkedOutAirNode).outAirWindSpeedSched != nullptr) {
2727 1 : state.dataHeatBal->Zone(ZoneNum).WindSpeed =
2728 1 : state.dataLoopNodes->Node(state.dataHeatBal->Zone(ZoneNum).LinkedOutAirNode).outAirWindSpeedSched->getCurrentVal();
2729 : } else {
2730 1 : state.dataHeatBal->Zone(ZoneNum).WindSpeed =
2731 1 : state.dataLoopNodes->Node(state.dataHeatBal->Zone(ZoneNum).LinkedOutAirNode).OutAirWindSpeed;
2732 : }
2733 2 : if (state.dataLoopNodes->Node(state.dataHeatBal->Zone(ZoneNum).LinkedOutAirNode).outAirWindDirSched != nullptr) {
2734 1 : state.dataHeatBal->Zone(ZoneNum).WindDir =
2735 1 : state.dataLoopNodes->Node(state.dataHeatBal->Zone(ZoneNum).LinkedOutAirNode).outAirWindDirSched->getCurrentVal();
2736 : } else {
2737 1 : state.dataHeatBal->Zone(ZoneNum).WindDir =
2738 1 : state.dataLoopNodes->Node(state.dataHeatBal->Zone(ZoneNum).LinkedOutAirNode).OutAirWindDir;
2739 : }
2740 : }
2741 : }
2742 : }
2743 :
2744 : // Overwriting surface and zone level environmental data with EMS override value
2745 249956 : if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
2746 240234 : for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
2747 124161 : if (state.dataHeatBal->Zone(ZoneNum).OutDryBulbTempEMSOverrideOn) {
2748 0 : state.dataHeatBal->Zone(ZoneNum).OutDryBulbTemp = state.dataHeatBal->Zone(ZoneNum).OutDryBulbTempEMSOverrideValue;
2749 : }
2750 124161 : if (state.dataHeatBal->Zone(ZoneNum).OutWetBulbTempEMSOverrideOn) {
2751 0 : state.dataHeatBal->Zone(ZoneNum).OutWetBulbTemp = state.dataHeatBal->Zone(ZoneNum).OutWetBulbTempEMSOverrideValue;
2752 : }
2753 124161 : if (state.dataHeatBal->Zone(ZoneNum).WindSpeedEMSOverrideOn) {
2754 0 : state.dataHeatBal->Zone(ZoneNum).WindSpeed = state.dataHeatBal->Zone(ZoneNum).WindSpeedEMSOverrideValue;
2755 : }
2756 124161 : if (state.dataHeatBal->Zone(ZoneNum).WindDirEMSOverrideOn) {
2757 0 : state.dataHeatBal->Zone(ZoneNum).WindDir = state.dataHeatBal->Zone(ZoneNum).WindDirEMSOverrideValue;
2758 : }
2759 : }
2760 : }
2761 :
2762 249956 : if (state.dataGlobal->BeginSimFlag) {
2763 235 : for (int zoneNum = 1; zoneNum <= state.dataGlobal->NumOfZones; ++zoneNum) {
2764 272 : for (int spaceNum : state.dataHeatBal->Zone(zoneNum).spaceIndexes) {
2765 145 : auto const &thisSpace = state.dataHeatBal->space(spaceNum);
2766 145 : int const firstSurfWin = thisSpace.WindowSurfaceFirst;
2767 145 : int const lastSurfWin = thisSpace.WindowSurfaceLast;
2768 194 : for (int SurfNum = firstSurfWin; SurfNum <= lastSurfWin; ++SurfNum) {
2769 98 : if (state.dataSurface->SurfWinWindowModelType(SurfNum) != DataSurfaces::WindowModel::BSDF &&
2770 49 : state.dataSurface->SurfWinWindowModelType(SurfNum) != DataSurfaces::WindowModel::EQL) {
2771 42 : state.dataSurface->SurfWinWindowModelType(SurfNum) = DataSurfaces::WindowModel::Detailed;
2772 : }
2773 : }
2774 : }
2775 : }
2776 : }
2777 249956 : }
2778 :
2779 176 : void AllocateZoneHeatBalArrays(EnergyPlusData &state)
2780 : {
2781 : // Allocate zone / encl hb arrays
2782 :
2783 : // TODO MJW: Punt for now, sometimes unit test will get here and need these to be allocated, but simulations need them sooner
2784 176 : if (!state.dataHeatBal->ZoneIntGain.allocated()) {
2785 47 : DataHeatBalance::AllocateIntGains(state);
2786 : }
2787 176 : state.dataZoneTempPredictorCorrector->zoneHeatBalance.allocate(state.dataGlobal->NumOfZones);
2788 : // Always allocate spaceHeatBalance, even if doSpaceHeatBalance is false, because it's used to gather some of the zone totals
2789 176 : state.dataZoneTempPredictorCorrector->spaceHeatBalance.allocate(state.dataGlobal->numSpaces);
2790 :
2791 176 : state.dataHeatBal->EnclSolQSDifSol.allocate(state.dataViewFactor->NumOfSolarEnclosures);
2792 176 : state.dataHeatBal->EnclSolQD.allocate(state.dataViewFactor->NumOfSolarEnclosures);
2793 176 : state.dataHeatBal->EnclSolQDforDaylight.allocate(state.dataViewFactor->NumOfSolarEnclosures);
2794 176 : state.dataHeatBal->EnclSolDB.allocate(state.dataViewFactor->NumOfSolarEnclosures);
2795 176 : state.dataHeatBal->EnclSolDBSSG.allocate(state.dataViewFactor->NumOfSolarEnclosures);
2796 176 : state.dataHeatBal->EnclSolDBIntWin.allocate(state.dataViewFactor->NumOfSolarEnclosures);
2797 176 : state.dataHeatBal->EnclSolQSWRad.allocate(state.dataViewFactor->NumOfSolarEnclosures);
2798 176 : state.dataHeatBal->EnclSolQSWRadLights.allocate(state.dataViewFactor->NumOfSolarEnclosures);
2799 356 : for (int enclosureNum = 1; enclosureNum <= state.dataViewFactor->NumOfSolarEnclosures; ++enclosureNum) {
2800 180 : state.dataHeatBal->EnclSolQSDifSol(enclosureNum) = 0.0;
2801 180 : state.dataHeatBal->EnclSolQD(enclosureNum) = 0.0;
2802 180 : state.dataHeatBal->EnclSolQDforDaylight(enclosureNum) = 0.0;
2803 180 : state.dataHeatBal->EnclSolQSWRad(enclosureNum) = 0.0;
2804 180 : state.dataHeatBal->EnclSolQSWRadLights(enclosureNum) = 0.0;
2805 180 : state.dataHeatBal->EnclSolDB(enclosureNum) = 0.0;
2806 180 : state.dataHeatBal->EnclSolDBSSG(enclosureNum) = 0.0;
2807 180 : state.dataHeatBal->EnclSolDBIntWin(enclosureNum) = 0.0;
2808 : }
2809 176 : }
2810 165 : void AllocateHeatBalArrays(EnergyPlusData &state)
2811 : {
2812 :
2813 : // SUBROUTINE INFORMATION:
2814 : // AUTHOR Richard Liesen
2815 : // DATE WRITTEN February 1998
2816 :
2817 : // Use the total number of zones or surfaces to allocate variables to avoid a limit
2818 165 : AllocateZoneHeatBalArrays(state);
2819 165 : state.dataHeatBalFanSys->SumConvHTRadSys.dimension(state.dataGlobal->NumOfZones, 0.0);
2820 165 : state.dataHeatBalFanSys->SumLatentHTRadSys.dimension(state.dataGlobal->NumOfZones, 0.0);
2821 165 : state.dataHeatBalFanSys->SumConvPool.dimension(state.dataGlobal->NumOfZones, 0.0);
2822 165 : state.dataHeatBalFanSys->SumLatentPool.dimension(state.dataGlobal->NumOfZones, 0.0);
2823 165 : state.dataHeatBalFanSys->ZoneQdotRadHVACToPerson.dimension(state.dataGlobal->NumOfZones, 0.0);
2824 165 : state.dataHeatBalFanSys->ZoneQHTRadSysToPerson.dimension(state.dataGlobal->NumOfZones, 0.0);
2825 165 : state.dataHeatBalFanSys->ZoneQHWBaseboardToPerson.dimension(state.dataGlobal->NumOfZones, 0.0);
2826 165 : state.dataHeatBalFanSys->ZoneQSteamBaseboardToPerson.dimension(state.dataGlobal->NumOfZones, 0.0);
2827 165 : state.dataHeatBalFanSys->ZoneQElecBaseboardToPerson.dimension(state.dataGlobal->NumOfZones, 0.0);
2828 165 : state.dataHeatBalFanSys->ZoneQCoolingPanelToPerson.dimension(state.dataGlobal->NumOfZones, 0.0);
2829 165 : state.dataHeatBalFanSys->ZoneReOrder.allocate(state.dataGlobal->NumOfZones);
2830 165 : state.dataHeatBalFanSys->ZoneMassBalanceFlag.dimension(state.dataGlobal->NumOfZones, false);
2831 165 : state.dataHeatBalFanSys->ZoneInfiltrationFlag.dimension(state.dataGlobal->NumOfZones, false);
2832 165 : state.dataHeatBalFanSys->ZoneReOrder = 0;
2833 165 : state.dataHeatBalFanSys->TempTstatAir.dimension(state.dataGlobal->NumOfZones, DataHeatBalance::ZoneInitialTemp);
2834 165 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
2835 0 : state.dataContaminantBalance->OutdoorCO2 = state.dataContaminantBalance->Contaminant.CO2OutdoorSched->getCurrentVal();
2836 0 : state.dataContaminantBalance->ZoneAirCO2.dimension(state.dataGlobal->NumOfZones, state.dataContaminantBalance->OutdoorCO2);
2837 0 : state.dataContaminantBalance->ZoneAirCO2Temp.dimension(state.dataGlobal->NumOfZones, state.dataContaminantBalance->OutdoorCO2);
2838 0 : state.dataContaminantBalance->ZoneAirCO2Avg.dimension(state.dataGlobal->NumOfZones, state.dataContaminantBalance->OutdoorCO2);
2839 : }
2840 165 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
2841 0 : state.dataContaminantBalance->OutdoorGC = state.dataContaminantBalance->Contaminant.genericOutdoorSched->getCurrentVal();
2842 0 : state.dataContaminantBalance->ZoneAirGC.dimension(state.dataGlobal->NumOfZones, state.dataContaminantBalance->OutdoorGC);
2843 0 : state.dataContaminantBalance->ZoneAirGCTemp.dimension(state.dataGlobal->NumOfZones, state.dataContaminantBalance->OutdoorGC);
2844 0 : state.dataContaminantBalance->ZoneAirGCAvg.dimension(state.dataGlobal->NumOfZones, state.dataContaminantBalance->OutdoorGC);
2845 : }
2846 165 : state.dataHeatBalMgr->MaxTempPrevDay.dimension(state.dataGlobal->NumOfZones, 0.0);
2847 165 : state.dataHeatBalMgr->MinTempPrevDay.dimension(state.dataGlobal->NumOfZones, 0.0);
2848 165 : state.dataHeatBalMgr->MaxHeatLoadPrevDay.dimension(state.dataGlobal->NumOfZones, 0.0);
2849 165 : state.dataHeatBalMgr->MaxCoolLoadPrevDay.dimension(state.dataGlobal->NumOfZones, 0.0);
2850 165 : state.dataHeatBalMgr->MaxHeatLoadZone.dimension(state.dataGlobal->NumOfZones, -9999.0);
2851 165 : state.dataHeatBalMgr->MaxCoolLoadZone.dimension(state.dataGlobal->NumOfZones, -9999.0);
2852 165 : state.dataHeatBalMgr->MaxTempZone.dimension(state.dataGlobal->NumOfZones, -9999.0);
2853 165 : state.dataHeatBalMgr->MinTempZone.dimension(state.dataGlobal->NumOfZones, 1000.0);
2854 165 : state.dataHeatBalMgr->TempZonePrevDay.dimension(state.dataGlobal->NumOfZones, 0.0);
2855 165 : state.dataHeatBalMgr->LoadZonePrevDay.dimension(state.dataGlobal->NumOfZones, 0.0);
2856 165 : state.dataHeatBalMgr->TempZoneSecPrevDay.dimension(state.dataGlobal->NumOfZones, 0.0);
2857 165 : state.dataHeatBalMgr->LoadZoneSecPrevDay.dimension(state.dataGlobal->NumOfZones, 0.0);
2858 165 : state.dataHeatBalMgr->WarmupTempDiff.dimension(state.dataGlobal->NumOfZones, 0.0);
2859 165 : state.dataHeatBalMgr->WarmupLoadDiff.dimension(state.dataGlobal->NumOfZones, 0.0);
2860 165 : state.dataHeatBalMgr->TempZone.dimension(state.dataGlobal->NumOfZones, 0.0);
2861 165 : state.dataHeatBalMgr->LoadZone.dimension(state.dataGlobal->NumOfZones, 0.0);
2862 165 : state.dataHeatBalMgr->TempZoneRpt.dimension(state.dataGlobal->NumOfZones, state.dataGlobal->TimeStepsInHour * Constant::iHoursInDay, 0.0);
2863 165 : state.dataHeatBalMgr->LoadZoneRpt.dimension(state.dataGlobal->NumOfZones, state.dataGlobal->TimeStepsInHour * Constant::iHoursInDay, 0.0);
2864 165 : state.dataHeatBalMgr->MaxLoadZoneRpt.dimension(state.dataGlobal->NumOfZones, state.dataGlobal->TimeStepsInHour * Constant::iHoursInDay, 0.0);
2865 165 : state.dataHeatBalMgr->WarmupConvergenceValues.allocate(state.dataGlobal->NumOfZones);
2866 165 : state.dataHeatBalMgr->TempZoneRptStdDev.allocate(state.dataGlobal->TimeStepsInHour * Constant::iHoursInDay);
2867 165 : state.dataHeatBalMgr->LoadZoneRptStdDev.allocate(state.dataGlobal->TimeStepsInHour * Constant::iHoursInDay);
2868 : // MassConservation.allocate( NumOfZones );
2869 :
2870 165 : state.dataHeatBalFanSys->CrossedColdThreshRepPeriod.allocate(state.dataGlobal->NumOfZones, state.dataWeather->TotThermalReportPers);
2871 165 : state.dataHeatBalFanSys->CrossedHeatThreshRepPeriod.allocate(state.dataGlobal->NumOfZones, state.dataWeather->TotThermalReportPers);
2872 165 : state.dataHeatBalFanSys->CrossedColdThreshRepPeriod = false;
2873 165 : state.dataHeatBalFanSys->CrossedHeatThreshRepPeriod = false;
2874 165 : if (state.dataWeather->TotThermalReportPers > 0) {
2875 0 : state.dataHeatBalFanSys->ZoneHeatIndexHourBinsRepPeriod.allocate(state.dataGlobal->NumOfZones, state.dataWeather->TotThermalReportPers);
2876 0 : state.dataHeatBalFanSys->ZoneHeatIndexOccupiedHourBinsRepPeriod.allocate(state.dataGlobal->NumOfZones,
2877 0 : state.dataWeather->TotThermalReportPers);
2878 0 : state.dataHeatBalFanSys->ZoneHeatIndexOccuHourBinsRepPeriod.allocate(state.dataGlobal->NumOfZones,
2879 0 : state.dataWeather->TotThermalReportPers);
2880 0 : state.dataHeatBalFanSys->ZoneHumidexHourBinsRepPeriod.allocate(state.dataGlobal->NumOfZones, state.dataWeather->TotThermalReportPers);
2881 0 : state.dataHeatBalFanSys->ZoneHumidexOccupiedHourBinsRepPeriod.allocate(state.dataGlobal->NumOfZones,
2882 0 : state.dataWeather->TotThermalReportPers);
2883 0 : state.dataHeatBalFanSys->ZoneHumidexOccuHourBinsRepPeriod.allocate(state.dataGlobal->NumOfZones, state.dataWeather->TotThermalReportPers);
2884 0 : state.dataHeatBalFanSys->ZoneColdHourOfSafetyBinsRepPeriod.allocate(state.dataGlobal->NumOfZones,
2885 0 : state.dataWeather->TotThermalReportPers);
2886 0 : state.dataHeatBalFanSys->ZoneHeatHourOfSafetyBinsRepPeriod.allocate(state.dataGlobal->NumOfZones,
2887 0 : state.dataWeather->TotThermalReportPers);
2888 0 : state.dataHeatBalFanSys->ZoneUnmetDegreeHourBinsRepPeriod.allocate(state.dataGlobal->NumOfZones, state.dataWeather->TotThermalReportPers);
2889 0 : state.dataHeatBalFanSys->ZoneDiscomfortWtExceedOccuHourBinsRepPeriod.allocate(state.dataGlobal->NumOfZones,
2890 0 : state.dataWeather->TotThermalReportPers);
2891 0 : state.dataHeatBalFanSys->ZoneDiscomfortWtExceedOccupiedHourBinsRepPeriod.allocate(state.dataGlobal->NumOfZones,
2892 0 : state.dataWeather->TotThermalReportPers);
2893 : }
2894 :
2895 165 : if (state.dataWeather->TotCO2ReportPers > 0) {
2896 0 : state.dataHeatBalFanSys->ZoneCO2LevelHourBinsRepPeriod.allocate(state.dataGlobal->NumOfZones, state.dataWeather->TotCO2ReportPers);
2897 0 : state.dataHeatBalFanSys->ZoneCO2LevelOccuHourBinsRepPeriod.allocate(state.dataGlobal->NumOfZones, state.dataWeather->TotCO2ReportPers);
2898 0 : state.dataHeatBalFanSys->ZoneCO2LevelOccupiedHourBinsRepPeriod.allocate(state.dataGlobal->NumOfZones,
2899 0 : state.dataWeather->TotCO2ReportPers);
2900 : }
2901 165 : if (state.dataWeather->TotVisualReportPers > 0) {
2902 0 : state.dataHeatBalFanSys->ZoneLightingLevelHourBinsRepPeriod.allocate(state.dataGlobal->NumOfZones,
2903 0 : state.dataWeather->TotVisualReportPers);
2904 0 : state.dataHeatBalFanSys->ZoneLightingLevelOccuHourBinsRepPeriod.allocate(state.dataGlobal->NumOfZones,
2905 0 : state.dataWeather->TotVisualReportPers);
2906 0 : state.dataHeatBalFanSys->ZoneLightingLevelOccupiedHourBinsRepPeriod.allocate(state.dataGlobal->NumOfZones,
2907 0 : state.dataWeather->TotVisualReportPers);
2908 : }
2909 :
2910 165 : state.dataHeatBalFanSys->ZoneLowSETHoursRepPeriod.allocate(state.dataGlobal->NumOfZones, state.dataWeather->TotThermalReportPers);
2911 165 : state.dataHeatBalFanSys->ZoneHighSETHoursRepPeriod.allocate(state.dataGlobal->NumOfZones, state.dataWeather->TotThermalReportPers);
2912 165 : state.dataHeatBalFanSys->lowSETLongestHoursRepPeriod.allocate(state.dataGlobal->NumOfZones, state.dataWeather->TotThermalReportPers);
2913 165 : state.dataHeatBalFanSys->highSETLongestHoursRepPeriod.allocate(state.dataGlobal->NumOfZones, state.dataWeather->TotThermalReportPers);
2914 165 : state.dataHeatBalFanSys->lowSETLongestStartRepPeriod.allocate(state.dataGlobal->NumOfZones, state.dataWeather->TotThermalReportPers);
2915 165 : state.dataHeatBalFanSys->highSETLongestStartRepPeriod.allocate(state.dataGlobal->NumOfZones, state.dataWeather->TotThermalReportPers);
2916 :
2917 165 : state.dataHeatBalMgr->CountWarmupDayPoints = 0;
2918 165 : }
2919 :
2920 : // End Initialization Section of the Module
2921 : //******************************************************************************
2922 :
2923 : // Beginning of Record Keeping subroutines for the HB Module
2924 : // *****************************************************************************
2925 :
2926 249945 : void RecKeepHeatBalance(EnergyPlusData &state)
2927 : {
2928 :
2929 : // SUBROUTINE INFORMATION:
2930 : // AUTHOR Rick Strand
2931 : // DATE WRITTEN April 1997
2932 : // MODIFIED June 2011, Daeho Kang for individual zone maximums & convergence outputs
2933 : // July 2016, Rick Strand for movable insulation bug fix
2934 :
2935 : // PURPOSE OF THIS SUBROUTINE:
2936 : // This subroutine is the main driver for record keeping within the
2937 : // heat balance.
2938 :
2939 : // Record Maxs & Mins for individual zone
2940 586584 : for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
2941 336639 : auto const &thisZoneHB = state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum);
2942 336639 : auto const &thisZoneSysEnergyDemand = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum);
2943 336639 : if (thisZoneHB.ZTAV > state.dataHeatBalMgr->MaxTempZone(ZoneNum)) {
2944 54041 : state.dataHeatBalMgr->MaxTempZone(ZoneNum) = thisZoneHB.ZTAV;
2945 : }
2946 336639 : if (thisZoneHB.ZTAV < state.dataHeatBalMgr->MinTempZone(ZoneNum)) {
2947 139777 : state.dataHeatBalMgr->MinTempZone(ZoneNum) = thisZoneHB.ZTAV;
2948 : }
2949 336639 : if (thisZoneSysEnergyDemand.airSysHeatRate > state.dataHeatBalMgr->MaxHeatLoadZone(ZoneNum)) {
2950 43220 : state.dataHeatBalMgr->MaxHeatLoadZone(ZoneNum) = thisZoneSysEnergyDemand.airSysHeatRate;
2951 : }
2952 336639 : if (thisZoneSysEnergyDemand.airSysCoolRate > state.dataHeatBalMgr->MaxCoolLoadZone(ZoneNum)) {
2953 27703 : state.dataHeatBalMgr->MaxCoolLoadZone(ZoneNum) = thisZoneSysEnergyDemand.airSysCoolRate;
2954 : }
2955 :
2956 : // Record temperature and load for individual zone
2957 336639 : state.dataHeatBalMgr->TempZoneSecPrevDay(ZoneNum) = state.dataHeatBalMgr->TempZonePrevDay(ZoneNum);
2958 336639 : state.dataHeatBalMgr->LoadZoneSecPrevDay(ZoneNum) = state.dataHeatBalMgr->LoadZonePrevDay(ZoneNum);
2959 336639 : state.dataHeatBalMgr->TempZonePrevDay(ZoneNum) = state.dataHeatBalMgr->TempZone(ZoneNum);
2960 336639 : state.dataHeatBalMgr->LoadZonePrevDay(ZoneNum) = state.dataHeatBalMgr->LoadZone(ZoneNum);
2961 336639 : state.dataHeatBalMgr->TempZone(ZoneNum) = thisZoneHB.ZTAV;
2962 336639 : state.dataHeatBalMgr->LoadZone(ZoneNum) = max(thisZoneSysEnergyDemand.airSysHeatRate, std::abs(thisZoneSysEnergyDemand.airSysCoolRate));
2963 :
2964 : // Calculate differences in temperature and load for the last two warmup days
2965 376912 : if (!state.dataGlobal->WarmupFlag && state.dataGlobal->DayOfSim == 1 &&
2966 40273 : (!state.dataGlobal->DoingSizing || state.dataGlobal->DoPureLoadCalc)) {
2967 28369 : state.dataHeatBalMgr->WarmupTempDiff(ZoneNum) =
2968 28369 : std::abs(state.dataHeatBalMgr->TempZoneSecPrevDay(ZoneNum) - state.dataHeatBalMgr->TempZonePrevDay(ZoneNum));
2969 28369 : state.dataHeatBalMgr->WarmupLoadDiff(ZoneNum) =
2970 28369 : std::abs(state.dataHeatBalMgr->LoadZoneSecPrevDay(ZoneNum) - state.dataHeatBalMgr->LoadZonePrevDay(ZoneNum));
2971 28369 : if (ZoneNum == 1) ++state.dataHeatBalMgr->CountWarmupDayPoints;
2972 28369 : state.dataHeatBalMgr->TempZoneRpt(ZoneNum, state.dataHeatBalMgr->CountWarmupDayPoints) =
2973 28369 : state.dataHeatBalMgr->WarmupTempDiff(ZoneNum);
2974 28369 : state.dataHeatBalMgr->LoadZoneRpt(ZoneNum, state.dataHeatBalMgr->CountWarmupDayPoints) =
2975 28369 : state.dataHeatBalMgr->WarmupLoadDiff(ZoneNum);
2976 28369 : state.dataHeatBalMgr->MaxLoadZoneRpt(ZoneNum, state.dataHeatBalMgr->CountWarmupDayPoints) = state.dataHeatBalMgr->LoadZone(ZoneNum);
2977 :
2978 28369 : if (state.dataSysVars->ReportDetailedWarmupConvergence) { // only do this detailed thing when requested by user is on
2979 : // Write Warmup Convergence Information to the initialization output file
2980 0 : if (state.dataHeatBalMgr->FirstWarmupWrite) {
2981 0 : constexpr const char *Format_732{"! <Warmup Convergence Information>,Zone Name,Time Step,Hour of Day,Warmup Temperature "
2982 : "Difference {{deltaC}},Warmup Load Difference {{W}}\n"};
2983 0 : print(state.files.eio, Format_732);
2984 0 : state.dataHeatBalMgr->FirstWarmupWrite = false;
2985 : }
2986 0 : constexpr const char *Format_731{" Warmup Convergence Information, {},{},{},{:.10R},{:.10R}\n"};
2987 0 : print(state.files.eio,
2988 : Format_731,
2989 0 : state.dataHeatBal->Zone(ZoneNum).Name,
2990 0 : state.dataGlobal->TimeStep,
2991 0 : state.dataGlobal->HourOfDay,
2992 0 : state.dataHeatBalMgr->WarmupTempDiff(ZoneNum),
2993 0 : state.dataHeatBalMgr->WarmupLoadDiff(ZoneNum));
2994 : }
2995 : }
2996 : }
2997 :
2998 : // Update interior movable insulation flag--needed at the end of a zone time step so that the interior radiant
2999 : // exchange algorithm knows whether there has been a change in interior movable insulation or not.
3000 249945 : if (state.dataSurface->AnyMovableInsulation) {
3001 0 : for (int surfNum : state.dataSurface->intMovInsulSurfNums) {
3002 0 : auto &movInsul = state.dataSurface->intMovInsuls(surfNum);
3003 0 : movInsul.presentPrevTS = movInsul.present;
3004 : }
3005 : }
3006 :
3007 : // For non-complex windows, update a report variable so this shows up in the output as something other than zero
3008 249945 : UpdateWindowFaceTempsNonBSDFWin(state);
3009 249945 : }
3010 :
3011 1822 : void CheckWarmupConvergence(EnergyPlusData &state)
3012 : {
3013 :
3014 : // SUBROUTINE INFORMATION:
3015 : // AUTHOR Rick Strand
3016 : // DATE WRITTEN April 1997
3017 : // MODIFIED June 2011, Daeho Kang for individual zone comparison
3018 :
3019 : // PURPOSE OF THIS SUBROUTINE:
3020 : // This subroutine checks warmup convergence values.
3021 :
3022 : // SUBROUTINE PARAMETER DEFINITIONS:
3023 1822 : Real64 constexpr MinLoad(100.0); // Minimum loads for convergence check
3024 : // To avoid big percentage difference in low load situations
3025 :
3026 : // Convergence criteria for warmup days:
3027 : // Perform another warmup day unless both the % change in loads and
3028 : // absolute change in zone temp min & max are less than their criteria.
3029 :
3030 1822 : if (state.dataGlobal->NumOfZones <= 0) { // if there are no zones, immediate convergence
3031 4 : state.dataGlobal->WarmupFlag = false;
3032 : } else {
3033 1818 : bool ConvergenceChecksFailed = false;
3034 :
3035 4341 : for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
3036 :
3037 2523 : state.dataHeatBalMgr->WarmupConvergenceValues(ZoneNum).TestMaxTempValue =
3038 2523 : std::abs(state.dataHeatBalMgr->MaxTempPrevDay(ZoneNum) - state.dataHeatBalMgr->MaxTempZone(ZoneNum));
3039 2523 : state.dataHeatBalMgr->WarmupConvergenceValues(ZoneNum).TestMinTempValue =
3040 2523 : std::abs(state.dataHeatBalMgr->MinTempPrevDay(ZoneNum) - state.dataHeatBalMgr->MinTempZone(ZoneNum));
3041 2523 : if (state.dataHeatBalMgr->WarmupConvergenceValues(ZoneNum).TestMaxTempValue <= state.dataHeatBal->TempConvergTol) {
3042 1272 : state.dataHeatBalMgr->WarmupConvergenceValues(ZoneNum).PassFlag(1) = 2;
3043 : } else {
3044 1251 : ConvergenceChecksFailed = true;
3045 1251 : state.dataHeatBalMgr->WarmupConvergenceValues(ZoneNum).PassFlag(1) = 1;
3046 : }
3047 :
3048 2523 : if (state.dataHeatBalMgr->WarmupConvergenceValues(ZoneNum).TestMinTempValue <= state.dataHeatBal->TempConvergTol) {
3049 1314 : state.dataHeatBalMgr->WarmupConvergenceValues(ZoneNum).PassFlag(2) = 2;
3050 : } else {
3051 1209 : ConvergenceChecksFailed = true;
3052 1209 : state.dataHeatBalMgr->WarmupConvergenceValues(ZoneNum).PassFlag(2) = 1;
3053 : }
3054 :
3055 2523 : if (state.dataHeatBalMgr->MaxHeatLoadZone(ZoneNum) > 1.0e-4) { // make sure load big enough to divide
3056 632 : state.dataHeatBalMgr->MaxHeatLoadZone(ZoneNum) = std::abs(max(state.dataHeatBalMgr->MaxHeatLoadZone(ZoneNum), MinLoad));
3057 632 : state.dataHeatBalMgr->MaxHeatLoadPrevDay(ZoneNum) = std::abs(max(state.dataHeatBalMgr->MaxHeatLoadPrevDay(ZoneNum), MinLoad));
3058 632 : state.dataHeatBalMgr->WarmupConvergenceValues(ZoneNum).TestMaxHeatLoadValue =
3059 632 : std::abs((state.dataHeatBalMgr->MaxHeatLoadZone(ZoneNum) - state.dataHeatBalMgr->MaxHeatLoadPrevDay(ZoneNum)) /
3060 632 : state.dataHeatBalMgr->MaxHeatLoadZone(ZoneNum));
3061 632 : if (state.dataHeatBalMgr->WarmupConvergenceValues(ZoneNum).TestMaxHeatLoadValue <= state.dataHeatBal->LoadsConvergTol) {
3062 507 : state.dataHeatBalMgr->WarmupConvergenceValues(ZoneNum).PassFlag(3) = 2;
3063 : } else {
3064 125 : ConvergenceChecksFailed = true;
3065 125 : state.dataHeatBalMgr->WarmupConvergenceValues(ZoneNum).PassFlag(3) = 1;
3066 : }
3067 : } else {
3068 1891 : state.dataHeatBalMgr->WarmupConvergenceValues(ZoneNum).PassFlag(3) = 2;
3069 : }
3070 :
3071 2523 : if (state.dataHeatBalMgr->MaxCoolLoadZone(ZoneNum) > 1.0e-4) {
3072 814 : state.dataHeatBalMgr->MaxCoolLoadZone(ZoneNum) = std::abs(max(state.dataHeatBalMgr->MaxCoolLoadZone(ZoneNum), MinLoad));
3073 814 : state.dataHeatBalMgr->MaxCoolLoadPrevDay(ZoneNum) = std::abs(max(state.dataHeatBalMgr->MaxCoolLoadPrevDay(ZoneNum), MinLoad));
3074 814 : state.dataHeatBalMgr->WarmupConvergenceValues(ZoneNum).TestMaxCoolLoadValue =
3075 814 : std::abs((state.dataHeatBalMgr->MaxCoolLoadZone(ZoneNum) - state.dataHeatBalMgr->MaxCoolLoadPrevDay(ZoneNum)) /
3076 814 : state.dataHeatBalMgr->MaxCoolLoadZone(ZoneNum));
3077 814 : if (state.dataHeatBalMgr->WarmupConvergenceValues(ZoneNum).TestMaxCoolLoadValue <= state.dataHeatBal->LoadsConvergTol) {
3078 586 : state.dataHeatBalMgr->WarmupConvergenceValues(ZoneNum).PassFlag(4) = 2;
3079 : } else {
3080 228 : ConvergenceChecksFailed = true;
3081 228 : state.dataHeatBalMgr->WarmupConvergenceValues(ZoneNum).PassFlag(4) = 1;
3082 : }
3083 : } else {
3084 1709 : state.dataHeatBalMgr->WarmupConvergenceValues(ZoneNum).PassFlag(4) = 2;
3085 : }
3086 :
3087 2523 : if (state.dataGlobal->DayOfSim >= state.dataHeatBal->MaxNumberOfWarmupDays && state.dataGlobal->WarmupFlag) {
3088 : // Check convergence for individual zone
3089 0 : if (sum(state.dataHeatBalMgr->WarmupConvergenceValues(ZoneNum).PassFlag) != 8) { // pass=2 * 4 values for convergence
3090 0 : ShowSevereError(state,
3091 0 : format("CheckWarmupConvergence: Loads Initialization, Zone=\"{}\" did not converge after {} warmup days.",
3092 0 : state.dataHeatBal->Zone(ZoneNum).Name,
3093 0 : state.dataHeatBal->MaxNumberOfWarmupDays));
3094 0 : if (!state.dataHeatBalMgr->WarmupConvergenceWarning && !state.dataGlobal->DoingSizing) {
3095 0 : ShowContinueError(state, "See Warmup Convergence Information in .eio file for details.");
3096 0 : state.dataHeatBalMgr->WarmupConvergenceWarning = true;
3097 0 : } else if (!state.dataHeatBalMgr->SizingWarmupConvergenceWarning && state.dataGlobal->DoingSizing) {
3098 0 : ShowContinueError(state, "Warmup Convergence failing during sizing.");
3099 0 : state.dataHeatBalMgr->SizingWarmupConvergenceWarning = true;
3100 : }
3101 0 : if (state.dataEnvrn->RunPeriodEnvironment) {
3102 0 : ShowContinueError(state, format("...Environment(RunPeriod)=\"{}\"", state.dataEnvrn->EnvironmentName));
3103 : } else {
3104 0 : ShowContinueError(state, format("...Environment(SizingPeriod)=\"{}\"", state.dataEnvrn->EnvironmentName));
3105 : }
3106 :
3107 0 : ShowContinueError(state,
3108 0 : format("..Max Temp Comparison = {:.2R} vs Temperature Convergence Tolerance={:.2R} - {} Convergence",
3109 0 : state.dataHeatBalMgr->WarmupConvergenceValues(ZoneNum).TestMaxTempValue,
3110 0 : state.dataHeatBal->TempConvergTol,
3111 0 : PassFail(state.dataHeatBalMgr->WarmupConvergenceValues(ZoneNum).PassFlag(1))));
3112 0 : ShowContinueError(state,
3113 0 : format("..Min Temp Comparison = {:.2R} vs Temperature Convergence Tolerance={:.2R} - {} Convergence",
3114 0 : state.dataHeatBalMgr->WarmupConvergenceValues(ZoneNum).TestMinTempValue,
3115 0 : state.dataHeatBal->TempConvergTol,
3116 0 : PassFail(state.dataHeatBalMgr->WarmupConvergenceValues(ZoneNum).PassFlag(2))));
3117 0 : ShowContinueError(state,
3118 0 : format("..Max Heat Load Comparison = {:.4R} vs Loads Convergence Tolerance={:.2R} - {} Convergence",
3119 0 : state.dataHeatBalMgr->WarmupConvergenceValues(ZoneNum).TestMaxHeatLoadValue,
3120 0 : state.dataHeatBal->LoadsConvergTol,
3121 0 : PassFail(state.dataHeatBalMgr->WarmupConvergenceValues(ZoneNum).PassFlag(3))));
3122 0 : ShowContinueError(state,
3123 0 : format("..Max Cool Load Comparison = {:.4R} vs Loads Convergence Tolerance={:.2R} - {} Convergence",
3124 0 : state.dataHeatBalMgr->WarmupConvergenceValues(ZoneNum).TestMaxCoolLoadValue,
3125 0 : state.dataHeatBal->LoadsConvergTol,
3126 0 : PassFail(state.dataHeatBalMgr->WarmupConvergenceValues(ZoneNum).PassFlag(4))));
3127 : }
3128 : }
3129 :
3130 : // Transfer current daily max and min loads and temperatures to the
3131 : // variables containing the last day's values
3132 2523 : state.dataHeatBalMgr->MaxHeatLoadPrevDay(ZoneNum) = state.dataHeatBalMgr->MaxHeatLoadZone(ZoneNum);
3133 2523 : state.dataHeatBalMgr->MaxCoolLoadPrevDay(ZoneNum) = state.dataHeatBalMgr->MaxCoolLoadZone(ZoneNum);
3134 2523 : state.dataHeatBalMgr->MaxTempPrevDay(ZoneNum) = state.dataHeatBalMgr->MaxTempZone(ZoneNum);
3135 2523 : state.dataHeatBalMgr->MinTempPrevDay(ZoneNum) = state.dataHeatBalMgr->MinTempZone(ZoneNum);
3136 :
3137 2523 : state.dataHeatBalMgr->MaxHeatLoadZone(ZoneNum) = -9999.0;
3138 2523 : state.dataHeatBalMgr->MaxCoolLoadZone(ZoneNum) = -9999.0;
3139 2523 : state.dataHeatBalMgr->MaxTempZone(ZoneNum) = -9999.0;
3140 2523 : state.dataHeatBalMgr->MinTempZone(ZoneNum) = 1000.0;
3141 : }
3142 :
3143 : // Limit the number of warmup days, regardless of the number of zones
3144 : // in the building, to some arbitrary value based on common sense and
3145 : // experience with the (I)BLAST program. If too many warmup days were
3146 : // required, notify the program user.
3147 :
3148 1818 : if ((state.dataGlobal->DayOfSim >= state.dataHeatBal->MaxNumberOfWarmupDays) && state.dataGlobal->WarmupFlag && ConvergenceChecksFailed) {
3149 0 : if (state.dataHeatBal->MaxNumberOfWarmupDays < DataHeatBalance::DefaultMaxNumberOfWarmupDays) {
3150 0 : ShowSevereError(state,
3151 0 : format("CheckWarmupConvergence: User supplied maximum warmup days={} is insufficient.",
3152 0 : state.dataHeatBal->MaxNumberOfWarmupDays));
3153 0 : ShowContinueError(
3154 : state,
3155 0 : format("Suggest setting maximum number of warmup days to at least {}.", DataHeatBalance::DefaultMaxNumberOfWarmupDays));
3156 : }
3157 : }
3158 :
3159 : // Set warmup flag to true depending on value of ConvergenceChecksFailed (true=fail)
3160 : // and minimum number of warmup days
3161 1818 : if (!ConvergenceChecksFailed && state.dataGlobal->DayOfSim >= state.dataHeatBal->MinNumberOfWarmupDays) {
3162 212 : state.dataGlobal->WarmupFlag = false;
3163 1606 : } else if (!ConvergenceChecksFailed && state.dataGlobal->DayOfSim < state.dataHeatBal->MinNumberOfWarmupDays) {
3164 454 : state.dataGlobal->WarmupFlag = true;
3165 : }
3166 :
3167 : // If max warmup days reached and still WarmupFlag, then go to non-warmup state.
3168 : // prior messages will have been displayed
3169 1818 : if ((state.dataGlobal->DayOfSim >= state.dataHeatBal->MaxNumberOfWarmupDays) && state.dataGlobal->WarmupFlag) {
3170 0 : state.dataGlobal->WarmupFlag = false;
3171 : }
3172 : }
3173 1822 : }
3174 :
3175 134 : void ReportWarmupConvergence(EnergyPlusData &state)
3176 : {
3177 :
3178 : // SUBROUTINE INFORMATION:
3179 : // AUTHOR Linda Lawrie
3180 : // DATE WRITTEN October 2011
3181 :
3182 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
3183 : Real64 AverageZoneTemp;
3184 : Real64 AverageZoneLoad;
3185 : Real64 StdDevZoneTemp;
3186 : Real64 StdDevZoneLoad;
3187 :
3188 134 : if (!state.dataGlobal->WarmupFlag) { // Report out average/std dev
3189 : // Write Warmup Convervence Information to the initialization output file
3190 134 : if (state.dataHeatBalMgr->ReportWarmupConvergenceFirstWarmupWrite && state.dataGlobal->NumOfZones > 0) {
3191 72 : constexpr const char *Format_730(
3192 : "! <Warmup Convergence Information>,Zone Name,Environment Type/Name,Average Warmup Temperature Difference "
3193 : "{{deltaC}},Std Dev Warmup Temperature Difference {{deltaC}},Max Temperature Pass/Fail Convergence,Min "
3194 : "Temperature Pass/Fail Convergence,Average Warmup Load Difference {{W}},Std Dev Warmup Load Difference "
3195 : "{{W}},Heating Load Pass/Fail Convergence,Cooling Load Pass/Fail Convergence\n");
3196 72 : print(state.files.eio, Format_730);
3197 72 : state.dataHeatBalMgr->ReportWarmupConvergenceFirstWarmupWrite = false;
3198 : }
3199 :
3200 134 : state.dataHeatBalMgr->TempZoneRptStdDev = 0.0;
3201 134 : state.dataHeatBalMgr->LoadZoneRptStdDev = 0.0;
3202 :
3203 134 : std::string EnvHeader;
3204 134 : if (state.dataEnvrn->RunPeriodEnvironment) {
3205 0 : EnvHeader = "RunPeriod:";
3206 : } else {
3207 134 : EnvHeader = "SizingPeriod:";
3208 : }
3209 :
3210 333 : for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
3211 398 : AverageZoneTemp = sum(state.dataHeatBalMgr->TempZoneRpt(ZoneNum, {1, state.dataHeatBalMgr->CountWarmupDayPoints})) /
3212 199 : double(state.dataHeatBalMgr->CountWarmupDayPoints);
3213 26263 : for (int Num = 1; Num <= state.dataHeatBalMgr->CountWarmupDayPoints; ++Num) {
3214 26064 : if (state.dataHeatBalMgr->MaxLoadZoneRpt(ZoneNum, Num) > 1.e-4) {
3215 12363 : state.dataHeatBalMgr->LoadZoneRpt(ZoneNum, Num) /= state.dataHeatBalMgr->MaxLoadZoneRpt(ZoneNum, Num);
3216 : } else {
3217 13701 : state.dataHeatBalMgr->LoadZoneRpt(ZoneNum, Num) = 0.0;
3218 : }
3219 : }
3220 398 : AverageZoneLoad = sum(state.dataHeatBalMgr->LoadZoneRpt(ZoneNum, {1, state.dataHeatBalMgr->CountWarmupDayPoints})) /
3221 199 : double(state.dataHeatBalMgr->CountWarmupDayPoints);
3222 199 : StdDevZoneTemp = 0.0;
3223 199 : StdDevZoneLoad = 0.0;
3224 26263 : for (int Num = 1; Num <= state.dataHeatBalMgr->CountWarmupDayPoints; ++Num) {
3225 26064 : state.dataHeatBalMgr->TempZoneRptStdDev(Num) = pow_2(state.dataHeatBalMgr->TempZoneRpt(ZoneNum, Num) - AverageZoneTemp);
3226 26064 : state.dataHeatBalMgr->LoadZoneRptStdDev(Num) = pow_2(state.dataHeatBalMgr->LoadZoneRpt(ZoneNum, Num) - AverageZoneLoad);
3227 : }
3228 199 : StdDevZoneTemp = std::sqrt(sum(state.dataHeatBalMgr->TempZoneRptStdDev({1, state.dataHeatBalMgr->CountWarmupDayPoints})) /
3229 199 : double(state.dataHeatBalMgr->CountWarmupDayPoints));
3230 199 : StdDevZoneLoad = std::sqrt(sum(state.dataHeatBalMgr->LoadZoneRptStdDev({1, state.dataHeatBalMgr->CountWarmupDayPoints})) /
3231 199 : double(state.dataHeatBalMgr->CountWarmupDayPoints));
3232 :
3233 199 : constexpr const char *Format_731(" Warmup Convergence Information,{},{},{:.10R},{:.10R},{},{},{:.10R},{:.10R},{},{}\n");
3234 199 : print(state.files.eio,
3235 : Format_731,
3236 199 : state.dataHeatBal->Zone(ZoneNum).Name,
3237 398 : EnvHeader + ' ' + state.dataEnvrn->EnvironmentName,
3238 : AverageZoneTemp,
3239 : StdDevZoneTemp,
3240 199 : PassFail(state.dataHeatBalMgr->WarmupConvergenceValues(ZoneNum).PassFlag(1)),
3241 199 : PassFail(state.dataHeatBalMgr->WarmupConvergenceValues(ZoneNum).PassFlag(2)),
3242 : AverageZoneLoad,
3243 : StdDevZoneLoad,
3244 199 : PassFail(state.dataHeatBalMgr->WarmupConvergenceValues(ZoneNum).PassFlag(3)),
3245 199 : PassFail(state.dataHeatBalMgr->WarmupConvergenceValues(ZoneNum).PassFlag(4)));
3246 : }
3247 134 : }
3248 134 : }
3249 :
3250 249946 : void UpdateWindowFaceTempsNonBSDFWin(EnergyPlusData &state)
3251 : {
3252 338508 : for (int SurfNum : state.dataSurface->AllHTWindowSurfaceList) {
3253 88562 : auto &thisConstruction = state.dataConstruction->Construct(state.dataSurface->Surface(SurfNum).Construction);
3254 88562 : if (thisConstruction.WindowTypeBSDF) continue;
3255 88560 : state.dataHeatBal->SurfWinFenLaySurfTempFront(SurfNum, 1) = state.dataHeatBalSurf->SurfOutsideTempHist(1)(SurfNum);
3256 88560 : state.dataHeatBal->SurfWinFenLaySurfTempBack(SurfNum, thisConstruction.TotLayers) = state.dataHeatBalSurf->SurfInsideTempHist(1)(SurfNum);
3257 : }
3258 249946 : }
3259 :
3260 : // End of Record Keeping subroutines for the HB Module
3261 : // *****************************************************************************
3262 :
3263 : // Beginning of Reporting subroutines for the HB Module
3264 : // *****************************************************************************
3265 :
3266 249945 : void ReportHeatBalance(EnergyPlusData &state)
3267 : {
3268 :
3269 : // SUBROUTINE INFORMATION:
3270 : // AUTHOR Rick Strand
3271 : // DATE WRITTEN July 1997
3272 :
3273 : // PURPOSE OF THIS SUBROUTINE:
3274 : // This subroutine is the main driver for reporting within the heat
3275 : // balance.
3276 :
3277 : // METHODOLOGY EMPLOYED:
3278 : // Uses the status flags to trigger record keeping events.
3279 :
3280 : // Using/Aliasing
3281 : using EconomicTariff::UpdateUtilityBills; // added for computing annual utility costs
3282 : using NodeInputManager::CalcMoreNodeInfo;
3283 : using OutputReportTabular::UpdateTabularReports;
3284 :
3285 249945 : Sched::ReportScheduleVals(state);
3286 :
3287 249945 : if (!state.dataGlobal->WarmupFlag && state.dataGlobal->DoOutputReporting) {
3288 18777 : if (!state.dataGlobal->DoingSizing) {
3289 16473 : CalcMoreNodeInfo(state);
3290 : }
3291 18777 : UpdateDataandReport(state, OutputProcessor::TimeStepType::Zone);
3292 37554 : if (state.dataGlobal->KindOfSim == Constant::KindOfSim::HVACSizeDesignDay ||
3293 18777 : state.dataGlobal->KindOfSim == Constant::KindOfSim::HVACSizeRunPeriodDesign) {
3294 0 : if (state.dataHVACSizingSimMgr->hvacSizingSimulationManager)
3295 0 : state.dataHVACSizingSimMgr->hvacSizingSimulationManager->UpdateSizingLogsZoneStep(state);
3296 : }
3297 :
3298 18777 : UpdateTabularReports(state, OutputProcessor::TimeStepType::Zone);
3299 18777 : UpdateUtilityBills(state);
3300 231168 : } else if (!state.dataGlobal->KickOffSimulation && state.dataGlobal->DoOutputReporting && state.dataSysVars->ReportDuringWarmup) {
3301 0 : if (state.dataGlobal->BeginDayFlag && !state.dataEnvrn->PrintEnvrnStampWarmupPrinted) {
3302 0 : state.dataEnvrn->PrintEnvrnStampWarmup = true;
3303 0 : state.dataEnvrn->PrintEnvrnStampWarmupPrinted = true;
3304 : }
3305 0 : if (!state.dataGlobal->BeginDayFlag) state.dataEnvrn->PrintEnvrnStampWarmupPrinted = false;
3306 0 : if (state.dataEnvrn->PrintEnvrnStampWarmup) {
3307 0 : if (state.dataReportFlag->PrintEndDataDictionary && state.dataGlobal->DoOutputReporting) {
3308 0 : constexpr const char *EndOfHeaderString("End of Data Dictionary"); // End of data dictionary marker
3309 0 : print(state.files.eso, "{}\n", EndOfHeaderString);
3310 0 : print(state.files.mtr, "{}\n", EndOfHeaderString);
3311 0 : state.dataReportFlag->PrintEndDataDictionary = false;
3312 : }
3313 0 : if (state.dataGlobal->DoOutputReporting) {
3314 0 : constexpr const char *EnvironmentStampFormatStr("{},{},{:7.2F},{:7.2F},{:7.2F},{:7.2F}\n"); // Format descriptor for environ stamp
3315 0 : print(state.files.eso,
3316 : EnvironmentStampFormatStr,
3317 : "1",
3318 0 : "Warmup {" + state.dataReportFlag->cWarmupDay + "} " + state.dataEnvrn->EnvironmentName,
3319 0 : state.dataEnvrn->Latitude,
3320 0 : state.dataEnvrn->Longitude,
3321 0 : state.dataEnvrn->TimeZoneNumber,
3322 0 : state.dataEnvrn->Elevation);
3323 :
3324 0 : print(state.files.mtr,
3325 : EnvironmentStampFormatStr,
3326 : "1",
3327 0 : "Warmup {" + state.dataReportFlag->cWarmupDay + "} " + state.dataEnvrn->EnvironmentName,
3328 0 : state.dataEnvrn->Latitude,
3329 0 : state.dataEnvrn->Longitude,
3330 0 : state.dataEnvrn->TimeZoneNumber,
3331 0 : state.dataEnvrn->Elevation);
3332 0 : state.dataEnvrn->PrintEnvrnStampWarmup = false;
3333 : }
3334 : }
3335 0 : if (!state.dataGlobal->DoingSizing) {
3336 0 : CalcMoreNodeInfo(state);
3337 : }
3338 0 : UpdateDataandReport(state, OutputProcessor::TimeStepType::Zone);
3339 0 : if (state.dataGlobal->KindOfSim == Constant::KindOfSim::HVACSizeDesignDay ||
3340 0 : state.dataGlobal->KindOfSim == Constant::KindOfSim::HVACSizeRunPeriodDesign) {
3341 0 : if (state.dataHVACSizingSimMgr->hvacSizingSimulationManager)
3342 0 : state.dataHVACSizingSimMgr->hvacSizingSimulationManager->UpdateSizingLogsZoneStep(state);
3343 : }
3344 :
3345 231168 : } else if (state.dataSysVars->UpdateDataDuringWarmupExternalInterface) { // added for FMI
3346 0 : UpdateDataandReport(state, OutputProcessor::TimeStepType::Zone);
3347 0 : if (state.dataGlobal->KindOfSim == Constant::KindOfSim::HVACSizeDesignDay ||
3348 0 : state.dataGlobal->KindOfSim == Constant::KindOfSim::HVACSizeRunPeriodDesign) {
3349 0 : if (state.dataHVACSizingSimMgr->hvacSizingSimulationManager)
3350 0 : state.dataHVACSizingSimMgr->hvacSizingSimulationManager->UpdateSizingLogsZoneStep(state);
3351 : }
3352 : }
3353 : // There is no hourly reporting in the heat balance.
3354 :
3355 : // There is no daily reporting in the heat balance.
3356 :
3357 : // There is no simulation level record keeping in the heat balance.
3358 249945 : }
3359 :
3360 : // End of Reporting subroutines for the HB Module
3361 :
3362 2 : void OpenShadingFile(EnergyPlusData &state)
3363 : {
3364 :
3365 : // SUBROUTINE INFORMATION:
3366 : // AUTHOR X Luo
3367 : // DATE WRITTEN August 2017
3368 :
3369 : // PURPOSE OF THIS SUBROUTINE:
3370 : // Open and set up headers for a external shading fraction export file.
3371 :
3372 4 : state.files.shade.ensure_open(state, "OpenOutputFiles", state.files.outputControl.extshd);
3373 2 : print(state.files.shade, "Surface Name,");
3374 6 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
3375 4 : print(state.files.shade, "{},", state.dataSurface->Surface(SurfNum).Name);
3376 : }
3377 2 : print(state.files.shade, "\n");
3378 2 : }
3379 138 : void GetFrameAndDividerData(EnergyPlusData &state) // set to true if errors found in input
3380 : {
3381 :
3382 : // SUBROUTINE INFORMATION:
3383 : // AUTHOR Fred Winkelmann
3384 : // DATE WRITTEN May 2000
3385 : // MODIFIED April 2002 (FCW): get window reveal data
3386 :
3387 : // PURPOSE OF THIS SUBROUTINE:
3388 : // Gets input data for window frame and/or divider and/or window
3389 : // inside/outside reveal.
3390 :
3391 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
3392 : int IOStat; // IO Status when calling get input subroutine
3393 138 : Array1D_string FrameDividerAlphas(3); // Frame/Divider Alpha names
3394 : int FrameDividerNum; // Counter to keep track of the frame/divider number
3395 : int FrameDividerNumAlpha; // Number of frame/divider alpha names being passed
3396 : int FrameDividerNumProp; // Number of frame/divider properties being passed
3397 138 : Array1D<Real64> FrameDividerProps(23); // Temporary array to transfer frame/divider properties
3398 : int Loop;
3399 :
3400 138 : constexpr std::array<std::string_view, static_cast<int>(DataSurfaces::NfrcProductOptions::Num)> NfrcProductNamesUC = {
3401 : "CASEMENTDOUBLE", "CASEMENTSINGLE", "DUALACTION",
3402 : "FIXED", "GARAGE", "GREENHOUSE",
3403 : "HINGEDESCAPE", "HORIZONTALSLIDER", "JAL",
3404 : "PIVOTED", "PROJECTINGSINGLE", "PROJECTINGDUAL",
3405 : "DOORSIDELITE", "SKYLIGHT", "SLIDINGPATIODOOR",
3406 : "CURTAINWALL", "SPANDRELPANEL", "SIDEHINGEDDOOR",
3407 : "DOORTRANSOM", "TROPICALAWNING", "TUBULARDAYLIGHTINGDEVICE",
3408 : "VERTICALSLIDER"};
3409 :
3410 138 : constexpr std::array<std::string_view, static_cast<int>(DataSurfaces::FrameDividerType::Num)> FrameDividerTypeNamesUC = {
3411 : "DIVIDEDLITE", // 0
3412 : "SUSPENDED" // 1
3413 : };
3414 :
3415 138 : state.dataHeatBalMgr->CurrentModuleObject = "WindowProperty:FrameAndDivider";
3416 276 : state.dataHeatBal->TotFrameDivider =
3417 138 : state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, state.dataHeatBalMgr->CurrentModuleObject);
3418 138 : state.dataSurface->FrameDivider.allocate(state.dataHeatBal->TotFrameDivider);
3419 138 : if (state.dataHeatBal->TotFrameDivider == 0) return;
3420 :
3421 21 : FrameDividerNum = 0;
3422 :
3423 42 : for (Loop = 1; Loop <= state.dataHeatBal->TotFrameDivider; ++Loop) {
3424 :
3425 : // Call Input Get routine to retrieve frame/divider data
3426 63 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
3427 21 : state.dataHeatBalMgr->CurrentModuleObject,
3428 : Loop,
3429 : FrameDividerAlphas,
3430 : FrameDividerNumAlpha,
3431 : FrameDividerProps,
3432 : FrameDividerNumProp,
3433 : IOStat,
3434 21 : state.dataIPShortCut->lNumericFieldBlanks,
3435 21 : state.dataIPShortCut->lAlphaFieldBlanks,
3436 21 : state.dataIPShortCut->cAlphaFieldNames,
3437 21 : state.dataIPShortCut->cNumericFieldNames);
3438 :
3439 : // Load the frame/divider derived type from the input data.
3440 21 : ++FrameDividerNum;
3441 21 : auto &frameDivider = state.dataSurface->FrameDivider(FrameDividerNum);
3442 21 : frameDivider.Name = FrameDividerAlphas(1);
3443 21 : frameDivider.FrameWidth = FrameDividerProps(1);
3444 21 : frameDivider.FrameProjectionOut = FrameDividerProps(2);
3445 21 : frameDivider.FrameProjectionIn = FrameDividerProps(3);
3446 21 : if (frameDivider.FrameWidth == 0.0) {
3447 0 : frameDivider.FrameProjectionOut = 0.0;
3448 0 : frameDivider.FrameProjectionIn = 0.0;
3449 : }
3450 21 : frameDivider.FrameConductance = FrameDividerProps(4);
3451 21 : frameDivider.FrEdgeToCenterGlCondRatio = FrameDividerProps(5);
3452 21 : frameDivider.FrameSolAbsorp = FrameDividerProps(6);
3453 21 : frameDivider.FrameVisAbsorp = FrameDividerProps(7);
3454 21 : frameDivider.FrameEmis = FrameDividerProps(8);
3455 :
3456 : DataSurfaces::FrameDividerType currentDividerType =
3457 21 : DataSurfaces::FrameDividerType(getEnumValue(FrameDividerTypeNamesUC, FrameDividerAlphas(2)));
3458 21 : if (currentDividerType == DataSurfaces::FrameDividerType::Invalid) {
3459 0 : ShowWarningError(state,
3460 0 : fmt::format("{}={}, Invalid {}",
3461 0 : state.dataHeatBalMgr->CurrentModuleObject,
3462 0 : std::quoted(FrameDividerAlphas(1)),
3463 0 : state.dataIPShortCut->cAlphaFieldNames(2)));
3464 0 : ShowContinueError(
3465 : state,
3466 0 : fmt::format("Entered={}, must be DividedLite or Suspended. Will be set to DividedLite.", std::quoted(FrameDividerAlphas(2))));
3467 0 : frameDivider.DividerType = DataSurfaces::FrameDividerType::DividedLite;
3468 : } else {
3469 21 : frameDivider.DividerType = currentDividerType;
3470 : }
3471 :
3472 21 : frameDivider.DividerWidth = FrameDividerProps(9);
3473 21 : frameDivider.HorDividers = FrameDividerProps(10);
3474 21 : frameDivider.VertDividers = FrameDividerProps(11);
3475 21 : frameDivider.DividerProjectionOut = FrameDividerProps(12);
3476 21 : frameDivider.DividerProjectionIn = FrameDividerProps(13);
3477 21 : if (frameDivider.DividerWidth == 0.0 || frameDivider.DividerType == DataSurfaces::FrameDividerType::Suspended) {
3478 0 : frameDivider.DividerProjectionOut = 0.0;
3479 0 : frameDivider.DividerProjectionIn = 0.0;
3480 : }
3481 21 : frameDivider.DividerConductance = FrameDividerProps(14);
3482 21 : frameDivider.DivEdgeToCenterGlCondRatio = FrameDividerProps(15);
3483 21 : frameDivider.DividerSolAbsorp = FrameDividerProps(16);
3484 21 : frameDivider.DividerVisAbsorp = FrameDividerProps(17);
3485 21 : frameDivider.DividerEmis = FrameDividerProps(18);
3486 :
3487 : // look up the NFRC Product Type for Assembly Calculations using the DataSurfaces::NfrcProductName
3488 21 : frameDivider.NfrcProductType = DataSurfaces::NfrcProductOptions(getEnumValue(NfrcProductNamesUC, FrameDividerAlphas(3)));
3489 21 : if (frameDivider.NfrcProductType == DataSurfaces::NfrcProductOptions::Invalid) {
3490 0 : frameDivider.NfrcProductType = DataSurfaces::NfrcProductOptions::CurtainWall;
3491 : }
3492 :
3493 21 : frameDivider.OutsideRevealSolAbs = FrameDividerProps(19);
3494 21 : frameDivider.InsideSillDepth = FrameDividerProps(20);
3495 21 : frameDivider.InsideSillSolAbs = FrameDividerProps(21);
3496 21 : frameDivider.InsideReveal = FrameDividerProps(22);
3497 21 : frameDivider.InsideRevealSolAbs = FrameDividerProps(23);
3498 :
3499 21 : if (frameDivider.DividerWidth > 0.0 && (frameDivider.HorDividers == 0 && frameDivider.VertDividers == 0)) {
3500 0 : ShowWarningError(state,
3501 0 : format("{}: In FrameAndDivider {} {} > 0 ",
3502 0 : state.dataHeatBalMgr->CurrentModuleObject,
3503 0 : frameDivider.Name,
3504 0 : state.dataIPShortCut->cNumericFieldNames(9)));
3505 0 : ShowContinueError(
3506 : state,
3507 0 : format("...but {} = 0 and {} = 0.", state.dataIPShortCut->cNumericFieldNames(10), state.dataIPShortCut->cNumericFieldNames(11)));
3508 0 : ShowContinueError(state, format("...{} set to 0.", state.dataIPShortCut->cNumericFieldNames(9)));
3509 0 : frameDivider.DividerWidth = 0.0;
3510 : }
3511 : // Prevent InsideSillDepth < InsideReveal
3512 21 : if (frameDivider.InsideSillDepth < state.dataSurface->FrameDivider(FrameDividerNum).InsideReveal) {
3513 0 : ShowWarningError(state,
3514 0 : format("{}: In FrameAndDivider {} {} is less than {}; it will be set to {}.",
3515 0 : state.dataHeatBalMgr->CurrentModuleObject,
3516 0 : frameDivider.Name,
3517 0 : state.dataIPShortCut->cNumericFieldNames(20),
3518 0 : state.dataIPShortCut->cNumericFieldNames(22),
3519 0 : state.dataIPShortCut->cNumericFieldNames(22)));
3520 0 : frameDivider.InsideSillDepth = state.dataSurface->FrameDivider(FrameDividerNum).InsideReveal;
3521 : }
3522 :
3523 : // ! Warn if InsideSillDepth OR InsideReveal > 0.2meters to warn of inaccuracies
3524 : // IF(FrameDivider(FrameDividerNum)%InsideSillDepth > 0.2d0) THEN
3525 : // CALL ShowWarningError(state, TRIM(state.dataHeatBalMgr->CurrentModuleObject)//': In FrameAndDivider
3526 : // '//TRIM(FrameDivider(FrameDividerNum)%Name)// &
3527 : // ' '//TRIM(cNumericFieldNames(20))//' is greater than 0.2 meters, which could cause inaccuracies in zone cooling energy.')
3528 : // END IF
3529 : // IF(FrameDivider(FrameDividerNum)%InsideReveal > 0.2d0) THEN
3530 : // CALL ShowWarningError(state, TRIM(state.dataHeatBalMgr->CurrentModuleObject)//': In FrameAndDivider
3531 : // '//TRIM(FrameDivider(FrameDividerNum)%Name)// &
3532 : // ' '//TRIM(cNumericFieldNames(22))//' is greater than 0.2 meters, which could cause inaccuracies in zone cooling energy.')
3533 : // END IF
3534 : }
3535 255 : }
3536 :
3537 2 : void SearchWindow5DataFile(EnergyPlusData &state,
3538 : fs::path const &DesiredFilePath, // File path that contains the Window5 constructions.
3539 : std::string const &DesiredConstructionName, // Name that will be searched for in the Window5 data file
3540 : bool &ConstructionFound, // True if DesiredConstructionName is in the Window5 data file
3541 : bool &EOFonFile, // True if EOF during file read
3542 : bool &ErrorsFound // True if there is a problem with the entry requested from the data file
3543 : )
3544 : {
3545 :
3546 : // SUBROUTINE INFORMATION:
3547 : // AUTHOR Fred Winkelmann
3548 : // DATE WRITTEN August 2001
3549 : // MODIFIED June 2002, FW: do all reallocation here for constructions found on
3550 : // data file; 1 new construction of entry has one glazing system;
3551 : // 2 new constructions if entry has two glazing systems.
3552 : // Nov 2002, FW: skip read of mullion data line if one glazing system;
3553 : // add error messages for bad data; increase length of input line
3554 : // from 132 to 200 to handle case where Window5 puts in extra blanks
3555 : // in gas data line.
3556 : // Feb 2007, LKL: Add more checks on Window5DataFile
3557 : // Jan 2008, LKL: Change Edge/Cond ratio check.
3558 :
3559 : // PURPOSE OF THIS SUBROUTINE:
3560 : // Searches the WINDOW5 data file for a window with the name "DesiredConstructionName,"
3561 : // which is the name of an idf Construction input using CONSTRUCTION FROM WINDOW5 DATA FILE.
3562 : // (The WINDOW5 data file contains data for one or more complete windows --
3563 : // glazing, frame, mullion, and divider.
3564 : // WINDOW5 writes the data file for export to EnergyPlus so that an annual energy
3565 : // analysis can be done on exactly the same window without having to re-input into
3566 : // EnergyPlus.)
3567 :
3568 : // If a match is found, a Construction is created and the Material objects associated with
3569 : // the Construction are created. If there is an associated frame or
3570 : // divider in the Window5 data file for this Construction, a FrameAndDivider object will
3571 : // also be created.
3572 :
3573 : // If the window on the data file has two glazing systems, a second Construction (and its
3574 : // associated materials) corresponding to the second glazing system is created.
3575 :
3576 : // Using/Aliasing
3577 : using namespace DataStringGlobals;
3578 : using DataSystemVariables::CheckForActualFilePath;
3579 :
3580 : // SUBROUTINE PARAMETER DEFINITIONS:
3581 2 : Array1D_string const NumName(5, {"1", "2", "3", "4", "5"});
3582 :
3583 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
3584 : int FileLineCount; // counter for number of lines read (used in some error messages)
3585 2 : Array1D_string DataLine(100); // Array of data lines
3586 2 : std::string WindowNameInW5DataFile;
3587 2 : std::string W5Name;
3588 2 : Array1D_string GasName(3); // Gas name from data file
3589 2 : std::string LayerName; // Layer name from data file
3590 2 : std::string MullionOrientation; // Horizontal, vertical or none
3591 : int LineNum;
3592 2 : Array1D_int NGlass(2); // Number of glass layers in glazing system
3593 2 : Array2D_int NumGases(4, 2); // Number of gases in each gap of a glazing system
3594 2 : Array2D_int MaterNumSysGlass(5, 2); // Material numbers for glazing system / glass combinations
3595 2 : Array2D_int MaterNumSysGap(4, 2); // Material numbers for glazing system / gap combinations
3596 : int TotFrameDividerPrev; // Number of FrameAndDivider objects before adding ones from W5DataFile
3597 2 : Array1D_int NGaps(2); // Number of gaps in window construction
3598 : int NGlSys; // Number of glazing systems (normally 1, but 2 for mullioned window
3599 : // with two different glazing systems
3600 : int loop; // DO loop counter
3601 : int ILine; // Line counter
3602 : int ConstrNum; // Construction number
3603 : int IGlass; // Glass layer counter
3604 : int IGap; // Gap counter
3605 : // INTEGER :: ICoeff ! Gas property coefficient counter
3606 : int IGlSys; // Glazing system counter
3607 : int FrDivNum; // FrameDivider number
3608 2 : Array1D<Real64> WinHeight(2); // Height, width for glazing system (m)
3609 2 : Array1D<Real64> WinWidth(2);
3610 2 : Array1D<Real64> UValCenter(2); // Center of glass U-value (W/m2-K) for glazing system
3611 2 : Array1D<Real64> SCCenter(2); // Center of glass shading coefficient for glazing system
3612 2 : Array1D<Real64> SHGCCenter(2); // Center of glass solar heat gain coefficient for glazing system
3613 2 : Array1D<Real64> TVisCenter(2); // Center of glass visible transmittance for glazing system
3614 2 : Array1D<Real64> TsolTemp(Window::numPhis + 1); // Solar transmittance vs incidence angle; diffuse trans.
3615 : std::array<Real64, Window::numPhis> Tsol;
3616 2 : Array2D<Real64> AbsSolTemp(Window::maxGlassLayers, Window::numPhis + 1); // Solar absorptance vs inc. angle in each glass layer
3617 2 : Array1D<std::array<Real64, Window::numPhis>> AbsSol(Window::maxGlassLayers); // Solar absorptance vs inc. angle in each glass layer
3618 2 : Array1D<Real64> RfsolTemp(Window::numPhis + 1); // Front solar reflectance vs inc. angle
3619 : std::array<Real64, Window::numPhis> Rfsol;
3620 2 : Array1D<Real64> RbsolTemp(Window::numPhis + 1); // Back solar reflectance vs inc. angle
3621 : std::array<Real64, Window::numPhis> Rbsol;
3622 2 : Array1D<Real64> TvisTemp(Window::numPhis + 1); // Visible transmittance vs inc. angle
3623 : std::array<Real64, Window::numPhis> Tvis;
3624 2 : Array1D<Real64> RfvisTemp(Window::numPhis + 1); // Front visible reflectance vs inc. angle
3625 : std::array<Real64, Window::numPhis> Rfvis;
3626 2 : Array1D<Real64> RbvisTemp(Window::numPhis + 1); // Back visible reflectance vs inc. angle
3627 : std::array<Real64, Window::numPhis> Rbvis;
3628 :
3629 : std::array<Real64, Window::numPhis> tsolFit; // Fitted solar transmittance vs incidence angle
3630 : std::array<Real64, Window::numPhis> tvisFit; // Fitted visible transmittance vs incidence angle
3631 : std::array<Real64, Window::numPhis> rfsolFit; // Fitted solar front reflectance vs incidence angle
3632 : Array1D<std::array<Real64, Window::numPhis>> solabsFit(
3633 2 : Window::maxGlassLayers); // Fitted solar absorptance vs incidence angle for each glass layer
3634 2 : Array1D_string DividerType(2); // Divider type: DividedLite or Suspended
3635 : Real64 FrameWidth;
3636 : Real64 MullionWidth;
3637 : Real64 FrameProjectionOut;
3638 : Real64 FrameProjectionIn;
3639 : Real64 FrameConductance;
3640 : Real64 FrEdgeToCenterGlCondRatio;
3641 : Real64 FrameSolAbsorp;
3642 : Real64 FrameVisAbsorp;
3643 : Real64 FrameEmis;
3644 2 : Array1D_int HorDividers(2); // For divider: number horizontal for each glazing system
3645 2 : Array1D_int VertDividers(2); // For divider: number vertical for each glazing system
3646 2 : Array1D<Real64> DividerWidth(2);
3647 2 : Array1D<Real64> DividerProjectionOut(2);
3648 2 : Array1D<Real64> DividerProjectionIn(2);
3649 2 : Array1D<Real64> DividerConductance(2);
3650 2 : Array1D<Real64> DivEdgeToCenterGlCondRatio(2);
3651 2 : Array1D<Real64> DividerSolAbsorp(2);
3652 2 : Array1D<Real64> DividerVisAbsorp(2);
3653 2 : Array1D<Real64> DividerEmis(2);
3654 : std::string::size_type endcol;
3655 :
3656 2 : auto &s_mat = state.dataMaterial;
3657 : // Object Data
3658 :
3659 : // In the following four gas-related data sets, the first
3660 : // index is gas type (1=air, 2=Argon, 3=Krypton, 4=Xenon)
3661 : // and the second index gives a,b,c in the expression
3662 : // property value = a + bT(K) + cT(K)**2, where T is mean
3663 : // gap temperature in deg K.
3664 :
3665 2 : ConstructionFound = false;
3666 : // ErrorsFound = .FALSE.
3667 2 : EOFonFile = false;
3668 2 : std::string contextString = "HeatBalanceManager::SearchWindow5DataFile: ";
3669 :
3670 2 : state.files.TempFullFilePath.filePath = CheckForActualFilePath(state, DesiredFilePath, contextString);
3671 :
3672 : // INQUIRE(FILE=TRIM(DesiredFileName), EXIST=exists)
3673 2 : if (state.files.TempFullFilePath.filePath.empty()) {
3674 0 : ShowFatalError(state, "Program terminates due to these conditions.");
3675 : }
3676 :
3677 4 : auto W5DataFile = state.files.TempFullFilePath.open(state, "SearchWindow5DataFile");
3678 2 : auto NextLine = W5DataFile.readLine();
3679 2 : endcol = len(NextLine.data);
3680 2 : if (endcol > 0) {
3681 2 : if (int(NextLine.data[endcol - 1]) == DataSystemVariables::iUnicode_end) {
3682 0 : ShowSevereError(state,
3683 0 : format("SearchWindow5DataFile: For \"{}\" in {} file, appears to be a Unicode or binary file.",
3684 : DesiredConstructionName,
3685 : DesiredFilePath));
3686 0 : ShowContinueError(state, "...This file cannot be read by this program. Please save as PC or Unix file and try again");
3687 0 : ShowFatalError(state, "Program terminates due to previous condition.");
3688 : }
3689 : }
3690 2 : W5DataFile.rewind();
3691 2 : FileLineCount = 0;
3692 :
3693 2 : NextLine = W5DataFile.readLine();
3694 2 : if (NextLine.eof) goto Label1000;
3695 2 : ++FileLineCount;
3696 2 : if (!has_prefixi(NextLine.data, "WINDOW5")) {
3697 0 : ShowSevereError(state, format("HeatBalanceManager: SearchWindow5DataFile: Error in Data File={}", DesiredFilePath));
3698 0 : ShowFatalError(
3699 : state,
3700 0 : format("Error reading Window5 Data File: first word of window entry is \"{}\", should be Window5.", NextLine.data.substr(0, 7)));
3701 : }
3702 :
3703 2 : Label10:;
3704 10 : for (LineNum = 2; LineNum <= 5; ++LineNum) {
3705 8 : NextLine = W5DataFile.readLine();
3706 8 : if (NextLine.eof) goto Label1000;
3707 8 : DataLine(LineNum) = NextLine.data;
3708 8 : ++FileLineCount;
3709 : }
3710 :
3711 : // Get window name and check for match
3712 2 : W5Name = std::string{DataLine(4).substr(19)};
3713 2 : WindowNameInW5DataFile = Util::makeUPPER(W5Name);
3714 2 : if (DesiredConstructionName != WindowNameInW5DataFile) {
3715 : // Doesn't match; read through file until next window entry is found
3716 0 : Label20:;
3717 0 : NextLine = W5DataFile.readLine();
3718 0 : if (NextLine.eof) goto Label1000;
3719 0 : ++FileLineCount;
3720 0 : if (!has_prefixi(NextLine.data, "WINDOW5")) goto Label20;
3721 : // Beginning of next window entry found
3722 0 : goto Label10;
3723 : } else {
3724 : // Match found
3725 2 : ConstructionFound = true;
3726 :
3727 : // Create Material:WindowGlass, Material:WindowGas, Construction
3728 : // and WindowFrameAndDividerObjects for this window
3729 :
3730 2 : NextLine = W5DataFile.readLine();
3731 2 : if (NextLine.eof) goto Label1000;
3732 2 : ++FileLineCount;
3733 2 : bool error = false;
3734 2 : NGlSys = static_cast<int>(Util::ProcessNumber(NextLine.data.substr(19), error));
3735 2 : if (NGlSys <= 0 || NGlSys > 2 || error) {
3736 0 : ShowFatalError(
3737 : state,
3738 0 : format("Construction={} from the Window5 data file cannot be used: it has {} glazing systems; only 1 or 2 are allowed.",
3739 : DesiredConstructionName,
3740 : NGlSys));
3741 : }
3742 2 : NextLine = W5DataFile.readLine();
3743 2 : if (NextLine.eof) goto Label1000;
3744 2 : ++FileLineCount;
3745 4 : for (IGlSys = 1; IGlSys <= NGlSys; ++IGlSys) {
3746 2 : NextLine = W5DataFile.readLine();
3747 2 : if (NextLine.eof) goto Label1000;
3748 2 : ++FileLineCount;
3749 :
3750 2 : const bool succeeded = readList(NextLine.data.substr(19),
3751 : WinHeight(IGlSys),
3752 : WinWidth(IGlSys),
3753 : NGlass(IGlSys),
3754 : UValCenter(IGlSys),
3755 : SCCenter(IGlSys),
3756 : SHGCCenter(IGlSys),
3757 : TVisCenter(IGlSys));
3758 2 : if (!succeeded) {
3759 0 : ShowSevereError(
3760 : state,
3761 0 : format("HeatBalanceManager: SearchWindow5DataFile: Error in Read of glazing system values. For glazing system={}", IGlSys));
3762 0 : ShowContinueError(state, format("Line (~{}) in error (first 100 characters)={}", FileLineCount, NextLine.data.substr(0, 100)));
3763 0 : ErrorsFound = true;
3764 : }
3765 2 : if (WinHeight(IGlSys) == 0.0 || WinWidth(IGlSys) == 0.0) {
3766 0 : ShowSevereError(state,
3767 0 : format("HeatBalanceManager: SearchWindow5DataFile: Construction={} from the Window5 data file cannot be used: it "
3768 : "has window height or width = 0 for glazing system {}",
3769 : DesiredConstructionName,
3770 : IGlSys));
3771 0 : ErrorsFound = true;
3772 : }
3773 2 : if (NGlass(IGlSys) <= 0 || NGlass(IGlSys) > 4) {
3774 0 : ShowSevereError(state,
3775 0 : format("HeatBalanceManager: SearchWindow5DataFile: Construction={} from the Window5 data file cannot be used: it "
3776 : "has 0 or more than 4 glass layers in glazing system {}",
3777 : DesiredConstructionName,
3778 : IGlSys));
3779 0 : ErrorsFound = true;
3780 : }
3781 2 : if (UValCenter(IGlSys) <= 0.0) {
3782 0 : ShowSevereError(state,
3783 0 : format("HeatBalanceManager: SearchWindow5DataFile: Construction={} from the Window5 data file cannot be used: it "
3784 : "has Center-of-Glass U-value <= 0 in glazing system {}",
3785 : DesiredConstructionName,
3786 : IGlSys));
3787 0 : ErrorsFound = true;
3788 : }
3789 2 : if (SCCenter(IGlSys) <= 0.0) {
3790 2 : ShowWarningError(
3791 : state,
3792 2 : format("HeatBalanceManager: SearchWindow5DataFile: Construction={} from the Window5 data file has flawed data: it "
3793 : "has a Shading Coefficient <= 0 in glazing system {}",
3794 : DesiredConstructionName,
3795 : IGlSys));
3796 : }
3797 2 : if (SHGCCenter(IGlSys) <= 0.0) {
3798 2 : ShowWarningError(
3799 : state,
3800 2 : format("HeatBalanceManager: SearchWindow5DataFile: Construction={} from the Window5 data file has flawed data: it "
3801 : "has a SHGC <= 0 in glazing system {}",
3802 : DesiredConstructionName,
3803 : IGlSys));
3804 : }
3805 2 : WinHeight(IGlSys) *= 0.001;
3806 2 : WinWidth(IGlSys) *= 0.001;
3807 : }
3808 24 : for (LineNum = 1; LineNum <= 11; ++LineNum) {
3809 22 : NextLine = W5DataFile.readLine();
3810 22 : if (NextLine.eof) goto Label1000;
3811 22 : DataLine(LineNum) = NextLine.data;
3812 : }
3813 :
3814 : // Mullion width and orientation
3815 2 : MullionWidth = 0.0;
3816 2 : MullionOrientation = "Vertical";
3817 2 : if (NGlSys == 2) {
3818 0 : error = false;
3819 0 : MullionWidth = Util::ProcessNumber(DataLine(10).substr(19), error);
3820 0 : if (error) {
3821 0 : ShowSevereError(state, "HeatBalanceManager: SearchWindow5DataFile: Error in Read of Mullion Width.");
3822 0 : ShowContinueError(state,
3823 0 : format("Line (~{}) in error (first 100 characters)={}", FileLineCount + 10, DataLine(10).substr(0, 100)));
3824 0 : ErrorsFound = true;
3825 : }
3826 0 : MullionWidth *= 0.001;
3827 0 : MullionOrientation = Util::ProcessNumber(DataLine(10).substr(88), error);
3828 0 : if (error) {
3829 0 : ShowSevereError(state, "HeatBalanceManager: SearchWindow5DataFile: Error in Read of Mullion Orientation.");
3830 0 : ShowContinueError(state,
3831 0 : format("Line (~{}) in error (first 100 characters)={}", FileLineCount + 10, DataLine(10).substr(0, 100)));
3832 0 : ErrorsFound = true;
3833 : }
3834 : }
3835 :
3836 : // Frame data; if there are two glazing systems, the frame is assumed to be
3837 : // the same for both.
3838 2 : FrameWidth = 0.0;
3839 2 : FrameProjectionOut = 0.0;
3840 2 : FrameProjectionIn = 0.0;
3841 2 : FrameConductance = 0.0;
3842 2 : FrEdgeToCenterGlCondRatio = 0.0;
3843 2 : FrameSolAbsorp = 0.0;
3844 2 : FrameVisAbsorp = 0.0;
3845 2 : FrameEmis = 0.0;
3846 2 : const bool succeeded = readList(DataLine(11).substr(19),
3847 : FrameWidth,
3848 : FrameProjectionOut,
3849 : FrameProjectionIn,
3850 : FrameConductance,
3851 : FrEdgeToCenterGlCondRatio,
3852 : FrameSolAbsorp,
3853 : FrameVisAbsorp,
3854 : FrameEmis);
3855 2 : if (!succeeded) {
3856 0 : ShowSevereError(state, "HeatBalanceManager: SearchWindow5DataFile: Error in Read of frame data values.");
3857 0 : ShowContinueError(state, format("Line (~{}) in error (first 100 characters)={}", FileLineCount + 11, DataLine(11).substr(0, 100)));
3858 0 : ErrorsFound = true;
3859 : }
3860 2 : if (FrameWidth > 0.0) {
3861 2 : if (FrameConductance <= 0.0) {
3862 0 : ShowSevereError(state,
3863 0 : format("HeatBalanceManager: SearchWindow5DataFile: Construction={} from the Window5 data file cannot be used: it "
3864 : "has Frame Conductance <= 0.0",
3865 : DesiredConstructionName));
3866 0 : ErrorsFound = true;
3867 : }
3868 : // Relax this check for Window5 data: 1/28/2008.
3869 : // IF(FrEdgeToCenterGlCondRatio < 1.0) THEN
3870 : // CALL ShowSevereError(state, 'HeatBalanceManager: SearchWindow5DataFile: Construction='//TRIM(DesiredConstructionName)//
3871 : // & ' from the Window5 data file cannot be used: it has Frame Edge-of-Glass Conduction Ratio < 1.0')
3872 : // ErrorsFound = .TRUE.
3873 : // END IF
3874 2 : if (FrameSolAbsorp < 0.0 || FrameSolAbsorp > 1.0) {
3875 0 : ShowSevereError(state,
3876 0 : "HeatBalanceManager: SearchWindow5DataFile: Construction=" + DesiredConstructionName +
3877 : " from the Window5 data file cannot be used: it has Frame Solar Absorptance < 0.0 or > 1.0");
3878 0 : ErrorsFound = true;
3879 : }
3880 2 : if (FrameEmis <= 0.0 || FrameEmis >= 1.0) {
3881 0 : ShowSevereError(
3882 : state,
3883 0 : format("HeatBalanceManager: SearchWindow5DataFile: Construction={} from the Window5 data file cannot be used: it has "
3884 : "Frame Emissivity <= 0.0 or >= 1.0",
3885 : DesiredConstructionName));
3886 0 : ErrorsFound = true;
3887 : }
3888 : }
3889 2 : FrameWidth *= 0.001;
3890 2 : FrameProjectionOut *= 0.001;
3891 2 : FrameProjectionIn *= 0.001;
3892 2 : FileLineCount += 11;
3893 :
3894 2 : NextLine = W5DataFile.readLine();
3895 2 : if (NextLine.eof) goto Label1000;
3896 2 : ++FileLineCount;
3897 :
3898 : // Divider data for each glazing system
3899 4 : for (IGlSys = 1; IGlSys <= NGlSys; ++IGlSys) {
3900 2 : NextLine = W5DataFile.readLine();
3901 2 : if (NextLine.eof) goto Label1000;
3902 2 : ++FileLineCount;
3903 :
3904 2 : const bool dividerReadSucceeded = readList(NextLine.data.substr(19),
3905 : DividerWidth(IGlSys),
3906 : DividerProjectionOut(IGlSys),
3907 : DividerProjectionIn(IGlSys),
3908 : DividerConductance(IGlSys),
3909 : DivEdgeToCenterGlCondRatio(IGlSys),
3910 : DividerSolAbsorp(IGlSys),
3911 : DividerVisAbsorp(IGlSys),
3912 : DividerEmis(IGlSys),
3913 : DividerType(IGlSys),
3914 : HorDividers(IGlSys),
3915 : VertDividers(IGlSys));
3916 2 : if (!dividerReadSucceeded) {
3917 0 : ShowSevereError(
3918 : state,
3919 0 : format("HeatBalanceManager: SearchWindow5DataFile: Error in Read of divider data values. For Glazing System={}", IGlSys));
3920 0 : ShowContinueError(state,
3921 0 : format("Line (~{}) in error (first 100 characters)={}", FileLineCount + 11, NextLine.data.substr(0, 100)));
3922 0 : ErrorsFound = true;
3923 : }
3924 2 : uppercase(DividerType(IGlSys));
3925 2 : if (DividerWidth(IGlSys) > 0.0) {
3926 2 : if (HorDividers(IGlSys) == 0 && VertDividers(IGlSys) == 0) {
3927 0 : ShowSevereError(
3928 : state,
3929 0 : format("HeatBalanceManager: SearchWindow5DataFile: Construction={} from the Window5 data file cannot be used:",
3930 : DesiredConstructionName));
3931 0 : ShowContinueError(
3932 0 : state, format("glazing system {} has a divider but number of horizontal and vertical divider elements = 0", IGlSys));
3933 0 : ErrorsFound = true;
3934 : }
3935 2 : if (DividerConductance(IGlSys) <= 0.0) {
3936 0 : ShowSevereError(
3937 : state,
3938 0 : format("HeatBalanceManager: SearchWindow5DataFile: Construction={} from the Window5 data file cannot be used:",
3939 : DesiredConstructionName));
3940 0 : ShowContinueError(state, format("glazing system {} has Divider Conductance <= 0.0", IGlSys));
3941 0 : ErrorsFound = true;
3942 : }
3943 2 : if (DivEdgeToCenterGlCondRatio(IGlSys) < 1.0) {
3944 0 : ShowSevereError(
3945 : state,
3946 0 : format("HeatBalanceManager: SearchWindow5DataFile: Construction={} from the Window5 data file cannot be used:",
3947 : DesiredConstructionName));
3948 0 : ShowContinueError(state, format("glazing system {} has Divider Edge-Of-Glass Conduction Ratio < 1.0", IGlSys));
3949 0 : ErrorsFound = true;
3950 : }
3951 2 : if (DividerSolAbsorp(IGlSys) < 0.0 || DividerSolAbsorp(IGlSys) > 1.0) {
3952 0 : ShowSevereError(
3953 : state,
3954 0 : format("HeatBalanceManager: SearchWindow5DataFile: Construction={} from the Window5 data file cannot be used:",
3955 : DesiredConstructionName));
3956 0 : ShowContinueError(state, format("glazing system {} has Divider Solar Absorptance < 0.0 or > 1.0", IGlSys));
3957 0 : ErrorsFound = true;
3958 : }
3959 2 : if (DividerEmis(IGlSys) <= 0.0 || DividerEmis(IGlSys) >= 1.0) {
3960 0 : ShowSevereError(
3961 : state,
3962 0 : format("HeatBalanceManager: SearchWindow5DataFile: Construction={} from the Window5 data file cannot be used:",
3963 : DesiredConstructionName));
3964 0 : ShowContinueError(state, format("glazing system {} has Divider Emissivity <= 0.0 or >= 1.0", IGlSys));
3965 0 : ErrorsFound = true;
3966 : }
3967 2 : if (DividerType(IGlSys) != "DIVIDEDLITE" && DividerType(IGlSys) != "SUSPENDED") {
3968 0 : ShowSevereError(
3969 : state,
3970 0 : format("HeatBalanceManager: SearchWindow5DataFile: Construction={} from the Window5 data file cannot be used:",
3971 : DesiredConstructionName));
3972 0 : ShowContinueError(
3973 : state,
3974 0 : format("glazing system {} has Divider Type = {}; it should be DIVIDEDLITE or SUSPENDED.", IGlSys, DividerType(IGlSys)));
3975 0 : ErrorsFound = true;
3976 : }
3977 : }
3978 2 : DividerWidth(IGlSys) *= 0.001;
3979 2 : if (DividerType(IGlSys) == "DIVIDEDLITE") {
3980 0 : DividerProjectionOut(IGlSys) *= 0.001;
3981 0 : DividerProjectionIn(IGlSys) *= 0.001;
3982 : } else {
3983 2 : DividerProjectionOut(IGlSys) = 0.0;
3984 2 : DividerProjectionIn(IGlSys) = 0.0;
3985 : }
3986 : }
3987 :
3988 2 : if (ErrorsFound)
3989 0 : ShowFatalError(state,
3990 0 : format("HeatBalanceManager: SearchWindow5DataFile: Construction={} from the Window5 data file cannot be used because "
3991 : "of above errors",
3992 : DesiredConstructionName));
3993 :
3994 4 : for (IGlSys = 1; IGlSys <= NGlSys; ++IGlSys) {
3995 2 : NGaps(IGlSys) = NGlass(IGlSys) - 1;
3996 : }
3997 :
3998 : // Glass objects
3999 2 : NextLine = W5DataFile.readLine();
4000 2 : if (NextLine.eof) goto Label1000;
4001 2 : ++FileLineCount;
4002 4 : for (IGlSys = 1; IGlSys <= NGlSys; ++IGlSys) {
4003 6 : for (IGlass = 1; IGlass <= NGlass(IGlSys); ++IGlass) {
4004 4 : auto *mat = new Material::MaterialGlass;
4005 4 : mat->group = Material::Group::Glass;
4006 8 : mat->Name = (NGlSys == 1) ? format("W5:{}:GLASS{}", DesiredConstructionName, NumName(IGlass))
4007 4 : : format("W5:{}:{}:GLASS{}", DesiredConstructionName, NumName(IGlSys), NumName(IGlass));
4008 :
4009 4 : s_mat->materials.push_back(mat);
4010 4 : mat->Num = s_mat->materials.isize();
4011 4 : s_mat->materialMap.insert_or_assign(mat->Name, mat->Num);
4012 :
4013 4 : MaterNumSysGlass(IGlass, IGlSys) = mat->Num;
4014 :
4015 4 : NextLine = W5DataFile.readLine();
4016 4 : ++FileLineCount;
4017 :
4018 4 : readList(NextLine.data.substr(25),
4019 4 : mat->Thickness,
4020 4 : mat->Conductivity,
4021 4 : mat->Trans,
4022 4 : mat->ReflectSolBeamFront,
4023 4 : mat->ReflectSolBeamBack,
4024 4 : mat->TransVis,
4025 4 : mat->ReflectVisBeamFront,
4026 4 : mat->ReflectVisBeamBack,
4027 4 : mat->TransThermal,
4028 4 : mat->AbsorpThermalFront,
4029 4 : mat->AbsorpThermalBack,
4030 : LayerName);
4031 :
4032 4 : mat->Thickness *= 0.001;
4033 4 : if (mat->Thickness <= 0.0) {
4034 : }
4035 4 : mat->Roughness = Material::SurfaceRoughness::VerySmooth;
4036 4 : mat->AbsorpThermal = mat->AbsorpThermalBack;
4037 4 : if (mat->Thickness <= 0.0) {
4038 0 : ShowSevereError(state,
4039 0 : format("SearchWindow5DataFile: Material=\"{}\" has thickness of 0.0. Will be set to thickness = .001 but "
4040 : "inaccuracies may result.",
4041 0 : mat->Name));
4042 0 : ShowContinueError(state, format("Line being read={}", NextLine.data));
4043 0 : ShowContinueError(state, format("Thickness field starts at column 26={}", NextLine.data.substr(25)));
4044 0 : mat->Thickness = 0.001;
4045 : }
4046 : }
4047 : }
4048 :
4049 : // Gap objects
4050 2 : NextLine = W5DataFile.readLine();
4051 2 : if (NextLine.eof) goto Label1000;
4052 2 : ++FileLineCount;
4053 4 : for (IGlSys = 1; IGlSys <= NGlSys; ++IGlSys) {
4054 4 : for (IGap = 1; IGap <= NGaps(IGlSys); ++IGap) {
4055 2 : auto *matGas = new Material::MaterialGasMix;
4056 4 : matGas->Name = (NGlSys == 1) ? format("W5:{}:GAP{}", DesiredConstructionName, NumName(IGap))
4057 2 : : format("W5:{}:{}:GAP{}", DesiredConstructionName, NumName(IGlSys), NumName(IGap));
4058 2 : s_mat->materials.push_back(matGas);
4059 2 : matGas->Num = s_mat->materials.isize();
4060 2 : s_mat->materialMap.insert_or_assign(matGas->Name, matGas->Num);
4061 :
4062 2 : MaterNumSysGap(IGap, IGlSys) = matGas->Num;
4063 2 : NextLine = W5DataFile.readLine();
4064 2 : ++FileLineCount;
4065 2 : readList(NextLine.data.substr(23), matGas->Thickness, NumGases(IGap, IGlSys));
4066 2 : matGas->Thickness *= 0.001;
4067 2 : matGas->Roughness = Material::SurfaceRoughness::MediumRough; // Unused
4068 : }
4069 : }
4070 :
4071 : // Gap/gas materials are read in multiple passes
4072 2 : NextLine = W5DataFile.readLine();
4073 2 : if (NextLine.eof) goto Label1000; // Exsqueeze me?
4074 2 : ++FileLineCount;
4075 4 : for (IGlSys = 1; IGlSys <= NGlSys; ++IGlSys) {
4076 4 : for (IGap = 1; IGap <= NGaps(IGlSys); ++IGap) {
4077 2 : int matNum = MaterNumSysGap(IGap, IGlSys);
4078 2 : auto *matGas = dynamic_cast<Material::MaterialGasMix *>(s_mat->materials(matNum));
4079 2 : assert(matGas != nullptr);
4080 2 : matGas->numGases = NumGases(IGap, IGlSys);
4081 4 : for (int IGas = 0; IGas < matGas->numGases; ++IGas) {
4082 2 : auto &gas = matGas->gases[IGas];
4083 2 : NextLine = W5DataFile.readLine();
4084 2 : ++FileLineCount;
4085 2 : readList(NextLine.data.substr(19),
4086 : GasName(IGas + 1),
4087 2 : matGas->gasFracts[IGas],
4088 2 : gas.wght,
4089 2 : gas.con.c0,
4090 2 : gas.con.c1,
4091 2 : gas.con.c2,
4092 2 : gas.vis.c0,
4093 2 : gas.vis.c1,
4094 2 : gas.vis.c2,
4095 2 : gas.cp.c0,
4096 2 : gas.cp.c1,
4097 2 : gas.cp.c2);
4098 : }
4099 : // Nominal resistance of gap at room temperature (based on first gas in mixture)
4100 2 : auto const &gas0 = matGas->gases[0];
4101 2 : matGas->NominalR = matGas->Thickness / (gas0.con.c0 + gas0.con.c1 * 300.0 + gas0.con.c2 * 90000.0);
4102 : }
4103 : }
4104 :
4105 : // Construction objects
4106 :
4107 : // reallocate Construct types
4108 2 : state.dataHeatBal->TotConstructs += NGlSys;
4109 2 : state.dataConstruction->Construct.redimension(state.dataHeatBal->TotConstructs);
4110 2 : state.dataHeatBal->NominalRforNominalUCalculation.redimension(state.dataHeatBal->TotConstructs);
4111 2 : state.dataHeatBal->NominalU.redimension(state.dataHeatBal->TotConstructs);
4112 2 : state.dataHeatBal->NominalUBeforeAdjusted.redimension(state.dataHeatBal->TotConstructs);
4113 2 : state.dataHeatBal->CoeffAdjRatio.redimension(state.dataHeatBal->TotConstructs) = 1.0;
4114 :
4115 : // these Construct arrays dimensioned based on MaxSolidWinLayers
4116 4 : for (int i = (state.dataHeatBal->TotConstructs - NGlSys + 1); i <= state.dataHeatBal->TotConstructs; ++i) {
4117 2 : auto &e = state.dataConstruction->Construct(i);
4118 2 : e.setArraysBasedOnMaxSolidWinLayers(state);
4119 : }
4120 :
4121 2 : NextLine = W5DataFile.readLine();
4122 2 : if (NextLine.eof) goto Label1000;
4123 2 : ++FileLineCount;
4124 :
4125 : // When pulling in develop, the following two blocks appear to have been modified in develop,
4126 : // but removed entirely in this branch. I'm going to leave them commented.
4127 : // Pre-calculate constants
4128 : // for (IPhi = 1; IPhi <= 10; ++IPhi) {
4129 : // CosPhiIndepVar(IPhi) = std::cos((IPhi - 1) * 10.0 * Constant::DegToRad);
4130 : //}
4131 :
4132 : // Pre-calculate constants
4133 : // for (IPhi = 1; IPhi <= 10; ++IPhi) {
4134 : // Phi = double(IPhi - 1) * 10.0;
4135 : // CosPhi(IPhi) = std::cos(Phi * Constant::DegToRad);
4136 : // if (std::abs(CosPhi(IPhi)) < 0.0001) CosPhi(IPhi) = 0.0;
4137 : //}
4138 :
4139 4 : for (IGlSys = 1; IGlSys <= NGlSys; ++IGlSys) {
4140 2 : ConstrNum = state.dataHeatBal->TotConstructs - NGlSys + IGlSys;
4141 2 : auto &thisConstruct = state.dataConstruction->Construct(ConstrNum);
4142 2 : if (IGlSys == 1) {
4143 2 : thisConstruct.Name = DesiredConstructionName;
4144 : } else {
4145 0 : thisConstruct.Name = DesiredConstructionName + ":2";
4146 : }
4147 24 : for (loop = 1; loop <= Construction::MaxLayersInConstruct; ++loop) {
4148 22 : thisConstruct.LayerPoint(loop) = 0;
4149 : }
4150 2 : thisConstruct.InsideAbsorpSolar = 0.0;
4151 2 : thisConstruct.OutsideAbsorpSolar = 0.0;
4152 2 : thisConstruct.DayltPropPtr = 0;
4153 2 : thisConstruct.CTFCross.fill(0.0);
4154 2 : thisConstruct.CTFFlux.fill(0.0);
4155 2 : thisConstruct.CTFInside.fill(0.0);
4156 2 : thisConstruct.CTFOutside.fill(0.0);
4157 2 : thisConstruct.CTFSourceIn.fill(0.0);
4158 2 : thisConstruct.CTFSourceOut.fill(0.0);
4159 2 : thisConstruct.CTFTimeStep = 0.0;
4160 2 : thisConstruct.CTFTSourceOut.fill(0.0);
4161 2 : thisConstruct.CTFTSourceIn.fill(0.0);
4162 2 : thisConstruct.CTFTSourceQ.fill(0.0);
4163 2 : thisConstruct.CTFTUserOut.fill(0.0);
4164 2 : thisConstruct.CTFTUserIn.fill(0.0);
4165 2 : thisConstruct.CTFTUserSource.fill(0.0);
4166 2 : thisConstruct.NumHistories = 0;
4167 2 : thisConstruct.NumCTFTerms = 0;
4168 2 : thisConstruct.UValue = 0.0;
4169 2 : thisConstruct.SourceSinkPresent = false;
4170 2 : thisConstruct.SolutionDimensions = 0;
4171 2 : thisConstruct.SourceAfterLayer = 0;
4172 2 : thisConstruct.TempAfterLayer = 0;
4173 2 : thisConstruct.ThicknessPerpend = 0.0;
4174 2 : thisConstruct.AbsDiff = 0.0;
4175 2 : thisConstruct.AbsDiffBack = 0.0;
4176 2 : thisConstruct.AbsDiffShade = 0.0;
4177 2 : thisConstruct.AbsDiffBackShade = 0.0;
4178 2 : thisConstruct.ShadeAbsorpThermal = 0.0;
4179 2 : std::fill(thisConstruct.AbsBeamShadeCoef.begin(), thisConstruct.AbsBeamShadeCoef.end(), 0.0);
4180 2 : thisConstruct.AbsDiffIn = 0.0;
4181 2 : thisConstruct.AbsDiffOut = 0.0;
4182 2 : thisConstruct.TransDiff = 0.0;
4183 2 : thisConstruct.TransDiffVis = 0.0;
4184 2 : thisConstruct.ReflectSolDiffBack = 0.0;
4185 2 : thisConstruct.ReflectSolDiffFront = 0.0;
4186 2 : thisConstruct.ReflectVisDiffBack = 0.0;
4187 2 : thisConstruct.ReflectVisDiffFront = 0.0;
4188 2 : std::fill(thisConstruct.TransSolBeamCoef.begin(), thisConstruct.TransSolBeamCoef.end(), 0.0);
4189 2 : std::fill(thisConstruct.TransVisBeamCoef.begin(), thisConstruct.TransVisBeamCoef.end(), 0.0);
4190 2 : std::fill(thisConstruct.ReflSolBeamFrontCoef.begin(), thisConstruct.ReflSolBeamFrontCoef.end(), 0.0);
4191 2 : std::fill(thisConstruct.ReflSolBeamBackCoef.begin(), thisConstruct.ReflSolBeamBackCoef.end(), 0.0);
4192 2 : thisConstruct.W5FrameDivider = 0;
4193 2 : thisConstruct.TotLayers = NGlass(IGlSys) + NGaps(IGlSys);
4194 2 : thisConstruct.TotGlassLayers = NGlass(IGlSys);
4195 2 : thisConstruct.TotSolidLayers = NGlass(IGlSys);
4196 :
4197 6 : for (int Layer = 1; Layer <= state.dataHeatBal->MaxSolidWinLayers; ++Layer) {
4198 4 : std::fill(thisConstruct.AbsBeamCoef(Layer).begin(), thisConstruct.AbsBeamCoef(Layer).end(), 0.0);
4199 4 : std::fill(thisConstruct.AbsBeamBackCoef(Layer).begin(), thisConstruct.AbsBeamBackCoef(Layer).end(), 0.0);
4200 : }
4201 :
4202 6 : for (IGlass = 1; IGlass <= NGlass(IGlSys); ++IGlass) {
4203 4 : thisConstruct.LayerPoint(2 * IGlass - 1) = MaterNumSysGlass(IGlass, IGlSys);
4204 4 : if (IGlass < NGlass(IGlSys)) thisConstruct.LayerPoint(2 * IGlass) = MaterNumSysGap(IGlass, IGlSys);
4205 : }
4206 :
4207 2 : thisConstruct.OutsideRoughness = Material::SurfaceRoughness::VerySmooth;
4208 2 : thisConstruct.InsideAbsorpThermal = s_mat->materials(thisConstruct.LayerPoint(thisConstruct.TotLayers))->AbsorpThermalBack;
4209 2 : thisConstruct.OutsideAbsorpThermal = s_mat->materials(thisConstruct.LayerPoint(1))->AbsorpThermalFront;
4210 2 : thisConstruct.TypeIsWindow = true;
4211 2 : thisConstruct.FromWindow5DataFile = true;
4212 2 : thisConstruct.W5FileGlazingSysHeight = WinHeight(IGlSys);
4213 2 : thisConstruct.W5FileGlazingSysWidth = WinWidth(IGlSys);
4214 :
4215 2 : thisConstruct.W5FileMullionOrientation = static_cast<DataWindowEquivalentLayer::Orientation>(
4216 2 : getEnumValue(DataWindowEquivalentLayer::orientationNamesUC, MullionOrientation));
4217 :
4218 2 : thisConstruct.W5FileMullionWidth = MullionWidth;
4219 :
4220 : // Fill Construct with system transmission, reflection and absorption properties
4221 :
4222 2 : NextLine = W5DataFile.readLine();
4223 2 : if (NextLine.eof) goto Label1000;
4224 2 : ++FileLineCount;
4225 2 : if (IGlSys == 1) {
4226 2 : NextLine = W5DataFile.readLine();
4227 2 : if (NextLine.eof) goto Label1000;
4228 2 : ++FileLineCount;
4229 : }
4230 2 : NextLine = W5DataFile.readLine();
4231 2 : if (NextLine.eof) goto Label1000;
4232 2 : ++FileLineCount;
4233 2 : if (!readItem(NextLine.data.substr(5), TsolTemp)) {
4234 0 : ShowSevereError(state, "HeatBalanceManager: SearchWindow5DataFile: Error in Read of TSol values.");
4235 0 : ShowContinueError(state, format("Line (~{}) in error (first 100 characters)={}", FileLineCount, NextLine.data.substr(0, 100)));
4236 0 : ErrorsFound = true;
4237 2 : } else if (any_lt(TsolTemp, 0.0) || any_gt(TsolTemp, 1.0)) {
4238 0 : ShowSevereError(state, "HeatBalanceManager: SearchWindow5DataFile: Error in Read of TSol values. (out of range [0,1])");
4239 0 : ShowContinueError(state, format("Line (~{}) in error (first 100 characters)={}", FileLineCount, NextLine.data.substr(0, 100)));
4240 0 : ErrorsFound = true;
4241 : }
4242 :
4243 6 : for (IGlass = 1; IGlass <= NGlass(IGlSys); ++IGlass) {
4244 4 : NextLine = W5DataFile.readLine();
4245 4 : ++FileLineCount;
4246 4 : if (!readItem(NextLine.data.substr(5), AbsSolTemp(IGlass, _))) {
4247 0 : ShowSevereError(state,
4248 0 : format("HeatBalanceManager: SearchWindow5DataFile: Error in Read of AbsSol values. For Glass={}", IGlass));
4249 0 : ShowContinueError(state,
4250 0 : format("Line (~{}) in error (first 100 characters)={}", FileLineCount, NextLine.data.substr(0, 100)));
4251 0 : ErrorsFound = true;
4252 4 : } else if (any_lt(AbsSolTemp(IGlass, _), 0.0) || any_gt(AbsSolTemp(IGlass, _), 1.0)) {
4253 0 : ShowSevereError(
4254 : state,
4255 0 : format("HeatBalanceManager: SearchWindow5DataFile: Error in Read of AbsSol values. (out of range [0,1]) For Glass={}",
4256 : IGlass));
4257 0 : ShowContinueError(state,
4258 0 : format("Line (~{}) in error (first 100 characters)={}", FileLineCount, NextLine.data.substr(0, 100)));
4259 0 : ErrorsFound = true;
4260 : }
4261 : }
4262 12 : for (ILine = 1; ILine <= 5; ++ILine) {
4263 10 : NextLine = W5DataFile.readLine();
4264 10 : DataLine(ILine) = NextLine.data;
4265 : }
4266 :
4267 2 : if (!readItem(DataLine(1).substr(5), RfsolTemp)) {
4268 0 : ShowSevereError(state, "HeatBalanceManager: SearchWindow5DataFile: Error in Read of RfSol values.");
4269 0 : ShowContinueError(state, format("Line (~{}) in error (first 100 characters)={}", FileLineCount + 1, DataLine(1).substr(0, 100)));
4270 0 : ErrorsFound = true;
4271 2 : } else if (any_lt(RfsolTemp, 0.0) || any_gt(RfsolTemp, 1.0)) {
4272 0 : ShowSevereError(state, "HeatBalanceManager: SearchWindow5DataFile: Error in Read of RfSol values. (out of range [0,1])");
4273 0 : ShowContinueError(state, format("Line (~{}) in error (first 100 characters)={}", FileLineCount + 1, DataLine(1).substr(0, 100)));
4274 0 : ErrorsFound = true;
4275 : }
4276 :
4277 2 : if (!readItem(DataLine(2).substr(5), RbsolTemp)) {
4278 0 : ShowSevereError(state, "HeatBalanceManager: SearchWindow5DataFile: Error in Read of RbSol values.");
4279 0 : ShowContinueError(state, format("Line (~{}) in error (first 100 characters)={}", FileLineCount + 2, DataLine(2).substr(0, 100)));
4280 0 : ErrorsFound = true;
4281 2 : } else if (any_lt(RbsolTemp, 0.0) || any_gt(RbsolTemp, 1.0)) {
4282 0 : ShowSevereError(state, "HeatBalanceManager: SearchWindow5DataFile: Error in Read of RbSol values. (out of range [0,1])");
4283 0 : ShowContinueError(state, format("Line (~{}) in error (first 100 characters)={}", FileLineCount + 2, DataLine(2).substr(0, 100)));
4284 0 : ErrorsFound = true;
4285 : }
4286 2 : if (!readItem(DataLine(3).substr(5), TvisTemp)) {
4287 0 : ShowSevereError(state, "HeatBalanceManager: SearchWindow5DataFile: Error in Read of Tvis values.");
4288 0 : ShowContinueError(state, format("Line (~{}) in error (first 100 characters)={}", FileLineCount + 3, DataLine(3).substr(0, 100)));
4289 0 : ErrorsFound = true;
4290 2 : } else if (any_lt(TvisTemp, 0.0) || any_gt(TvisTemp, 1.0)) {
4291 0 : ShowSevereError(state, "HeatBalanceManager: SearchWindow5DataFile: Error in Read of Tvis values. (out of range [0,1])");
4292 0 : ShowContinueError(state, format("Line (~{}) in error (first 100 characters)={}", FileLineCount + 3, DataLine(3).substr(0, 100)));
4293 0 : ErrorsFound = true;
4294 : }
4295 2 : if (!readItem(DataLine(4).substr(5), RfvisTemp)) {
4296 0 : ShowSevereError(state, "HeatBalanceManager: SearchWindow5DataFile: Error in Read of Rfvis values.");
4297 0 : ShowContinueError(state, format("Line (~{}) in error (first 100 characters)={}", FileLineCount + 4, DataLine(4).substr(0, 100)));
4298 0 : ErrorsFound = true;
4299 2 : } else if (any_lt(RfvisTemp, 0.0) || any_gt(RfvisTemp, 1.0)) {
4300 0 : ShowSevereError(state, "HeatBalanceManager: SearchWindow5DataFile: Error in Read of Rfvis values. (out of range [0,1])");
4301 0 : ShowContinueError(state, format("Line (~{}) in error (first 100 characters)={}", FileLineCount + 4, DataLine(4).substr(0, 100)));
4302 0 : ErrorsFound = true;
4303 : }
4304 2 : if (!readItem(DataLine(5).substr(5), RbvisTemp)) {
4305 0 : ShowSevereError(state, "HeatBalanceManager: SearchWindow5DataFile: Error in Read of Rbvis values.");
4306 0 : ShowContinueError(state, format("Line (~{}) in error (first 100 characters)={}", FileLineCount + 5, DataLine(5).substr(0, 100)));
4307 0 : ErrorsFound = true;
4308 2 : } else if (any_lt(RbvisTemp, 0.0) || any_gt(RbvisTemp, 1.0)) {
4309 0 : ShowSevereError(state, "HeatBalanceManager: SearchWindow5DataFile: Error in Read of Rbvis values. (out of range [0,1])");
4310 0 : ShowContinueError(state, format("Line (~{}) in error (first 100 characters)={}", FileLineCount + 5, DataLine(5).substr(0, 100)));
4311 0 : ErrorsFound = true;
4312 : }
4313 2 : FileLineCount += 5;
4314 :
4315 2 : if (ErrorsFound)
4316 0 : ShowFatalError(
4317 : state,
4318 0 : format("HeatBalanceManager: SearchWindow5DataFile: Construction={} from the Window5 data file cannot be used because "
4319 : "of above errors",
4320 : DesiredConstructionName));
4321 :
4322 22 : for (int iPhi = 0; iPhi < Window::numPhis; ++iPhi) {
4323 20 : Tsol[iPhi] = TsolTemp(iPhi + 1);
4324 20 : Tvis[iPhi] = TvisTemp(iPhi + 1);
4325 20 : Rfsol[iPhi] = RfsolTemp(iPhi + 1);
4326 20 : Rbsol[iPhi] = RbsolTemp(iPhi + 1);
4327 20 : Rfvis[iPhi] = RfvisTemp(iPhi + 1);
4328 20 : Rbvis[iPhi] = RbvisTemp(iPhi + 1);
4329 : }
4330 :
4331 6 : for (IGlass = 1; IGlass <= NGlass(IGlSys); ++IGlass) {
4332 44 : for (int iPhi = 0; iPhi < Window::numPhis; ++iPhi) {
4333 40 : AbsSol(IGlass)[iPhi] = AbsSolTemp(IGlass, iPhi + 1);
4334 : }
4335 : }
4336 :
4337 : // Hemis
4338 2 : thisConstruct.TransDiff = TsolTemp(11);
4339 2 : thisConstruct.TransDiffVis = TvisTemp(11);
4340 2 : thisConstruct.ReflectSolDiffFront = RfsolTemp(11);
4341 2 : thisConstruct.ReflectSolDiffBack = RbsolTemp(11);
4342 2 : thisConstruct.ReflectVisDiffFront = RfvisTemp(11);
4343 2 : thisConstruct.ReflectVisDiffBack = RbvisTemp(11);
4344 :
4345 : // Using pre-calculated/hard-coded cosPhis in this module is okay. Shrug.
4346 2 : Window::W5LsqFit(Window::cosPhis, Tsol, thisConstruct.TransSolBeamCoef);
4347 2 : Window::W5LsqFit(Window::cosPhis, Tvis, thisConstruct.TransVisBeamCoef);
4348 2 : Window::W5LsqFit(Window::cosPhis, Rfsol, thisConstruct.ReflSolBeamFrontCoef);
4349 6 : for (IGlass = 1; IGlass <= NGlass(IGlSys); ++IGlass) {
4350 4 : Window::W5LsqFit(Window::cosPhis, AbsSol(IGlass), thisConstruct.AbsBeamCoef(IGlass));
4351 : }
4352 :
4353 : // For comparing fitted vs. input distribution in incidence angle
4354 22 : for (int iPhi = 0; iPhi < Window::numPhis; ++iPhi) {
4355 20 : tsolFit[iPhi] = Window::POLYF(Window::cosPhis[iPhi], thisConstruct.TransSolBeamCoef);
4356 20 : tvisFit[iPhi] = Window::POLYF(Window::cosPhis[iPhi], thisConstruct.TransVisBeamCoef);
4357 20 : rfsolFit[iPhi] = Window::POLYF(Window::cosPhis[iPhi], thisConstruct.ReflSolBeamFrontCoef);
4358 60 : for (IGlass = 1; IGlass <= NGlass(IGlSys); ++IGlass) {
4359 40 : solabsFit(IGlass)[iPhi] = Window::POLYF(Window::cosPhis[iPhi], thisConstruct.AbsBeamCoef(IGlass));
4360 : }
4361 : }
4362 : // end
4363 :
4364 : // NominalRforNominalUCalculation of this construction (actually the total resistance of all of its layers; gas layer
4365 : // conductivity here ignores convective effects in gap.)
4366 2 : state.dataHeatBal->NominalRforNominalUCalculation(ConstrNum) = 0.0;
4367 8 : for (loop = 1; loop <= NGlass(IGlSys) + NGaps(IGlSys); ++loop) {
4368 6 : int matNum = thisConstruct.LayerPoint(loop);
4369 6 : auto const *matBase = s_mat->materials(matNum);
4370 6 : assert(matBase != nullptr);
4371 6 : if (matBase->group == Material::Group::Glass) {
4372 4 : state.dataHeatBal->NominalRforNominalUCalculation(ConstrNum) += matBase->Thickness / matBase->Conductivity;
4373 2 : } else if (matBase->group == Material::Group::Gas || matBase->group == Material::Group::GasMixture) {
4374 2 : auto const *matGas = dynamic_cast<Material::MaterialGasMix const *>(matBase);
4375 2 : assert(matGas != nullptr);
4376 :
4377 : // If mixture, use conductivity of first gas in mixture
4378 2 : state.dataHeatBal->NominalRforNominalUCalculation(ConstrNum) +=
4379 2 : matGas->Thickness / (matGas->gases[0].con.c0 + matGas->gases[0].con.c1 * 300.0 + matGas->gases[0].con.c2 * 90000.0);
4380 : }
4381 : }
4382 :
4383 : } // End of loop over glazing systems
4384 :
4385 : // WindowFrameAndDivider objects
4386 :
4387 2 : TotFrameDividerPrev = state.dataHeatBal->TotFrameDivider;
4388 4 : for (IGlSys = 1; IGlSys <= NGlSys; ++IGlSys) {
4389 2 : if (FrameWidth > 0.0 || DividerWidth(IGlSys) > 0.0) {
4390 2 : ++state.dataHeatBal->TotFrameDivider;
4391 2 : state.dataConstruction->Construct(state.dataHeatBal->TotConstructs - NGlSys + IGlSys).W5FrameDivider =
4392 2 : state.dataHeatBal->TotFrameDivider;
4393 : }
4394 : }
4395 :
4396 2 : if (state.dataHeatBal->TotFrameDivider > TotFrameDividerPrev) {
4397 2 : state.dataSurface->FrameDivider.redimension(state.dataHeatBal->TotFrameDivider);
4398 : }
4399 :
4400 4 : for (IGlSys = 1; IGlSys <= NGlSys; ++IGlSys) {
4401 2 : if (FrameWidth > 0.0 || DividerWidth(IGlSys) > 0.0) {
4402 2 : FrDivNum = state.dataConstruction->Construct(state.dataHeatBal->TotConstructs - NGlSys + IGlSys).W5FrameDivider;
4403 2 : state.dataSurface->FrameDivider(FrDivNum).FrameWidth = FrameWidth;
4404 2 : state.dataSurface->FrameDivider(FrDivNum).FrameProjectionOut = FrameProjectionOut;
4405 2 : state.dataSurface->FrameDivider(FrDivNum).FrameProjectionIn = FrameProjectionIn;
4406 2 : state.dataSurface->FrameDivider(FrDivNum).FrameConductance = FrameConductance;
4407 2 : state.dataSurface->FrameDivider(FrDivNum).FrEdgeToCenterGlCondRatio = FrEdgeToCenterGlCondRatio;
4408 2 : state.dataSurface->FrameDivider(FrDivNum).FrameSolAbsorp = FrameSolAbsorp;
4409 2 : state.dataSurface->FrameDivider(FrDivNum).FrameVisAbsorp = FrameVisAbsorp;
4410 2 : state.dataSurface->FrameDivider(FrDivNum).FrameEmis = FrameEmis;
4411 2 : state.dataSurface->FrameDivider(FrDivNum).FrameEdgeWidth = 0.06355; // 2.5 in
4412 :
4413 2 : state.dataSurface->FrameDivider(FrDivNum).MullionOrientation = static_cast<DataWindowEquivalentLayer::Orientation>(
4414 2 : getEnumValue(DataWindowEquivalentLayer::orientationNamesUC, MullionOrientation));
4415 :
4416 2 : if (Util::SameString(DividerType(IGlSys), "DividedLite")) {
4417 0 : state.dataSurface->FrameDivider(FrDivNum).DividerType = DataSurfaces::FrameDividerType::DividedLite;
4418 2 : } else if (Util::SameString(DividerType(IGlSys), "Suspended")) {
4419 2 : state.dataSurface->FrameDivider(FrDivNum).DividerType = DataSurfaces::FrameDividerType::Suspended;
4420 : }
4421 2 : state.dataSurface->FrameDivider(FrDivNum).DividerWidth = DividerWidth(IGlSys);
4422 2 : state.dataSurface->FrameDivider(FrDivNum).HorDividers = HorDividers(IGlSys);
4423 2 : state.dataSurface->FrameDivider(FrDivNum).VertDividers = VertDividers(IGlSys);
4424 2 : state.dataSurface->FrameDivider(FrDivNum).DividerProjectionOut = DividerProjectionOut(IGlSys);
4425 2 : state.dataSurface->FrameDivider(FrDivNum).DividerProjectionIn = DividerProjectionIn(IGlSys);
4426 2 : state.dataSurface->FrameDivider(FrDivNum).DividerConductance = DividerConductance(IGlSys);
4427 2 : state.dataSurface->FrameDivider(FrDivNum).DivEdgeToCenterGlCondRatio = DivEdgeToCenterGlCondRatio(IGlSys);
4428 2 : state.dataSurface->FrameDivider(FrDivNum).DividerSolAbsorp = DividerSolAbsorp(IGlSys);
4429 2 : state.dataSurface->FrameDivider(FrDivNum).DividerVisAbsorp = DividerVisAbsorp(IGlSys);
4430 2 : state.dataSurface->FrameDivider(FrDivNum).DividerEmis = DividerEmis(IGlSys);
4431 2 : state.dataSurface->FrameDivider(FrDivNum).DividerEdgeWidth = 0.06355; // 2.5 in
4432 2 : if (NGlSys == 1) {
4433 2 : state.dataSurface->FrameDivider(FrDivNum).Name = "W5:" + DesiredConstructionName;
4434 : } else {
4435 0 : state.dataSurface->FrameDivider(FrDivNum).Name = "W5:" + DesiredConstructionName + ':' + NumName(IGlSys);
4436 : }
4437 : }
4438 : }
4439 :
4440 2 : if (FrameWidth > 0.0 && DividerWidth(1) > 0.0) {
4441 2 : DisplayString(state, "--Construction and associated frame and divider found");
4442 0 : } else if (FrameWidth > 0.0) {
4443 0 : DisplayString(state, "--Construction and associated frame found");
4444 0 : } else if (DividerWidth(1) > 0.0) {
4445 0 : DisplayString(state, "--Construction and associated divider found");
4446 : } else {
4447 0 : DisplayString(state, "--Construction without frame or divider found");
4448 : }
4449 : }
4450 :
4451 2 : return;
4452 :
4453 0 : Label1000:;
4454 0 : EOFonFile = true;
4455 82 : }
4456 :
4457 0 : void SetStormWindowControl(EnergyPlusData &state)
4458 : {
4459 :
4460 : // SUBROUTINE INFORMATION:
4461 : // AUTHOR Fred Winkelmann
4462 : // DATE WRITTEN Jan 2004
4463 :
4464 : // PURPOSE OF THIS SUBROUTINE:
4465 : // Sets the storm window flag for each window, which is:
4466 : // -1: if storm window is not applicable (this will always be the value for interior
4467 : // windows since storm windows can only be applied to exterior windows
4468 : // 0: if the window has a storm window but it is off
4469 : // 1: if the window has a storm window and it is on
4470 :
4471 : // A "storm window" is a single layer of exterior glass separated from the main window by air gap.
4472 : // Whether the storm window is in place is determined by the following values, which
4473 : // which are specified in the Storm Window object for the window:
4474 : // -Month that Storm Window Is Put On
4475 : // -Day of Month that Storm Window Is Put On
4476 : // -Month that Storm Window Is Taken Off
4477 : // -Day of Month that Storm Window Is Taken Off
4478 :
4479 : int StormWinFlag; // Storm window flag; this routine sets the following values:
4480 : // 0: if the storm window is off this time step
4481 : // 1: if the storm window is on this time step
4482 :
4483 0 : state.dataHeatBal->StormWinChangeThisDay = false;
4484 :
4485 0 : for (int StormWinNum = 1; StormWinNum <= state.dataSurface->TotStormWin; ++StormWinNum) {
4486 0 : int SurfNum = state.dataSurface->StormWindow(StormWinNum).BaseWindowNum;
4487 0 : state.dataSurface->SurfWinStormWinFlagPrevDay(SurfNum) = state.dataSurface->SurfWinStormWinFlag(SurfNum);
4488 0 : int DateOff = state.dataSurface->StormWindow(StormWinNum).DateOff - 1;
4489 : // Note: Dateon = Dateoff is not allowed and will have produced an error in getinput.
4490 0 : if (DateOff == 0) DateOff = 366;
4491 0 : if (General::BetweenDates(state.dataEnvrn->DayOfYear_Schedule, state.dataSurface->StormWindow(StormWinNum).DateOn, DateOff)) {
4492 0 : StormWinFlag = 1;
4493 : } else {
4494 0 : StormWinFlag = 0;
4495 : }
4496 0 : state.dataSurface->SurfWinStormWinFlag(SurfNum) = StormWinFlag;
4497 0 : if (state.dataGlobal->BeginSimFlag) state.dataSurface->SurfWinStormWinFlagPrevDay(SurfNum) = StormWinFlag;
4498 0 : if (state.dataSurface->SurfWinStormWinFlag(SurfNum) != state.dataSurface->SurfWinStormWinFlagPrevDay(SurfNum))
4499 0 : state.dataHeatBal->StormWinChangeThisDay = true;
4500 : }
4501 0 : }
4502 :
4503 0 : void CreateFCfactorConstructions(EnergyPlusData &state,
4504 : int &ConstrNum, // Counter for Constructions
4505 : bool &ErrorsFound // If errors found in input
4506 : )
4507 : {
4508 :
4509 : // SUBROUTINE INFORMATION:
4510 : // AUTHOR Tianzhen Hong
4511 : // DATE WRITTEN July 2009
4512 :
4513 : // PURPOSE OF THIS SUBROUTINE:
4514 : // This subroutine goes through each construction defined with Ffactor or Cfactor method,
4515 : // and creates a construction (concrete + insulation) used in the heat transfer calculation.
4516 : // This subroutine only gets called once in the GetConstructionData subroutine
4517 :
4518 : // ASHRAE Handbook Fundamental 2005
4519 : // Thermal resistance of the inside air film, m2.K/W. Average of 0.16 (heat flow down) and 0.11 (heat flow up)
4520 0 : Real64 constexpr Rfilm_in(0.135);
4521 : // Thermal resistance of the outside air film used in calculating the Ffactor, m2.K/W. 0.17/5.678
4522 0 : Real64 constexpr Rfilm_out(0.03);
4523 :
4524 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
4525 : int ConstructNumAlpha; // Number of construction alpha names being passed
4526 : int DummyNumProp; // dummy variable for properties being passed
4527 : int IOStat; // IO Status when calling get input subroutine
4528 0 : Array1D_string ConstructAlphas(1); // Construction Alpha names defined
4529 0 : Array1D<Real64> DummyProps(4); // Temporary array to transfer construction properties
4530 :
4531 : int TotFfactorConstructs; // Number of slabs-on-grade or underground floor constructions defined with F factors
4532 : int TotCfactorConstructs; // Number of underground wall constructions defined with C factors
4533 :
4534 : Real64 Ffactor; // Ffactor in W/m-K, applies to deltaT of outside - indoor air temperature
4535 : Real64 Cfactor; // Cfactor in W/m2-K, does not include soil or air films
4536 : Real64 Area; // floor area in m2
4537 : Real64 PerimeterExposed; // perimeter exposed in m
4538 : Real64 Height; // Height of the underground wall in m
4539 :
4540 : Real64 Reff; // Effective thermal resistance, m2.K/W
4541 : Real64 Rcon; // Concrete layer thermal resistance, m2.K/W
4542 : Real64 Rfic; // Thermal resistance of the fictitious material, m2.K/W
4543 : Real64 Rsoilequ; // Effective R-value of soil for underground walls
4544 : int iFCConcreteLayer; // Layer pointer to the materials array
4545 :
4546 0 : auto &s_mat = state.dataMaterial;
4547 : // First get the concrete layer
4548 0 : iFCConcreteLayer = Material::GetMaterialNum(state, "~FC_CONCRETE");
4549 0 : Rcon = s_mat->materials(iFCConcreteLayer)->Resistance;
4550 :
4551 : // Count number of constructions defined with Ffactor or Cfactor method
4552 0 : TotFfactorConstructs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Construction:FfactorGroundFloor");
4553 0 : TotCfactorConstructs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Construction:CfactorUndergroundWall");
4554 :
4555 0 : if (TotFfactorConstructs > 0) {
4556 0 : state.dataHeatBal->NoFfactorConstructionsUsed = false;
4557 : }
4558 :
4559 0 : if (TotCfactorConstructs > 0) {
4560 0 : state.dataHeatBal->NoCfactorConstructionsUsed = false;
4561 : }
4562 :
4563 : // First create ground floor constructions defined with F factor method if any
4564 0 : state.dataHeatBalMgr->CurrentModuleObject = "Construction:FfactorGroundFloor";
4565 :
4566 : // Loop through all constructs defined with Ffactor method
4567 0 : for (int Loop = 1; Loop <= TotFfactorConstructs; ++Loop) {
4568 :
4569 : // Get the object names for each construction from the input processor
4570 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
4571 0 : state.dataHeatBalMgr->CurrentModuleObject,
4572 : Loop,
4573 : ConstructAlphas,
4574 : ConstructNumAlpha,
4575 : DummyProps,
4576 : DummyNumProp,
4577 : IOStat,
4578 0 : state.dataIPShortCut->lNumericFieldBlanks,
4579 0 : state.dataIPShortCut->lAlphaFieldBlanks,
4580 0 : state.dataIPShortCut->cAlphaFieldNames,
4581 0 : state.dataIPShortCut->cNumericFieldNames);
4582 0 : if (GlobalNames::VerifyUniqueInterObjectName(state,
4583 0 : state.dataHeatBalMgr->UniqueConstructNames,
4584 0 : ConstructAlphas(1),
4585 0 : state.dataHeatBalMgr->CurrentModuleObject,
4586 0 : state.dataIPShortCut->cAlphaFieldNames(1),
4587 : ErrorsFound)) {
4588 0 : continue;
4589 : }
4590 :
4591 0 : ++ConstrNum;
4592 :
4593 0 : auto &thisConstruct = state.dataConstruction->Construct(ConstrNum);
4594 0 : thisConstruct.Name = ConstructAlphas(1);
4595 0 : thisConstruct.TypeIsFfactorFloor = true;
4596 :
4597 0 : Ffactor = DummyProps(1);
4598 0 : Area = DummyProps(2);
4599 0 : PerimeterExposed = DummyProps(3);
4600 :
4601 0 : thisConstruct.Area = Area;
4602 0 : thisConstruct.PerimeterExposed = PerimeterExposed;
4603 0 : thisConstruct.FFactor = Ffactor;
4604 :
4605 0 : if (Ffactor <= 0.0) {
4606 0 : ShowSevereError(state,
4607 0 : format("{}=\"{}\" has {} <= 0.0, must be > 0.0.",
4608 0 : state.dataHeatBalMgr->CurrentModuleObject,
4609 : ConstructAlphas(1),
4610 0 : state.dataIPShortCut->cNumericFieldNames(1)));
4611 0 : ShowContinueError(state, format("Entered value=[{:.2R}]", Ffactor));
4612 0 : ErrorsFound = true;
4613 : }
4614 :
4615 0 : if (Area <= 0.0) {
4616 0 : ShowSevereError(state,
4617 0 : format("{}=\"{}\" has {} <= 0.0, must be > 0.0.",
4618 0 : state.dataHeatBalMgr->CurrentModuleObject,
4619 : ConstructAlphas(1),
4620 0 : state.dataIPShortCut->cNumericFieldNames(2)));
4621 0 : ShowContinueError(state, format("Entered value=[{:.2R}]", Area));
4622 0 : ErrorsFound = true;
4623 : }
4624 :
4625 0 : if (PerimeterExposed < 0.0) {
4626 0 : ShowSevereError(state,
4627 0 : format("{}=\"{}\" has {} <= 0.0, must be > 0.0.",
4628 0 : state.dataHeatBalMgr->CurrentModuleObject,
4629 : ConstructAlphas(1),
4630 0 : state.dataIPShortCut->cNumericFieldNames(3)));
4631 0 : ShowContinueError(state, format("Entered value=[{:.2R}]", PerimeterExposed));
4632 0 : ErrorsFound = true;
4633 : }
4634 :
4635 : // The construction has two layers which have been created in GetMaterialData
4636 0 : thisConstruct.TotLayers = 2;
4637 :
4638 : // The concrete is the inside layer
4639 0 : thisConstruct.LayerPoint(2) = iFCConcreteLayer;
4640 :
4641 : // The fictitious insulation is the outside layer
4642 0 : thisConstruct.LayerPoint(1) = Material::GetMaterialNum(state, format("~FC_INSULATION_{}", Loop));
4643 :
4644 : // Calculate the thermal resistance of the fictitious insulation layer
4645 : // effective thermal resistance excludes inside and outside air films
4646 0 : if (PerimeterExposed > 0.0) {
4647 0 : Reff = Area / (PerimeterExposed * Ffactor) - Rfilm_in - Rfilm_out;
4648 : } else { // PerimeterExposed = 0 for underground floor, assume R-1000 (IP)
4649 0 : Reff = 177.0;
4650 : }
4651 :
4652 0 : Rfic = Reff - Rcon;
4653 0 : if (Rfic <= 0.0) {
4654 0 : ShowSevereError(
4655 : state,
4656 0 : format("{}=\"{}\" has calculated R value <= 0.0, must be > 0.0.", state.dataHeatBalMgr->CurrentModuleObject, ConstructAlphas(1)));
4657 0 : ShowContinueError(state, format("Calculated value=[{:.2R}] Check definition.", Rfic));
4658 0 : ErrorsFound = true;
4659 : }
4660 :
4661 0 : auto *mat = s_mat->materials(thisConstruct.LayerPoint(1));
4662 0 : mat->Resistance = mat->NominalR = Rfic;
4663 :
4664 : // excluding thermal resistance of inside or outside air film
4665 : // 1/Reff gets reported as the "U-Factor no Film" in the summary report Envelope Summary | Opaque Exterior
4666 0 : state.dataHeatBal->NominalRforNominalUCalculation(ConstrNum) = Reff;
4667 : }
4668 :
4669 : // Then create underground wall constructions defined with C factor method if any
4670 0 : state.dataHeatBalMgr->CurrentModuleObject = "Construction:CfactorUndergroundWall";
4671 :
4672 0 : for (int Loop = 1; Loop <= TotCfactorConstructs; ++Loop) { // Loop through all constructs defined with Ffactor method
4673 :
4674 : // Get the object names for each construction from the input processor
4675 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
4676 0 : state.dataHeatBalMgr->CurrentModuleObject,
4677 : Loop,
4678 : ConstructAlphas,
4679 : ConstructNumAlpha,
4680 : DummyProps,
4681 : DummyNumProp,
4682 : IOStat,
4683 0 : state.dataIPShortCut->lNumericFieldBlanks,
4684 0 : state.dataIPShortCut->lAlphaFieldBlanks,
4685 0 : state.dataIPShortCut->cAlphaFieldNames,
4686 0 : state.dataIPShortCut->cNumericFieldNames);
4687 0 : if (GlobalNames::VerifyUniqueInterObjectName(state,
4688 0 : state.dataHeatBalMgr->UniqueConstructNames,
4689 0 : ConstructAlphas(1),
4690 0 : state.dataHeatBalMgr->CurrentModuleObject,
4691 0 : state.dataIPShortCut->cAlphaFieldNames(1),
4692 : ErrorsFound)) {
4693 0 : continue;
4694 : }
4695 :
4696 0 : ++ConstrNum;
4697 :
4698 0 : auto &thisConstruct = state.dataConstruction->Construct(ConstrNum);
4699 0 : thisConstruct.Name = ConstructAlphas(1);
4700 0 : thisConstruct.TypeIsCfactorWall = true;
4701 :
4702 0 : Cfactor = DummyProps(1);
4703 0 : Height = DummyProps(2);
4704 :
4705 0 : thisConstruct.Height = Height;
4706 0 : thisConstruct.CFactor = Cfactor;
4707 :
4708 0 : if (Cfactor <= 0.0) {
4709 0 : ShowSevereError(state,
4710 0 : format("{} {} has {} <= 0.0, must be > 0.0.",
4711 0 : state.dataHeatBalMgr->CurrentModuleObject,
4712 : ConstructAlphas(1),
4713 0 : state.dataIPShortCut->cNumericFieldNames(1)));
4714 0 : ShowContinueError(state, format("Entered value=[{:.2R}]", Cfactor));
4715 0 : ErrorsFound = true;
4716 : }
4717 :
4718 0 : if (Height <= 0.0) {
4719 0 : ShowSevereError(state,
4720 0 : format("{} {} has {} <= 0.0, must be > 0.0.",
4721 0 : state.dataHeatBalMgr->CurrentModuleObject,
4722 : ConstructAlphas(1),
4723 0 : state.dataIPShortCut->cNumericFieldNames(2)));
4724 0 : ShowContinueError(state, format("Entered value=[{:.2R}]", Height));
4725 0 : ErrorsFound = true;
4726 : }
4727 :
4728 : // The construction has two layers which have been created in GetMaterialData
4729 0 : thisConstruct.TotLayers = 2;
4730 :
4731 : // The concrete is the inside layer
4732 0 : thisConstruct.LayerPoint(2) = iFCConcreteLayer;
4733 :
4734 : // The fictitious insulation is the outside layer
4735 0 : thisConstruct.LayerPoint(1) = Material::GetMaterialNum(state, format("~FC_INSULATION_{}", Loop + TotFfactorConstructs));
4736 :
4737 : // CR 8886 Rsoil should be in SI unit. From ASHRAE 90.1-2010 SI
4738 0 : if (Height <= 0.25) {
4739 0 : Rsoilequ = 0.12; // m2K/W
4740 0 : } else if (Height >= 2.5) {
4741 0 : Rsoilequ = 0.92;
4742 : } else { // regression from ASHRAE 90.1-2010 SI TABLE C6.10.1 Effective R-Value of Soil, R2 = 0.9967
4743 0 : Rsoilequ = 0.0607 + 0.3479 * Height;
4744 : }
4745 :
4746 : // effective thermal resistance excludes inside and outside air films
4747 0 : Reff = 1.0 / Cfactor + Rsoilequ; // Cfactor does not include air films
4748 :
4749 0 : Rfic = Reff - Rcon;
4750 0 : if (Rfic <= 0) {
4751 0 : ShowSevereError(
4752 : state,
4753 0 : format("{}=\"{}\" has calculated R value <= 0.0, must be > 0.0.", state.dataHeatBalMgr->CurrentModuleObject, ConstructAlphas(1)));
4754 0 : ShowContinueError(state, format("Calculated value=[{:.2R}] Check definition.", Rfic));
4755 0 : ErrorsFound = true;
4756 : }
4757 :
4758 0 : auto *mat = s_mat->materials(thisConstruct.LayerPoint(1));
4759 0 : mat->Resistance = mat->NominalR = Rfic;
4760 :
4761 : // Reff includes the wall itself and soil, but excluding thermal resistance of inside or outside air film
4762 : // 1/Reff gets reported as the "U-Factor no Film" in the summary report Envelope Summary | Opaque Exterior
4763 0 : state.dataHeatBal->NominalRforNominalUCalculation(ConstrNum) = Reff;
4764 : }
4765 0 : }
4766 :
4767 11 : void CreateAirBoundaryConstructions(EnergyPlusData &state,
4768 : int &constrNum, // Counter for Constructions
4769 : bool &errorsFound // If errors found in input
4770 : )
4771 : {
4772 : static constexpr std::string_view routineName = "CreateAirBoundaryConstructions";
4773 :
4774 11 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
4775 11 : cCurrentModuleObject = "Construction:AirBoundary";
4776 11 : int numAirBoundaryConstructs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
4777 11 : if (numAirBoundaryConstructs > 0) {
4778 11 : auto const instances = state.dataInputProcessing->inputProcessor->epJSON.find(cCurrentModuleObject);
4779 11 : if (instances == state.dataInputProcessing->inputProcessor->epJSON.end()) {
4780 : // Cannot imagine how you would have numAirBoundaryConstructs > 0 and yet the instances is empty
4781 : // this would indicate a major problem in the input processor, not a problem here
4782 : // I'll still catch this with errorsFound but I cannot make a unit test for it so excluding the line from coverage
4783 0 : ShowSevereError(state,
4784 : format("{}: Somehow getNumObjectsFound was > 0 but epJSON.find found 0", cCurrentModuleObject)); // LCOV_EXCL_LINE
4785 : errorsFound = true; // LCOV_EXCL_LINE
4786 : }
4787 11 : auto &instancesValue = instances.value();
4788 23 : for (auto instance = instancesValue.begin(); instance != instancesValue.end(); ++instance) {
4789 12 : auto const &fields = instance.value();
4790 12 : std::string const &thisObjectName = instance.key();
4791 :
4792 12 : ErrorObjectHeader eoh{routineName, cCurrentModuleObject, thisObjectName};
4793 :
4794 12 : state.dataInputProcessing->inputProcessor->markObjectAsUsed(cCurrentModuleObject, thisObjectName);
4795 :
4796 24 : if (GlobalNames::VerifyUniqueInterObjectName(
4797 12 : state, state.dataHeatBalMgr->UniqueConstructNames, thisObjectName, cCurrentModuleObject, "Name", errorsFound)) {
4798 0 : continue;
4799 : }
4800 :
4801 12 : ++constrNum;
4802 12 : auto &thisConstruct = state.dataConstruction->Construct(constrNum);
4803 :
4804 12 : thisConstruct.Name = Util::makeUPPER(thisObjectName);
4805 12 : thisConstruct.TypeIsAirBoundary = true;
4806 12 : thisConstruct.IsUsedCTF = false;
4807 :
4808 : // Air Exchange Method
4809 24 : std::string airMethod = "None";
4810 12 : if (auto found = fields.find("air_exchange_method");
4811 12 : found != fields.end()) { // find("x") followed by at("x") is the same lookup twice
4812 12 : airMethod = found.value().get<std::string>();
4813 : }
4814 12 : if (Util::SameString(airMethod, "SimpleMixing")) {
4815 4 : thisConstruct.TypeIsAirBoundaryMixing = true;
4816 8 : if (auto found = fields.find("simple_mixing_air_changes_per_hour"); found != fields.end()) {
4817 4 : thisConstruct.AirBoundaryACH = found.value().get<Real64>();
4818 : } else {
4819 0 : if (!state.dataInputProcessing->inputProcessor->getDefaultValue(
4820 0 : state, cCurrentModuleObject, "simple_mixing_air_changes_per_hour", thisConstruct.AirBoundaryACH)) {
4821 0 : errorsFound = true;
4822 : }
4823 : }
4824 :
4825 8 : if (auto found = fields.find("simple_mixing_schedule_name"); found != fields.end()) {
4826 2 : std::string schedName = found.value().get<std::string>(); // .get<std::string>() creates and returns a new string, no &
4827 2 : if ((thisConstruct.airBoundaryMixingSched = Sched::GetSchedule(state, Util::makeUPPER(schedName))) == nullptr) {
4828 1 : ShowSevereItemNotFound(state, eoh, "Simple Mixing Schedule Name", schedName);
4829 1 : errorsFound = true;
4830 : }
4831 2 : } else {
4832 2 : thisConstruct.airBoundaryMixingSched =
4833 2 : Sched::GetScheduleAlwaysOn(state); // Not an availability manager, but defaults to constant-1.0
4834 : }
4835 : }
4836 12 : }
4837 : }
4838 11 : }
4839 :
4840 116 : void GetScheduledSurfaceGains(EnergyPlusData &state, bool &ErrorsFound) // If errors found in input
4841 : {
4842 :
4843 : // SUBROUTINE INFORMATION:
4844 : // AUTHOR Simon Vidanovic
4845 : // DATE WRITTEN June 2013
4846 :
4847 : // PURPOSE OF THIS SUBROUTINE:
4848 : // Loads scheduled surface gains for solar incident on interior side of the surfaces and absorbed solar energy in
4849 : // window layers
4850 :
4851 : // SUBROUTINE PARAMETER DEFINITIONS:
4852 : static constexpr std::string_view RoutineName("GetScheduledSurfaceGains: ");
4853 : static constexpr std::string_view routineName = "GetScheduledSurfaceGains";
4854 :
4855 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
4856 : int NumArgs;
4857 : int NumAlpha;
4858 : int NumNumeric;
4859 : int Loop;
4860 : int IOStat;
4861 : int SurfNum;
4862 : int ConstrNum;
4863 :
4864 : //-----------------------------------------------------------------------
4865 : // SurfaceProperty:SolarIncidentInside
4866 : //-----------------------------------------------------------------------
4867 116 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
4868 116 : cCurrentModuleObject = "SurfaceProperty:SolarIncidentInside";
4869 :
4870 : // Check if IDD definition is correct
4871 116 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, NumArgs, NumAlpha, NumNumeric);
4872 116 : if (NumAlpha != 4) {
4873 0 : ShowSevereError(
4874 : state,
4875 0 : format("{}{}: Object Definition indicates not = 4 Alpha Objects, Number Indicated={}", RoutineName, cCurrentModuleObject, NumAlpha));
4876 0 : ErrorsFound = true;
4877 : }
4878 :
4879 116 : state.dataSurface->TotSurfIncSolSSG = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
4880 116 : if (state.dataSurface->TotSurfIncSolSSG > 0) {
4881 0 : if (!allocated(state.dataSurface->SurfIncSolSSG)) {
4882 0 : state.dataSurface->SurfIncSolSSG.allocate(state.dataSurface->TotSurfIncSolSSG);
4883 : }
4884 :
4885 0 : for (Loop = 1; Loop <= state.dataSurface->TotSurfIncSolSSG; ++Loop) {
4886 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
4887 : cCurrentModuleObject,
4888 : Loop,
4889 0 : state.dataIPShortCut->cAlphaArgs,
4890 : NumAlpha,
4891 0 : state.dataIPShortCut->rNumericArgs,
4892 : NumNumeric,
4893 : IOStat,
4894 0 : state.dataIPShortCut->lNumericFieldBlanks,
4895 0 : state.dataIPShortCut->lAlphaFieldBlanks,
4896 0 : state.dataIPShortCut->cAlphaFieldNames,
4897 0 : state.dataIPShortCut->cNumericFieldNames);
4898 :
4899 0 : ErrorObjectHeader eoh{routineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)};
4900 :
4901 0 : state.dataSurface->SurfIncSolSSG(Loop).Name = state.dataIPShortCut->cAlphaArgs(1);
4902 :
4903 : // Assign surface number
4904 0 : SurfNum = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(2), state.dataSurface->Surface);
4905 0 : if (SurfNum == 0) {
4906 0 : ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(2), state.dataIPShortCut->cAlphaArgs(2));
4907 0 : ErrorsFound = true;
4908 : } else {
4909 0 : state.dataSurface->SurfIncSolSSG(Loop).SurfPtr = SurfNum;
4910 0 : if (state.dataSurface->UseRepresentativeSurfaceCalculations) {
4911 0 : int repSurfNum = state.dataSurface->Surface(SurfNum).RepresentativeCalcSurfNum;
4912 0 : if (repSurfNum != SurfNum) {
4913 : // Do not use representative surfaces
4914 :
4915 : // remove surface from representative constituent list
4916 0 : auto &vec = state.dataSurface->Surface(repSurfNum).ConstituentSurfaceNums;
4917 0 : vec.erase(std::remove(vec.begin(), vec.end(), SurfNum), vec.end());
4918 :
4919 : // reset representative surface number
4920 0 : state.dataSurface->Surface(SurfNum).RepresentativeCalcSurfNum = SurfNum;
4921 : }
4922 : }
4923 : }
4924 :
4925 : // Assign construction number
4926 0 : ConstrNum = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(3), state.dataConstruction->Construct);
4927 0 : if (ConstrNum == 0) {
4928 0 : ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(3), state.dataIPShortCut->cAlphaArgs(3));
4929 0 : ErrorsFound = true;
4930 : } else {
4931 0 : state.dataSurface->SurfIncSolSSG(Loop).ConstrPtr = ConstrNum;
4932 : }
4933 :
4934 0 : if ((state.dataSurface->SurfIncSolSSG(Loop).sched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(4))) == nullptr) {
4935 0 : ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(4), state.dataIPShortCut->cAlphaArgs(4));
4936 0 : ErrorsFound = true;
4937 : }
4938 : }
4939 : }
4940 :
4941 : //-----------------------------------------------------------------------
4942 : // SurfaceProperty:SolarIncidentInside
4943 : //-----------------------------------------------------------------------
4944 116 : cCurrentModuleObject = "ComplexFenestrationProperty:SolarAbsorbedLayers";
4945 :
4946 116 : state.dataSurface->TotFenLayAbsSSG = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
4947 116 : if (state.dataSurface->TotFenLayAbsSSG > 0) {
4948 0 : if (!allocated(state.dataSurface->FenLayAbsSSG)) {
4949 0 : state.dataSurface->FenLayAbsSSG.allocate(state.dataSurface->TotFenLayAbsSSG);
4950 : }
4951 :
4952 0 : for (Loop = 1; Loop <= state.dataSurface->TotFenLayAbsSSG; ++Loop) {
4953 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
4954 : cCurrentModuleObject,
4955 : Loop,
4956 0 : state.dataIPShortCut->cAlphaArgs,
4957 : NumAlpha,
4958 0 : state.dataIPShortCut->rNumericArgs,
4959 : NumNumeric,
4960 : IOStat,
4961 0 : state.dataIPShortCut->lNumericFieldBlanks,
4962 0 : state.dataIPShortCut->lAlphaFieldBlanks,
4963 0 : state.dataIPShortCut->cAlphaFieldNames,
4964 0 : state.dataIPShortCut->cNumericFieldNames);
4965 :
4966 0 : ErrorObjectHeader eoh{routineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)};
4967 :
4968 0 : state.dataSurface->FenLayAbsSSG(Loop).Name = state.dataIPShortCut->cAlphaArgs(1);
4969 :
4970 : // Assign surface number
4971 0 : SurfNum = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(2), state.dataSurface->Surface);
4972 0 : if (SurfNum == 0) {
4973 0 : ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(2), state.dataIPShortCut->cAlphaArgs(2));
4974 0 : ErrorsFound = true;
4975 : } else {
4976 0 : state.dataSurface->FenLayAbsSSG(Loop).SurfPtr = SurfNum;
4977 : }
4978 :
4979 : // Assign construction number
4980 0 : ConstrNum = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(3), state.dataConstruction->Construct);
4981 0 : auto const &thisConstruct = state.dataConstruction->Construct(ConstrNum); // Why is this before the error check?
4982 0 : if (ConstrNum == 0) {
4983 0 : ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(3), state.dataIPShortCut->cAlphaArgs(3));
4984 0 : ErrorsFound = true;
4985 : } else {
4986 0 : state.dataSurface->FenLayAbsSSG(Loop).ConstrPtr = ConstrNum;
4987 0 : int NumOfScheduledLayers = NumAlpha - 3;
4988 0 : bool NumOfLayersMatch = false;
4989 : // Check if number of layers in construction matches number of layers in schedule surface gains object
4990 0 : if (NumOfScheduledLayers == thisConstruct.TotSolidLayers) {
4991 0 : NumOfLayersMatch = true;
4992 : }
4993 :
4994 0 : if (!NumOfLayersMatch) {
4995 0 : ShowSevereError(
4996 : state,
4997 0 : format("{}{}=\"{}, object. Number of scheduled surface gains for each layer does not match number of layers in "
4998 : "referenced construction.",
4999 : RoutineName,
5000 : cCurrentModuleObject,
5001 0 : state.dataIPShortCut->cAlphaArgs(1)));
5002 0 : ShowContinueError(state,
5003 0 : format("{} have {} schedule layers and {} have {} layers.",
5004 0 : state.dataIPShortCut->cAlphaArgs(1),
5005 : NumOfScheduledLayers,
5006 0 : state.dataIPShortCut->cAlphaArgs(3),
5007 0 : thisConstruct.TotSolidLayers));
5008 0 : ErrorsFound = true;
5009 : }
5010 :
5011 0 : if (!allocated(state.dataSurface->FenLayAbsSSG(Loop).scheds)) {
5012 0 : state.dataSurface->FenLayAbsSSG(Loop).scheds.allocate(NumOfScheduledLayers);
5013 : }
5014 :
5015 0 : state.dataSurface->FenLayAbsSSG(Loop).NumOfSched = NumOfScheduledLayers;
5016 :
5017 0 : for (int i = 1; i <= NumOfScheduledLayers; ++i) {
5018 0 : if ((state.dataSurface->FenLayAbsSSG(Loop).scheds(i) = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(i + 3))) ==
5019 : nullptr) {
5020 0 : ShowSevereItemNotFound(state,
5021 : eoh,
5022 0 : state.dataIPShortCut->cAlphaFieldNames(NumOfScheduledLayers + 3),
5023 0 : state.dataIPShortCut->cAlphaArgs(NumOfScheduledLayers + 3));
5024 0 : ErrorsFound = true;
5025 : }
5026 : }
5027 : }
5028 : }
5029 : }
5030 :
5031 : // Check if scheduled surface gains are assigined to each surface in every zone. If not then warning message to user will be
5032 : // issued
5033 116 : if ((state.dataSurface->TotSurfIncSolSSG > 0) || (state.dataSurface->TotFenLayAbsSSG > 0)) {
5034 0 : for (int iZone = 1; iZone <= state.dataGlobal->NumOfZones; ++iZone) {
5035 0 : CheckScheduledSurfaceGains(state, iZone);
5036 : }
5037 : }
5038 116 : }
5039 :
5040 0 : void CheckScheduledSurfaceGains(EnergyPlusData &state, int const ZoneNum) // Zone number for which error check will be performed
5041 : {
5042 :
5043 : // SUBROUTINE INFORMATION:
5044 : // AUTHOR Simon Vidanovic
5045 : // DATE WRITTEN July 2013
5046 :
5047 : // PURPOSE OF THIS SUBROUTINE:
5048 : // Check if all surfaces within zone are scheduled with surface gains. If not all surfaces within zone are scheduled,
5049 : // warning message will be issued and program will continue to execute.
5050 :
5051 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
5052 : int SchedPtr; // scheduled surface gains pointer
5053 :
5054 0 : bool ZoneUnscheduled = false; // true if all surfaces in the zone are unscheduled
5055 0 : bool ZoneScheduled = false; // true if all surfaces in the zone are scheduled
5056 :
5057 0 : bool firstZoneSurface = true;
5058 0 : for (int spaceNum : state.dataHeatBal->Zone(ZoneNum).spaceIndexes) {
5059 0 : auto const &thisSpace = state.dataHeatBal->space(spaceNum);
5060 0 : for (int iSurf = thisSpace.HTSurfaceFirst; iSurf <= thisSpace.HTSurfaceLast; ++iSurf) {
5061 0 : int iConst = state.dataSurface->Surface(iSurf).Construction;
5062 0 : if (state.dataSurface->Surface(iSurf).Class == DataSurfaces::SurfaceClass::Window) {
5063 0 : SchedPtr = SolarShading::WindowScheduledSolarAbs(state, iSurf, iConst);
5064 : } else {
5065 0 : SchedPtr = SolarShading::SurfaceScheduledSolarInc(state, iSurf, iConst);
5066 : }
5067 0 : if (firstZoneSurface) {
5068 0 : if (SchedPtr != 0) {
5069 0 : ZoneScheduled = true;
5070 0 : ZoneUnscheduled = false;
5071 : } else {
5072 0 : ZoneScheduled = false;
5073 0 : ZoneUnscheduled = true;
5074 : }
5075 0 : firstZoneSurface = false;
5076 : } else {
5077 0 : if (SchedPtr != 0) {
5078 0 : ZoneUnscheduled = false;
5079 : } else {
5080 0 : ZoneScheduled = false;
5081 : }
5082 : }
5083 : }
5084 : }
5085 0 : if ((!ZoneScheduled) && (!ZoneUnscheduled)) {
5086 : // zone is not scheduled nor unscheduled
5087 0 : ShowWarningError(state,
5088 0 : format("Zone {} does not have all surfaces scheduled with surface gains.", state.dataHeatBal->Zone(ZoneNum).Name));
5089 0 : ShowContinueError(state,
5090 : "If at least one surface in the zone is scheduled with surface gains, then all other surfaces within the same zone "
5091 : "should be scheduled as well.");
5092 0 : for (int spaceNum : state.dataHeatBal->Zone(ZoneNum).spaceIndexes) {
5093 0 : auto const &thisSpace = state.dataHeatBal->space(spaceNum);
5094 0 : for (int iSurf = thisSpace.HTSurfaceFirst; iSurf <= thisSpace.HTSurfaceLast; ++iSurf) {
5095 0 : int iConst = state.dataSurface->Surface(iSurf).Construction;
5096 0 : if (state.dataSurface->Surface(iSurf).Class == DataSurfaces::SurfaceClass::Window) {
5097 0 : SchedPtr = SolarShading::WindowScheduledSolarAbs(state, iSurf, iConst);
5098 : } else {
5099 0 : SchedPtr = SolarShading::SurfaceScheduledSolarInc(state, iSurf, iConst);
5100 : }
5101 :
5102 0 : if (SchedPtr == 0) {
5103 0 : ShowContinueError(state, format("Surface {} does not have scheduled surface gains.", state.dataSurface->Surface(iSurf).Name));
5104 : }
5105 : }
5106 : }
5107 : }
5108 0 : }
5109 :
5110 116 : void CreateTCConstructions(EnergyPlusData &state, [[maybe_unused]] bool &ErrorsFound) // If errors found in input
5111 : {
5112 :
5113 : // SUBROUTINE INFORMATION:
5114 : // AUTHOR Tianzhen Hong
5115 : // DATE WRITTEN January 2009
5116 :
5117 : // PURPOSE OF THIS SUBROUTINE:
5118 : // This subroutine goes through each TC master construction and creates a complete series
5119 : // of the slave thermochromic constructions.
5120 : // This subroutine only gets called once in the GetHeatBalanceInput subroutine
5121 : // after materials, constructions and building geometry data are read.
5122 116 : auto &s_mat = state.dataMaterial;
5123 :
5124 116 : int NumNewConst = 0;
5125 459 : for (int Loop = 1; Loop <= state.dataHeatBal->TotConstructs; ++Loop) {
5126 343 : auto &constr = state.dataConstruction->Construct(Loop);
5127 :
5128 343 : if (!constr.isTCMaster) continue;
5129 :
5130 0 : auto const *matGlassTC = dynamic_cast<Material::MaterialGlassTC const *>(s_mat->materials(constr.TCMasterMatNum));
5131 0 : assert(matGlassTC != nullptr);
5132 0 : NumNewConst += matGlassTC->numMatRefs;
5133 : }
5134 :
5135 116 : if (NumNewConst == 0) return; // no need to go further
5136 :
5137 : // Increase Construct() and copy the extra constructions
5138 0 : state.dataConstruction->Construct.redimension(state.dataHeatBal->TotConstructs + NumNewConst);
5139 0 : state.dataHeatBal->NominalRforNominalUCalculation.redimension(state.dataHeatBal->TotConstructs + NumNewConst);
5140 0 : state.dataHeatBal->NominalU.redimension(state.dataHeatBal->TotConstructs + NumNewConst);
5141 0 : state.dataHeatBal->NominalUBeforeAdjusted.redimension(state.dataHeatBal->TotConstructs + NumNewConst);
5142 0 : state.dataHeatBal->CoeffAdjRatio.redimension(state.dataHeatBal->TotConstructs + NumNewConst) = 1.0;
5143 :
5144 0 : NumNewConst = state.dataHeatBal->TotConstructs;
5145 0 : for (int Loop = 1; Loop <= state.dataHeatBal->TotConstructs; ++Loop) {
5146 0 : auto &constr = state.dataConstruction->Construct(Loop);
5147 0 : if (!constr.isTCMaster) continue;
5148 :
5149 0 : auto const *matGlassTC = dynamic_cast<Material::MaterialGlassTC *>(s_mat->materials(constr.TCMasterMatNum));
5150 0 : assert(matGlassTC != nullptr);
5151 :
5152 0 : constr.numTCChildConstrs = matGlassTC->numMatRefs;
5153 0 : constr.TCChildConstrs.allocate(constr.numTCChildConstrs);
5154 :
5155 : // The master thermochromic construction uses the first (i.e., lowest temp) glazing
5156 0 : constr.LayerPoint(constr.TCLayerNum) = matGlassTC->matRefs(1).matNum;
5157 0 : constr.specTemp = matGlassTC->matRefs(1).specTemp;
5158 :
5159 0 : for (int iTC = 1; iTC <= constr.numTCChildConstrs; ++iTC) {
5160 0 : ++NumNewConst;
5161 0 : auto &constrNew = state.dataConstruction->Construct(NumNewConst);
5162 :
5163 0 : constrNew = constr; // This should be a deep copy
5164 0 : constrNew.Name = format("{}_TC_{:.0R}", constr.Name, matGlassTC->matRefs(iTC).specTemp);
5165 0 : constrNew.LayerPoint(constrNew.TCLayerNum) = matGlassTC->matRefs(iTC).matNum;
5166 0 : constrNew.specTemp = matGlassTC->matRefs(iTC).specTemp;
5167 :
5168 0 : constrNew.isTCWindow = true;
5169 0 : constrNew.isTCMaster = false;
5170 0 : constrNew.TCMasterConstrNum = Loop;
5171 :
5172 0 : constr.TCChildConstrs(iTC).specTemp = matGlassTC->matRefs(iTC).specTemp;
5173 0 : constr.TCChildConstrs(iTC).constrNum = NumNewConst;
5174 : }
5175 : }
5176 0 : state.dataHeatBal->TotConstructs = NumNewConst;
5177 : }
5178 :
5179 1 : void SetupComplexFenestrationStateInput(EnergyPlusData &state,
5180 : int &ConstrNum, // num of construction items thus far
5181 : bool &ErrorsFound)
5182 : {
5183 :
5184 : // SUBROUTINE INFORMATION:
5185 : // AUTHOR B. Griffith
5186 : // DATE WRITTEN June 2010
5187 : // MODIFIED January 2012 (Simon Vidanovic)
5188 : // MODIFIED May 2012 (Simon Vidanovic)
5189 :
5190 : // PURPOSE OF THIS SUBROUTINE:
5191 : // get input for complex fenestration construction
5192 :
5193 : // METHODOLOGY EMPLOYED:
5194 : // usual GetInput processing. Matrix input from MatrixDataManager
5195 :
5196 : // SUBROUTINE PARAMETER DEFINITIONS:
5197 : static constexpr std::string_view routineName = "SetupComlexFenestrationStateInput";
5198 :
5199 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
5200 : int NumAlphas; // Number of Alphas for each GetObjectItem call
5201 : int NumNumbers; // Number of Numbers for each GetObjectItem call
5202 : int TotalArgs; // Number of fields for each GetObjectItem call
5203 : int IOStatus; // Used in GetObjectItem
5204 : int NumRows; // temporary size of matrix
5205 : int NumCols; // temporary size of matrix
5206 : int NBasis; // temporary number of elements in basis
5207 : int AlphaIndex;
5208 : int NumOfTotalLayers; // total number of layers in the construction
5209 : int NumOfOpticalLayers; // number of optical layers in the construction (excluding gasses and gas mixtures)
5210 : int currentOpticalLayer; // current optical layer number. This is important since optical structures should
5211 : // be loaded only with optical layers
5212 :
5213 : // When reading Construction:ComplexFenestrationState, there is a call of GetMatrix2D which also uses same
5214 : // variables from DataIPShortCuts. Since this can cause some errors in reading, it is important
5215 : // to declare local variables for reading Construction:ComplexFenestrationState object(s)
5216 1 : Array1D_string locAlphaFieldNames;
5217 1 : Array1D_string locNumericFieldNames;
5218 1 : Array1D_bool locNumericFieldBlanks;
5219 1 : Array1D_bool locAlphaFieldBlanks;
5220 1 : Array1D_string locAlphaArgs;
5221 1 : Array1D<Real64> locNumericArgs;
5222 1 : std::string locCurrentModuleObject;
5223 :
5224 1 : auto &s_ipsc = state.dataIPShortCut;
5225 1 : auto &s_mat = state.dataMaterial;
5226 :
5227 : // Reading WindowThermalModel:Params
5228 1 : s_ipsc->cCurrentModuleObject = "WindowThermalModel:Params";
5229 1 : state.dataBSDFWindow->TotThermalModels = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
5230 1 : s_mat->WindowThermalModel.allocate(state.dataBSDFWindow->TotThermalModels);
5231 :
5232 2 : for (int Loop = 1; Loop <= state.dataBSDFWindow->TotThermalModels; ++Loop) {
5233 3 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
5234 1 : s_ipsc->cCurrentModuleObject,
5235 : Loop,
5236 1 : s_ipsc->cAlphaArgs,
5237 : NumAlphas,
5238 1 : s_ipsc->rNumericArgs,
5239 : NumNumbers,
5240 : IOStatus,
5241 1 : s_ipsc->lNumericFieldBlanks,
5242 : _,
5243 1 : s_ipsc->cAlphaFieldNames,
5244 1 : s_ipsc->cNumericFieldNames);
5245 :
5246 1 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
5247 :
5248 1 : auto &windowThermalModel = s_mat->WindowThermalModel(Loop);
5249 1 : windowThermalModel.Name = s_ipsc->cAlphaArgs(1);
5250 :
5251 1 : windowThermalModel.SDScalar = s_ipsc->rNumericArgs(1);
5252 1 : if ((s_ipsc->rNumericArgs(1) < 0.0) || (s_ipsc->rNumericArgs(1) > 1.0)) {
5253 0 : ShowSevereCustom(
5254 : state,
5255 : eoh,
5256 0 : format("{} should be >= 0.0 and <= 1.0, entered value = {:.2R}", s_ipsc->cNumericFieldNames(1), s_ipsc->rNumericArgs(1)));
5257 0 : ErrorsFound = true;
5258 : }
5259 :
5260 1 : windowThermalModel.CalculationStandard =
5261 1 : static_cast<TARCOGGassesParams::Stdrd>(getEnumValue(TARCOGGassesParams::stdrdNamesUC, s_ipsc->cAlphaArgs(2)));
5262 1 : windowThermalModel.ThermalModel =
5263 1 : static_cast<TARCOGParams::TARCOGThermalModel>(getEnumValue(TARCOGParams::thermalModelNamesUC, s_ipsc->cAlphaArgs(3)));
5264 1 : windowThermalModel.DeflectionModel =
5265 1 : static_cast<TARCOGParams::DeflectionCalculation>(getEnumValue(TARCOGParams::deflectionCalculationNamesUC, s_ipsc->cAlphaArgs(4)));
5266 :
5267 1 : if (windowThermalModel.DeflectionModel == TARCOGParams::DeflectionCalculation::TEMPERATURE) {
5268 0 : windowThermalModel.VacuumPressureLimit = s_ipsc->rNumericArgs(2);
5269 0 : if (s_ipsc->rNumericArgs(2) <= 0.0) {
5270 0 : ErrorsFound = true;
5271 0 : ShowSevereCustom(
5272 0 : state, eoh, format("{} must be > 0, entered value = {:.2R}", s_ipsc->cNumericFieldNames(2), s_ipsc->rNumericArgs(2)));
5273 : }
5274 :
5275 0 : windowThermalModel.InitialTemperature = s_ipsc->rNumericArgs(3);
5276 0 : if (s_ipsc->rNumericArgs(3) <= 0.0) {
5277 0 : ErrorsFound = true;
5278 0 : ShowSevereCustom(
5279 0 : state, eoh, format("{} must be > 0, entered value = {:.2R}", s_ipsc->cNumericFieldNames(3), s_ipsc->rNumericArgs(3)));
5280 : }
5281 :
5282 0 : windowThermalModel.InitialPressure = s_ipsc->rNumericArgs(4);
5283 0 : if (s_ipsc->rNumericArgs(4) <= 0.0) {
5284 0 : ErrorsFound = true;
5285 0 : ShowSevereCustom(
5286 0 : state, eoh, format("{} must be > 0, entered value = {:.2R}", s_ipsc->cNumericFieldNames(4), s_ipsc->rNumericArgs(4)));
5287 : }
5288 : }
5289 :
5290 : } // DO Loop = 1, TotThermalModels
5291 :
5292 : // Reading Construction:ComplexFenestrationState
5293 1 : locCurrentModuleObject = "Construction:ComplexFenestrationState";
5294 1 : state.dataBSDFWindow->TotComplexFenStates = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, locCurrentModuleObject);
5295 :
5296 1 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, locCurrentModuleObject, TotalArgs, NumAlphas, NumNumbers);
5297 1 : if (!allocated(locAlphaFieldNames)) locAlphaFieldNames.allocate(NumAlphas);
5298 1 : if (!allocated(locNumericFieldNames)) locNumericFieldNames.allocate(NumNumbers);
5299 1 : if (!allocated(locNumericFieldBlanks)) locNumericFieldBlanks.allocate(NumNumbers);
5300 1 : if (!allocated(locAlphaFieldBlanks)) locAlphaFieldBlanks.allocate(NumAlphas);
5301 1 : if (!allocated(locAlphaArgs)) locAlphaArgs.allocate(NumAlphas);
5302 1 : if (!allocated(locNumericArgs)) locNumericArgs.allocate(NumNumbers);
5303 :
5304 1 : state.dataBSDFWindow->FirstBSDF = ConstrNum + 1; // Location of first BSDF construction input (They will be consecutive)
5305 2 : for (int Loop = 1; Loop <= state.dataBSDFWindow->TotComplexFenStates; ++Loop) {
5306 1 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
5307 : locCurrentModuleObject,
5308 : Loop,
5309 : locAlphaArgs,
5310 : NumAlphas,
5311 : locNumericArgs,
5312 : NumNumbers,
5313 : IOStatus,
5314 : locNumericFieldBlanks,
5315 : _,
5316 : locAlphaFieldNames,
5317 : locNumericFieldNames);
5318 :
5319 1 : ErrorObjectHeader eoh{routineName, locCurrentModuleObject, locAlphaArgs(1)};
5320 :
5321 2 : if (GlobalNames::VerifyUniqueInterObjectName(state,
5322 1 : state.dataHeatBalMgr->UniqueConstructNames,
5323 1 : locAlphaArgs(1),
5324 1 : state.dataHeatBalMgr->CurrentModuleObject,
5325 1 : locAlphaFieldNames(1),
5326 : ErrorsFound)) {
5327 0 : continue;
5328 : }
5329 1 : ++ConstrNum;
5330 1 : auto &thisConstruct = state.dataConstruction->Construct(ConstrNum);
5331 : // Simon TODO: This is to be confirmed. If this is just initial value, then we might want to make better guess
5332 1 : state.dataHeatBal->NominalRforNominalUCalculation(ConstrNum) = 0.1;
5333 : // Simon TODO: If I do not put this, then it is considered that surface is NOT window
5334 1 : thisConstruct.TransDiff = 0.1; // This is a place holder to flag
5335 : // the construction as a window until
5336 : // the correct value is entered in WindowComplexManager
5337 :
5338 : // Now override the deraults as appropriate
5339 1 : thisConstruct.Name = locAlphaArgs(1);
5340 :
5341 : // ALLOCATE(Construct(ConstrNum)%BSDFInput)
5342 :
5343 : // Construct(ConstrNum)%BSDFInput%ThermalConstruction = ThConstNum
5344 :
5345 1 : thisConstruct.BSDFInput.BasisType = static_cast<DataBSDFWindow::Basis>(getEnumValue(DataBSDFWindow::basisNamesUC, locAlphaArgs(2)));
5346 1 : thisConstruct.BSDFInput.BasisSymmetryType =
5347 1 : static_cast<DataBSDFWindow::BasisSymmetry>(getEnumValue(DataBSDFWindow::basisSymmetryNamesUC, locAlphaArgs(3)));
5348 :
5349 : // Simon: Assign thermal model number
5350 1 : thisConstruct.BSDFInput.ThermalModel = Util::FindItemInList(locAlphaArgs(4), s_mat->WindowThermalModel);
5351 1 : if (thisConstruct.BSDFInput.ThermalModel == 0) {
5352 0 : ShowSevereItemNotFound(state, eoh, locAlphaFieldNames(4), locAlphaArgs(4));
5353 : }
5354 :
5355 : // ***************************************************************************************
5356 : // Basis matrix
5357 : // ***************************************************************************************
5358 1 : thisConstruct.BSDFInput.BasisMatIndex = MatrixDataManager::MatrixIndex(state, locAlphaArgs(5));
5359 1 : MatrixDataManager::Get2DMatrixDimensions(state, thisConstruct.BSDFInput.BasisMatIndex, NumRows, NumCols);
5360 1 : thisConstruct.BSDFInput.BasisMatNrows = NumRows;
5361 1 : thisConstruct.BSDFInput.BasisMatNcols = NumCols;
5362 :
5363 1 : if (NumCols != 2 && NumCols != 1) {
5364 0 : ErrorsFound = true;
5365 0 : ShowSevereCustom(state,
5366 : eoh,
5367 0 : format("{} entered value=\"{}\" invalid matrix dimensions. Basis matrix dimension can only be 2 x 1.",
5368 : locAlphaFieldNames(5),
5369 : locAlphaArgs(5)));
5370 : }
5371 1 : thisConstruct.BSDFInput.BasisMat.allocate(NumCols, NumRows);
5372 1 : MatrixDataManager::Get2DMatrix(state, thisConstruct.BSDFInput.BasisMatIndex, thisConstruct.BSDFInput.BasisMat);
5373 1 : if (thisConstruct.BSDFInput.BasisType == DataBSDFWindow::Basis::WINDOW)
5374 1 : WindowComplexManager::CalculateBasisLength(state, thisConstruct.BSDFInput, ConstrNum, thisConstruct.BSDFInput.NBasis);
5375 :
5376 : // determine number of layers and optical layers
5377 1 : NumOfTotalLayers = (NumAlphas - 9) / 3;
5378 1 : thisConstruct.TotLayers = NumOfTotalLayers;
5379 :
5380 1 : NumOfOpticalLayers = NumOfTotalLayers / 2 + 1;
5381 :
5382 1 : thisConstruct.BSDFInput.NumLayers = NumOfOpticalLayers;
5383 1 : thisConstruct.BSDFInput.Layer.allocate(NumOfOpticalLayers);
5384 :
5385 : // check for incomplete field set
5386 1 : if (mod((NumAlphas - 9), 3) != 0) {
5387 : // throw warning if incomplete field set
5388 0 : ErrorsFound = true;
5389 0 : ShowSevereCustom(state, eoh, format("{} is missing some of the layers or/and gaps.", locAlphaArgs(1)));
5390 : }
5391 :
5392 1 : if (thisConstruct.BSDFInput.BasisSymmetryType == DataBSDFWindow::BasisSymmetry::None) {
5393 : // Non-Symmetric basis
5394 :
5395 1 : NBasis = thisConstruct.BSDFInput.NBasis;
5396 :
5397 : // *******************************************************************************
5398 : // Solar front transmittance
5399 : // *******************************************************************************
5400 1 : thisConstruct.BSDFInput.SolFrtTransIndex = MatrixDataManager::MatrixIndex(state, locAlphaArgs(6));
5401 1 : MatrixDataManager::Get2DMatrixDimensions(state, thisConstruct.BSDFInput.SolFrtTransIndex, NumRows, NumCols);
5402 1 : thisConstruct.BSDFInput.SolFrtTransNrows = NumRows;
5403 1 : thisConstruct.BSDFInput.SolFrtTransNcols = NumCols;
5404 :
5405 1 : if (NumRows != NBasis) {
5406 0 : ErrorsFound = true;
5407 0 : ShowSevereCustom(
5408 : state,
5409 : eoh,
5410 0 : format("Solar front transmittance matrix \"{}\" is not the same size as it is defined by basis definition. Basis "
5411 : "size is defined by Matrix:TwoDimension = \"{}\".",
5412 : locAlphaArgs(6),
5413 : locAlphaArgs(5)));
5414 : }
5415 :
5416 1 : if (NumRows != NumCols) {
5417 0 : ErrorsFound = true;
5418 0 : ShowSevereCustom(
5419 : state,
5420 : eoh,
5421 0 : format("Solar front transmittance matrix \"{}\" must have the same number of rows and columns.", locAlphaArgs(6)));
5422 : }
5423 :
5424 1 : if (thisConstruct.BSDFInput.BasisType == DataBSDFWindow::Basis::Custom) {
5425 0 : thisConstruct.BSDFInput.NBasis = NumRows; // For custom basis, no rows in transmittance
5426 : // matrix defines the basis length
5427 : }
5428 :
5429 1 : thisConstruct.BSDFInput.SolFrtTrans.allocate(NumCols, NumRows);
5430 1 : if (thisConstruct.BSDFInput.SolFrtTransIndex == 0) {
5431 0 : ErrorsFound = true;
5432 0 : ShowSevereCustom(
5433 : state,
5434 : eoh,
5435 0 : format("Solar front transmittance Matrix:TwoDimension = \"{}\" is missing from the input file.", locAlphaArgs(6)));
5436 : } else {
5437 1 : MatrixDataManager::Get2DMatrix(state, thisConstruct.BSDFInput.SolFrtTransIndex, thisConstruct.BSDFInput.SolFrtTrans);
5438 : }
5439 :
5440 : // *******************************************************************************
5441 : // Solar back reflectance
5442 : // *******************************************************************************
5443 1 : thisConstruct.BSDFInput.SolBkReflIndex = MatrixDataManager::MatrixIndex(state, locAlphaArgs(7));
5444 1 : MatrixDataManager::Get2DMatrixDimensions(state, thisConstruct.BSDFInput.SolBkReflIndex, NumRows, NumCols);
5445 1 : thisConstruct.BSDFInput.SolBkReflNrows = NumRows;
5446 1 : thisConstruct.BSDFInput.SolBkReflNcols = NumCols;
5447 :
5448 1 : if (NumRows != NBasis) {
5449 0 : ErrorsFound = true;
5450 0 : ShowSevereCustom(
5451 : state,
5452 : eoh,
5453 0 : format("Solar back reflectance matrix \"{}\" is not the same size as it is defined by basis definition. Basis size "
5454 : "is defined by Matrix:TwoDimension = \"{}\".",
5455 : locAlphaArgs(7),
5456 : locAlphaArgs(5)));
5457 : }
5458 :
5459 1 : if (NumRows != NumCols) {
5460 0 : ErrorsFound = true;
5461 0 : ShowSevereCustom(
5462 0 : state, eoh, format("Solar back reflectance matrix \"{}\" must have the same number of rows and columns.", locAlphaArgs(7)));
5463 : }
5464 :
5465 1 : thisConstruct.BSDFInput.SolBkRefl.allocate(NumCols, NumRows);
5466 1 : if (thisConstruct.BSDFInput.SolBkReflIndex == 0) {
5467 0 : ErrorsFound = true;
5468 0 : ShowSevereCustom(
5469 0 : state, eoh, format("Solar back reflectance Matrix:TwoDimension = \"{}\" is missing from the input file.", locAlphaArgs(7)));
5470 : } else {
5471 1 : MatrixDataManager::Get2DMatrix(state, thisConstruct.BSDFInput.SolBkReflIndex, thisConstruct.BSDFInput.SolBkRefl);
5472 : }
5473 :
5474 : // *******************************************************************************
5475 : // Visible front transmittance
5476 : // *******************************************************************************
5477 1 : thisConstruct.BSDFInput.VisFrtTransIndex = MatrixDataManager::MatrixIndex(state, locAlphaArgs(8));
5478 1 : MatrixDataManager::Get2DMatrixDimensions(state, thisConstruct.BSDFInput.VisFrtTransIndex, NumRows, NumCols);
5479 1 : thisConstruct.BSDFInput.VisFrtTransNrows = NumRows;
5480 1 : thisConstruct.BSDFInput.VisFrtTransNcols = NumCols;
5481 :
5482 1 : if (NumRows != NBasis) {
5483 0 : ErrorsFound = true;
5484 0 : ShowSevereCustom(
5485 : state,
5486 : eoh,
5487 0 : format("Visible front transmittance matrix \"{}\" is not the same size as it is defined by basis definition. Basis "
5488 : "size is defined by Matrix:TwoDimension = \"{}\".",
5489 : locAlphaArgs(8),
5490 : locAlphaArgs(5)));
5491 : }
5492 :
5493 1 : if (NumRows != NumCols) {
5494 0 : ErrorsFound = true;
5495 0 : ShowSevereCustom(
5496 : state,
5497 : eoh,
5498 0 : format("Visible front transmittance matrix \"{}\" must have the same number of rows and columns.", locAlphaArgs(8)));
5499 : }
5500 :
5501 1 : thisConstruct.BSDFInput.VisFrtTrans.allocate(NumCols, NumRows);
5502 1 : if (thisConstruct.BSDFInput.VisFrtTransIndex == 0) {
5503 0 : ErrorsFound = true;
5504 0 : ShowSevereCustom(
5505 : state,
5506 : eoh,
5507 0 : format("Visible front transmittance Matrix:TwoDimension = \"{}\" is missing from the input file.", locAlphaArgs(8)));
5508 : } else {
5509 1 : MatrixDataManager::Get2DMatrix(state, thisConstruct.BSDFInput.VisFrtTransIndex, thisConstruct.BSDFInput.VisFrtTrans);
5510 : }
5511 :
5512 : // *******************************************************************************
5513 : // Visible back reflectance
5514 : // *******************************************************************************
5515 1 : thisConstruct.BSDFInput.VisBkReflIndex = MatrixDataManager::MatrixIndex(state, locAlphaArgs(9));
5516 1 : MatrixDataManager::Get2DMatrixDimensions(state, thisConstruct.BSDFInput.VisBkReflIndex, NumRows, NumCols);
5517 1 : thisConstruct.BSDFInput.VisBkReflNrows = NumRows;
5518 1 : thisConstruct.BSDFInput.VisBkReflNcols = NumCols;
5519 :
5520 1 : if (NumRows != NBasis) {
5521 0 : ErrorsFound = true;
5522 0 : ShowSevereCustom(state,
5523 : eoh,
5524 0 : format("Visible back reflectance matrix \"{}\" is not the same size as it is defined by basis definition. Basis "
5525 : "size is defined by Matrix:TwoDimension = \"{}\".",
5526 : locAlphaArgs(9),
5527 : locAlphaArgs(5)));
5528 : }
5529 :
5530 1 : if (NumRows != NumCols) {
5531 0 : ErrorsFound = true;
5532 0 : ShowSevereCustom(
5533 0 : state, eoh, format("Visible back reflectance \"{}\" must have the same number of rows and columns.", locAlphaArgs(9)));
5534 : }
5535 :
5536 1 : thisConstruct.BSDFInput.VisBkRefl.allocate(NumCols, NumRows);
5537 1 : if (thisConstruct.BSDFInput.VisBkReflIndex == 0) {
5538 0 : ErrorsFound = true;
5539 0 : ShowSevereCustom(
5540 0 : state, eoh, format("Visble back reflectance Matrix:TwoDimension = \"{}\" is missing from the input file.", locAlphaArgs(9)));
5541 : } else {
5542 1 : MatrixDataManager::Get2DMatrix(state, thisConstruct.BSDFInput.VisBkReflIndex, thisConstruct.BSDFInput.VisBkRefl);
5543 : }
5544 :
5545 : // ALLOCATE(Construct(ConstrNum)%BSDFInput%Layer(NumOfOpticalLayers))
5546 6 : for (int Layer = 1; Layer <= thisConstruct.TotLayers; ++Layer) {
5547 5 : AlphaIndex = 9 + (Layer * 3) - 2;
5548 5 : currentOpticalLayer = int(Layer / 2) + 1;
5549 : // Material info is contained in the thermal construct
5550 5 : thisConstruct.LayerPoint(Layer) = Material::GetMaterialNum(state, locAlphaArgs(AlphaIndex));
5551 :
5552 : // Simon: Load only if optical layer
5553 5 : if (mod(Layer, 2) != 0) {
5554 3 : thisConstruct.BSDFInput.Layer(currentOpticalLayer).MaterialIndex = thisConstruct.LayerPoint(Layer);
5555 :
5556 3 : ++AlphaIndex;
5557 : // *******************************************************************************
5558 : // Front absorptance matrix
5559 : // *******************************************************************************
5560 6 : thisConstruct.BSDFInput.Layer(currentOpticalLayer).FrtAbsIndex =
5561 3 : MatrixDataManager::MatrixIndex(state, locAlphaArgs(AlphaIndex));
5562 3 : MatrixDataManager::Get2DMatrixDimensions(
5563 3 : state, thisConstruct.BSDFInput.Layer(currentOpticalLayer).FrtAbsIndex, NumRows, NumCols);
5564 :
5565 3 : if (NumRows != 1) {
5566 0 : ErrorsFound = true;
5567 0 : ShowSevereCustom(state,
5568 : eoh,
5569 0 : format("Front absorbtance Matrix:TwoDimension = \"{}\" for layer {} must have only one row.",
5570 : locAlphaArgs(AlphaIndex),
5571 : currentOpticalLayer));
5572 : }
5573 :
5574 3 : if (NumCols != NBasis) {
5575 0 : ErrorsFound = true;
5576 0 : ShowSevereCustom(state,
5577 : eoh,
5578 0 : format("Front absorbtance Matrix:TwoDimension = \"{}\" for layer {} must have same number of columns "
5579 : "as it is defined by basis matrix."
5580 : "Matrix has {} number of columns, while basis definition specifies {} number of columns.",
5581 : locAlphaArgs(AlphaIndex),
5582 : currentOpticalLayer,
5583 : NumCols,
5584 : NBasis));
5585 : }
5586 :
5587 3 : thisConstruct.BSDFInput.Layer(currentOpticalLayer).AbsNcols = NumCols;
5588 3 : thisConstruct.BSDFInput.Layer(currentOpticalLayer).FrtAbs.allocate(NumCols, NumRows);
5589 3 : if (thisConstruct.BSDFInput.Layer(currentOpticalLayer).FrtAbsIndex == 0) {
5590 0 : ErrorsFound = true;
5591 0 : ShowSevereCustom(state,
5592 : eoh,
5593 0 : format("Front absorbtance Matrix:TwoDimension = \"{}\" for layer {} is missing from the input file.",
5594 : locAlphaArgs(AlphaIndex),
5595 : currentOpticalLayer));
5596 : } else {
5597 3 : MatrixDataManager::Get2DMatrix(state,
5598 3 : thisConstruct.BSDFInput.Layer(currentOpticalLayer).FrtAbsIndex,
5599 3 : thisConstruct.BSDFInput.Layer(currentOpticalLayer).FrtAbs);
5600 : }
5601 :
5602 3 : ++AlphaIndex;
5603 : // *******************************************************************************
5604 : // Back absorptance matrix
5605 : // *******************************************************************************
5606 6 : thisConstruct.BSDFInput.Layer(currentOpticalLayer).BkAbsIndex =
5607 3 : MatrixDataManager::MatrixIndex(state, locAlphaArgs(AlphaIndex));
5608 3 : MatrixDataManager::Get2DMatrixDimensions(
5609 3 : state, thisConstruct.BSDFInput.Layer(currentOpticalLayer).BkAbsIndex, NumRows, NumCols);
5610 :
5611 3 : if (NumRows != 1) {
5612 0 : ErrorsFound = true;
5613 0 : ShowSevereCustom(state,
5614 : eoh,
5615 0 : format("Back absorbtance Matrix:TwoDimension = \"{}\" for layer {} must have only one row.",
5616 : locAlphaArgs(AlphaIndex),
5617 : currentOpticalLayer));
5618 : }
5619 :
5620 3 : if (NumCols != NBasis) {
5621 0 : ErrorsFound = true;
5622 0 : ShowSevereCustom(state,
5623 : eoh,
5624 0 : format("Back absorbtance Matrix:TwoDimension = \"{}\" for layer {} must have same number of columns as "
5625 : "it is defined by basis matrix."
5626 : "Matrix has {} number of columns, while basis definition specifies {} number of columns.",
5627 : locAlphaArgs(AlphaIndex),
5628 : currentOpticalLayer,
5629 : NumCols,
5630 : NBasis));
5631 : }
5632 :
5633 3 : thisConstruct.BSDFInput.Layer(currentOpticalLayer).BkAbs.allocate(NumCols, NumRows);
5634 3 : if (thisConstruct.BSDFInput.Layer(currentOpticalLayer).BkAbsIndex == 0) {
5635 0 : ErrorsFound = true;
5636 0 : ShowSevereCustom(state,
5637 : eoh,
5638 0 : format("Back absorbtance Matrix:TwoDimension = \"{}\" for layer {} is missing from the input file.",
5639 : locAlphaArgs(AlphaIndex),
5640 : currentOpticalLayer));
5641 : } else {
5642 3 : MatrixDataManager::Get2DMatrix(state,
5643 3 : thisConstruct.BSDFInput.Layer(currentOpticalLayer).BkAbsIndex,
5644 3 : thisConstruct.BSDFInput.Layer(currentOpticalLayer).BkAbs);
5645 : }
5646 : } // if (Mod(Layer, 2) <> 0) then
5647 : }
5648 : } else {
5649 : // Axisymmetric basis
5650 0 : NBasis = thisConstruct.BSDFInput.NBasis; // Basis length has already been calculated
5651 0 : state.dataBSDFWindow->BSDFTempMtrx.allocate(NBasis, 1);
5652 :
5653 : // *******************************************************************************
5654 : // Solar front transmittance
5655 : // *******************************************************************************
5656 0 : thisConstruct.BSDFInput.SolFrtTransIndex = MatrixDataManager::MatrixIndex(state, locAlphaArgs(6));
5657 0 : MatrixDataManager::Get2DMatrixDimensions(state, thisConstruct.BSDFInput.SolFrtTransIndex, NumRows, NumCols);
5658 0 : thisConstruct.BSDFInput.SolFrtTransNrows = NBasis;
5659 0 : thisConstruct.BSDFInput.SolFrtTransNcols = NBasis;
5660 :
5661 0 : if (NumRows != NBasis) {
5662 0 : ErrorsFound = true;
5663 0 : ShowSevereCustom(
5664 : state,
5665 : eoh,
5666 0 : format("Solar front transmittance matrix \"{}\" is not the same size as it is defined by basis definition. Basis "
5667 : "size is defined by Matrix:TwoDimension = \"{}\".",
5668 : locAlphaArgs(6),
5669 : locAlphaArgs(5)));
5670 : }
5671 :
5672 0 : if (NumRows != NumCols) {
5673 0 : ErrorsFound = true;
5674 0 : ShowSevereCustom(
5675 : state,
5676 : eoh,
5677 0 : format("Solar front transmittance matrix \"{}\" must have the same number of rows and columns.", locAlphaArgs(6)));
5678 : }
5679 :
5680 0 : thisConstruct.BSDFInput.SolFrtTrans.allocate(NBasis, NBasis);
5681 0 : if (thisConstruct.BSDFInput.SolFrtTransIndex == 0) {
5682 0 : ErrorsFound = true;
5683 0 : ShowSevereCustom(
5684 : state,
5685 : eoh,
5686 0 : format("Solar front transmittance Matrix:TwoDimension = \"{}\" is missing from the input file.", locAlphaArgs(6)));
5687 : } else {
5688 0 : MatrixDataManager::Get2DMatrix(state, thisConstruct.BSDFInput.SolFrtTransIndex, state.dataBSDFWindow->BSDFTempMtrx);
5689 :
5690 0 : thisConstruct.BSDFInput.SolFrtTrans = 0.0;
5691 0 : for (int I = 1; I <= NBasis; ++I) {
5692 0 : thisConstruct.BSDFInput.SolFrtTrans(I, I) = state.dataBSDFWindow->BSDFTempMtrx(I, 1);
5693 : }
5694 : }
5695 :
5696 : // *******************************************************************************
5697 : // Solar back reflectance
5698 : // *******************************************************************************
5699 0 : thisConstruct.BSDFInput.SolBkReflIndex = MatrixDataManager::MatrixIndex(state, locAlphaArgs(7));
5700 0 : MatrixDataManager::Get2DMatrixDimensions(state, thisConstruct.BSDFInput.SolBkReflIndex, NumRows, NumCols);
5701 0 : thisConstruct.BSDFInput.SolBkReflNrows = NBasis;
5702 0 : thisConstruct.BSDFInput.SolBkReflNcols = NBasis;
5703 :
5704 0 : if (NumRows != NBasis) {
5705 0 : ErrorsFound = true;
5706 0 : ShowSevereCustom(
5707 : state,
5708 : eoh,
5709 0 : format("Solar back reflectance matrix \"{}\" is not the same size as it is defined by basis definition. Basis size "
5710 : "is defined by Matrix:TwoDimension = \"{}\".",
5711 : locAlphaArgs(7),
5712 : locAlphaArgs(5)));
5713 : }
5714 :
5715 0 : if (NumRows != NumCols) {
5716 0 : ErrorsFound = true;
5717 0 : ShowSevereCustom(
5718 0 : state, eoh, format("Solar back reflectance matrix \"{}\" must have the same number of rows and columns.", locAlphaArgs(7)));
5719 : }
5720 :
5721 0 : thisConstruct.BSDFInput.SolBkRefl.allocate(NBasis, NBasis);
5722 0 : if (thisConstruct.BSDFInput.SolBkReflIndex == 0) {
5723 0 : ErrorsFound = true;
5724 0 : ShowSevereCustom(
5725 0 : state, eoh, format("Solar back reflectance Matrix:TwoDimension = \"{}\" is missing from the input file.", locAlphaArgs(7)));
5726 : } else {
5727 0 : MatrixDataManager::Get2DMatrix(state, thisConstruct.BSDFInput.SolBkReflIndex, state.dataBSDFWindow->BSDFTempMtrx);
5728 0 : thisConstruct.BSDFInput.SolBkRefl = 0.0;
5729 0 : for (int I = 1; I <= NBasis; ++I) {
5730 0 : thisConstruct.BSDFInput.SolBkRefl(I, I) = state.dataBSDFWindow->BSDFTempMtrx(I, 1);
5731 : }
5732 : }
5733 :
5734 : // *******************************************************************************
5735 : // Visible front transmittance
5736 : // *******************************************************************************
5737 0 : thisConstruct.BSDFInput.VisFrtTransIndex = MatrixDataManager::MatrixIndex(state, locAlphaArgs(8));
5738 0 : MatrixDataManager::Get2DMatrixDimensions(state, thisConstruct.BSDFInput.VisFrtTransIndex, NumRows, NumCols);
5739 0 : thisConstruct.BSDFInput.VisFrtTransNrows = NBasis;
5740 0 : thisConstruct.BSDFInput.VisFrtTransNcols = NBasis;
5741 :
5742 0 : if (NumRows != NBasis) {
5743 0 : ErrorsFound = true;
5744 0 : ShowSevereCustom(
5745 : state,
5746 : eoh,
5747 0 : format("Visible front transmittance matrix \"{}\" is not the same size as it is defined by basis definition. Basis "
5748 : "size is defined by Matrix:TwoDimension = \"{}\".",
5749 : locAlphaArgs(8),
5750 : locAlphaArgs(5)));
5751 : }
5752 :
5753 0 : if (NumRows != NumCols) {
5754 0 : ErrorsFound = true;
5755 0 : ShowSevereCustom(
5756 : state,
5757 : eoh,
5758 0 : format("Visible front transmittance matrix \"{}\" must have the same number of rows and columns.", locAlphaArgs(8)));
5759 : }
5760 :
5761 0 : thisConstruct.BSDFInput.VisFrtTrans.allocate(NBasis, NBasis);
5762 0 : if (thisConstruct.BSDFInput.VisFrtTransIndex == 0) {
5763 0 : ErrorsFound = true;
5764 0 : ShowSevereCustom(
5765 : state,
5766 : eoh,
5767 0 : format("Visible front transmittance Matrix:TwoDimension = \"{}\" is missing from the input file.", locAlphaArgs(8)));
5768 : } else {
5769 0 : MatrixDataManager::Get2DMatrix(state, thisConstruct.BSDFInput.VisFrtTransIndex, state.dataBSDFWindow->BSDFTempMtrx);
5770 0 : thisConstruct.BSDFInput.VisFrtTrans = 0.0;
5771 0 : for (int I = 1; I <= NBasis; ++I) {
5772 0 : thisConstruct.BSDFInput.VisFrtTrans(I, I) = state.dataBSDFWindow->BSDFTempMtrx(I, 1);
5773 : }
5774 : }
5775 :
5776 : // *******************************************************************************
5777 : // Visible back reflectance
5778 : // *******************************************************************************
5779 0 : thisConstruct.BSDFInput.VisBkReflIndex = MatrixDataManager::MatrixIndex(state, locAlphaArgs(9));
5780 0 : MatrixDataManager::Get2DMatrixDimensions(state, thisConstruct.BSDFInput.VisBkReflIndex, NumRows, NumCols);
5781 0 : thisConstruct.BSDFInput.VisBkReflNrows = NBasis;
5782 0 : thisConstruct.BSDFInput.VisBkReflNcols = NBasis;
5783 :
5784 0 : if (NumRows != NBasis) {
5785 0 : ErrorsFound = true;
5786 0 : ShowSevereCustom(state,
5787 : eoh,
5788 0 : format("Visible back reflectance matrix \"{}\" is not the same size as it is defined by basis definition. Basis "
5789 : "size is defined by Matrix:TwoDimension = \"{}\".",
5790 : locAlphaArgs(9),
5791 : locAlphaArgs(5)));
5792 : }
5793 :
5794 0 : if (NumRows != NumCols) {
5795 0 : ErrorsFound = true;
5796 0 : ShowSevereCustom(
5797 0 : state, eoh, format("Visible back reflectance matrix \"{}\" must have the same number of rows and columns.", locAlphaArgs(9)));
5798 : }
5799 :
5800 0 : thisConstruct.BSDFInput.VisBkRefl.allocate(NBasis, NBasis);
5801 0 : if (thisConstruct.BSDFInput.VisBkReflIndex == 0) {
5802 0 : ErrorsFound = true;
5803 0 : ShowSevereCustom(
5804 0 : state, eoh, format("Visible back reflectance Matrix:TwoDimension = \"{}\" is missing from the input file.", locAlphaArgs(9)));
5805 : } else {
5806 0 : MatrixDataManager::Get2DMatrix(state, thisConstruct.BSDFInput.VisBkReflIndex, state.dataBSDFWindow->BSDFTempMtrx);
5807 0 : thisConstruct.BSDFInput.VisBkRefl = 0.0;
5808 0 : for (int I = 1; I <= NBasis; ++I) {
5809 0 : thisConstruct.BSDFInput.VisBkRefl(I, I) = state.dataBSDFWindow->BSDFTempMtrx(I, 1);
5810 : }
5811 : }
5812 :
5813 : // determine number of layers
5814 : // Construct(ConstrNum)%TotLayers = (NumAlphas - 9)/3
5815 :
5816 : // check for incomplete field set
5817 : // IF (Mod((NumAlphas - 9), 3) /= 0) Then
5818 : // throw warning if incomplete field set
5819 : // CALL ShowWarningError(state, 'Construction:ComplexFenestrationState: Axisymmetric properties have incomplete field &
5820 : // & set')
5821 : // ENDIF
5822 :
5823 : // ALLOCATE(Construct(ConstrNum)%BSDFInput%Layer(NumOfOpticalLayers))
5824 0 : for (int Layer = 1; Layer <= thisConstruct.TotLayers; ++Layer) {
5825 :
5826 0 : if (mod(Layer, 2) != 0) {
5827 0 : thisConstruct.BSDFInput.Layer(currentOpticalLayer).MaterialIndex = thisConstruct.LayerPoint(Layer);
5828 :
5829 : // *******************************************************************************
5830 : // Front absorptance matrix
5831 : // *******************************************************************************
5832 0 : ++AlphaIndex;
5833 0 : thisConstruct.BSDFInput.Layer(currentOpticalLayer).FrtAbsIndex =
5834 0 : MatrixDataManager::MatrixIndex(state, locAlphaArgs(AlphaIndex));
5835 0 : MatrixDataManager::Get2DMatrixDimensions(
5836 0 : state, thisConstruct.BSDFInput.Layer(currentOpticalLayer).FrtAbsIndex, NumRows, NumCols);
5837 :
5838 0 : if (NumRows != 1) {
5839 0 : ErrorsFound = true;
5840 0 : ShowSevereCustom(state,
5841 : eoh,
5842 0 : format("Front absorbtance Matrix:TwoDimension = \"{}\" for layer {} must have only one row.",
5843 : locAlphaArgs(AlphaIndex),
5844 : currentOpticalLayer));
5845 : }
5846 :
5847 0 : if (NumCols != NBasis) {
5848 0 : ErrorsFound = true;
5849 0 : ShowSevereCustom(state,
5850 : eoh,
5851 0 : format("Front absorbtance Matrix:TwoDimension = \"{}\" for layer {} must have same number of columns "
5852 : "as it is defined by basis matrix."
5853 : "Matrix has {} number of columns, while basis definition specifies {} number of columns.",
5854 : locAlphaArgs(AlphaIndex),
5855 : currentOpticalLayer,
5856 : NumCols,
5857 : NBasis));
5858 : }
5859 :
5860 0 : thisConstruct.BSDFInput.Layer(currentOpticalLayer).AbsNcols = NumCols;
5861 0 : thisConstruct.BSDFInput.Layer(currentOpticalLayer).FrtAbs.allocate(NumCols, NumRows);
5862 :
5863 0 : if (thisConstruct.BSDFInput.Layer(currentOpticalLayer).FrtAbsIndex == 0) {
5864 0 : ErrorsFound = true;
5865 0 : ShowSevereCustom(state,
5866 : eoh,
5867 0 : format("Front absorbtance Matrix:TwoDimension = \"{}\" for layer {} is missing from the input file.",
5868 : locAlphaArgs(AlphaIndex),
5869 : currentOpticalLayer));
5870 : } else {
5871 0 : MatrixDataManager::Get2DMatrix(state,
5872 0 : thisConstruct.BSDFInput.Layer(currentOpticalLayer).FrtAbsIndex,
5873 0 : thisConstruct.BSDFInput.Layer(currentOpticalLayer).FrtAbs);
5874 : }
5875 :
5876 : // *******************************************************************************
5877 : // Back absorptance matrix
5878 : // *******************************************************************************
5879 0 : ++AlphaIndex;
5880 0 : thisConstruct.BSDFInput.Layer(currentOpticalLayer).BkAbsIndex =
5881 0 : MatrixDataManager::MatrixIndex(state, locAlphaArgs(AlphaIndex));
5882 0 : MatrixDataManager::Get2DMatrixDimensions(
5883 0 : state, thisConstruct.BSDFInput.Layer(currentOpticalLayer).BkAbsIndex, NumRows, NumCols);
5884 :
5885 0 : if (NumRows != 1) {
5886 0 : ErrorsFound = true;
5887 0 : ShowSevereCustom(state,
5888 : eoh,
5889 0 : format("Back absorbtance Matrix:TwoDimension = \"{}\" for layer {} must have only one row.",
5890 : locAlphaArgs(AlphaIndex),
5891 : currentOpticalLayer));
5892 : }
5893 :
5894 0 : if (NumCols != NBasis) {
5895 0 : ErrorsFound = true;
5896 0 : ShowSevereCustom(state,
5897 : eoh,
5898 0 : format("Back absorbtance Matrix:TwoDimension = \"{}\" for layer {} must have same number of columns as "
5899 : "it is defined by basis matrix."
5900 : "Matrix has {} number of columns, while basis definition specifies {} number of columns.",
5901 : locAlphaArgs(AlphaIndex),
5902 : currentOpticalLayer,
5903 : NumCols,
5904 : NBasis));
5905 : }
5906 :
5907 0 : thisConstruct.BSDFInput.Layer(currentOpticalLayer).BkAbs.allocate(NumCols, NumRows);
5908 :
5909 0 : if (thisConstruct.BSDFInput.Layer(currentOpticalLayer).BkAbsIndex == 0) {
5910 0 : ErrorsFound = true;
5911 0 : ShowSevereCustom(state,
5912 : eoh,
5913 0 : format("Back absorbtance Matrix:TwoDimension = \"{}\" for layer {} is missing from the input file.",
5914 : locAlphaArgs(AlphaIndex),
5915 : currentOpticalLayer));
5916 : } else {
5917 0 : MatrixDataManager::Get2DMatrix(state,
5918 0 : thisConstruct.BSDFInput.Layer(currentOpticalLayer).BkAbsIndex,
5919 0 : thisConstruct.BSDFInput.Layer(currentOpticalLayer).BkAbs);
5920 : }
5921 : } // if (Mod(Layer, 2) <> 0) then
5922 : }
5923 :
5924 0 : state.dataBSDFWindow->BSDFTempMtrx.deallocate();
5925 : }
5926 1 : thisConstruct.TypeIsWindow = true;
5927 1 : thisConstruct.WindowTypeBSDF = true;
5928 : }
5929 :
5930 : // Do not forget to deallocate localy allocated variables
5931 1 : if (allocated(locAlphaFieldNames)) locAlphaFieldNames.deallocate();
5932 1 : if (allocated(locNumericFieldNames)) locNumericFieldNames.deallocate();
5933 1 : if (allocated(locNumericFieldBlanks)) locNumericFieldBlanks.deallocate();
5934 1 : if (allocated(locAlphaFieldBlanks)) locAlphaFieldBlanks.deallocate();
5935 1 : if (allocated(locAlphaArgs)) locAlphaArgs.deallocate();
5936 1 : if (allocated(locNumericArgs)) locNumericArgs.deallocate();
5937 :
5938 1 : if (ErrorsFound) ShowFatalError(state, "Error in complex fenestration input.");
5939 1 : }
5940 :
5941 105 : void InitConductionTransferFunctions(EnergyPlusData &state)
5942 : {
5943 105 : bool ErrorsFound(false); // Flag for input error condition
5944 105 : bool DoCTFErrorReport(false);
5945 405 : for (auto &construction : state.dataConstruction->Construct) {
5946 300 : construction.calculateTransferFunction(state, ErrorsFound, DoCTFErrorReport);
5947 300 : if (construction.NumHistories > 1) {
5948 0 : state.dataHeatBal->SimpleCTFOnly = false;
5949 : }
5950 300 : if (construction.NumCTFTerms > state.dataHeatBal->MaxCTFTerms) {
5951 148 : state.dataHeatBal->MaxCTFTerms = construction.NumCTFTerms;
5952 : }
5953 : }
5954 105 : if (state.dataHeatBal->AnyInternalHeatSourceInInput) {
5955 0 : state.dataHeatBal->SimpleCTFOnly = false;
5956 : }
5957 :
5958 405 : for (auto &construction : state.dataConstruction->Construct) {
5959 300 : if (!construction.IsUsedCTF) continue;
5960 246 : construction.reportLayers(state);
5961 : }
5962 :
5963 : bool InitCTFDoReport;
5964 315 : General::ScanForReports(state, "Constructions", InitCTFDoReport, "Constructions");
5965 105 : if (InitCTFDoReport || DoCTFErrorReport) {
5966 22 : print(state.files.eio,
5967 : "! <Construction CTF>,Construction Name,Index,#Layers,#CTFs,Time Step {{hours}},ThermalConductance "
5968 : "{{w/m2-K}},OuterThermalAbsorptance,InnerThermalAbsorptance,OuterSolarAbsorptance,InnerSolarAbsorptance,Roughness\n");
5969 22 : print(state.files.eio,
5970 : "! <Material CTF Summary>,Material Name,Thickness {{m}},Conductivity {{w/m-K}},Density {{kg/m3}},Specific Heat "
5971 : "{{J/kg-K}},ThermalResistance {{m2-K/w}}\n");
5972 22 : print(state.files.eio, "! <Material:Air>,Material Name,ThermalResistance {{m2-K/w}}\n");
5973 22 : print(state.files.eio, "! <CTF>,Time,Outside,Cross,Inside,Flux (except final one)\n");
5974 :
5975 22 : int cCounter = 0; // just used to keep construction index in output report
5976 110 : for (auto &construction : state.dataConstruction->Construct) {
5977 88 : cCounter++;
5978 88 : if (!construction.IsUsedCTF) continue;
5979 74 : construction.reportTransferFunction(state, cCounter);
5980 : }
5981 : }
5982 :
5983 105 : if (ErrorsFound) {
5984 0 : ShowFatalError(state, "Program terminated for reasons listed (InitConductionTransferFunctions)");
5985 : }
5986 105 : }
5987 :
5988 : } // namespace HeatBalanceManager
5989 :
5990 : } // namespace EnergyPlus
|