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