Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2024, 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 <cassert>
51 : #include <cmath>
52 : #include <string>
53 :
54 : // ObjexxFCL Headers
55 : #include <ObjexxFCL/Fmath.hh>
56 : #include <ObjexxFCL/member.functions.hh>
57 : #include <ObjexxFCL/string.functions.hh>
58 :
59 : // EnergyPlus Headers
60 : #include <EnergyPlus/Construction.hh>
61 : #include <EnergyPlus/ConvectionCoefficients.hh>
62 : #include <EnergyPlus/ConvectionConstants.hh>
63 : #include <EnergyPlus/Data/EnergyPlusData.hh>
64 : #include <EnergyPlus/DataEnvironment.hh>
65 : #include <EnergyPlus/DataErrorTracking.hh>
66 : #include <EnergyPlus/DataHeatBalSurface.hh>
67 : #include <EnergyPlus/DataHeatBalance.hh>
68 : #include <EnergyPlus/DataIPShortCuts.hh>
69 : #include <EnergyPlus/DataLoopNode.hh>
70 : #include <EnergyPlus/DataReportingFlags.hh>
71 : #include <EnergyPlus/DataSystemVariables.hh>
72 : #include <EnergyPlus/DataViewFactorInformation.hh>
73 : #include <EnergyPlus/DataWindowEquivalentLayer.hh>
74 : #include <EnergyPlus/DataZoneEquipment.hh>
75 : #include <EnergyPlus/DaylightingManager.hh>
76 : #include <EnergyPlus/DisplayRoutines.hh>
77 : #include <EnergyPlus/EMSManager.hh>
78 : #include <EnergyPlus/General.hh>
79 : #include <EnergyPlus/GlobalNames.hh>
80 : #include <EnergyPlus/HeatBalanceManager.hh>
81 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
82 : #include <EnergyPlus/Material.hh>
83 : #include <EnergyPlus/NodeInputManager.hh>
84 : #include <EnergyPlus/OutAirNodeManager.hh>
85 : #include <EnergyPlus/OutputProcessor.hh>
86 : #include <EnergyPlus/OutputReportPredefined.hh>
87 : #include <EnergyPlus/ScheduleManager.hh>
88 : #include <EnergyPlus/SolarShading.hh>
89 : #include <EnergyPlus/SurfaceGeometry.hh>
90 : #include <EnergyPlus/UtilityRoutines.hh>
91 : #include <EnergyPlus/Vectors.hh>
92 : #include <EnergyPlus/WeatherManager.hh>
93 : #include <EnergyPlus/WindowManager.hh>
94 : #include <EnergyPlus/ZoneEquipmentManager.hh>
95 :
96 : namespace EnergyPlus {
97 :
98 : namespace SurfaceGeometry {
99 :
100 : // Module containing the routines dealing with the Surface Geometry
101 :
102 : // MODULE INFORMATION:
103 : // AUTHOR Linda Lawrie
104 : // DATE WRITTEN June 2000
105 : // MODIFIED DJS (PSU Dec 2006) to add ecoroof
106 : // RE-ENGINEERED na
107 :
108 : // PURPOSE OF THIS MODULE:
109 : // This module performs the functions required of the surface geometry.
110 :
111 : using namespace DataEnvironment;
112 : using namespace DataHeatBalance;
113 : using namespace DataSurfaces;
114 : using DataWindowEquivalentLayer::CFSMAXNL;
115 :
116 : static std::string const BlankString;
117 :
118 : int constexpr UnenteredAdjacentZoneSurface = -998; // allows users to enter one zone surface ("Zone")
119 : // referencing another in adjacent zone
120 : int constexpr UnreconciledZoneSurface = -999; // interim value between entering surfaces ("Surface") and reconciling
121 :
122 796 : void AllocateSurfaceWindows(EnergyPlusData &state, int NumSurfaces)
123 : {
124 796 : state.dataSurface->SurfWinA.dimension(state.dataSurface->TotSurfaces, CFSMAXNL + 1, 0.0);
125 796 : state.dataSurface->SurfWinADiffFront.dimension(state.dataSurface->TotSurfaces, CFSMAXNL + 1, 0.0);
126 796 : state.dataSurface->SurfWinACFOverlap.dimension(state.dataSurface->TotSurfaces, state.dataHeatBal->MaxSolidWinLayers, 0.0);
127 :
128 796 : state.dataSurface->SurfWinFrameQRadOutAbs.dimension(NumSurfaces, 0);
129 796 : state.dataSurface->SurfWinFrameQRadInAbs.dimension(NumSurfaces, 0);
130 796 : state.dataSurface->SurfWinDividerQRadOutAbs.dimension(NumSurfaces, 0);
131 796 : state.dataSurface->SurfWinDividerQRadInAbs.dimension(NumSurfaces, 0);
132 796 : state.dataSurface->SurfWinExtBeamAbsByShade.dimension(NumSurfaces, 0);
133 796 : state.dataSurface->SurfWinExtDiffAbsByShade.dimension(NumSurfaces, 0);
134 796 : state.dataSurface->SurfWinIntBeamAbsByShade.dimension(NumSurfaces, 0);
135 796 : state.dataSurface->SurfWinIntSWAbsByShade.dimension(NumSurfaces, 0);
136 796 : state.dataSurface->SurfWinInitialDifSolAbsByShade.dimension(NumSurfaces, 0);
137 796 : state.dataSurface->SurfWinIntLWAbsByShade.dimension(NumSurfaces, 0);
138 796 : state.dataSurface->SurfWinConvHeatFlowNatural.dimension(NumSurfaces, 0);
139 796 : state.dataSurface->SurfWinConvHeatGainToZoneAir.dimension(NumSurfaces, 0);
140 796 : state.dataSurface->SurfWinRetHeatGainToZoneAir.dimension(NumSurfaces, 0);
141 796 : state.dataSurface->SurfWinDividerHeatGain.dimension(NumSurfaces, 0);
142 796 : state.dataSurface->SurfWinBlTsolBmBm.dimension(NumSurfaces, 0);
143 796 : state.dataSurface->SurfWinBlTsolBmDif.dimension(NumSurfaces, 0);
144 796 : state.dataSurface->SurfWinBlTsolDifDif.dimension(NumSurfaces, 0);
145 796 : state.dataSurface->SurfWinBlGlSysTsolBmBm.dimension(NumSurfaces, 0);
146 796 : state.dataSurface->SurfWinBlGlSysTsolDifDif.dimension(NumSurfaces, 0);
147 796 : state.dataSurface->SurfWinScTsolBmBm.dimension(NumSurfaces, 0);
148 796 : state.dataSurface->SurfWinScTsolBmDif.dimension(NumSurfaces, 0);
149 796 : state.dataSurface->SurfWinScTsolDifDif.dimension(NumSurfaces, 0);
150 796 : state.dataSurface->SurfWinScGlSysTsolBmBm.dimension(NumSurfaces, 0);
151 796 : state.dataSurface->SurfWinScGlSysTsolDifDif.dimension(NumSurfaces, 0);
152 796 : state.dataSurface->SurfWinGlTsolBmBm.dimension(NumSurfaces, 0);
153 796 : state.dataSurface->SurfWinGlTsolBmDif.dimension(NumSurfaces, 0);
154 796 : state.dataSurface->SurfWinGlTsolDifDif.dimension(NumSurfaces, 0);
155 796 : state.dataSurface->SurfWinBmSolTransThruIntWinRep.dimension(NumSurfaces, 0);
156 796 : state.dataSurface->SurfWinBmSolAbsdOutsReveal.dimension(NumSurfaces, 0);
157 796 : state.dataSurface->SurfWinBmSolRefldOutsRevealReport.dimension(NumSurfaces, 0);
158 796 : state.dataSurface->SurfWinBmSolAbsdInsReveal.dimension(NumSurfaces, 0);
159 796 : state.dataSurface->SurfWinBmSolRefldInsReveal.dimension(NumSurfaces, 0);
160 796 : state.dataSurface->SurfWinBmSolRefldInsRevealReport.dimension(NumSurfaces, 0);
161 796 : state.dataSurface->SurfWinOutsRevealDiffOntoGlazing.dimension(NumSurfaces, 0);
162 796 : state.dataSurface->SurfWinInsRevealDiffOntoGlazing.dimension(NumSurfaces, 0);
163 796 : state.dataSurface->SurfWinInsRevealDiffIntoZone.dimension(NumSurfaces, 0);
164 796 : state.dataSurface->SurfWinOutsRevealDiffOntoFrame.dimension(NumSurfaces, 0);
165 796 : state.dataSurface->SurfWinInsRevealDiffOntoFrame.dimension(NumSurfaces, 0);
166 796 : state.dataSurface->SurfWinInsRevealDiffOntoGlazingReport.dimension(NumSurfaces, 0);
167 796 : state.dataSurface->SurfWinInsRevealDiffIntoZoneReport.dimension(NumSurfaces, 0);
168 796 : state.dataSurface->SurfWinInsRevealDiffOntoFrameReport.dimension(NumSurfaces, 0);
169 796 : state.dataSurface->SurfWinBmSolAbsdInsRevealReport.dimension(NumSurfaces, 0);
170 796 : state.dataSurface->SurfWinBmSolTransThruIntWinRepEnergy.dimension(NumSurfaces, 0);
171 796 : state.dataSurface->SurfWinBmSolRefldOutsRevealRepEnergy.dimension(NumSurfaces, 0);
172 796 : state.dataSurface->SurfWinBmSolRefldInsRevealRepEnergy.dimension(NumSurfaces, 0);
173 796 : state.dataSurface->SurfWinProfileAngHor.dimension(NumSurfaces, 0);
174 796 : state.dataSurface->SurfWinProfileAngVert.dimension(NumSurfaces, 0);
175 :
176 796 : state.dataSurface->SurfWinShadingFlag.dimension(NumSurfaces, WinShadingType::ShadeOff);
177 796 : state.dataSurface->SurfWinShadingFlagEMSOn.dimension(NumSurfaces, 0);
178 796 : state.dataSurface->SurfWinShadingFlagEMSValue.dimension(NumSurfaces, 0.0);
179 796 : state.dataSurface->SurfWinStormWinFlag.dimension(NumSurfaces, 0);
180 796 : state.dataSurface->SurfWinStormWinFlagPrevDay.dimension(NumSurfaces, 0);
181 796 : state.dataSurface->SurfWinFracTimeShadingDeviceOn.dimension(NumSurfaces, 0);
182 796 : state.dataSurface->SurfWinExtIntShadePrevTS.dimension(NumSurfaces, WinShadingType::ShadeOff);
183 796 : state.dataSurface->SurfWinHasShadeOrBlindLayer.dimension(NumSurfaces, 0);
184 796 : state.dataSurface->SurfWinSurfDayLightInit.dimension(NumSurfaces, 0);
185 796 : state.dataSurface->SurfWinDaylFacPoint.dimension(NumSurfaces, 0);
186 796 : state.dataSurface->SurfWinVisTransSelected.dimension(NumSurfaces, 0);
187 796 : state.dataSurface->SurfWinSwitchingFactor.dimension(NumSurfaces, 0);
188 796 : state.dataSurface->SurfWinVisTransRatio.dimension(NumSurfaces, 0);
189 796 : state.dataSurface->SurfWinIRfromParentZone.dimension(NumSurfaces, 0);
190 796 : state.dataSurface->SurfWinFrameArea.dimension(NumSurfaces, 0);
191 796 : state.dataSurface->SurfWinFrameConductance.dimension(NumSurfaces, 0);
192 796 : state.dataSurface->SurfWinFrameSolAbsorp.dimension(NumSurfaces, 0);
193 796 : state.dataSurface->SurfWinFrameVisAbsorp.dimension(NumSurfaces, 0);
194 796 : state.dataSurface->SurfWinFrameEmis.dimension(NumSurfaces, 0);
195 796 : state.dataSurface->SurfWinFrEdgeToCenterGlCondRatio.dimension(NumSurfaces, 1.0);
196 796 : state.dataSurface->SurfWinFrameEdgeArea.dimension(NumSurfaces, 0);
197 796 : state.dataSurface->SurfWinFrameTempIn.dimension(NumSurfaces, 23.0);
198 796 : state.dataSurface->SurfWinFrameTempInOld.dimension(NumSurfaces, 23.0);
199 796 : state.dataSurface->SurfWinFrameTempSurfOut.dimension(NumSurfaces, 23.0);
200 796 : state.dataSurface->SurfWinProjCorrFrOut.dimension(NumSurfaces, 0);
201 796 : state.dataSurface->SurfWinProjCorrFrIn.dimension(NumSurfaces, 0);
202 796 : state.dataSurface->SurfWinDividerType.dimension(NumSurfaces, DataSurfaces::FrameDividerType::DividedLite);
203 796 : state.dataSurface->SurfWinDividerArea.dimension(NumSurfaces, 0);
204 796 : state.dataSurface->SurfWinDividerConductance.dimension(NumSurfaces, 0);
205 796 : state.dataSurface->SurfWinDividerSolAbsorp.dimension(NumSurfaces, 0);
206 796 : state.dataSurface->SurfWinDividerVisAbsorp.dimension(NumSurfaces, 0);
207 796 : state.dataSurface->SurfWinDividerEmis.dimension(NumSurfaces, 0);
208 796 : state.dataSurface->SurfWinDivEdgeToCenterGlCondRatio.dimension(NumSurfaces, 1);
209 796 : state.dataSurface->SurfWinDividerEdgeArea.dimension(NumSurfaces, 0);
210 796 : state.dataSurface->SurfWinDividerTempIn.dimension(NumSurfaces, 23.0);
211 796 : state.dataSurface->SurfWinDividerTempInOld.dimension(NumSurfaces, 23.0);
212 796 : state.dataSurface->SurfWinDividerTempSurfOut.dimension(NumSurfaces, 23.0);
213 796 : state.dataSurface->SurfWinProjCorrDivOut.dimension(NumSurfaces, 0);
214 796 : state.dataSurface->SurfWinProjCorrDivIn.dimension(NumSurfaces, 0);
215 796 : state.dataSurface->SurfWinShadeAbsFacFace1.dimension(NumSurfaces, 0.5);
216 796 : state.dataSurface->SurfWinShadeAbsFacFace2.dimension(NumSurfaces, 0.5);
217 796 : state.dataSurface->SurfWinConvCoeffWithShade.dimension(NumSurfaces, 0);
218 796 : state.dataSurface->SurfWinOtherConvHeatGain.dimension(NumSurfaces, 0);
219 796 : state.dataSurface->SurfWinBlindNumber.dimension(NumSurfaces, 0);
220 796 : state.dataSurface->SurfWinEffInsSurfTemp.dimension(NumSurfaces, 23.0);
221 796 : state.dataSurface->SurfWinMovableSlats.dimension(NumSurfaces, 0);
222 796 : state.dataSurface->SurfWinSlatAngThisTS.dimension(NumSurfaces, 0);
223 796 : state.dataSurface->SurfWinSlatAngThisTSDeg.dimension(NumSurfaces, 0);
224 796 : state.dataSurface->SurfWinSlatAngThisTSDegEMSon.dimension(NumSurfaces, 0);
225 796 : state.dataSurface->SurfWinSlatAngThisTSDegEMSValue.dimension(NumSurfaces, 0);
226 796 : state.dataSurface->SurfWinSlatsBlockBeam.dimension(NumSurfaces, 0);
227 796 : state.dataSurface->SurfWinSlatsAngIndex.dimension(NumSurfaces, 0);
228 796 : state.dataSurface->SurfWinSlatsAngInterpFac.dimension(NumSurfaces, 0);
229 796 : state.dataSurface->SurfWinProfileAng.dimension(NumSurfaces, 0);
230 796 : state.dataSurface->SurfWinProfAngIndex.dimension(NumSurfaces, 0);
231 796 : state.dataSurface->SurfWinProfAngInterpFac.dimension(NumSurfaces, 0);
232 796 : state.dataSurface->SurfWinBlindBmBmTrans.dimension(NumSurfaces, 0);
233 796 : state.dataSurface->SurfWinBlindAirFlowPermeability.dimension(NumSurfaces, 0);
234 796 : state.dataSurface->SurfWinTotGlazingThickness.dimension(NumSurfaces, 0);
235 796 : state.dataSurface->SurfWinTanProfileAngHor.dimension(NumSurfaces, 0);
236 796 : state.dataSurface->SurfWinTanProfileAngVert.dimension(NumSurfaces, 0);
237 796 : state.dataSurface->SurfWinInsideSillDepth.dimension(NumSurfaces, 0);
238 796 : state.dataSurface->SurfWinInsideReveal.dimension(NumSurfaces, 0);
239 796 : state.dataSurface->SurfWinInsideSillSolAbs.dimension(NumSurfaces, 0);
240 796 : state.dataSurface->SurfWinInsideRevealSolAbs.dimension(NumSurfaces, 0);
241 796 : state.dataSurface->SurfWinOutsideRevealSolAbs.dimension(NumSurfaces, 0);
242 796 : state.dataSurface->SurfWinAirflowSource.dimension(NumSurfaces, DataSurfaces::WindowAirFlowSource::Invalid);
243 796 : state.dataSurface->SurfWinAirflowDestination.dimension(NumSurfaces, DataSurfaces::WindowAirFlowDestination::Invalid);
244 796 : state.dataSurface->SurfWinAirflowReturnNodePtr.dimension(NumSurfaces, 0);
245 796 : state.dataSurface->SurfWinMaxAirflow.dimension(NumSurfaces, 0);
246 796 : state.dataSurface->SurfWinAirflowControlType.dimension(NumSurfaces, DataSurfaces::WindowAirFlowControlType::Invalid);
247 796 : state.dataSurface->SurfWinAirflowHasSchedule.dimension(NumSurfaces, 0);
248 796 : state.dataSurface->SurfWinAirflowSchedulePtr.dimension(NumSurfaces, 0);
249 796 : state.dataSurface->SurfWinAirflowThisTS.dimension(NumSurfaces, 0);
250 796 : state.dataSurface->SurfWinTAirflowGapOutlet.dimension(NumSurfaces, 0);
251 796 : state.dataSurface->SurfWinWindowCalcIterationsRep.dimension(NumSurfaces, 0);
252 796 : state.dataSurface->SurfWinVentingOpenFactorMultRep.dimension(NumSurfaces, 0);
253 796 : state.dataSurface->SurfWinInsideTempForVentingRep.dimension(NumSurfaces, 0);
254 796 : state.dataSurface->SurfWinVentingAvailabilityRep.dimension(NumSurfaces, 0);
255 796 : state.dataSurface->SurfWinSkyGndSolarInc.dimension(NumSurfaces, 0);
256 796 : state.dataSurface->SurfWinBmGndSolarInc.dimension(NumSurfaces, 0);
257 796 : state.dataSurface->SurfWinSolarDiffusing.dimension(NumSurfaces, 0);
258 796 : state.dataSurface->SurfWinFrameHeatGain.dimension(NumSurfaces, 0);
259 796 : state.dataSurface->SurfWinFrameHeatLoss.dimension(NumSurfaces, 0);
260 796 : state.dataSurface->SurfWinDividerHeatLoss.dimension(NumSurfaces, 0);
261 796 : state.dataSurface->SurfWinTCLayerTemp.dimension(NumSurfaces, 0);
262 796 : state.dataSurface->SurfWinSpecTemp.dimension(NumSurfaces, 0);
263 796 : state.dataSurface->SurfWinWindowModelType.dimension(NumSurfaces, WindowModel::Detailed);
264 796 : state.dataSurface->SurfWinTDDPipeNum.dimension(NumSurfaces, 0);
265 796 : state.dataSurface->SurfWinStormWinConstr.dimension(NumSurfaces, 0);
266 796 : state.dataSurface->SurfActiveConstruction.dimension(NumSurfaces, 0);
267 796 : state.dataSurface->SurfWinActiveShadedConstruction.dimension(NumSurfaces, 0);
268 796 : }
269 :
270 796 : void SetupZoneGeometry(EnergyPlusData &state, bool &ErrorsFound)
271 : {
272 :
273 : // SUBROUTINE INFORMATION:
274 : // AUTHOR George Walton
275 : // DATE WRITTEN September 1977
276 : // MODIFIED April 2002 (FCW): add warning for Solar Distribution
277 : // = FullInteriorExterior when window has reveal
278 : // Add fatal error when triangular window has reveal
279 : // May 2002(FCW): Allow triangular windows to have reveal (subr SHDRVL
280 : // in SolarShading). Remove above warning and fatal error.
281 : // RE-ENGINEERED November 1997 (RKS,LKL)
282 :
283 : // PURPOSE OF THIS SUBROUTINE:
284 : // This subroutine controls the processing of detached shadowing and
285 : // zone surfaces for computing their vertices.
286 :
287 : static constexpr std::string_view RoutineName("SetUpZoneGeometry: ");
288 :
289 : // Zones must have been "gotten" before this call
290 : // The RelNorth variables are used if "relative" coordinates are input as well
291 : // as setting up DaylightingCoords
292 :
293 : // these include building north axis and Building Rotation for Appendix G
294 1592 : state.dataSurfaceGeometry->CosBldgRelNorth =
295 796 : std::cos(-(state.dataHeatBal->BuildingAzimuth + state.dataHeatBal->BuildingRotationAppendixG) * Constant::DegToRadians);
296 1592 : state.dataSurfaceGeometry->SinBldgRelNorth =
297 796 : std::sin(-(state.dataHeatBal->BuildingAzimuth + state.dataHeatBal->BuildingRotationAppendixG) * Constant::DegToRadians);
298 :
299 : // these are only for Building Rotation for Appendix G when using world coordinate system
300 796 : state.dataSurfaceGeometry->CosBldgRotAppGonly = std::cos(-state.dataHeatBal->BuildingRotationAppendixG * Constant::DegToRadians);
301 796 : state.dataSurfaceGeometry->SinBldgRotAppGonly = std::sin(-state.dataHeatBal->BuildingRotationAppendixG * Constant::DegToRadians);
302 :
303 796 : state.dataSurfaceGeometry->CosZoneRelNorth.allocate(state.dataGlobal->NumOfZones);
304 796 : state.dataSurfaceGeometry->SinZoneRelNorth.allocate(state.dataGlobal->NumOfZones);
305 :
306 5852 : for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
307 :
308 5056 : state.dataSurfaceGeometry->CosZoneRelNorth(ZoneNum) = std::cos(-state.dataHeatBal->Zone(ZoneNum).RelNorth * Constant::DegToRadians);
309 5056 : state.dataSurfaceGeometry->SinZoneRelNorth(ZoneNum) = std::sin(-state.dataHeatBal->Zone(ZoneNum).RelNorth * Constant::DegToRadians);
310 : }
311 796 : GetSurfaceData(state, ErrorsFound);
312 :
313 796 : if (ErrorsFound) {
314 0 : state.dataSurfaceGeometry->CosZoneRelNorth.deallocate();
315 0 : state.dataSurfaceGeometry->SinZoneRelNorth.deallocate();
316 0 : return;
317 : }
318 :
319 796 : ZoneEquipmentManager::GetZoneEquipment(state); // Necessary to get this before window air gap code
320 :
321 796 : GetWindowGapAirflowControlData(state, ErrorsFound);
322 :
323 796 : GetStormWindowData(state, ErrorsFound);
324 :
325 796 : if (!ErrorsFound && state.dataSurface->TotStormWin > 0) CreateStormWindowConstructions(state);
326 :
327 796 : SetFlagForWindowConstructionWithShadeOrBlindLayer(state);
328 :
329 796 : state.dataSurfaceGeometry->CosZoneRelNorth.deallocate();
330 796 : state.dataSurfaceGeometry->SinZoneRelNorth.deallocate();
331 :
332 796 : state.dataHeatBal->CalcWindowRevealReflection = false; // Set to True in ProcessSurfaceVertices if beam solar reflection from window reveals
333 : // is requested for one or more exterior windows.
334 796 : state.dataSurface->BuildingShadingCount = 0;
335 796 : state.dataSurface->FixedShadingCount = 0;
336 796 : state.dataSurface->AttachedShadingCount = 0;
337 796 : state.dataSurface->ShadingSurfaceFirst = 0;
338 796 : state.dataSurface->ShadingSurfaceLast = -1;
339 :
340 : // Reserve space to avoid excess allocations
341 796 : state.dataSurface->AllExtSolAndShadingSurfaceList.reserve(state.dataSurface->TotSurfaces);
342 :
343 46840 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) { // Loop through all surfaces...
344 46044 : auto &thisSurface = state.dataSurface->Surface(SurfNum);
345 :
346 46044 : state.dataSurface->SurfAirSkyRadSplit(SurfNum) = std::sqrt(0.5 * (1.0 + thisSurface.CosTilt));
347 :
348 : // Set flag that determines whether a surface is a shadowing surface
349 46044 : thisSurface.IsShadowing = false;
350 46044 : if (thisSurface.Class == SurfaceClass::Shading || thisSurface.Class == SurfaceClass::Detached_F ||
351 44450 : thisSurface.Class == SurfaceClass::Detached_B) {
352 1636 : thisSurface.IsShadowing = true;
353 1636 : if (state.dataSurface->ShadingSurfaceFirst == 0) state.dataSurface->ShadingSurfaceFirst = SurfNum;
354 1636 : state.dataSurface->ShadingSurfaceLast = SurfNum;
355 : }
356 46044 : if ((thisSurface.HeatTransSurf && thisSurface.ExtSolar) || thisSurface.IsShadowing) {
357 : // Some attached shading surfaces may be true for both
358 19332 : state.dataSurface->AllExtSolAndShadingSurfaceList.push_back(SurfNum);
359 : }
360 46044 : if (thisSurface.Class == SurfaceClass::Shading) ++state.dataSurface->AttachedShadingCount;
361 46044 : if (thisSurface.Class == SurfaceClass::Detached_F) ++state.dataSurface->FixedShadingCount;
362 46044 : if (thisSurface.Class == SurfaceClass::Detached_B) ++state.dataSurface->BuildingShadingCount;
363 :
364 46044 : if (thisSurface.Class != SurfaceClass::IntMass) ProcessSurfaceVertices(state, SurfNum, ErrorsFound);
365 : }
366 :
367 5852 : for (auto &e : state.dataHeatBal->Zone) {
368 5056 : e.ExtWindowArea = 0.0;
369 5056 : e.HasWindow = false;
370 5056 : e.ExtGrossWallArea = 0.0;
371 5056 : e.ExtNetWallArea = 0.0;
372 5056 : e.TotalSurfArea = 0.0;
373 796 : }
374 :
375 5877 : for (auto &s : state.dataHeatBal->space) {
376 5081 : s.extWindowArea = 0.0;
377 5081 : s.totalSurfArea = 0.0;
378 796 : }
379 796 : bool DetailedWWR = (state.dataInputProcessing->inputProcessor->getNumSectionsFound("DETAILEDWWR_DEBUG") > 0);
380 796 : if (DetailedWWR) {
381 0 : print(state.files.debug, "{}", "=======User Entered Classification =================");
382 0 : print(state.files.debug, "{}", "Surface,Class,Area,Tilt");
383 : }
384 :
385 46840 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) { // Loop through all surfaces to find windows...
386 46044 : auto &thisSurface = state.dataSurface->Surface(SurfNum);
387 :
388 46044 : if (!thisSurface.HeatTransSurf && !thisSurface.IsAirBoundarySurf) continue; // Skip shadowing (sub)surfaces
389 44408 : auto &thisZone = state.dataHeatBal->Zone(thisSurface.Zone);
390 44408 : auto &thisSpace = state.dataHeatBal->space(thisSurface.spaceNum);
391 :
392 44408 : thisZone.TotalSurfArea += thisSurface.Area;
393 44408 : thisSpace.totalSurfArea += thisSurface.Area;
394 44408 : if (thisSurface.Class == SurfaceClass::Roof) {
395 5801 : thisZone.geometricCeilingArea += thisSurface.GrossArea;
396 38607 : } else if (thisSurface.Class == SurfaceClass::Floor) {
397 6890 : thisZone.geometricFloorArea += thisSurface.GrossArea;
398 : }
399 44408 : if (state.dataConstruction->Construct(thisSurface.Construction).TypeIsWindow) {
400 6219 : thisZone.TotalSurfArea += state.dataSurface->SurfWinFrameArea(SurfNum);
401 6219 : thisZone.HasWindow = true;
402 6219 : thisSpace.totalSurfArea += state.dataSurface->SurfWinFrameArea(SurfNum);
403 6219 : if (((thisSurface.ExtBoundCond == ExternalEnvironment) || (thisSurface.ExtBoundCond == OtherSideCondModeledExt)) &&
404 6205 : (thisSurface.Class != SurfaceClass::TDD_Dome)) {
405 6203 : thisZone.ExtWindowArea += thisSurface.GrossArea;
406 6203 : thisSpace.extWindowArea += thisSurface.GrossArea;
407 6203 : thisZone.ExtWindowArea_Multiplied =
408 6203 : thisZone.ExtWindowArea + thisSurface.GrossArea * thisSurface.Multiplier * thisZone.Multiplier * thisZone.ListMultiplier;
409 6203 : if (DetailedWWR) {
410 0 : print(state.files.debug,
411 : "{},Window,{:.2R},{:.1R}\n",
412 0 : thisSurface.Name,
413 0 : thisSurface.GrossArea * thisSurface.Multiplier * thisZone.Multiplier * thisZone.ListMultiplier,
414 0 : thisSurface.Tilt);
415 : }
416 : }
417 : } else {
418 38189 : if (thisSurface.ExtBoundCond == ExternalEnvironment || thisSurface.ExtBoundCond == OtherSideCondModeledExt) {
419 11649 : thisZone.ExteriorTotalSurfArea += thisSurface.GrossArea;
420 11649 : thisSpace.ExteriorTotalSurfArea += thisSurface.GrossArea;
421 11649 : if (thisSurface.Class == SurfaceClass::Wall) {
422 8906 : thisZone.ExtNetWallArea += thisSurface.Area;
423 8906 : thisZone.ExtGrossWallArea += thisSurface.GrossArea;
424 8906 : thisSpace.ExtGrossWallArea += thisSurface.GrossArea;
425 8906 : thisZone.ExtGrossWallArea_Multiplied += thisSurface.GrossArea * thisZone.Multiplier * thisZone.ListMultiplier;
426 8906 : if (DetailedWWR) {
427 0 : print(state.files.debug,
428 : "{},Wall,{:.2R},{:.1R}\n",
429 0 : thisSurface.Name,
430 0 : thisSurface.GrossArea * thisZone.Multiplier * thisZone.ListMultiplier,
431 0 : thisSurface.Tilt);
432 : }
433 : }
434 26540 : } else if (thisSurface.ExtBoundCond == Ground || thisSurface.ExtBoundCond == GroundFCfactorMethod ||
435 24155 : thisSurface.ExtBoundCond == KivaFoundation) {
436 2423 : thisZone.ExteriorTotalGroundSurfArea += thisSurface.GrossArea;
437 2423 : if (thisSurface.Class == SurfaceClass::Wall) {
438 211 : thisZone.ExtGrossGroundWallArea += thisSurface.GrossArea;
439 211 : thisZone.ExtGrossGroundWallArea_Multiplied += thisSurface.GrossArea * thisZone.Multiplier * thisZone.ListMultiplier;
440 211 : if (DetailedWWR) {
441 0 : print(state.files.debug,
442 : "{},Wall-GroundContact,{:.2R},{:.1R}\n",
443 0 : thisSurface.Name,
444 0 : thisSurface.GrossArea * thisZone.Multiplier * thisZone.ListMultiplier,
445 0 : thisSurface.Tilt);
446 : }
447 : }
448 : }
449 : }
450 :
451 : } // ...end of surfaces windows DO loop
452 :
453 796 : if (DetailedWWR) {
454 0 : print(state.files.debug, "{}\n", "========================");
455 0 : print(state.files.debug, "{}\n", "Zone,ExtWallArea,ExtWindowArea");
456 : }
457 :
458 5852 : for (auto &thisZone : state.dataHeatBal->Zone) {
459 5056 : int CeilCount = 0;
460 5056 : int FloorCount = 0;
461 5056 : int WallCount = 0;
462 5056 : Real64 AverageHeight = 0.0; // Used to keep track of average height of a surface/zone
463 5056 : Real64 ZMax = -99999.0; // Maximum Z of a surface (detailed outside coefficient calculation)
464 5056 : Real64 ZMin = 99999.0; // Minimum Z of a surface (detailed outside coefficient calculation)
465 5056 : Real64 ZCeilAvg = 0.0;
466 5056 : Real64 ZFlrAvg = 0.0;
467 5056 : if (DetailedWWR) {
468 0 : print(state.files.debug, "{},{:.2R},{:.2R}\n", thisZone.Name, thisZone.ExtGrossWallArea, thisZone.ExtWindowArea);
469 : }
470 10124 : for (int spaceNum : thisZone.spaceIndexes) {
471 5068 : auto &thisSpace = state.dataHeatBal->space(spaceNum);
472 : // Use AllSurfaceFirst which includes air boundaries
473 49476 : for (int SurfNum = thisSpace.AllSurfaceFirst; SurfNum <= thisSpace.AllSurfaceLast; ++SurfNum) {
474 44408 : auto &thisSurface = state.dataSurface->Surface(SurfNum);
475 :
476 44408 : if (thisSurface.Class == SurfaceClass::Roof) {
477 : // Use Average Z for surface, more important for roofs than floors...
478 5801 : ++CeilCount;
479 5801 : Real64 Z1 = minval(thisSurface.Vertex, &Vector::z);
480 5801 : Real64 Z2 = maxval(thisSurface.Vertex, &Vector::z);
481 : // ZCeilAvg=ZCeilAvg+(Z1+Z2)/2.d0
482 5801 : ZCeilAvg += ((Z1 + Z2) / 2.0) * (thisSurface.GrossArea / thisZone.geometricCeilingArea);
483 : }
484 44408 : if (thisSurface.Class == SurfaceClass::Floor) {
485 : // Use Average Z for surface, more important for roofs than floors...
486 6890 : ++FloorCount;
487 6890 : Real64 Z1 = minval(thisSurface.Vertex, &Vector::z);
488 6890 : Real64 Z2 = maxval(thisSurface.Vertex, &Vector::z);
489 : // ZFlrAvg=ZFlrAvg+(Z1+Z2)/2.d0
490 6890 : ZFlrAvg += ((Z1 + Z2) / 2.0) * (thisSurface.GrossArea / thisZone.geometricFloorArea);
491 : }
492 44408 : if (thisSurface.Class == SurfaceClass::Wall) {
493 : // Use Wall calculation in case no roof & floor in zone
494 22621 : ++WallCount;
495 22621 : if (WallCount == 1) {
496 5034 : ZMax = thisSurface.Vertex(1).z;
497 5034 : ZMin = ZMax;
498 : }
499 22621 : ZMax = max(ZMax, maxval(thisSurface.Vertex, &Vector::z));
500 22621 : ZMin = min(ZMin, minval(thisSurface.Vertex, &Vector::z));
501 : }
502 : }
503 5056 : }
504 5056 : if (CeilCount > 0 && FloorCount > 0) {
505 5053 : AverageHeight = ZCeilAvg - ZFlrAvg;
506 : } else {
507 3 : AverageHeight = (ZMax - ZMin);
508 : }
509 5056 : if (AverageHeight <= 0.0) {
510 0 : AverageHeight = (ZMax - ZMin);
511 : }
512 :
513 5056 : if (thisZone.CeilingHeight > 0.0) {
514 1810 : thisZone.ceilingHeightEntered = true;
515 1810 : if (AverageHeight > 0.0) {
516 1810 : if (std::abs(AverageHeight - thisZone.CeilingHeight) / thisZone.CeilingHeight > 0.05) {
517 8 : if (state.dataSurfaceGeometry->ErrCount == 1 && !state.dataGlobal->DisplayExtraWarnings) {
518 0 : ShowWarningError(
519 : state,
520 0 : format("{}Entered Ceiling Height for some zone(s) significantly different from calculated Ceiling Height",
521 : RoutineName));
522 0 : ShowContinueError(state,
523 : "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on each max iteration exceeded.");
524 : }
525 8 : if (state.dataGlobal->DisplayExtraWarnings) {
526 0 : ShowWarningError(state,
527 0 : format("{}Entered Ceiling Height for Zone=\"{}\" significantly different from calculated Ceiling Height",
528 : RoutineName,
529 0 : thisZone.Name));
530 : static constexpr std::string_view ValFmt("{:.2F}");
531 0 : std::string String1 = format(ValFmt, thisZone.CeilingHeight);
532 0 : std::string String2 = format(ValFmt, AverageHeight);
533 0 : ShowContinueError(
534 : state,
535 0 : format("{}Entered Ceiling Height={}, Calculated Ceiling Height={}, entered height will be used in calculations.",
536 : RoutineName,
537 : String1,
538 : String2));
539 0 : }
540 : }
541 : }
542 : }
543 5056 : if ((thisZone.CeilingHeight <= 0.0) && (AverageHeight > 0.0)) thisZone.CeilingHeight = AverageHeight;
544 : // Need to add check here - don't touch if already user-specified
545 796 : }
546 :
547 796 : CalculateZoneVolume(state); // Calculate Zone Volumes
548 :
549 : // Calculate zone centroid (and min/max x,y,z for zone)
550 : // Use AllSurfaceFirst which includes air boundaries
551 5852 : for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
552 5056 : auto &thisZone = state.dataHeatBal->Zone(ZoneNum);
553 5056 : bool nonInternalMassSurfacesPresent = false;
554 5056 : bool internalMassSurfacesPresent = false;
555 5056 : Real64 TotSurfArea = 0.0;
556 5056 : thisZone.Centroid = Vector(0.0, 0.0, 0.0);
557 5056 : if ((thisZone.AllSurfaceFirst > 0) && (state.dataSurface->Surface(thisZone.AllSurfaceFirst).Sides > 0)) {
558 5056 : thisZone.MinimumX = state.dataSurface->Surface(thisZone.AllSurfaceFirst).Vertex(1).x;
559 5056 : thisZone.MaximumX = state.dataSurface->Surface(thisZone.AllSurfaceFirst).Vertex(1).x;
560 5056 : thisZone.MinimumY = state.dataSurface->Surface(thisZone.AllSurfaceFirst).Vertex(1).y;
561 5056 : thisZone.MaximumY = state.dataSurface->Surface(thisZone.AllSurfaceFirst).Vertex(1).y;
562 5056 : thisZone.MinimumZ = state.dataSurface->Surface(thisZone.AllSurfaceFirst).Vertex(1).z;
563 5056 : thisZone.MaximumZ = state.dataSurface->Surface(thisZone.AllSurfaceFirst).Vertex(1).z;
564 : }
565 10124 : for (int spaceNum : thisZone.spaceIndexes) {
566 5068 : auto &thisSpace = state.dataHeatBal->space(spaceNum);
567 :
568 49476 : for (int SurfNum = thisSpace.AllSurfaceFirst; SurfNum <= thisSpace.AllSurfaceLast; ++SurfNum) {
569 44408 : auto &thisSurface = state.dataSurface->Surface(SurfNum);
570 44408 : if (thisSurface.Class == SurfaceClass::IntMass) {
571 2398 : internalMassSurfacesPresent = true;
572 2398 : continue;
573 : }
574 42010 : if (!thisSurface.IsAirBoundarySurf) nonInternalMassSurfacesPresent = true;
575 42010 : if (thisSurface.Class == SurfaceClass::Wall || (thisSurface.Class == SurfaceClass::Roof) ||
576 13588 : (thisSurface.Class == SurfaceClass::Floor)) {
577 :
578 35312 : thisZone.Centroid.x += thisSurface.Centroid.x * thisSurface.GrossArea;
579 35312 : thisZone.Centroid.y += thisSurface.Centroid.y * thisSurface.GrossArea;
580 35312 : thisZone.Centroid.z += thisSurface.Centroid.z * thisSurface.GrossArea;
581 35312 : TotSurfArea += thisSurface.GrossArea;
582 : }
583 42010 : thisZone.MinimumX = min(thisZone.MinimumX, minval(thisSurface.Vertex, &Vector::x));
584 42010 : thisZone.MaximumX = max(thisZone.MaximumX, maxval(thisSurface.Vertex, &Vector::x));
585 42010 : thisZone.MinimumY = min(thisZone.MinimumY, minval(thisSurface.Vertex, &Vector::y));
586 42010 : thisZone.MaximumY = max(thisZone.MaximumY, maxval(thisSurface.Vertex, &Vector::y));
587 42010 : thisZone.MinimumZ = min(thisZone.MinimumZ, minval(thisSurface.Vertex, &Vector::z));
588 42010 : thisZone.MaximumZ = max(thisZone.MaximumZ, maxval(thisSurface.Vertex, &Vector::z));
589 : }
590 5056 : }
591 5056 : if (TotSurfArea > 0.0) {
592 5056 : thisZone.Centroid.x /= TotSurfArea;
593 5056 : thisZone.Centroid.y /= TotSurfArea;
594 5056 : thisZone.Centroid.z /= TotSurfArea;
595 : }
596 5056 : if (internalMassSurfacesPresent && !nonInternalMassSurfacesPresent) {
597 0 : ShowSevereError(
598 0 : state, format("{}Zone=\"{}\" has only internal mass surfaces. Need at least one other surface.", RoutineName, thisZone.Name));
599 0 : ErrorsFound = true;
600 : }
601 : }
602 :
603 796 : state.dataSurface->SurfAdjacentZone.dimension(state.dataSurface->TotSurfaces, 0);
604 : // note -- adiabatic surfaces will show same zone as surface
605 46840 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
606 46044 : if (state.dataSurface->Surface(SurfNum).ExtBoundCond <= 0) continue;
607 24098 : state.dataSurface->SurfAdjacentZone(SurfNum) = state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).ExtBoundCond).Zone;
608 : }
609 :
610 5852 : for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
611 1275666 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
612 1270610 : auto &thisSurface = state.dataSurface->Surface(SurfNum);
613 1270610 : if (!thisSurface.HeatTransSurf && thisSurface.ZoneName == state.dataHeatBal->Zone(ZoneNum).Name)
614 1502 : ++state.dataHeatBal->Zone(ZoneNum).NumShadingSurfaces;
615 :
616 1270610 : if (thisSurface.Zone != ZoneNum) continue;
617 :
618 44408 : if (thisSurface.HeatTransSurf &&
619 44390 : (thisSurface.Class == SurfaceClass::Wall || thisSurface.Class == SurfaceClass::Roof || thisSurface.Class == SurfaceClass::Floor))
620 35294 : ++state.dataHeatBal->Zone(ZoneNum).NumSurfaces;
621 :
622 44408 : if (thisSurface.HeatTransSurf && (thisSurface.Class == SurfaceClass::Window || thisSurface.Class == SurfaceClass::GlassDoor ||
623 38173 : thisSurface.Class == SurfaceClass::Door || thisSurface.Class == SurfaceClass::TDD_Dome ||
624 37692 : thisSurface.Class == SurfaceClass::TDD_Diffuser))
625 6698 : ++state.dataHeatBal->Zone(ZoneNum).NumSubSurfaces;
626 :
627 : } // surfaces
628 : } // zones
629 :
630 46840 : for (int const SurfNum : state.dataSurface->AllSurfaceListReportOrder) {
631 46044 : auto &thisSurface = state.dataSurface->Surface(SurfNum);
632 46044 : bool isWithConvCoefValid = false;
633 46044 : Real64 NominalUwithConvCoeffs = 0.0;
634 46044 : std::string cNominalUwithConvCoeffs;
635 46044 : std::string cNominalU;
636 46044 : if (thisSurface.Construction > 0 && thisSurface.Construction <= state.dataHeatBal->TotConstructs) {
637 44408 : NominalUwithConvCoeffs = ComputeNominalUwithConvCoeffs(state, SurfNum, isWithConvCoefValid);
638 44408 : if (isWithConvCoefValid) {
639 44390 : cNominalUwithConvCoeffs = format("{:.3R}", NominalUwithConvCoeffs);
640 : } else {
641 18 : cNominalUwithConvCoeffs = "[invalid]";
642 : }
643 44408 : if ((thisSurface.Class == SurfaceClass::Window) || (thisSurface.Class == SurfaceClass::TDD_Dome)) {
644 : // SurfaceClass::Window also covers glass doors and TDD:Diffusers
645 6219 : cNominalU = "N/A";
646 : } else {
647 38189 : cNominalU = format("{:.3R}", state.dataHeatBal->NominalU(thisSurface.Construction));
648 : }
649 : } else {
650 1636 : cNominalUwithConvCoeffs = "**";
651 1636 : cNominalU = "**";
652 : }
653 :
654 : // populate the predefined report related to u-values with films
655 : // only exterior surfaces including underground
656 46044 : DataSurfaces::SurfaceClass const SurfaceClass(thisSurface.Class);
657 46044 : if ((thisSurface.ExtBoundCond == ExternalEnvironment) || (thisSurface.ExtBoundCond == Ground) ||
658 24408 : (thisSurface.ExtBoundCond == KivaFoundation) || (thisSurface.ExtBoundCond == GroundFCfactorMethod)) {
659 21858 : if ((SurfaceClass == SurfaceClass::Wall) || (SurfaceClass == SurfaceClass::Floor) || (SurfaceClass == SurfaceClass::Roof)) {
660 27236 : OutputReportPredefined::PreDefTableEntry(
661 40854 : state, state.dataOutRptPredefined->pdchOpUfactFilm, thisSurface.Name, NominalUwithConvCoeffs, 3);
662 8240 : } else if (SurfaceClass == SurfaceClass::Door) {
663 798 : OutputReportPredefined::PreDefTableEntry(
664 1197 : state, state.dataOutRptPredefined->pdchDrUfactFilm, thisSurface.Name, NominalUwithConvCoeffs, 3);
665 : }
666 : } else {
667 24186 : if ((SurfaceClass == SurfaceClass::Wall) || (SurfaceClass == SurfaceClass::Floor) || (SurfaceClass == SurfaceClass::Roof)) {
668 43388 : OutputReportPredefined::PreDefTableEntry(
669 65082 : state, state.dataOutRptPredefined->pdchIntOpUfactFilm, thisSurface.Name, NominalUwithConvCoeffs, 3);
670 2492 : } else if (SurfaceClass == SurfaceClass::Door) {
671 160 : OutputReportPredefined::PreDefTableEntry(
672 240 : state, state.dataOutRptPredefined->pdchIntDrUfactFilm, thisSurface.Name, NominalUwithConvCoeffs, 3);
673 : }
674 : }
675 46840 : } // surfaces
676 :
677 : // Write number of shadings to initialization output file
678 796 : print(state.files.eio,
679 : "! <Shading Summary>, Number of Fixed Detached Shades, Number of Building Detached Shades, Number of Attached Shades\n");
680 :
681 796 : print(state.files.eio,
682 : " Shading Summary,{},{},{}\n",
683 796 : state.dataSurface->FixedShadingCount,
684 796 : state.dataSurface->BuildingShadingCount,
685 796 : state.dataSurface->AttachedShadingCount);
686 :
687 : // Write number of zones header to initialization output file
688 796 : print(state.files.eio, "! <Zone Summary>, Number of Zones, Number of Zone Surfaces, Number of SubSurfaces\n");
689 :
690 796 : print(state.files.eio,
691 : " Zone Summary,{},{},{}\n",
692 796 : state.dataGlobal->NumOfZones,
693 796 : state.dataSurface->TotSurfaces - state.dataSurface->FixedShadingCount - state.dataSurface->BuildingShadingCount -
694 796 : state.dataSurface->AttachedShadingCount,
695 796 : sum(state.dataHeatBal->Zone, &ZoneData::NumSubSurfaces));
696 :
697 : // Write Zone Information header to the initialization output file
698 : static constexpr std::string_view Format_721(
699 : "! <Zone Information>,Zone Name,North Axis {deg},Origin X-Coordinate {m},Origin Y-Coordinate {m},Origin Z-Coordinate "
700 : "{m},Centroid X-Coordinate {m},Centroid Y-Coordinate {m},Centroid Z-Coordinate {m},Type,Zone Multiplier,Zone List "
701 : "Multiplier,Minimum X {m},Maximum X {m},Minimum Y {m},Maximum Y {m},Minimum Z {m},Maximum Z {m},Ceiling Height {m},Volume "
702 : "{m3},Zone Inside Convection Algorithm {Simple-Detailed-CeilingDiffuser-TrombeWall},Zone Outside Convection Algorithm "
703 : "{Simple-Detailed-Tarp-MoWitt-DOE-2-BLAST}, Floor Area {m2},Exterior Gross Wall Area {m2},Exterior Net Wall Area {m2},Exterior "
704 : "Window "
705 : "Area {m2}, Number of Surfaces, Number of SubSurfaces, Number of Shading SubSurfaces, Part of Total Building Area");
706 796 : print(state.files.eio, "{}\n", Format_721);
707 :
708 5852 : for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
709 : // Write Zone Information to the initialization output file
710 5056 : std::string String1;
711 5056 : std::string String2;
712 5056 : std::string String3;
713 :
714 5056 : switch (state.dataHeatBal->Zone(ZoneNum).IntConvAlgo) {
715 1094 : case Convect::HcInt::ASHRAESimple: {
716 1094 : String1 = "Simple";
717 1094 : } break;
718 3936 : case Convect::HcInt::ASHRAETARP: {
719 3936 : String1 = "TARP";
720 3936 : } break;
721 10 : case Convect::HcInt::CeilingDiffuser: {
722 10 : String1 = "CeilingDiffuser";
723 10 : } break;
724 1 : case Convect::HcInt::TrombeWall: {
725 1 : String1 = "TrombeWall";
726 1 : } break;
727 14 : case Convect::HcInt::AdaptiveConvectionAlgorithm: {
728 14 : String1 = "AdaptiveConvectionAlgorithm";
729 14 : } break;
730 1 : case Convect::HcInt::ASTMC1340: {
731 1 : String1 = "ASTMC1340";
732 1 : } break;
733 0 : default:
734 0 : break;
735 : }
736 :
737 5056 : switch (state.dataHeatBal->Zone(ZoneNum).ExtConvAlgo) {
738 1102 : case Convect::HcExt::ASHRAESimple: {
739 1102 : String2 = "Simple";
740 1102 : } break;
741 492 : case Convect::HcExt::ASHRAETARP: {
742 492 : String2 = "TARP";
743 492 : } break;
744 0 : case Convect::HcExt::TarpHcOutside: {
745 0 : String2 = "TARP";
746 0 : } break;
747 0 : case Convect::HcExt::MoWiTTHcOutside: {
748 0 : String2 = "MoWitt";
749 0 : } break;
750 3446 : case Convect::HcExt::DOE2HcOutside: {
751 3446 : String2 = "DOE-2";
752 3446 : } break;
753 16 : case Convect::HcExt::AdaptiveConvectionAlgorithm: {
754 16 : String2 = "AdaptiveConvectionAlgorithm";
755 16 : } break;
756 0 : default:
757 0 : break;
758 : }
759 :
760 5056 : String3 = (state.dataHeatBal->Zone(ZoneNum).isPartOfTotalArea) ? "Yes" : "No";
761 :
762 : static constexpr std::string_view Format_720(
763 : " Zone Information, "
764 : "{},{:.1R},{:.2R},{:.2R},{:.2R},{:.2R},{:.2R},{:.2R},{},{},{},{:.2R},{:.2R},{:.2R},{:.2R},{:.2R},{:.2R},"
765 : "{:.2R},{:.2R},{},{},{:.2R},{:.2R},{:.2R},{:.2R},{},{},{},{}\n");
766 :
767 5056 : print(state.files.eio,
768 : Format_720,
769 5056 : state.dataHeatBal->Zone(ZoneNum).Name,
770 5056 : state.dataHeatBal->Zone(ZoneNum).RelNorth,
771 5056 : state.dataHeatBal->Zone(ZoneNum).OriginX,
772 5056 : state.dataHeatBal->Zone(ZoneNum).OriginY,
773 5056 : state.dataHeatBal->Zone(ZoneNum).OriginZ,
774 5056 : state.dataHeatBal->Zone(ZoneNum).Centroid.x,
775 5056 : state.dataHeatBal->Zone(ZoneNum).Centroid.y,
776 5056 : state.dataHeatBal->Zone(ZoneNum).Centroid.z,
777 5056 : state.dataHeatBal->Zone(ZoneNum).OfType,
778 5056 : state.dataHeatBal->Zone(ZoneNum).Multiplier,
779 5056 : state.dataHeatBal->Zone(ZoneNum).ListMultiplier,
780 5056 : state.dataHeatBal->Zone(ZoneNum).MinimumX,
781 5056 : state.dataHeatBal->Zone(ZoneNum).MaximumX,
782 5056 : state.dataHeatBal->Zone(ZoneNum).MinimumY,
783 5056 : state.dataHeatBal->Zone(ZoneNum).MaximumY,
784 5056 : state.dataHeatBal->Zone(ZoneNum).MinimumZ,
785 5056 : state.dataHeatBal->Zone(ZoneNum).MaximumZ,
786 5056 : state.dataHeatBal->Zone(ZoneNum).CeilingHeight,
787 5056 : state.dataHeatBal->Zone(ZoneNum).Volume,
788 : String1,
789 : String2,
790 5056 : state.dataHeatBal->Zone(ZoneNum).FloorArea,
791 5056 : state.dataHeatBal->Zone(ZoneNum).ExtGrossWallArea,
792 5056 : state.dataHeatBal->Zone(ZoneNum).ExtNetWallArea,
793 5056 : state.dataHeatBal->Zone(ZoneNum).ExtWindowArea,
794 5056 : state.dataHeatBal->Zone(ZoneNum).NumSurfaces,
795 5056 : state.dataHeatBal->Zone(ZoneNum).NumSubSurfaces,
796 5056 : state.dataHeatBal->Zone(ZoneNum).NumShadingSurfaces,
797 : String3);
798 :
799 5056 : } // ZoneNum
800 :
801 : // Set up solar distribution enclosures allowing for any air boundaries
802 796 : SetupEnclosuresAndAirBoundaries(state, state.dataViewFactor->EnclSolInfo, SurfaceGeometry::enclosureType::SolarEnclosures, ErrorsFound);
803 :
804 : // Do the Stratosphere check
805 796 : SetZoneOutBulbTempAt(state);
806 796 : CheckZoneOutBulbTempAt(state);
807 : }
808 :
809 796 : void AllocateSurfaceArrays(EnergyPlusData &state)
810 : {
811 :
812 : // SUBROUTINE INFORMATION:
813 : // AUTHOR Rick Strand
814 : // DATE WRITTEN February 1998
815 : // MODIFIED na
816 : // RE-ENGINEERED na
817 :
818 : // PURPOSE OF THIS SUBROUTINE:
819 : // This subroutine allocates all of the arrays at the module level which
820 : // require allocation.
821 :
822 : // METHODOLOGY EMPLOYED:
823 : // Allocation is dependent on the user input file.
824 :
825 : // REFERENCES:
826 : // na
827 :
828 : // USE STATEMENTS:
829 : // na
830 :
831 : // SUBROUTINE PARAMETER DEFINITIONS:
832 : // na
833 :
834 : // INTERFACE BLOCK SPECIFICATIONS
835 : // na
836 :
837 : // DERIVED TYPE DEFINITIONS
838 : // na
839 :
840 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
841 : // na
842 796 : state.dataSurface->ShadeV.allocate(state.dataSurface->TotSurfaces);
843 46840 : for (auto &e : state.dataSurface->ShadeV)
844 46840 : e.NVert = 0;
845 : // Individual components (XV,YV,ZV) allocated in routine ProcessSurfaceVertices
846 796 : state.dataSurface->X0.dimension(state.dataSurface->TotSurfaces, 0.0);
847 796 : state.dataSurface->Y0.dimension(state.dataSurface->TotSurfaces, 0.0);
848 796 : state.dataSurface->Z0.dimension(state.dataSurface->TotSurfaces, 0.0);
849 :
850 : // Surface EMS arrays
851 796 : state.dataSurface->SurfEMSConstructionOverrideON.allocate(state.dataSurface->TotSurfaces);
852 796 : state.dataSurface->SurfEMSConstructionOverrideValue.allocate(state.dataSurface->TotSurfaces);
853 796 : state.dataSurface->SurfEMSOverrideIntConvCoef.allocate(state.dataSurface->TotSurfaces);
854 796 : state.dataSurface->SurfEMSValueForIntConvCoef.allocate(state.dataSurface->TotSurfaces);
855 796 : state.dataSurface->SurfEMSOverrideExtConvCoef.allocate(state.dataSurface->TotSurfaces);
856 796 : state.dataSurface->SurfEMSValueForExtConvCoef.allocate(state.dataSurface->TotSurfaces);
857 796 : state.dataSurface->SurfOutDryBulbTempEMSOverrideOn.allocate(state.dataSurface->TotSurfaces);
858 796 : state.dataSurface->SurfOutDryBulbTempEMSOverrideValue.allocate(state.dataSurface->TotSurfaces);
859 796 : state.dataSurface->SurfOutWetBulbTempEMSOverrideOn.allocate(state.dataSurface->TotSurfaces);
860 796 : state.dataSurface->SurfOutWetBulbTempEMSOverrideValue.allocate(state.dataSurface->TotSurfaces);
861 796 : state.dataSurface->SurfWindSpeedEMSOverrideOn.allocate(state.dataSurface->TotSurfaces);
862 796 : state.dataSurface->SurfWindSpeedEMSOverrideValue.allocate(state.dataSurface->TotSurfaces);
863 796 : state.dataSurface->SurfViewFactorGroundEMSOverrideOn.allocate(state.dataSurface->TotSurfaces);
864 796 : state.dataSurface->SurfViewFactorGroundEMSOverrideValue.allocate(state.dataSurface->TotSurfaces);
865 796 : state.dataSurface->SurfWindDirEMSOverrideOn.allocate(state.dataSurface->TotSurfaces);
866 796 : state.dataSurface->SurfWindDirEMSOverrideValue.allocate(state.dataSurface->TotSurfaces);
867 46840 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
868 46044 : state.dataSurface->SurfEMSConstructionOverrideON(SurfNum) = false;
869 46044 : state.dataSurface->SurfEMSConstructionOverrideValue(SurfNum) = 0.0;
870 46044 : state.dataSurface->SurfEMSOverrideIntConvCoef(SurfNum) = false;
871 46044 : state.dataSurface->SurfEMSValueForIntConvCoef(SurfNum) = 0.0;
872 46044 : state.dataSurface->SurfEMSOverrideExtConvCoef(SurfNum) = false;
873 46044 : state.dataSurface->SurfEMSValueForExtConvCoef(SurfNum) = 0.0;
874 46044 : state.dataSurface->SurfOutDryBulbTempEMSOverrideOn(SurfNum) = false;
875 46044 : state.dataSurface->SurfOutDryBulbTempEMSOverrideValue(SurfNum) = 0.0;
876 46044 : state.dataSurface->SurfOutWetBulbTempEMSOverrideOn(SurfNum) = false;
877 46044 : state.dataSurface->SurfOutWetBulbTempEMSOverrideValue(SurfNum) = 0.0;
878 46044 : state.dataSurface->SurfWindSpeedEMSOverrideOn(SurfNum) = false;
879 46044 : state.dataSurface->SurfWindSpeedEMSOverrideValue(SurfNum) = 0.0;
880 46044 : state.dataSurface->SurfViewFactorGroundEMSOverrideOn(SurfNum) = false;
881 46044 : state.dataSurface->SurfViewFactorGroundEMSOverrideValue(SurfNum) = 0.0;
882 46044 : state.dataSurface->SurfWindDirEMSOverrideOn(SurfNum) = false;
883 46044 : state.dataSurface->SurfWindDirEMSOverrideValue(SurfNum) = 0.0;
884 : }
885 : // Following are surface hb arrays
886 796 : state.dataSurface->SurfOutDryBulbTemp.allocate(state.dataSurface->TotSurfaces);
887 796 : state.dataSurface->SurfOutWetBulbTemp.allocate(state.dataSurface->TotSurfaces);
888 796 : state.dataSurface->SurfOutWindSpeed.allocate(state.dataSurface->TotSurfaces);
889 796 : state.dataSurface->SurfOutWindDir.allocate(state.dataSurface->TotSurfaces);
890 796 : state.dataSurface->SurfGenericContam.allocate(state.dataSurface->TotSurfaces);
891 796 : state.dataSurface->SurfPenumbraID.allocate(state.dataSurface->TotSurfaces);
892 796 : state.dataSurface->SurfAirSkyRadSplit.allocate(state.dataSurface->TotSurfaces);
893 46840 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
894 46044 : state.dataSurface->SurfOutDryBulbTemp(SurfNum) = 0.0;
895 46044 : state.dataSurface->SurfOutWetBulbTemp(SurfNum) = 0.0;
896 46044 : state.dataSurface->SurfOutWindSpeed(SurfNum) = 0.0;
897 46044 : state.dataSurface->SurfOutWindDir(SurfNum) = 0.0;
898 46044 : state.dataSurface->SurfGenericContam(SurfNum) = 0.0;
899 46044 : state.dataSurface->SurfPenumbraID(SurfNum) = -1;
900 46044 : state.dataSurface->SurfAirSkyRadSplit(SurfNum) = 0.0;
901 : }
902 : // Following are surface property arrays used in SurfaceGeometry
903 796 : state.dataSurface->SurfShadowRecSurfNum.allocate(state.dataSurface->TotSurfaces);
904 796 : state.dataSurface->SurfShadowDisabledZoneList.allocate(state.dataSurface->TotSurfaces);
905 796 : state.dataSurface->SurfShadowDiffuseSolRefl.allocate(state.dataSurface->TotSurfaces);
906 796 : state.dataSurface->SurfShadowDiffuseVisRefl.allocate(state.dataSurface->TotSurfaces);
907 796 : state.dataSurface->SurfShadowGlazingFrac.allocate(state.dataSurface->TotSurfaces);
908 796 : state.dataSurface->SurfShadowGlazingConstruct.allocate(state.dataSurface->TotSurfaces);
909 796 : state.dataSurface->SurfMaterialMovInsulExt.allocate(state.dataSurface->TotSurfaces);
910 796 : state.dataSurface->SurfMaterialMovInsulInt.allocate(state.dataSurface->TotSurfaces);
911 796 : state.dataSurface->SurfSchedMovInsulExt.allocate(state.dataSurface->TotSurfaces);
912 796 : state.dataSurface->SurfSchedMovInsulInt.allocate(state.dataSurface->TotSurfaces);
913 46840 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
914 46044 : state.dataSurface->SurfShadowRecSurfNum(SurfNum) = 0;
915 46044 : state.dataSurface->SurfShadowDiffuseSolRefl(SurfNum) = 0.0;
916 46044 : state.dataSurface->SurfShadowDiffuseVisRefl(SurfNum) = 0.0;
917 46044 : state.dataSurface->SurfShadowGlazingFrac(SurfNum) = 0.0;
918 46044 : state.dataSurface->SurfShadowGlazingConstruct(SurfNum) = 0;
919 46044 : state.dataSurface->SurfMaterialMovInsulExt(SurfNum) = 0;
920 46044 : state.dataSurface->SurfMaterialMovInsulInt(SurfNum) = 0;
921 46044 : state.dataSurface->SurfSchedMovInsulExt(SurfNum) = 0;
922 46044 : state.dataSurface->SurfSchedMovInsulInt(SurfNum) = 0;
923 : }
924 796 : state.dataSurface->SurfExtEcoRoof.allocate(state.dataSurface->TotSurfaces);
925 796 : state.dataSurface->SurfExtCavityPresent.allocate(state.dataSurface->TotSurfaces);
926 796 : state.dataSurface->SurfExtCavNum.allocate(state.dataSurface->TotSurfaces);
927 796 : state.dataSurface->SurfIsPV.allocate(state.dataSurface->TotSurfaces);
928 796 : state.dataSurface->SurfIsICS.allocate(state.dataSurface->TotSurfaces);
929 796 : state.dataSurface->SurfIsPool.allocate(state.dataSurface->TotSurfaces);
930 796 : state.dataSurface->SurfICSPtr.allocate(state.dataSurface->TotSurfaces);
931 796 : state.dataSurface->SurfIsRadSurfOrVentSlabOrPool.allocate(state.dataSurface->TotSurfaces);
932 796 : state.dataSurface->SurfDaylightingShelfInd.allocate(state.dataSurface->TotSurfaces);
933 46840 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
934 46044 : state.dataSurface->SurfExtEcoRoof(SurfNum) = false;
935 46044 : state.dataSurface->SurfExtCavityPresent(SurfNum) = false;
936 46044 : state.dataSurface->SurfExtCavNum(SurfNum) = 0;
937 46044 : state.dataSurface->SurfIsPV(SurfNum) = false;
938 46044 : state.dataSurface->SurfIsICS(SurfNum) = false;
939 46044 : state.dataSurface->SurfIsPool(SurfNum) = false;
940 46044 : state.dataSurface->SurfICSPtr(SurfNum) = 0;
941 46044 : state.dataSurface->SurfIsRadSurfOrVentSlabOrPool(SurfNum) = false;
942 46044 : state.dataSurface->SurfDaylightingShelfInd(SurfNum) = 0;
943 : }
944 796 : state.dataSurface->SurfLowTempErrCount.allocate(state.dataSurface->TotSurfaces);
945 796 : state.dataSurface->SurfHighTempErrCount.allocate(state.dataSurface->TotSurfaces);
946 796 : state.dataSurface->surfIntConv.allocate(state.dataSurface->TotSurfaces);
947 796 : state.dataSurface->SurfTAirRef.allocate(state.dataSurface->TotSurfaces);
948 796 : state.dataSurface->SurfTAirRefRpt.allocate(state.dataSurface->TotSurfaces);
949 796 : state.dataSurface->surfExtConv.allocate(state.dataSurface->TotSurfaces);
950 46840 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
951 46044 : state.dataSurface->SurfLowTempErrCount(SurfNum) = 0;
952 46044 : state.dataSurface->SurfHighTempErrCount(SurfNum) = 0;
953 46044 : state.dataSurface->surfIntConv(SurfNum) = SurfIntConv();
954 46044 : state.dataSurface->surfExtConv(SurfNum) = SurfExtConv();
955 46044 : state.dataSurface->SurfTAirRef(SurfNum) = DataSurfaces::RefAirTemp::Invalid;
956 46044 : state.dataSurface->SurfTAirRefRpt(SurfNum) = static_cast<int>(DataSurfaces::RefAirTemp::Invalid);
957 : }
958 796 : }
959 :
960 796 : void GetSurfaceData(EnergyPlusData &state, bool &ErrorsFound) // If errors found in input
961 : {
962 :
963 : // SUBROUTINE INFORMATION:
964 : // AUTHOR Richard Liesen
965 : // DATE WRITTEN November 1997
966 : // MODIFIED April 1999, Linda Lawrie
967 : // Dec. 2000, FW (add "one-wall zone" checks)
968 : // RE-ENGINEERED May 2000, Linda Lawrie (breakout surface type gets)
969 :
970 : // PURPOSE OF THIS SUBROUTINE:
971 : // The purpose of this subroutine is to read in the surface information
972 : // from the input data file and interpret and put in the derived type
973 :
974 : // METHODOLOGY EMPLOYED:
975 : // The order of surfaces does not matter and the surfaces are resorted into
976 : // the hierarchical order:
977 : // All Shading Surfaces
978 : // Airwalls for space x1
979 : // Base Surfaces for space x1
980 : // Opaque Subsurfaces for space x1
981 : // Window Subsurfaces for space x1
982 : // TDD Dome Surfaces for space x1
983 : // Airwalls for space x2
984 : // Base Surfaces for space x2
985 : // etc
986 : // Pointers are set in the spaces (AllSurfaceFirst/Last, HTSurfaceFirst/Last, OpaqOrIntMassSurfaceFirst/Last, WindowSurfaceFirst/Last,
987 : // OpaqOrWinSurfaceFirst/Last, TDDDomeFirst/Last)
988 :
989 : // REFERENCES:
990 : // This routine manages getting the input for the following Objects:
991 : // SurfaceGeometry
992 : // Surface:Shading:Detached
993 : // Surface:HeatTransfer
994 : // Surface:HeatTransfer:Sub
995 : // Surface:Shading:Attached
996 : // Surface:InternalMass
997 :
998 : // Vertex input:
999 : // N3 , \field Number of Surface Vertices -- Number of (X,Y,Z) groups in this surface
1000 : // \note currently limited 3 or 4, later?
1001 : // \min 3
1002 : // \max 4
1003 : // \memo vertices are given in SurfaceGeometry coordinates -- if relative, all surface coordinates
1004 : // \memo are "relative" to the Zone Origin. if WCS, then building and zone origins are used
1005 : // \memo for some internal calculations, but all coordinates are given in an "absolute" system.
1006 : // N4, \field Vertex 1 X-coordinate
1007 : // \units m
1008 : // \type real
1009 : // N5 , \field Vertex 1 Y-coordinate
1010 : // \units m
1011 : // \type real
1012 : // N6 , \field Vertex 1 Z-coordinate
1013 : // \units m
1014 : // \type real
1015 : // N7, \field Vertex 2 X-coordinate
1016 : // \units m
1017 : // \type real
1018 : // N8, \field Vertex 2 Y-coordinate
1019 : // \units m
1020 : // \type real
1021 : // N9, \field Vertex 2 Z-coordinate
1022 : // \units m
1023 : // \type real
1024 : // N10, \field Vertex 3 X-coordinate
1025 : // \units m
1026 : // \type real
1027 : // N11, \field Vertex 3 Y-coordinate
1028 : // \units m
1029 : // \type real
1030 : // N12, \field Vertex 3 Z-coordinate
1031 : // \units m
1032 : // \type real
1033 : // N13, \field Vertex 4 X-coordinate
1034 : // \units m
1035 : // \type real
1036 : // N14, \field Vertex 4 Y-coordinate
1037 : // \type real
1038 : // \units m
1039 : // N15; \field Vertex 4 Z-coordinate
1040 : // \units m
1041 : // \type real
1042 :
1043 : // The vertices are stored in the surface derived type.
1044 : // +(1)-------------------------(4)+
1045 : // | |
1046 : // | |
1047 : // | |
1048 : // +(2)-------------------------(3)+
1049 : // The above diagram shows the actual coordinate points of a typical wall
1050 : // (you're on the outside looking toward the wall) as stored into
1051 : // Surface%Vertex(1:<number-of-sides>)
1052 :
1053 : using namespace Vectors;
1054 : using ScheduleManager::GetScheduleMaxValue;
1055 : using ScheduleManager::GetScheduleMinValue;
1056 : using namespace DataErrorTracking;
1057 :
1058 : static constexpr std::string_view RoutineName("GetSurfaceData: ");
1059 :
1060 : int ConstrNum; // Construction number
1061 : int Found; // For matching interzone surfaces
1062 : int ConstrNumFound; // Construction number of matching interzone surface
1063 796 : bool NonMatch(false); // Error for non-matching interzone surfaces
1064 : int MovedSurfs; // Number of Moved Surfaces (when sorting into hierarchical structure)
1065 796 : bool SurfError(false); // General Surface Error, causes fatal error at end of routine
1066 : int TotLay; // Total layers in a construction
1067 : int TotLayFound; // Total layers in the construction of a matching interzone surface
1068 : int TotDetachedFixed; // Total Shading:Site:Detailed entries
1069 : int TotDetachedBldg; // Total Shading:Building:Detailed entries
1070 : int TotRectDetachedFixed; // Total Shading:Site entries
1071 : int TotRectDetachedBldg; // Total Shading:Building entries
1072 : int TotHTSurfs; // Number of BuildingSurface:Detailed items to obtain
1073 : int TotDetailedWalls; // Number of Wall:Detailed items to obtain
1074 : int TotDetailedRoofs; // Number of RoofCeiling:Detailed items to obtain
1075 : int TotDetailedFloors; // Number of Floor:Detailed items to obtain
1076 : int TotHTSubs; // Number of FenestrationSurface:Detailed items to obtain
1077 : int TotShdSubs; // Number of Shading:Zone:Detailed items to obtain
1078 : int TotIntMassSurfaces; // Number of InternalMass surfaces to obtain
1079 : // Simple Surfaces (Rectangular)
1080 : int TotRectExtWalls; // Number of Exterior Walls to obtain
1081 : int TotRectIntWalls; // Number of Adiabatic Walls to obtain
1082 : int TotRectIZWalls; // Number of Interzone Walls to obtain
1083 : int TotRectUGWalls; // Number of Underground to obtain
1084 : int TotRectRoofs; // Number of Roofs to obtain
1085 : int TotRectCeilings; // Number of Adiabatic Ceilings to obtain
1086 : int TotRectIZCeilings; // Number of Interzone Ceilings to obtain
1087 : int TotRectGCFloors; // Number of Floors with Ground Contact to obtain
1088 : int TotRectIntFloors; // Number of Adiabatic Walls to obtain
1089 : int TotRectIZFloors; // Number of Interzone Floors to obtain
1090 : int TotRectWindows;
1091 : int TotRectDoors;
1092 : int TotRectGlazedDoors;
1093 : int TotRectIZWindows;
1094 : int TotRectIZDoors;
1095 : int TotRectIZGlazedDoors;
1096 : int TotOverhangs;
1097 : int TotOverhangsProjection;
1098 : int TotFins;
1099 : int TotFinsProjection;
1100 796 : bool RelWarning(false);
1101 : int ConstrNumSh; // Shaded construction number for a window
1102 : int LayNumOutside; // Outside material numbers for a shaded construction
1103 : int BlNum; // Blind number
1104 : int AddedSubSurfaces; // Subsurfaces (windows) added when windows reference Window5 Data File
1105 : // entries with two glazing systems
1106 : int NeedToAddSurfaces; // Surfaces that will be added due to "unentered" other zone surface
1107 : int NeedToAddSubSurfaces; // SubSurfaces that will be added due to "unentered" other zone surface
1108 : int CurNewSurf;
1109 : int FirstTotalSurfaces;
1110 : int NVert;
1111 : int Vert;
1112 : int n;
1113 : Real64 SurfWorldAz;
1114 : Real64 SurfTilt;
1115 :
1116 : int MultFound;
1117 : int MultSurfNum;
1118 796 : std::string MultString;
1119 : bool SubSurfaceSevereDisplayed;
1120 796 : bool subSurfaceError(false);
1121 : bool errFlag;
1122 :
1123 : int iTmp1;
1124 : int iTmp2;
1125 : // unused INTEGER :: SchID
1126 : int BlNumNew;
1127 796 : int WinShadingControlPtr(0);
1128 : int ErrCount;
1129 : bool izConstDiff; // differences in construction for IZ surfaces
1130 : bool izConstDiffMsg; // display message about hb diffs only once.
1131 :
1132 : // Get the total number of surfaces to allocate derived type and for surface loops
1133 :
1134 796 : if (state.dataSurfaceGeometry->GetSurfaceDataOneTimeFlag) {
1135 0 : return;
1136 : } else {
1137 796 : state.dataSurfaceGeometry->GetSurfaceDataOneTimeFlag = true;
1138 : }
1139 :
1140 796 : GetGeometryParameters(state, ErrorsFound);
1141 :
1142 796 : if (state.dataSurface->WorldCoordSystem) {
1143 357 : if (state.dataHeatBal->BuildingAzimuth != 0.0) RelWarning = true;
1144 1392 : for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
1145 1035 : if (state.dataHeatBal->Zone(ZoneNum).RelNorth != 0.0) RelWarning = true;
1146 : }
1147 357 : if (RelWarning && !state.dataSurfaceGeometry->WarningDisplayed) {
1148 2 : ShowWarningError(
1149 : state,
1150 2 : format("{}World Coordinate System selected. Any non-zero Building/Zone North Axes or non-zero Zone Origins are ignored.",
1151 : RoutineName));
1152 1 : ShowContinueError(state,
1153 : "These may be used in daylighting reference point coordinate calculations but not in normal geometry inputs.");
1154 1 : state.dataSurfaceGeometry->WarningDisplayed = true;
1155 : }
1156 357 : RelWarning = false;
1157 1392 : for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
1158 1035 : if (state.dataHeatBal->Zone(ZoneNum).OriginX != 0.0) RelWarning = true;
1159 1035 : if (state.dataHeatBal->Zone(ZoneNum).OriginY != 0.0) RelWarning = true;
1160 1035 : if (state.dataHeatBal->Zone(ZoneNum).OriginZ != 0.0) RelWarning = true;
1161 : }
1162 357 : if (RelWarning && !state.dataSurfaceGeometry->WarningDisplayed) {
1163 24 : ShowWarningError(
1164 : state,
1165 24 : format("{}World Coordinate System selected. Any non-zero Building/Zone North Axes or non-zero Zone Origins are ignored.",
1166 : RoutineName));
1167 12 : ShowContinueError(state,
1168 : "These may be used in daylighting reference point coordinate calculations but not in normal geometry inputs.");
1169 12 : state.dataSurfaceGeometry->WarningDisplayed = true;
1170 : }
1171 : }
1172 :
1173 796 : TotDetachedFixed = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Site:Detailed");
1174 796 : TotDetachedBldg = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Building:Detailed");
1175 796 : TotRectDetachedFixed = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Site");
1176 796 : TotRectDetachedBldg = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Building");
1177 796 : TotHTSurfs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "BuildingSurface:Detailed");
1178 796 : TotDetailedWalls = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Wall:Detailed");
1179 796 : TotDetailedRoofs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "RoofCeiling:Detailed");
1180 796 : TotDetailedFloors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Floor:Detailed");
1181 796 : TotHTSubs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "FenestrationSurface:Detailed");
1182 796 : TotShdSubs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Zone:Detailed");
1183 796 : TotOverhangs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Overhang");
1184 796 : TotOverhangsProjection = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Overhang:Projection");
1185 796 : TotFins = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Fin");
1186 796 : TotFinsProjection = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Fin:Projection");
1187 796 : TotRectWindows = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Window");
1188 796 : TotRectDoors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Door");
1189 796 : TotRectGlazedDoors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "GlazedDoor");
1190 796 : TotRectIZWindows = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Window:Interzone");
1191 796 : TotRectIZDoors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Door:Interzone");
1192 796 : TotRectIZGlazedDoors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "GlazedDoor:Interzone");
1193 796 : TotRectExtWalls = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Wall:Exterior");
1194 796 : TotRectIntWalls = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Wall:Adiabatic");
1195 796 : TotRectIZWalls = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Wall:Interzone");
1196 796 : TotRectUGWalls = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Wall:Underground");
1197 796 : TotRectRoofs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Roof");
1198 796 : TotRectCeilings = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Ceiling:Adiabatic");
1199 796 : TotRectIZCeilings = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Ceiling:Interzone");
1200 796 : TotRectGCFloors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Floor:GroundContact");
1201 796 : TotRectIntFloors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Floor:Adiabatic");
1202 796 : TotRectIZFloors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Floor:Interzone");
1203 :
1204 796 : state.dataSurface->TotOSC = 0;
1205 :
1206 796 : TotIntMassSurfaces = GetNumIntMassSurfaces(state);
1207 :
1208 1592 : state.dataSurface->TotSurfaces = (TotDetachedFixed + TotDetachedBldg + TotRectDetachedFixed + TotRectDetachedBldg) * 2 + TotHTSurfs +
1209 796 : TotHTSubs + TotShdSubs * 2 + TotIntMassSurfaces + TotOverhangs * 2 + TotOverhangsProjection * 2 +
1210 796 : TotFins * 4 + TotFinsProjection * 4 + TotDetailedWalls + TotDetailedRoofs + TotDetailedFloors +
1211 796 : TotRectWindows + TotRectDoors + TotRectGlazedDoors + TotRectIZWindows + TotRectIZDoors +
1212 796 : TotRectIZGlazedDoors + TotRectExtWalls + TotRectIntWalls + TotRectIZWalls + TotRectUGWalls + TotRectRoofs +
1213 796 : TotRectCeilings + TotRectIZCeilings + TotRectGCFloors + TotRectIntFloors + TotRectIZFloors;
1214 :
1215 796 : state.dataSurfaceGeometry->SurfaceTmp.allocate(state.dataSurface->TotSurfaces); // Allocate the Surface derived type appropriately
1216 796 : state.dataSurfaceGeometry->UniqueSurfaceNames.reserve(state.dataSurface->TotSurfaces);
1217 : // SurfaceTmp structure is allocated via derived type initialization.
1218 :
1219 796 : int NumSurfs = 0;
1220 796 : AddedSubSurfaces = 0;
1221 796 : state.dataErrTracking->AskForSurfacesReport = true;
1222 :
1223 796 : GetDetShdSurfaceData(state, ErrorsFound, NumSurfs, TotDetachedFixed, TotDetachedBldg);
1224 :
1225 796 : GetRectDetShdSurfaceData(state, ErrorsFound, NumSurfs, TotRectDetachedFixed, TotRectDetachedBldg);
1226 :
1227 796 : GetHTSurfaceData(state,
1228 : ErrorsFound,
1229 : NumSurfs,
1230 : TotHTSurfs,
1231 : TotDetailedWalls,
1232 : TotDetailedRoofs,
1233 : TotDetailedFloors,
1234 796 : state.dataSurfaceGeometry->BaseSurfCls,
1235 796 : state.dataSurfaceGeometry->BaseSurfIDs,
1236 : NeedToAddSurfaces);
1237 :
1238 796 : GetRectSurfaces(state,
1239 : ErrorsFound,
1240 : NumSurfs,
1241 : TotRectExtWalls,
1242 : TotRectIntWalls,
1243 : TotRectIZWalls,
1244 : TotRectUGWalls,
1245 : TotRectRoofs,
1246 : TotRectCeilings,
1247 : TotRectIZCeilings,
1248 : TotRectGCFloors,
1249 : TotRectIntFloors,
1250 : TotRectIZFloors,
1251 796 : state.dataSurfaceGeometry->BaseSurfIDs,
1252 : NeedToAddSurfaces);
1253 :
1254 796 : GetHTSubSurfaceData(state,
1255 : ErrorsFound,
1256 : NumSurfs,
1257 : TotHTSubs,
1258 796 : state.dataSurfaceGeometry->SubSurfCls,
1259 796 : state.dataSurfaceGeometry->SubSurfIDs,
1260 : AddedSubSurfaces,
1261 : NeedToAddSubSurfaces);
1262 :
1263 796 : GetRectSubSurfaces(state,
1264 : ErrorsFound,
1265 : NumSurfs,
1266 : TotRectWindows,
1267 : TotRectDoors,
1268 : TotRectGlazedDoors,
1269 : TotRectIZWindows,
1270 : TotRectIZDoors,
1271 : TotRectIZGlazedDoors,
1272 796 : state.dataSurfaceGeometry->SubSurfIDs,
1273 : AddedSubSurfaces,
1274 : NeedToAddSubSurfaces);
1275 :
1276 796 : GetAttShdSurfaceData(state, ErrorsFound, NumSurfs, TotShdSubs);
1277 :
1278 796 : GetSimpleShdSurfaceData(state, ErrorsFound, NumSurfs, TotOverhangs, TotOverhangsProjection, TotFins, TotFinsProjection);
1279 :
1280 796 : GetIntMassSurfaceData(state, ErrorsFound, NumSurfs);
1281 :
1282 796 : state.dataSurface->TotSurfaces = NumSurfs + AddedSubSurfaces + NeedToAddSurfaces + NeedToAddSubSurfaces;
1283 :
1284 796 : if (ErrorsFound) {
1285 0 : ShowFatalError(state, format("{}Errors discovered, program terminates.", RoutineName));
1286 : }
1287 :
1288 796 : state.dataSurface->Surface.allocate(state.dataSurface->TotSurfaces); // Allocate the Surface derived type appropriately
1289 796 : state.dataSurface->SurfaceWindow.allocate(state.dataSurface->TotSurfaces);
1290 796 : AllocateSurfaceArrays(state);
1291 796 : AllocateSurfaceWindows(state, state.dataSurface->TotSurfaces);
1292 :
1293 : // Have to make room for added surfaces, if needed
1294 796 : FirstTotalSurfaces = NumSurfs + AddedSubSurfaces;
1295 796 : if (NeedToAddSurfaces + NeedToAddSubSurfaces > 0) {
1296 31 : state.dataSurfaceGeometry->SurfaceTmp.redimension(state.dataSurface->TotSurfaces);
1297 : }
1298 :
1299 : // add the "need to add" surfaces
1300 : // Debug write(outputfiledebug,*) ' need to add ',NeedtoAddSurfaces+NeedToAddSubSurfaces
1301 796 : if (NeedToAddSurfaces + NeedToAddSubSurfaces > 0) CurNewSurf = FirstTotalSurfaces;
1302 46470 : for (int SurfNum = 1; SurfNum <= FirstTotalSurfaces; ++SurfNum) {
1303 45674 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond != UnenteredAdjacentZoneSurface) continue;
1304 : // Need to add surface
1305 370 : ++CurNewSurf;
1306 : // Debug write(outputfiledebug,*) ' adding surface=',curnewsurf
1307 370 : state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf) = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
1308 : // Basic parameters are the same for both surfaces.
1309 370 : Found = Util::FindItemInList(
1310 370 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCondName, state.dataHeatBal->Zone, state.dataGlobal->NumOfZones);
1311 370 : if (Found == 0) continue;
1312 370 : state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).Zone = Found;
1313 370 : state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).ZoneName = state.dataHeatBal->Zone(Found).Name;
1314 : // Reverse Construction
1315 370 : state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).Construction =
1316 370 : AssignReverseConstructionNumber(state, state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction, SurfError);
1317 370 : state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).ConstructionStoredInputValue =
1318 370 : state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).Construction;
1319 : // Reverse Vertices
1320 370 : NVert = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides;
1321 1850 : for (Vert = 1; Vert <= state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides; ++Vert) {
1322 1480 : state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).Vertex(Vert) = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(NVert);
1323 1480 : --NVert;
1324 : }
1325 370 : if (state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).Sides > 2) {
1326 370 : CreateNewellAreaVector(state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).Vertex,
1327 370 : state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).Sides,
1328 370 : state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).NewellAreaVector);
1329 370 : state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).GrossArea =
1330 370 : VecLength(state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).NewellAreaVector);
1331 370 : state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).Area = state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).GrossArea;
1332 370 : state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).NetAreaShadowCalc = state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).Area;
1333 370 : CreateNewellSurfaceNormalVector(state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).Vertex,
1334 370 : state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).Sides,
1335 370 : state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).NewellSurfaceNormalVector);
1336 370 : DetermineAzimuthAndTilt(state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).Vertex,
1337 : SurfWorldAz,
1338 : SurfTilt,
1339 370 : state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).lcsx,
1340 370 : state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).lcsy,
1341 370 : state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).lcsz,
1342 370 : state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).NewellSurfaceNormalVector);
1343 370 : state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).Azimuth = SurfWorldAz;
1344 370 : state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).Tilt = SurfTilt;
1345 370 : state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).convOrientation =
1346 370 : Convect::GetSurfConvOrientation(state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).Tilt);
1347 :
1348 : // Sine and cosine of azimuth and tilt
1349 370 : state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).SinAzim = std::sin(SurfWorldAz * Constant::DegToRadians);
1350 370 : state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).CosAzim = std::cos(SurfWorldAz * Constant::DegToRadians);
1351 370 : state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).SinTilt = std::sin(SurfTilt * Constant::DegToRadians);
1352 370 : state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).CosTilt = std::cos(SurfTilt * Constant::DegToRadians);
1353 : // Outward normal unit vector (pointing away from room)
1354 370 : state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).OutNormVec =
1355 740 : state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).NewellSurfaceNormalVector;
1356 1480 : for (n = 1; n <= 3; ++n) {
1357 1110 : if (std::abs(state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).OutNormVec(n) - 1.0) < 1.e-06)
1358 87 : state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).OutNormVec(n) = +1.0;
1359 1110 : if (std::abs(state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).OutNormVec(n) + 1.0) < 1.e-06)
1360 241 : state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).OutNormVec(n) = -1.0;
1361 1110 : if (std::abs(state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).OutNormVec(n)) < 1.e-06)
1362 698 : state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).OutNormVec(n) = 0.0;
1363 : }
1364 :
1365 : // Can perform tests on this surface here
1366 370 : state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).ViewFactorSky =
1367 370 : 0.5 * (1.0 + state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).CosTilt);
1368 370 : state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).ViewFactorGround =
1369 370 : 0.5 * (1.0 - state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).CosTilt);
1370 :
1371 : // The following IR view factors are modified in subr. SkyDifSolarShading if there are shadowing
1372 : // surfaces
1373 370 : state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).ViewFactorSkyIR = state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).ViewFactorSky;
1374 370 : state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).ViewFactorGroundIR =
1375 370 : 0.5 * (1.0 - state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).CosTilt);
1376 : }
1377 :
1378 : // Change Name
1379 370 : state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).Name = "iz-" + state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name;
1380 : // Debug write(outputfiledebug,*) ' new surf name=',TRIM(SurfaceTmp(CurNewSurf)%Name)
1381 : // Debug write(outputfiledebug,*) ' new surf in zone=',TRIM(surfacetmp(curnewsurf)%zoneName)
1382 370 : state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).ExtBoundCond = UnreconciledZoneSurface;
1383 370 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond = UnreconciledZoneSurface;
1384 370 : state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).ExtBoundCondName = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name;
1385 370 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCondName = state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).Name;
1386 370 : if (state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).Class == SurfaceClass::Roof ||
1387 390 : state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).Class == SurfaceClass::Wall ||
1388 20 : state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).Class == SurfaceClass::Floor) {
1389 : // base surface
1390 366 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == SurfaceClass::Roof) {
1391 96 : state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).Class = SurfaceClass::Floor;
1392 : // Debug write(outputfiledebug,*) ' new surfaces is a floor'
1393 270 : } else if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == SurfaceClass::Floor) {
1394 16 : state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).Class = SurfaceClass::Roof;
1395 : // Debug write(outputfiledebug,*) ' new surfaces is a roof'
1396 : }
1397 366 : state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).BaseSurf = CurNewSurf;
1398 366 : state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).BaseSurfName = state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).Name;
1399 : // Debug write(outputfiledebug,*) ' basesurf, extboundcondname=',TRIM(SurfaceTmp(CurNewSurf)%ExtBoundCondName)
1400 : } else {
1401 : // subsurface
1402 4 : Found = Util::FindItemInList("iz-" + state.dataSurfaceGeometry->SurfaceTmp(SurfNum).BaseSurfName,
1403 4 : state.dataSurfaceGeometry->SurfaceTmp,
1404 4 : FirstTotalSurfaces + CurNewSurf - 1);
1405 4 : if (Found > 0) {
1406 4 : state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).BaseSurfName =
1407 8 : "iz-" + state.dataSurfaceGeometry->SurfaceTmp(SurfNum).BaseSurfName;
1408 4 : state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).BaseSurf = Found;
1409 4 : state.dataSurfaceGeometry->SurfaceTmp(Found).Area -= state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).Area;
1410 7 : if (state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).Class == SurfaceClass::Window ||
1411 3 : state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).Class == SurfaceClass::GlassDoor) {
1412 2 : state.dataSurfaceGeometry->SurfaceTmp(Found).NetAreaShadowCalc -=
1413 2 : state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).Area / state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).Multiplier;
1414 : } else { // Door, TDD:Diffuser, TDD:DOME
1415 2 : state.dataSurfaceGeometry->SurfaceTmp(Found).NetAreaShadowCalc -= state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).Area;
1416 : }
1417 4 : state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).ExtBoundCond = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCond;
1418 4 : state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).ExtBoundCondName = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name;
1419 4 : state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).ExtSolar = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtSolar;
1420 4 : state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).ExtWind = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtWind;
1421 4 : state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).Zone = state.dataSurfaceGeometry->SurfaceTmp(Found).Zone;
1422 4 : state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).ZoneName = state.dataSurfaceGeometry->SurfaceTmp(Found).ZoneName;
1423 4 : state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf).OSCPtr = state.dataSurfaceGeometry->SurfaceTmp(Found).OSCPtr;
1424 : // Debug write(outputfiledebug,*) ' subsurf, extboundcondname=',TRIM(SurfaceTmp(CurNewSurf)%ExtBoundCondName)
1425 : // Debug write(outputfiledebug,*) ' subsurf, basesurf=',TRIM('iz-'//SurfaceTmp(SurfNum)%BaseSurfName)
1426 : } else {
1427 0 : ShowSevereError(state,
1428 0 : format("{}Adding unentered subsurface, could not find base surface=iz-{}",
1429 : RoutineName,
1430 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).BaseSurfName));
1431 0 : SurfError = true;
1432 : }
1433 : }
1434 : }
1435 : //**********************************************************************************
1436 : // After all of the surfaces have been defined then the base surfaces for the
1437 : // sub-surfaces can be defined. Loop through surfaces and match with the sub-surface
1438 : // names.
1439 46840 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
1440 46044 : if (!state.dataSurfaceGeometry->SurfaceTmp(SurfNum).HeatTransSurf) continue;
1441 :
1442 : // why are we doing this again? this should have already been done.
1443 44408 : if (Util::SameString(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).BaseSurfName, state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name)) {
1444 37710 : Found = SurfNum;
1445 : } else {
1446 6698 : Found = Util::FindItemInList(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).BaseSurfName,
1447 6698 : state.dataSurfaceGeometry->SurfaceTmp,
1448 6698 : state.dataSurface->TotSurfaces);
1449 : }
1450 44408 : if (Found > 0) {
1451 44408 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).BaseSurf = Found;
1452 44408 : if (SurfNum != Found) { // for subsurfaces
1453 6698 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).HeatTransSurf) ++state.dataSurfaceGeometry->SurfaceTmp(Found).NumSubSurfaces;
1454 13396 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class < SurfaceClass::Window ||
1455 6698 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class > SurfaceClass::TDD_Diffuser) {
1456 0 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == SurfaceClass::None) {
1457 0 : ShowSevereError(state,
1458 0 : format("{}Invalid SubSurface detected, Surface={}",
1459 : RoutineName,
1460 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name));
1461 : } else {
1462 0 : ShowSevereError(
1463 : state,
1464 0 : format("{}Invalid SubSurface detected, Surface={}, class={} invalid class for subsurface",
1465 : RoutineName,
1466 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
1467 0 : state.dataSurfaceGeometry->BaseSurfCls(int(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class))));
1468 0 : SurfError = true;
1469 : }
1470 : }
1471 : }
1472 : }
1473 :
1474 : } // ...end of the Surface DO loop for finding BaseSurf
1475 : //**********************************************************************************
1476 : // The surfaces need to be hierarchical by space. Input is allowed to be in any order. In
1477 : // this section the surfaces are reordered into:
1478 : // All shadowing surfaces (if mirrored, Mir- surface follows immediately after original)
1479 : // Shading:Site
1480 : // Shading:Building
1481 : // Shading:space (and variants)
1482 : // For each space:
1483 : // Walls
1484 : // Floors
1485 : // Roofs/Ceilings
1486 : // Internal Mass
1487 : // Non-Window subsurfaces (including doors)
1488 : // Window subsurfaces (including TubularDaylightingDiffusers)
1489 : // TubularDaylightingDomes
1490 : // After reordering, MovedSurfs should equal TotSurfaces
1491 :
1492 : // For reporting purposes, the legacy surface order is also saved in DataSurfaces::AllSurfaceListReportOrder:
1493 : // All shadowing surfaces (if mirrored, Mir- surface follows immediately after original)
1494 : // Shading:Site
1495 : // Shading:Building
1496 : // Shading:Zone (and variants)
1497 : // For each zone:
1498 : // Walls
1499 : // subsurfaces for each wall (windows, doors, in input order, not sorted) follow the base surface
1500 : // Floors
1501 : // subsurfaces for each floor (windows, doors, in input order, not sorted) follow the base surface
1502 : // Roofs/Ceilings
1503 : // subsurfaces for each roof/ceiling (windows, doors, in input order, not sorted) follow the base surface
1504 : // Internal Mass
1505 : // After reordering, MovedSurfs should equal TotSurfaces
1506 :
1507 796 : MovedSurfs = 0;
1508 796 : Array1D<bool> SurfaceTmpClassMoved; // Tmp class is moved
1509 796 : SurfaceTmpClassMoved.dimension(state.dataSurface->TotSurfaces, false);
1510 796 : state.dataSurface->AllSurfaceListReportOrder.reserve(state.dataSurface->TotSurfaces);
1511 :
1512 796 : CreateMissingSpaces(state, state.dataSurfaceGeometry->SurfaceTmp);
1513 :
1514 : // Old SurfNum to New SurfNum
1515 : // Old = order in state.dataSurfaceGeometry->SurfaceTmp
1516 : // New = order in state.dataSurface->Surface
1517 796 : EPVector<int> oldToNewSurfNums;
1518 796 : oldToNewSurfNums.resize(state.dataSurface->TotSurfaces, -1);
1519 :
1520 : // Move all shading Surfaces to Front
1521 46840 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
1522 46044 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class != SurfaceClass::Detached_F &&
1523 91936 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class != SurfaceClass::Detached_B &&
1524 45892 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class != SurfaceClass::Shading)
1525 44408 : continue;
1526 :
1527 : // A shading surface
1528 1636 : ++MovedSurfs;
1529 : // Store list of moved surface numbers in reporting order
1530 1636 : state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
1531 1636 : SurfaceTmpClassMoved(SurfNum) = true; //'Moved'
1532 1636 : state.dataSurface->AllSurfaceListReportOrder.push_back(SurfNum);
1533 1636 : oldToNewSurfNums(SurfNum) = MovedSurfs;
1534 : }
1535 :
1536 : // For each zone
1537 :
1538 5852 : for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
1539 10124 : for (int spaceNum : state.dataHeatBal->Zone(ZoneNum).spaceIndexes) {
1540 : // Group air boundary surfaces first within each space
1541 1276522 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
1542 1271454 : if (SurfaceTmpClassMoved(SurfNum)) continue;
1543 655964 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).spaceNum != spaceNum) continue;
1544 44408 : int constNum = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction;
1545 44408 : if (constNum == 0) continue;
1546 44408 : if (!state.dataConstruction->Construct(constNum).TypeIsAirBoundary) continue;
1547 :
1548 : // An air boundary surface
1549 18 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).IsAirBoundarySurf = true;
1550 18 : ++MovedSurfs;
1551 18 : state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
1552 : // If base Surface Type (Wall, Floor, Roof/Ceiling)
1553 18 : if ((state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == state.dataSurfaceGeometry->BaseSurfIDs(1)) ||
1554 18 : (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == state.dataSurfaceGeometry->BaseSurfIDs(2)) ||
1555 0 : (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == state.dataSurfaceGeometry->BaseSurfIDs(3))) {
1556 : // Store list of moved surface numbers in reporting order. We use the old position, we'll reconcile later
1557 : // We don't do it for Air Door/Air Windows yet, we want them listed below each base surf they belong to
1558 18 : state.dataSurface->AllSurfaceListReportOrder.push_back(SurfNum);
1559 : }
1560 18 : oldToNewSurfNums(SurfNum) = MovedSurfs;
1561 18 : SurfaceTmpClassMoved(SurfNum) = true; //'Moved'
1562 : }
1563 :
1564 : // For each Base Surface Type (Wall, Floor, Roof/Ceiling) - put these first
1565 :
1566 20272 : for (const DataSurfaces::SurfaceClass Loop : state.dataSurfaceGeometry->BaseSurfIDs) {
1567 :
1568 3829566 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
1569 :
1570 3814362 : if (SurfaceTmpClassMoved(SurfNum)) continue;
1571 1915742 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Zone == 0) continue;
1572 :
1573 1915742 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).spaceNum != spaceNum) continue;
1574 81074 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class != Loop) continue;
1575 :
1576 35294 : ++MovedSurfs;
1577 35294 : state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
1578 35294 : oldToNewSurfNums(SurfNum) = MovedSurfs;
1579 35294 : SurfaceTmpClassMoved(SurfNum) = true; // 'Moved'
1580 : // Store list of moved surface numbers in order reporting order (subsurfaces follow their base surface)
1581 35294 : state.dataSurface->AllSurfaceListReportOrder.push_back(SurfNum);
1582 :
1583 : // Find all subsurfaces to this surface - just to update Report them in order
1584 9280844 : for (int SubSurfNum = 1; SubSurfNum <= state.dataSurface->TotSurfaces; ++SubSurfNum) {
1585 : // Gotta avoid pushing myself again!
1586 9245550 : if (SubSurfNum == SurfNum) continue;
1587 : // We don't check if already moved, because we didn't add them to AllSurfaceListReportOrder above!
1588 9210256 : if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).Zone == 0) continue;
1589 9133486 : if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).BaseSurf != SurfNum) continue;
1590 : // Add original sub-surface numbers as placeholders in surface list for reporting
1591 6698 : state.dataSurface->AllSurfaceListReportOrder.push_back(SubSurfNum);
1592 : }
1593 : }
1594 : }
1595 :
1596 : // Internal mass goes next
1597 1276522 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
1598 :
1599 1271454 : if (SurfaceTmpClassMoved(SurfNum)) continue;
1600 620652 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).spaceNum != spaceNum) continue;
1601 9096 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class != SurfaceClass::IntMass) continue;
1602 2398 : ++MovedSurfs;
1603 2398 : state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
1604 2398 : oldToNewSurfNums(SurfNum) = MovedSurfs;
1605 2398 : SurfaceTmpClassMoved(SurfNum) = true; // 'Moved'
1606 : // Store list of moved surface numbers in reporting order
1607 2398 : state.dataSurface->AllSurfaceListReportOrder.push_back(SurfNum);
1608 : }
1609 :
1610 : // Opaque door goes next
1611 1276522 : for (int SubSurfNum = 1; SubSurfNum <= state.dataSurface->TotSurfaces; ++SubSurfNum) {
1612 :
1613 1271454 : if (SurfaceTmpClassMoved(SubSurfNum)) continue;
1614 618254 : if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).spaceNum != spaceNum) continue;
1615 6698 : if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).Class != SurfaceClass::Door) continue;
1616 :
1617 479 : ++MovedSurfs;
1618 479 : state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum);
1619 479 : oldToNewSurfNums(SubSurfNum) = MovedSurfs;
1620 479 : SurfaceTmpClassMoved(SubSurfNum) = true; // 'Moved'
1621 : }
1622 :
1623 : // The exterior window subsurfaces (includes SurfaceClass::Window and SurfaceClass::GlassDoor) goes next
1624 1276522 : for (int SubSurfNum = 1; SubSurfNum <= state.dataSurface->TotSurfaces; ++SubSurfNum) {
1625 :
1626 1271454 : if (SurfaceTmpClassMoved(SubSurfNum)) continue;
1627 617775 : if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).spaceNum != spaceNum) continue;
1628 6219 : if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).ExtBoundCond > 0) continue; // Exterior window
1629 6762 : if ((state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).Class != SurfaceClass::Window) &&
1630 543 : (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).Class != SurfaceClass::GlassDoor))
1631 4 : continue;
1632 :
1633 6215 : ++MovedSurfs;
1634 6215 : state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum);
1635 6215 : oldToNewSurfNums(SubSurfNum) = MovedSurfs;
1636 6215 : SurfaceTmpClassMoved(SubSurfNum) = true; // 'Moved'
1637 : }
1638 :
1639 : // The interior window subsurfaces (includes SurfaceClass::Window and SurfaceClass::GlassDoor) goes next
1640 1276522 : for (int SubSurfNum = 1; SubSurfNum <= state.dataSurface->TotSurfaces; ++SubSurfNum) {
1641 :
1642 1271454 : if (SurfaceTmpClassMoved(SubSurfNum)) continue;
1643 611560 : if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).spaceNum != spaceNum) continue;
1644 4 : if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).ExtBoundCond <= 0) continue;
1645 0 : if ((state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).Class != SurfaceClass::Window) &&
1646 0 : (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).Class != SurfaceClass::GlassDoor))
1647 0 : continue;
1648 :
1649 0 : ++MovedSurfs;
1650 0 : state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum);
1651 0 : oldToNewSurfNums(SubSurfNum) = MovedSurfs;
1652 0 : SurfaceTmpClassMoved(SubSurfNum) = true; // 'Moved'
1653 : }
1654 :
1655 : // The SurfaceClass::TDD_Diffuser (OriginalClass = Window) goes next
1656 1276522 : for (int SubSurfNum = 1; SubSurfNum <= state.dataSurface->TotSurfaces; ++SubSurfNum) {
1657 :
1658 1271454 : if (SurfaceTmpClassMoved(SubSurfNum)) continue;
1659 611560 : if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).spaceNum != spaceNum) continue;
1660 4 : if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).Class != SurfaceClass::TDD_Diffuser) continue;
1661 :
1662 2 : ++MovedSurfs;
1663 2 : state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum);
1664 2 : oldToNewSurfNums(SubSurfNum) = MovedSurfs;
1665 2 : SurfaceTmpClassMoved(SubSurfNum) = true; // 'Moved'
1666 : }
1667 :
1668 : // Last but not least, SurfaceClass::TDD_Dome
1669 1276522 : for (int SubSurfNum = 1; SubSurfNum <= state.dataSurface->TotSurfaces; ++SubSurfNum) {
1670 :
1671 1271454 : if (SurfaceTmpClassMoved(SubSurfNum)) continue;
1672 611558 : if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).spaceNum != spaceNum) continue;
1673 2 : if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).Class != SurfaceClass::TDD_Dome) continue;
1674 :
1675 2 : ++MovedSurfs;
1676 2 : state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum);
1677 2 : oldToNewSurfNums(SubSurfNum) = MovedSurfs;
1678 2 : SurfaceTmpClassMoved(SubSurfNum) = true; // 'Moved'
1679 : }
1680 5056 : }
1681 : }
1682 :
1683 : // Validity checking
1684 796 : assert(state.dataSurface->TotSurfaces == MovedSurfs);
1685 796 : assert(state.dataSurface->TotSurfaces == static_cast<int>(state.dataSurface->AllSurfaceListReportOrder.size()));
1686 796 : assert(state.dataSurface->TotSurfaces == static_cast<int>(oldToNewSurfNums.size()));
1687 :
1688 : // Assert validity of indices
1689 46840 : assert(std::find_if(state.dataSurface->AllSurfaceListReportOrder.cbegin(), state.dataSurface->AllSurfaceListReportOrder.cend(), [](int i) {
1690 : return i < 1;
1691 : }) == state.dataSurface->AllSurfaceListReportOrder.cend());
1692 :
1693 46840 : assert(std::find_if(oldToNewSurfNums.cbegin(), oldToNewSurfNums.cend(), [](int i) { return i < 1; }) == oldToNewSurfNums.cend());
1694 :
1695 796 : if (MovedSurfs != state.dataSurface->TotSurfaces) {
1696 0 : ShowSevereError(
1697 : state,
1698 0 : format("{}Reordered # of Surfaces ({}) not = Total # of Surfaces ({})", RoutineName, MovedSurfs, state.dataSurface->TotSurfaces));
1699 0 : SurfError = true;
1700 0 : for (int Loop = 1; Loop <= state.dataSurface->TotSurfaces; ++Loop) {
1701 0 : if (!SurfaceTmpClassMoved(Loop) && state.dataSurfaceGeometry->SurfaceTmp(Loop).Class == SurfaceClass::Invalid) {
1702 0 : ShowSevereError(state,
1703 0 : format("{}Error in Surface= \"{} indicated Zone=\"{}\"",
1704 : RoutineName,
1705 0 : state.dataSurfaceGeometry->SurfaceTmp(Loop).Name,
1706 0 : state.dataSurfaceGeometry->SurfaceTmp(Loop).ZoneName));
1707 : }
1708 : }
1709 0 : ShowWarningError(
1710 0 : state, format("{}Remaining surface checks will use \"reordered number of surfaces\", not number of original surfaces", RoutineName));
1711 : }
1712 :
1713 : // Realign the relationship: surface to base surface
1714 46840 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
1715 46044 : auto &movedSurf = state.dataSurface->Surface(SurfNum);
1716 46044 : if (movedSurf.BaseSurf > 0) {
1717 44408 : int newBaseSurfNum = oldToNewSurfNums(movedSurf.BaseSurf);
1718 44408 : movedSurf.BaseSurf = newBaseSurfNum;
1719 :
1720 44408 : if (newBaseSurfNum < 1) {
1721 0 : ShowFatalError(
1722 : state,
1723 0 : format("{}Couldn't find the new Surface Number for surface index {} named '{}'. Looking for BaseSurf old index of {}",
1724 : RoutineName,
1725 : SurfNum,
1726 0 : movedSurf.Name,
1727 0 : movedSurf.BaseSurf));
1728 : }
1729 : }
1730 46044 : auto &reportOrderNum = state.dataSurface->AllSurfaceListReportOrder[SurfNum - 1];
1731 46044 : if (reportOrderNum > 0) {
1732 46044 : int newReportOrderNum = oldToNewSurfNums(reportOrderNum);
1733 46044 : reportOrderNum = newReportOrderNum;
1734 : }
1735 : }
1736 :
1737 796 : state.dataSurfaceGeometry->SurfaceTmp.deallocate(); // DeAllocate the Temp Surface derived type
1738 :
1739 796 : createSpaceSurfaceLists(state);
1740 :
1741 : // For each Base Surface Type (Wall, Floor, Roof)
1742 :
1743 3184 : for (const DataSurfaces::SurfaceClass Loop : state.dataSurfaceGeometry->BaseSurfIDs) {
1744 140520 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
1745 :
1746 138132 : if (state.dataSurface->Surface(SurfNum).Zone == 0) continue;
1747 :
1748 133224 : if (state.dataSurface->Surface(SurfNum).Class != Loop) continue;
1749 :
1750 : // Find all subsurfaces to this surface
1751 9281884 : for (int SubSurfNum = 1; SubSurfNum <= state.dataSurface->TotSurfaces; ++SubSurfNum) {
1752 :
1753 9246572 : if (SurfNum == SubSurfNum) continue;
1754 9211260 : if (state.dataSurface->Surface(SubSurfNum).Zone == 0) continue;
1755 9134418 : if (state.dataSurface->Surface(SubSurfNum).BaseSurf != SurfNum) continue;
1756 :
1757 : // Check facing angle of Sub compared to base
1758 6698 : checkSubSurfAzTiltNorm(state, state.dataSurface->Surface(SurfNum), state.dataSurface->Surface(SubSurfNum), subSurfaceError);
1759 6698 : if (subSurfaceError) SurfError = true;
1760 : }
1761 : }
1762 : }
1763 :
1764 : //**********************************************************************************
1765 : // Now, match up interzone surfaces
1766 796 : NonMatch = false;
1767 796 : izConstDiffMsg = false;
1768 46840 : for (int SurfNum = 1; SurfNum <= MovedSurfs; ++SurfNum) { // TotSurfaces
1769 : // Clean up Shading Surfaces, make sure they don't go through here.
1770 46044 : if (!state.dataSurface->Surface(SurfNum).HeatTransSurf) continue;
1771 : // If other surface, match it up
1772 : // Both interzone and "internal" surfaces have this pointer set
1773 : // Internal surfaces point to themselves, Interzone to another
1774 44408 : if (state.dataSurface->Surface(SurfNum).ExtBoundCond == UnreconciledZoneSurface) {
1775 15213 : if (not_blank(state.dataSurface->Surface(SurfNum).ExtBoundCondName)) {
1776 15213 : if (state.dataSurface->Surface(SurfNum).ExtBoundCondName == state.dataSurface->Surface(SurfNum).Name) {
1777 6286 : Found = SurfNum;
1778 : } else {
1779 8927 : Found = Util::FindItemInList(state.dataSurface->Surface(SurfNum).ExtBoundCondName, state.dataSurface->Surface, MovedSurfs);
1780 : }
1781 15213 : if (Found != 0) {
1782 15213 : state.dataSurface->Surface(SurfNum).ExtBoundCond = Found;
1783 : // Check that matching surface is also "OtherZoneSurface"
1784 24105 : if (state.dataSurface->Surface(Found).ExtBoundCond <= 0 &&
1785 8892 : state.dataSurface->Surface(Found).ExtBoundCond != UnreconciledZoneSurface) {
1786 0 : ShowSevereError(state, format("{}Potential \"OtherZoneSurface\" is not matched correctly:", RoutineName));
1787 :
1788 0 : ShowContinueError(state,
1789 0 : format("Surface={}, Zone={}",
1790 0 : state.dataSurface->Surface(SurfNum).Name,
1791 0 : state.dataSurface->Surface(SurfNum).ZoneName));
1792 0 : ShowContinueError(state,
1793 0 : format("Nonmatched Other/InterZone Surface={}, Zone={}",
1794 0 : state.dataSurface->Surface(Found).Name,
1795 0 : state.dataSurface->Surface(Found).ZoneName));
1796 0 : SurfError = true;
1797 : }
1798 : // Check that matching interzone surface has construction with reversed layers
1799 15213 : if (Found != SurfNum) { // Interzone surface
1800 : // Make sure different zones too (CR 4110)
1801 8927 : if (state.dataSurface->Surface(SurfNum).spaceNum == state.dataSurface->Surface(Found).spaceNum) {
1802 3 : ++state.dataSurfaceGeometry->ErrCount2;
1803 3 : if (state.dataSurfaceGeometry->ErrCount2 == 1 && !state.dataGlobal->DisplayExtraWarnings) {
1804 4 : ShowWarningError(state,
1805 4 : format("{}CAUTION -- Interspace surfaces are occuring in the same space(s).", RoutineName));
1806 2 : ShowContinueError(
1807 : state, "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on individual occurrences.");
1808 : }
1809 3 : if (state.dataGlobal->DisplayExtraWarnings) {
1810 0 : ShowWarningError(state, format("{}CAUTION -- Interspace surfaces are usually in different spaces", RoutineName));
1811 0 : ShowContinueError(state,
1812 0 : format("Surface={}, Space={}, Zone={}",
1813 0 : state.dataSurface->Surface(SurfNum).Name,
1814 0 : state.dataHeatBal->space(state.dataSurface->Surface(SurfNum).spaceNum).Name,
1815 0 : state.dataSurface->Surface(SurfNum).ZoneName));
1816 0 : ShowContinueError(state,
1817 0 : format("Surface={}, Space={}, Zone={}",
1818 0 : state.dataSurface->Surface(Found).Name,
1819 0 : state.dataHeatBal->space(state.dataSurface->Surface(Found).spaceNum).Name,
1820 0 : state.dataSurface->Surface(Found).ZoneName));
1821 : }
1822 : }
1823 8927 : ConstrNum = state.dataSurface->Surface(SurfNum).Construction;
1824 8927 : ConstrNumFound = state.dataSurface->Surface(Found).Construction;
1825 8927 : if (ConstrNum <= 0 || ConstrNumFound <= 0) continue;
1826 8927 : if (state.dataConstruction->Construct(ConstrNum).ReverseConstructionNumLayersWarning &&
1827 0 : state.dataConstruction->Construct(ConstrNumFound).ReverseConstructionNumLayersWarning)
1828 0 : continue;
1829 8939 : if (state.dataConstruction->Construct(ConstrNum).ReverseConstructionLayersOrderWarning &&
1830 12 : state.dataConstruction->Construct(ConstrNumFound).ReverseConstructionLayersOrderWarning)
1831 12 : continue;
1832 8915 : TotLay = state.dataConstruction->Construct(ConstrNum).TotLayers;
1833 8915 : TotLayFound = state.dataConstruction->Construct(ConstrNumFound).TotLayers;
1834 8915 : if (TotLay != TotLayFound) { // Different number of layers
1835 : // match on like Uvalues (nominal)
1836 0 : if (std::abs(state.dataHeatBal->NominalU(ConstrNum) - state.dataHeatBal->NominalU(ConstrNumFound)) > 0.001) {
1837 0 : ShowSevereError(state,
1838 0 : format("{}Construction {} of interzone surface {} does not have the same number of layers as the "
1839 : "construction {} of adjacent surface {}",
1840 : RoutineName,
1841 0 : state.dataConstruction->Construct(ConstrNum).Name,
1842 0 : state.dataSurface->Surface(SurfNum).Name,
1843 0 : state.dataConstruction->Construct(ConstrNumFound).Name,
1844 0 : state.dataSurface->Surface(Found).Name));
1845 0 : if (!state.dataConstruction->Construct(ConstrNum).ReverseConstructionNumLayersWarning ||
1846 0 : !state.dataConstruction->Construct(ConstrNumFound).ReverseConstructionNumLayersWarning) {
1847 0 : ShowContinueError(state, "...this problem for this pair will not be reported again.");
1848 0 : state.dataConstruction->Construct(ConstrNum).ReverseConstructionNumLayersWarning = true;
1849 0 : state.dataConstruction->Construct(ConstrNumFound).ReverseConstructionNumLayersWarning = true;
1850 : }
1851 0 : SurfError = true;
1852 : }
1853 : } else { // Same number of layers; check for reverse layers
1854 : // check layers as number of layers is the same
1855 8915 : izConstDiff = false;
1856 : // ok if same nominal U
1857 8915 : CheckForReversedLayers(state, izConstDiff, ConstrNum, ConstrNumFound, TotLay);
1858 8917 : if (izConstDiff &&
1859 2 : std::abs(state.dataHeatBal->NominalU(ConstrNum) - state.dataHeatBal->NominalU(ConstrNumFound)) > 0.001) {
1860 0 : ShowSevereError(state,
1861 0 : format("{}Construction {} of interzone surface {} does not have the same materials in the "
1862 : "reverse order as the construction {} of adjacent surface {}",
1863 : RoutineName,
1864 0 : state.dataConstruction->Construct(ConstrNum).Name,
1865 0 : state.dataSurface->Surface(SurfNum).Name,
1866 0 : state.dataConstruction->Construct(ConstrNumFound).Name,
1867 0 : state.dataSurface->Surface(Found).Name));
1868 0 : ShowContinueError(state,
1869 : "or the properties of the reversed layers are not correct due to differing layer front and "
1870 : "back side values");
1871 0 : if (!state.dataConstruction->Construct(ConstrNum).ReverseConstructionLayersOrderWarning ||
1872 0 : !state.dataConstruction->Construct(ConstrNumFound).ReverseConstructionLayersOrderWarning) {
1873 0 : ShowContinueError(state, "...this problem for this pair will not be reported again.");
1874 0 : state.dataConstruction->Construct(ConstrNum).ReverseConstructionLayersOrderWarning = true;
1875 0 : state.dataConstruction->Construct(ConstrNumFound).ReverseConstructionLayersOrderWarning = true;
1876 : }
1877 0 : SurfError = true;
1878 8915 : } else if (izConstDiff) {
1879 4 : ShowWarningError(state,
1880 4 : format("{}Construction {} of interzone surface {} does not have the same materials in the "
1881 : "reverse order as the construction {} of adjacent surface {}",
1882 : RoutineName,
1883 2 : state.dataConstruction->Construct(ConstrNum).Name,
1884 2 : state.dataSurface->Surface(SurfNum).Name,
1885 2 : state.dataConstruction->Construct(ConstrNumFound).Name,
1886 2 : state.dataSurface->Surface(Found).Name));
1887 2 : ShowContinueError(state,
1888 : "or the properties of the reversed layers are not correct due to differing layer front and "
1889 : "back side values");
1890 4 : ShowContinueError(
1891 : state,
1892 4 : format("...but Nominal U values are similar, diff=[{:.4R}] ... simulation proceeds.",
1893 2 : std::abs(state.dataHeatBal->NominalU(ConstrNum) - state.dataHeatBal->NominalU(ConstrNumFound))));
1894 2 : if (!izConstDiffMsg) {
1895 2 : ShowContinueError(state,
1896 : "...if the two zones are expected to have significantly different temperatures, the proper "
1897 : "\"reverse\" construction should be created.");
1898 2 : izConstDiffMsg = true;
1899 : }
1900 2 : if (!state.dataConstruction->Construct(ConstrNum).ReverseConstructionLayersOrderWarning ||
1901 0 : !state.dataConstruction->Construct(ConstrNumFound).ReverseConstructionLayersOrderWarning) {
1902 2 : ShowContinueError(state, "...this problem for this pair will not be reported again.");
1903 2 : state.dataConstruction->Construct(ConstrNum).ReverseConstructionLayersOrderWarning = true;
1904 2 : state.dataConstruction->Construct(ConstrNumFound).ReverseConstructionLayersOrderWarning = true;
1905 : }
1906 : }
1907 : }
1908 :
1909 : // If significantly different areas -- this would not be good
1910 8915 : MultFound = state.dataHeatBal->Zone(state.dataSurface->Surface(Found).Zone).Multiplier *
1911 8915 : state.dataHeatBal->Zone(state.dataSurface->Surface(Found).Zone).ListMultiplier;
1912 8915 : MultSurfNum = state.dataHeatBal->Zone(state.dataSurface->Surface(SurfNum).Zone).Multiplier *
1913 8915 : state.dataHeatBal->Zone(state.dataSurface->Surface(SurfNum).Zone).ListMultiplier;
1914 8915 : if (state.dataSurface->Surface(Found).Area > 0.0) {
1915 8915 : if (std::abs((state.dataSurface->Surface(Found).Area * MultFound -
1916 8915 : state.dataSurface->Surface(SurfNum).Area * MultSurfNum) /
1917 8915 : state.dataSurface->Surface(Found).Area * MultFound) > 0.02) { // 2% difference in areas
1918 0 : ++state.dataSurfaceGeometry->ErrCount4;
1919 0 : if (state.dataSurfaceGeometry->ErrCount4 == 1 && !state.dataGlobal->DisplayExtraWarnings) {
1920 0 : ShowWarningError(
1921 : state,
1922 0 : format("{}InterZone Surface Areas do not match as expected and might not satisfy conservation of energy:",
1923 : RoutineName));
1924 0 : ShowContinueError(
1925 : state, "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on individual mismatches.");
1926 : }
1927 0 : if (state.dataGlobal->DisplayExtraWarnings) {
1928 0 : ShowWarningError(
1929 : state,
1930 0 : format("{}InterZone Surface Areas do not match as expected and might not satisfy conservation of energy:",
1931 : RoutineName));
1932 :
1933 0 : if (MultFound == 1 && MultSurfNum == 1) {
1934 0 : ShowContinueError(state,
1935 0 : format(" Area={:.1T} in Surface={}, Zone={}",
1936 0 : state.dataSurface->Surface(SurfNum).Area,
1937 0 : state.dataSurface->Surface(SurfNum).Name,
1938 0 : state.dataSurface->Surface(SurfNum).ZoneName));
1939 0 : ShowContinueError(state,
1940 0 : format(" Area={:.1T} in Surface={}, Zone={}",
1941 0 : state.dataSurface->Surface(Found).Area,
1942 0 : state.dataSurface->Surface(Found).Name,
1943 0 : state.dataSurface->Surface(Found).ZoneName));
1944 : } else { // Show multiplier info
1945 0 : ShowContinueError(state,
1946 0 : format(" Area={:.1T}, Multipliers={}, Total Area={:.1T} in Surface={} Zone={}",
1947 0 : state.dataSurface->Surface(SurfNum).Area,
1948 : MultSurfNum,
1949 0 : state.dataSurface->Surface(SurfNum).Area * MultSurfNum,
1950 0 : state.dataSurface->Surface(SurfNum).Name,
1951 0 : state.dataSurface->Surface(SurfNum).ZoneName));
1952 :
1953 0 : ShowContinueError(state,
1954 0 : format(" Area={:.1T}, Multipliers={}, Total Area={:.1T} in Surface={} Zone={}",
1955 0 : state.dataSurface->Surface(Found).Area,
1956 : MultFound,
1957 0 : state.dataSurface->Surface(Found).Area * MultFound,
1958 0 : state.dataSurface->Surface(Found).Name,
1959 0 : state.dataSurface->Surface(Found).ZoneName));
1960 : }
1961 : }
1962 : }
1963 : }
1964 : // Check opposites Azimuth and Tilt
1965 : // Tilt
1966 8915 : if (std::abs(std::abs(state.dataSurface->Surface(Found).Tilt + state.dataSurface->Surface(SurfNum).Tilt) - 180.0) > 1.0) {
1967 0 : ShowWarningError(state, format("{}InterZone Surface Tilts do not match as expected.", RoutineName));
1968 0 : ShowContinueError(state,
1969 0 : format(" Tilt={:.1T} in Surface={}, Zone={}",
1970 0 : state.dataSurface->Surface(SurfNum).Tilt,
1971 0 : state.dataSurface->Surface(SurfNum).Name,
1972 0 : state.dataSurface->Surface(SurfNum).ZoneName));
1973 0 : ShowContinueError(state,
1974 0 : format(" Tilt={:.1T} in Surface={}, Zone={}",
1975 0 : state.dataSurface->Surface(Found).Tilt,
1976 0 : state.dataSurface->Surface(Found).Name,
1977 0 : state.dataSurface->Surface(Found).ZoneName));
1978 : }
1979 : // check surface class match. interzone surface.
1980 :
1981 8915 : if ((state.dataSurface->Surface(SurfNum).Class == SurfaceClass::Wall &&
1982 17830 : state.dataSurface->Surface(Found).Class != SurfaceClass::Wall) ||
1983 8915 : (state.dataSurface->Surface(SurfNum).Class != SurfaceClass::Wall &&
1984 3039 : state.dataSurface->Surface(Found).Class == SurfaceClass::Wall)) {
1985 0 : ShowWarningError(state, format("{}InterZone Surface Classes do not match as expected.", RoutineName));
1986 0 : ShowContinueError(state,
1987 0 : format("Surface=\"{}\", surface class={}",
1988 0 : state.dataSurface->Surface(SurfNum).Name,
1989 0 : cSurfaceClass(state.dataSurface->Surface(SurfNum).Class)));
1990 0 : ShowContinueError(state,
1991 0 : format("Adjacent Surface=\"{}\", surface class={}",
1992 0 : state.dataSurface->Surface(Found).Name,
1993 0 : cSurfaceClass(state.dataSurface->Surface(Found).Class)));
1994 0 : ShowContinueError(state, "Other errors/warnings may follow about these surfaces.");
1995 : }
1996 8915 : if ((state.dataSurface->Surface(SurfNum).Class == SurfaceClass::Roof &&
1997 17830 : state.dataSurface->Surface(Found).Class != SurfaceClass::Floor) ||
1998 8915 : (state.dataSurface->Surface(SurfNum).Class != SurfaceClass::Roof &&
1999 7442 : state.dataSurface->Surface(Found).Class == SurfaceClass::Floor)) {
2000 0 : ShowWarningError(state, format("{}InterZone Surface Classes do not match as expected.", RoutineName));
2001 0 : ShowContinueError(state,
2002 0 : format("Surface=\"{}\", surface class={}",
2003 0 : state.dataSurface->Surface(SurfNum).Name,
2004 0 : cSurfaceClass(state.dataSurface->Surface(SurfNum).Class)));
2005 0 : ShowContinueError(state,
2006 0 : format("Adjacent Surface=\"{}\", surface class={}",
2007 0 : state.dataSurface->Surface(Found).Name,
2008 0 : cSurfaceClass(state.dataSurface->Surface(Found).Class)));
2009 0 : ShowContinueError(state, "Other errors/warnings may follow about these surfaces.");
2010 : }
2011 16357 : if (state.dataSurface->Surface(SurfNum).Class != SurfaceClass::Roof &&
2012 7442 : state.dataSurface->Surface(SurfNum).Class != SurfaceClass::Floor) {
2013 : // Walls, Windows, Doors, Glass Doors
2014 5916 : if (state.dataSurface->Surface(SurfNum).Class != SurfaceClass::Wall) {
2015 : // Surface is a Door, Window or Glass Door
2016 40 : if (state.dataSurface->Surface(SurfNum).BaseSurf == 0) continue; // error detected elsewhere
2017 79 : if (state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Class == SurfaceClass::Roof ||
2018 39 : state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Class == SurfaceClass::Floor)
2019 2 : continue;
2020 : }
2021 5914 : if (std::abs(std::abs(state.dataSurface->Surface(SurfNum).Azimuth - state.dataSurface->Surface(Found).Azimuth) -
2022 5914 : 180.0) > 1.0) {
2023 0 : if (std::abs(state.dataSurface->Surface(SurfNum).SinTilt) > 0.5 || state.dataGlobal->DisplayExtraWarnings) {
2024 : // if horizontal surfaces, then these are windows/doors/etc in those items.
2025 0 : ShowWarningError(state, format("{}InterZone Surface Azimuths do not match as expected.", RoutineName));
2026 0 : ShowContinueError(state,
2027 0 : format(" Azimuth={:.1T}, Tilt={:.1T}, in Surface={}, Zone={}",
2028 0 : state.dataSurface->Surface(SurfNum).Azimuth,
2029 0 : state.dataSurface->Surface(SurfNum).Tilt,
2030 0 : state.dataSurface->Surface(SurfNum).Name,
2031 0 : state.dataSurface->Surface(SurfNum).ZoneName));
2032 0 : ShowContinueError(state,
2033 0 : format(" Azimuth={:.1T}, Tilt={:.1T}, in Surface={}, Zone={}",
2034 0 : state.dataSurface->Surface(Found).Azimuth,
2035 0 : state.dataSurface->Surface(Found).Tilt,
2036 0 : state.dataSurface->Surface(Found).Name,
2037 0 : state.dataSurface->Surface(Found).ZoneName));
2038 0 : ShowContinueError(
2039 : state,
2040 0 : format("..surface class of first surface={}", cSurfaceClass(state.dataSurface->Surface(SurfNum).Class)));
2041 0 : ShowContinueError(
2042 : state,
2043 0 : format("..surface class of second surface={}", cSurfaceClass(state.dataSurface->Surface(Found).Class)));
2044 : }
2045 : }
2046 : }
2047 :
2048 : // Make sure exposures (Sun, Wind) are the same.....and are "not"
2049 8913 : if (state.dataSurface->Surface(SurfNum).ExtSolar || state.dataSurface->Surface(Found).ExtSolar) {
2050 0 : ShowWarningError(state, format("{}Interzone surfaces cannot be \"SunExposed\" -- removing SunExposed", RoutineName));
2051 0 : ShowContinueError(state,
2052 0 : format(" Surface={}, Zone={}",
2053 0 : state.dataSurface->Surface(SurfNum).Name,
2054 0 : state.dataSurface->Surface(SurfNum).ZoneName));
2055 0 : ShowContinueError(state,
2056 0 : format(" Surface={}, Zone={}",
2057 0 : state.dataSurface->Surface(Found).Name,
2058 0 : state.dataSurface->Surface(Found).ZoneName));
2059 0 : state.dataSurface->Surface(SurfNum).ExtSolar = false;
2060 0 : state.dataSurface->Surface(Found).ExtSolar = false;
2061 : }
2062 8913 : if (state.dataSurface->Surface(SurfNum).ExtWind || state.dataSurface->Surface(Found).ExtWind) {
2063 0 : ShowWarningError(state,
2064 0 : format("{}Interzone surfaces cannot be \"WindExposed\" -- removing WindExposed", RoutineName));
2065 0 : ShowContinueError(state,
2066 0 : format(" Surface={}, Zone={}",
2067 0 : state.dataSurface->Surface(SurfNum).Name,
2068 0 : state.dataSurface->Surface(SurfNum).ZoneName));
2069 0 : ShowContinueError(state,
2070 0 : format(" Surface={}, Zone={}",
2071 0 : state.dataSurface->Surface(Found).Name,
2072 0 : state.dataSurface->Surface(Found).ZoneName));
2073 0 : state.dataSurface->Surface(SurfNum).ExtWind = false;
2074 0 : state.dataSurface->Surface(Found).ExtWind = false;
2075 : }
2076 : }
2077 : // Set opposing surface back to this one (regardless of error)
2078 15199 : state.dataSurface->Surface(Found).ExtBoundCond = SurfNum;
2079 : // Check subsurfaces... make sure base surface is also an interzone surface
2080 15199 : if (state.dataSurface->Surface(SurfNum).BaseSurf != SurfNum) { // Subsurface
2081 76 : if ((state.dataSurface->Surface(SurfNum).ExtBoundCond != SurfNum) &&
2082 38 : not_blank(state.dataSurface->Surface(SurfNum).ExtBoundCondName)) {
2083 : // if not internal subsurface
2084 38 : if (state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond ==
2085 38 : state.dataSurface->Surface(SurfNum).BaseSurf) {
2086 : // base surface is not interzone surface
2087 0 : ShowSevereError(state,
2088 0 : format("{}SubSurface=\"{}\" is an interzone subsurface.",
2089 : RoutineName,
2090 0 : state.dataSurface->Surface(SurfNum).Name));
2091 0 : ShowContinueError(state,
2092 0 : format("..but the Base Surface is not an interzone surface, Surface=\"{}\".",
2093 0 : state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Name));
2094 0 : SurfError = true;
2095 : }
2096 : }
2097 : }
2098 : } else {
2099 : // Seems unlikely that an internal surface would be missing itself, so this message
2100 : // only indicates for adjacent (interzone) surfaces.
2101 0 : ShowSevereError(state,
2102 0 : format("{}Adjacent Surface not found: {} adjacent to surface {}",
2103 : RoutineName,
2104 0 : state.dataSurface->Surface(SurfNum).ExtBoundCondName,
2105 0 : state.dataSurface->Surface(SurfNum).Name));
2106 0 : NonMatch = true;
2107 0 : SurfError = true;
2108 : }
2109 0 : } else if (state.dataSurface->Surface(SurfNum).BaseSurf != SurfNum) { // Subsurface
2110 0 : if (state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond > 0 &&
2111 0 : state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond !=
2112 0 : state.dataSurface->Surface(SurfNum).BaseSurf) { // If Interzone surface, subsurface must be also.
2113 0 : ShowSevereError(state, format("{}SubSurface on Interzone Surface must be an Interzone SubSurface.", RoutineName));
2114 0 : ShowContinueError(state,
2115 0 : format("...OutsideFaceEnvironment is blank, in Surface={}", state.dataSurface->Surface(SurfNum).Name));
2116 0 : SurfError = true;
2117 : } else {
2118 0 : ++state.dataSurfaceGeometry->ErrCount3;
2119 0 : if (state.dataSurfaceGeometry->ErrCount3 == 1 && !state.dataGlobal->DisplayExtraWarnings) {
2120 0 : ShowWarningError(state, format("{}Blank name for Outside Boundary Condition Objects.", RoutineName));
2121 0 : ShowContinueError(state, "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on individual surfaces.");
2122 : }
2123 0 : if (state.dataGlobal->DisplayExtraWarnings) {
2124 0 : ShowWarningError(state,
2125 0 : format("{}Blank name for Outside Boundary Condition Object, in surface={}",
2126 : RoutineName,
2127 0 : state.dataSurface->Surface(SurfNum).Name));
2128 0 : ShowContinueError(state,
2129 0 : format("Resetting this surface to be an internal zone surface, zone={}",
2130 0 : state.dataSurface->Surface(SurfNum).ZoneName));
2131 : }
2132 0 : state.dataSurface->Surface(SurfNum).ExtBoundCondName = state.dataSurface->Surface(SurfNum).Name;
2133 0 : state.dataSurface->Surface(SurfNum).ExtBoundCond = SurfNum;
2134 : }
2135 : } else {
2136 0 : ++state.dataSurfaceGeometry->ErrCount3;
2137 0 : if (state.dataSurfaceGeometry->ErrCount3 == 1 && !state.dataGlobal->DisplayExtraWarnings) {
2138 0 : ShowSevereError(state, format("{}Blank name for Outside Boundary Condition Objects.", RoutineName));
2139 0 : ShowContinueError(state, "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on individual surfaces.");
2140 : }
2141 0 : if (state.dataGlobal->DisplayExtraWarnings) {
2142 0 : ShowWarningError(state,
2143 0 : format("{}Blank name for Outside Boundary Condition Object, in surface={}",
2144 : RoutineName,
2145 0 : state.dataSurface->Surface(SurfNum).Name));
2146 0 : ShowContinueError(state,
2147 0 : format("Resetting this surface to be an internal zone (adiabatic) surface, zone={}",
2148 0 : state.dataSurface->Surface(SurfNum).ZoneName));
2149 : }
2150 0 : state.dataSurface->Surface(SurfNum).ExtBoundCondName = state.dataSurface->Surface(SurfNum).Name;
2151 0 : state.dataSurface->Surface(SurfNum).ExtBoundCond = SurfNum;
2152 0 : SurfError = true;
2153 : }
2154 : }
2155 :
2156 : } // ...end of the Surface DO loop for finding BaseSurf
2157 796 : if (NonMatch) {
2158 0 : ShowSevereError(state, format("{}Non matching interzone surfaces found", RoutineName));
2159 : }
2160 :
2161 : //**********************************************************************************
2162 : // Warn about interzone surfaces that have adiabatic windows/vice versa
2163 796 : SubSurfaceSevereDisplayed = false;
2164 46840 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
2165 46044 : if (!state.dataSurface->Surface(SurfNum).HeatTransSurf) continue;
2166 44408 : if (state.dataSurface->Surface(SurfNum).BaseSurf == SurfNum) continue; // base surface
2167 : // not base surface. Check it.
2168 6698 : if (state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond <= 0) { // exterior or other base surface
2169 6618 : if (state.dataSurface->Surface(SurfNum).ExtBoundCond !=
2170 6618 : state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond) { // should match base surface
2171 0 : if (state.dataSurface->Surface(SurfNum).ExtBoundCond == SurfNum) {
2172 0 : ShowSevereError(
2173 : state,
2174 0 : format("{}Subsurface=\"{}\" exterior condition [adiabatic surface] in a base surface=\"{}\" with exterior condition [{}]",
2175 : RoutineName,
2176 0 : state.dataSurface->Surface(SurfNum).Name,
2177 0 : state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Name,
2178 0 : cExtBoundCondition(state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond)));
2179 0 : SurfError = true;
2180 0 : } else if (state.dataSurface->Surface(SurfNum).ExtBoundCond > 0) {
2181 0 : ShowSevereError(
2182 : state,
2183 0 : format("{}Subsurface=\"{}\" exterior condition [interzone surface] in a base surface=\"{}\" with exterior condition [{}]",
2184 : RoutineName,
2185 0 : state.dataSurface->Surface(SurfNum).Name,
2186 0 : state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Name,
2187 0 : cExtBoundCondition(state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond)));
2188 0 : SurfError = true;
2189 0 : } else if (state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond == OtherSideCondModeledExt) {
2190 0 : ShowWarningError(
2191 : state,
2192 0 : format("{}Subsurface=\"{}\" exterior condition [{}] in a base surface=\"{}\" with exterior condition [{}]",
2193 : RoutineName,
2194 0 : state.dataSurface->Surface(SurfNum).Name,
2195 0 : cExtBoundCondition(state.dataSurface->Surface(SurfNum).ExtBoundCond),
2196 0 : state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Name,
2197 0 : cExtBoundCondition(state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond)));
2198 0 : ShowContinueError(state, "...SubSurface will not use the exterior condition model of the base surface.");
2199 : } else {
2200 0 : ShowSevereError(
2201 : state,
2202 0 : format("{}Subsurface=\"{}\" exterior condition [{}] in a base surface=\"{}\" with exterior condition [{}]",
2203 : RoutineName,
2204 0 : state.dataSurface->Surface(SurfNum).Name,
2205 0 : cExtBoundCondition(state.dataSurface->Surface(SurfNum).ExtBoundCond),
2206 0 : state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Name,
2207 0 : cExtBoundCondition(state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond)));
2208 0 : SurfError = true;
2209 : }
2210 0 : if (!SubSurfaceSevereDisplayed && SurfError) {
2211 0 : ShowContinueError(state, "...calculations for heat balance would be compromised.");
2212 0 : SubSurfaceSevereDisplayed = true;
2213 : }
2214 : }
2215 80 : } else if (state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).BaseSurf ==
2216 80 : state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond) {
2217 : // adiabatic surface. make sure subsurfaces match
2218 0 : if (state.dataSurface->Surface(SurfNum).ExtBoundCond != SurfNum) { // not adiabatic surface
2219 0 : if (state.dataSurface->Surface(SurfNum).ExtBoundCond > 0) {
2220 0 : ShowSevereError(state,
2221 0 : format("{}Subsurface=\"{}\" exterior condition [interzone surface] in a base surface=\"{}\" with exterior "
2222 : "condition [adiabatic surface]",
2223 : RoutineName,
2224 0 : state.dataSurface->Surface(SurfNum).Name,
2225 0 : state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Name));
2226 : } else {
2227 0 : ShowSevereError(
2228 : state,
2229 0 : format("{}Subsurface=\"{}\" exterior condition [{}] in a base surface=\"{}\" with exterior condition [adiabatic surface]",
2230 : RoutineName,
2231 0 : state.dataSurface->Surface(SurfNum).Name,
2232 0 : cExtBoundCondition(state.dataSurface->Surface(SurfNum).ExtBoundCond),
2233 0 : state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Name));
2234 : }
2235 0 : if (!SubSurfaceSevereDisplayed) {
2236 0 : ShowContinueError(state, "...calculations for heat balance would be compromised.");
2237 0 : SubSurfaceSevereDisplayed = true;
2238 : }
2239 0 : SurfError = true;
2240 : }
2241 80 : } else if (state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond > 0) { // interzone surface
2242 80 : if (state.dataSurface->Surface(SurfNum).ExtBoundCond == SurfNum) {
2243 0 : ShowSevereError(state,
2244 0 : format("{}Subsurface=\"{}\" is an adiabatic surface in an Interzone base surface=\"{}\"",
2245 : RoutineName,
2246 0 : state.dataSurface->Surface(SurfNum).Name,
2247 0 : state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Name));
2248 0 : if (!SubSurfaceSevereDisplayed) {
2249 0 : ShowContinueError(state, "...calculations for heat balance would be compromised.");
2250 0 : SubSurfaceSevereDisplayed = true;
2251 : }
2252 : // SurfError=.TRUE.
2253 : }
2254 : }
2255 : }
2256 :
2257 796 : setSurfaceFirstLast(state);
2258 :
2259 : // Set up Floor Areas for Zones and Spaces
2260 796 : Real64 constexpr floorAreaTolerance(0.05);
2261 796 : Real64 constexpr floorAreaPercentTolerance(floorAreaTolerance * 100.0);
2262 796 : if (!SurfError) {
2263 5852 : for (auto &thisZone : state.dataHeatBal->Zone) {
2264 10124 : for (int spaceNum : thisZone.spaceIndexes) {
2265 5068 : auto &thisSpace = state.dataHeatBal->space(spaceNum);
2266 49458 : for (int SurfNum = thisSpace.HTSurfaceFirst; SurfNum <= thisSpace.HTSurfaceLast; ++SurfNum) {
2267 44390 : auto &thisSurf = state.dataSurface->Surface(SurfNum);
2268 44390 : if (thisSurf.Class == SurfaceClass::Floor) {
2269 6890 : thisZone.HasFloor = true;
2270 6890 : thisSpace.hasFloor = true;
2271 6890 : thisSpace.calcFloorArea += thisSurf.Area;
2272 : }
2273 44390 : if (thisSurf.Class == SurfaceClass::Roof) {
2274 5801 : thisZone.CeilingArea += thisSurf.Area;
2275 5801 : thisZone.HasRoof = true;
2276 : }
2277 : }
2278 5056 : }
2279 796 : }
2280 796 : ErrCount = 0;
2281 5877 : for (auto &thisSpace : state.dataHeatBal->space) {
2282 5081 : if (thisSpace.userEnteredFloorArea != Constant::AutoCalculate) {
2283 : // Check entered vs calculated
2284 0 : if (thisSpace.userEnteredFloorArea > 0.0) { // User entered Space floor area,
2285 : // produce message if not near calculated
2286 0 : if (thisSpace.calcFloorArea > 0.0) {
2287 0 : Real64 diffp = std::abs(thisSpace.calcFloorArea - thisSpace.userEnteredFloorArea) / thisSpace.userEnteredFloorArea;
2288 0 : if (diffp > floorAreaTolerance) {
2289 0 : ++ErrCount;
2290 0 : if (ErrCount == 1 && !state.dataGlobal->DisplayExtraWarnings) {
2291 0 : ShowWarningError(
2292 : state,
2293 0 : format("{}Entered Space Floor Area(s) differ more than {:.0R}% from calculated Space Floor Area(s).",
2294 0 : std::string(RoutineName),
2295 : floorAreaPercentTolerance));
2296 0 : ShowContinueError(state,
2297 : "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on individual Spaces.");
2298 : }
2299 0 : if (state.dataGlobal->DisplayExtraWarnings) {
2300 : // Warn user of using specified Space Floor Area
2301 0 : ShowWarningError(
2302 : state,
2303 0 : format("{}Entered Floor Area for Space=\"{}\" is {:.1R}% different from the calculated Floor Area.",
2304 0 : std::string(RoutineName),
2305 0 : thisSpace.Name,
2306 0 : diffp * 100.0));
2307 0 : ShowContinueError(state,
2308 0 : format("Entered Space Floor Area={:.2R}, Calculated Space Floor Area={:.2R}, entered "
2309 : "Floor Area will be used.",
2310 0 : thisSpace.userEnteredFloorArea,
2311 0 : thisSpace.calcFloorArea));
2312 : }
2313 : }
2314 : }
2315 0 : thisSpace.FloorArea = thisSpace.userEnteredFloorArea;
2316 0 : thisSpace.hasFloor = true;
2317 : }
2318 : } else {
2319 5081 : thisSpace.FloorArea = thisSpace.calcFloorArea;
2320 : }
2321 796 : }
2322 796 : ErrCount = 0;
2323 5852 : for (auto &thisZone : state.dataHeatBal->Zone) {
2324 : // Calculate zone floor area as sum of space floor areas
2325 10124 : for (int spaceNum : thisZone.spaceIndexes) {
2326 5068 : thisZone.CalcFloorArea += state.dataHeatBal->space(spaceNum).FloorArea;
2327 5068 : thisZone.HasFloor |= state.dataHeatBal->space(spaceNum).hasFloor;
2328 5056 : }
2329 5056 : if (thisZone.UserEnteredFloorArea != Constant::AutoCalculate) {
2330 : // Check entered vs calculated
2331 4 : if (thisZone.UserEnteredFloorArea > 0.0) { // User entered zone floor area,
2332 : // produce message if not near calculated
2333 4 : if (thisZone.CalcFloorArea > 0.0) {
2334 4 : Real64 diffp = std::abs(thisZone.CalcFloorArea - thisZone.UserEnteredFloorArea) / thisZone.UserEnteredFloorArea;
2335 4 : if (diffp > 0.05) {
2336 1 : ++ErrCount;
2337 1 : if (ErrCount == 1 && !state.dataGlobal->DisplayExtraWarnings) {
2338 2 : ShowWarningError(
2339 : state,
2340 2 : format("{}Entered Zone Floor Area(s) differ more than {:.0R}% from the sum of the Space Floor Area(s).",
2341 2 : std::string(RoutineName),
2342 : floorAreaPercentTolerance));
2343 1 : ShowContinueError(state,
2344 : "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on individual zones.");
2345 : }
2346 1 : if (state.dataGlobal->DisplayExtraWarnings) {
2347 : // Warn user of using specified Zone Floor Area
2348 0 : ShowWarningError(state,
2349 0 : format("{}Entered Floor Area for Zone=\"{}\" is {:.1R}% different from the sum of the "
2350 : "Space Floor Area(s).",
2351 0 : std::string(RoutineName),
2352 0 : thisZone.Name,
2353 0 : diffp * 100.0));
2354 0 : ShowContinueError(state,
2355 0 : format("Entered Zone Floor Area={:.2R}, Sum of Space Floor Area(s)={:.2R}",
2356 0 : thisZone.UserEnteredFloorArea,
2357 0 : thisZone.CalcFloorArea));
2358 0 : ShowContinueError(
2359 : state, "Entered Zone Floor Area will be used and Space Floor Area(s) will be adjusted proportionately.");
2360 : }
2361 : }
2362 : }
2363 4 : thisZone.FloorArea = thisZone.UserEnteredFloorArea;
2364 4 : thisZone.HasFloor = true;
2365 :
2366 : // Adjust space floor areas to match zone floor area
2367 4 : if (thisZone.numSpaces == 1) {
2368 : // If the zone contains only one space, then set the Space area to the Zone area
2369 4 : int spaceNum = thisZone.spaceIndexes(1);
2370 4 : state.dataHeatBal->space(spaceNum).FloorArea = thisZone.FloorArea;
2371 0 : } else if (thisZone.CalcFloorArea > 0.0) {
2372 : // Adjust space areas proportionately
2373 0 : Real64 areaRatio = thisZone.FloorArea / thisZone.CalcFloorArea;
2374 0 : for (int spaceNum : thisZone.spaceIndexes) {
2375 0 : state.dataHeatBal->space(spaceNum).FloorArea *= areaRatio;
2376 0 : }
2377 : } else {
2378 0 : if (state.dataGlobal->DisplayExtraWarnings) {
2379 : // Warn if calculated floor area was zero and there is more than one Space
2380 0 : ShowWarningError(
2381 : state,
2382 0 : format("{}Entered Floor Area entered for Zone=\"{}\" significantly different from sum of Space Floor Areas",
2383 : RoutineName,
2384 0 : thisZone.Name));
2385 0 : ShowContinueError(state,
2386 : "But the sum of the Space Floor Areas is zero and there is more than one Space in the zone."
2387 : "Unable to apportion the zone floor area. Space Floor Areas are zero.");
2388 : }
2389 : }
2390 : } else {
2391 0 : if (thisZone.CalcFloorArea > 0.0) thisZone.FloorArea = thisZone.CalcFloorArea;
2392 : }
2393 : } else {
2394 5052 : thisZone.FloorArea = thisZone.CalcFloorArea;
2395 : }
2396 5056 : Real64 totSpacesFloorArea = 0.0;
2397 10124 : for (int spaceNum : thisZone.spaceIndexes) {
2398 5068 : totSpacesFloorArea += state.dataHeatBal->space(spaceNum).FloorArea;
2399 5056 : }
2400 5056 : if (totSpacesFloorArea > 0.0) {
2401 10120 : for (int spaceNum : thisZone.spaceIndexes) {
2402 5066 : state.dataHeatBal->space(spaceNum).fracZoneFloorArea = state.dataHeatBal->space(spaceNum).FloorArea / totSpacesFloorArea;
2403 5054 : }
2404 : } // else leave fractions at zero
2405 796 : }
2406 : }
2407 :
2408 46840 : for (int SurfNum = 1; SurfNum <= MovedSurfs; ++SurfNum) { // TotSurfaces
2409 46044 : if (state.dataSurface->Surface(SurfNum).Area < 1.e-06) {
2410 0 : ShowSevereError(state,
2411 0 : format("{}Zero or negative surface area[{:.5R}], Surface={}",
2412 : RoutineName,
2413 0 : state.dataSurface->Surface(SurfNum).Area,
2414 0 : state.dataSurface->Surface(SurfNum).Name));
2415 0 : SurfError = true;
2416 : }
2417 46044 : if (state.dataSurface->Surface(SurfNum).Area >= 1.e-06 && state.dataSurface->Surface(SurfNum).Area < 0.001) {
2418 0 : ShowWarningError(state,
2419 0 : format("{}Very small surface area[{:.5R}], Surface={}",
2420 : RoutineName,
2421 0 : state.dataSurface->Surface(SurfNum).Area,
2422 0 : state.dataSurface->Surface(SurfNum).Name));
2423 : }
2424 : }
2425 :
2426 46840 : for (int SurfNum = 1; SurfNum <= MovedSurfs; ++SurfNum) { // TotSurfaces
2427 46044 : auto &surf = state.dataSurface->Surface(SurfNum);
2428 : // GLASSDOORs and TDD:DIFFUSERs will be treated as windows in the subsequent heat transfer and daylighting
2429 : // calculations. Reset class to 'Window' after saving the original designation in SurfaceWindow.
2430 :
2431 46044 : surf.OriginalClass = surf.Class;
2432 :
2433 46044 : if (surf.Class == SurfaceClass::GlassDoor || surf.Class == SurfaceClass::TDD_Diffuser) surf.Class = SurfaceClass::Window;
2434 :
2435 46044 : if (surf.Class == SurfaceClass::TDD_Dome) {
2436 : // Reset the TDD:DOME subsurface to act as a base surface that can shade and be shaded
2437 : // NOTE: This must be set early so that subsequent shading calculations are done correctly
2438 2 : surf.BaseSurf = SurfNum;
2439 : }
2440 : }
2441 :
2442 796 : errFlag = false;
2443 796 : if (!SurfError) {
2444 46840 : for (int SurfNum = 1; SurfNum <= MovedSurfs; ++SurfNum) { // TotSurfaces
2445 46044 : auto &surf = state.dataSurface->Surface(SurfNum);
2446 46044 : if (surf.HasShadeControl) {
2447 151 : WinShadingControlPtr = surf.activeWindowShadingControl; // use first item since others should be identical
2448 151 : if (state.dataSurface->WindowShadingControl(WinShadingControlPtr).slatAngleControl != SlatAngleControl::Fixed) {
2449 3 : state.dataSurface->SurfWinMovableSlats(SurfNum) = true;
2450 3 : state.dataSurface->AnyMovableSlat = true;
2451 3 : state.dataHeatBalSurf->SurfMovSlatsIndexList.push_back(SurfNum);
2452 : }
2453 :
2454 151 : ConstrNumSh = surf.activeShadedConstruction;
2455 151 : if (ConstrNumSh <= 0) continue;
2456 :
2457 151 : WinShadingType ShadingType = state.dataSurface->WindowShadingControl(WinShadingControlPtr).ShadingType;
2458 :
2459 : // only for blinds
2460 151 : if (ANY_BLIND(ShadingType)) {
2461 :
2462 : // TH 1/7/2010. CR 7930
2463 : // The old code did not consider between-glass blind. Also there should not be two blinds - both interior and exterior
2464 : // Use the new generic code (assuming only one blind) as follows
2465 91 : for (iTmp1 = 1; iTmp1 <= state.dataConstruction->Construct(ConstrNumSh).TotLayers; ++iTmp1) {
2466 91 : iTmp2 = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(iTmp1);
2467 91 : auto *mat = state.dataMaterial->Material(iTmp2);
2468 :
2469 91 : if (mat->group != Material::Group::WindowBlind) continue;
2470 :
2471 42 : auto *matBlind = dynamic_cast<Material::MaterialChild *>(mat);
2472 42 : assert(matBlind != nullptr);
2473 :
2474 42 : BlNum = matBlind->BlindDataPtr;
2475 42 : state.dataSurface->SurfWinBlindNumber(SurfNum) = BlNum;
2476 : // TH 2/18/2010. CR 8010
2477 : // if it is a blind with movable slats, create one new blind and set it to VariableSlat if not done so yet.
2478 : // the new blind is created only once, it can be shared by multiple windows though.
2479 45 : if (state.dataSurface->SurfWinMovableSlats(SurfNum) &&
2480 3 : state.dataMaterial->Blind(BlNum).SlatAngleType != DataWindowEquivalentLayer::AngleType::Variable) {
2481 3 : errFlag = false;
2482 3 : AddVariableSlatBlind(state, BlNum, BlNumNew, errFlag);
2483 : // point to the new blind
2484 3 : matBlind->BlindDataPtr = BlNumNew;
2485 : // window surface points to new blind
2486 3 : state.dataSurface->SurfWinBlindNumber(SurfNum) = BlNumNew;
2487 : }
2488 42 : break;
2489 : }
2490 :
2491 42 : if (errFlag) {
2492 0 : ErrorsFound = true;
2493 0 : ShowContinueError(state,
2494 0 : format("WindowShadingControl {} has errors, program will terminate.",
2495 0 : state.dataSurface->WindowShadingControl(WinShadingControlPtr).Name));
2496 : }
2497 : }
2498 : } // End of surface loop
2499 :
2500 : // final associate fenestration surfaces referenced in WindowShadingControl
2501 46044 : FinalAssociateWindowShadingControlFenestration(state, ErrorsFound);
2502 46044 : CheckWindowShadingControlSimilarForWindow(state, ErrorsFound);
2503 : }
2504 :
2505 : // Check for zones with not enough surfaces
2506 5852 : for (auto &thisZone : state.dataHeatBal->Zone) {
2507 5056 : int OpaqueHTSurfs = 0; // Number of floors, walls and roofs in a zone
2508 5056 : int OpaqueHTSurfsWithWin = 0; // Number of floors, walls and roofs with windows in a zone
2509 5056 : int InternalMassSurfs = 0; // Number of internal mass surfaces in a zone
2510 5056 : int priorBaseSurfNum = 0;
2511 :
2512 10124 : for (int spaceNum : thisZone.spaceIndexes) {
2513 5068 : auto &thisSpace = state.dataHeatBal->space(spaceNum);
2514 5068 : if (thisSpace.HTSurfaceFirst == 0) continue; // Zone with no surfaces
2515 49458 : for (int SurfNum = thisSpace.HTSurfaceFirst; SurfNum <= thisSpace.HTSurfaceLast; ++SurfNum) {
2516 44390 : auto &thisSurf = state.dataSurface->Surface(SurfNum);
2517 44390 : if (thisSurf.Class == SurfaceClass::Floor || thisSurf.Class == SurfaceClass::Wall || thisSurf.Class == SurfaceClass::Roof)
2518 35294 : ++OpaqueHTSurfs;
2519 44390 : if (thisSurf.Class == SurfaceClass::IntMass) ++InternalMassSurfs;
2520 44390 : if (thisSurf.Class == SurfaceClass::Window) {
2521 : // Count base surface only once for multiple windows on a wall
2522 6217 : int thisBaseSurfNum = thisSurf.BaseSurf;
2523 6217 : if (thisBaseSurfNum != priorBaseSurfNum) {
2524 4133 : ++OpaqueHTSurfsWithWin;
2525 4133 : priorBaseSurfNum = thisBaseSurfNum;
2526 : }
2527 : }
2528 : }
2529 5056 : }
2530 5056 : if (OpaqueHTSurfsWithWin == 1 && OpaqueHTSurfs == 1 && InternalMassSurfs == 0) {
2531 0 : SurfError = true;
2532 0 : ShowSevereError(state,
2533 0 : format("{}Zone {} has only one floor, wall or roof, and this surface has a window.", RoutineName, thisZone.Name));
2534 0 : ShowContinueError(state, "Add more floors, walls or roofs, or an internal mass surface.");
2535 : }
2536 796 : }
2537 :
2538 : // set up vertex of centroid for each surface.
2539 796 : CalcSurfaceCentroid(state);
2540 :
2541 796 : SetupShadeSurfacesForSolarCalcs(state); // if shading surfaces are solar collectors or PV, then we need full solar calc.
2542 :
2543 796 : GetMovableInsulationData(state, ErrorsFound);
2544 :
2545 796 : if (state.dataSurface->CalcSolRefl) GetShadingSurfReflectanceData(state, ErrorsFound);
2546 :
2547 796 : LayNumOutside = 0;
2548 46840 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
2549 46044 : auto &surf = state.dataSurface->Surface(SurfNum);
2550 : // Check for EcoRoof and only 1 allowed to be used.
2551 46044 : if (surf.Construction > 0)
2552 44408 : state.dataSurface->SurfExtEcoRoof(SurfNum) = state.dataConstruction->Construct(surf.Construction).TypeIsEcoRoof;
2553 46044 : if (!state.dataSurface->SurfExtEcoRoof(SurfNum)) continue;
2554 20 : if (LayNumOutside == 0) {
2555 4 : LayNumOutside = state.dataConstruction->Construct(surf.Construction).LayerPoint(1);
2556 4 : continue;
2557 : }
2558 16 : if (LayNumOutside != state.dataConstruction->Construct(surf.Construction).LayerPoint(1)) {
2559 0 : ShowSevereError(state, format("{}Only one EcoRoof Material is currently allowed for all constructions.", RoutineName));
2560 0 : ShowContinueError(state, format("... first material={}", state.dataMaterial->Material(LayNumOutside)->Name));
2561 0 : ShowContinueError(state,
2562 0 : format("... conflicting Construction={} uses material={}",
2563 0 : state.dataConstruction->Construct(surf.Construction).Name,
2564 0 : state.dataMaterial->Material(state.dataConstruction->Construct(surf.Construction).LayerPoint(1))->Name));
2565 0 : ErrorsFound = true;
2566 : }
2567 : }
2568 :
2569 : // Reserve space to avoid excess allocations
2570 796 : state.dataSurface->AllHTSurfaceList.reserve(state.dataSurface->TotSurfaces);
2571 796 : state.dataSurface->AllExtSolarSurfaceList.reserve(state.dataSurface->TotSurfaces);
2572 796 : state.dataSurface->AllShadowPossObstrSurfaceList.reserve(state.dataSurface->TotSurfaces);
2573 796 : state.dataSurface->AllIZSurfaceList.reserve(state.dataSurface->TotSurfaces);
2574 796 : state.dataSurface->AllHTNonWindowSurfaceList.reserve(state.dataSurface->TotSurfaces - state.dataSurface->TotWindows);
2575 796 : state.dataSurface->AllHTWindowSurfaceList.reserve(state.dataSurface->TotWindows);
2576 796 : state.dataSurface->AllExtSolWindowSurfaceList.reserve(state.dataSurface->TotWindows);
2577 796 : state.dataSurface->AllExtSolWinWithFrameSurfaceList.reserve(state.dataSurface->TotWindows);
2578 796 : state.dataSurface->AllHTKivaSurfaceList.reserve(state.dataSurface->TotSurfaces);
2579 :
2580 : // Set flag that determines whether a surface can be an exterior obstruction
2581 : // Also set associated surfaces for Kiva foundations and build heat transfer surface lists
2582 46840 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
2583 46044 : auto &surf = state.dataSurface->Surface(SurfNum);
2584 46044 : surf.IsShadowPossibleObstruction = false;
2585 46044 : if (surf.ExtSolar) {
2586 : // This may include some attached shading surfaces
2587 19332 : state.dataSurface->AllExtSolarSurfaceList.push_back(SurfNum);
2588 : }
2589 46044 : if (surf.HeatTransSurf) {
2590 : // Outside light shelves get tagged later as HeatTransSurf=true but they haven't been processed yet
2591 44390 : state.dataSurface->AllHTSurfaceList.push_back(SurfNum);
2592 44390 : int const zoneNum(surf.Zone);
2593 44390 : auto &surfZone(state.dataHeatBal->Zone(zoneNum));
2594 44390 : surfZone.ZoneHTSurfaceList.push_back(SurfNum);
2595 : // Sort window vs non-window surfaces
2596 44390 : if (surf.Class == DataSurfaces::SurfaceClass::Window) {
2597 6217 : state.dataSurface->AllHTWindowSurfaceList.push_back(SurfNum);
2598 6217 : surfZone.ZoneHTWindowSurfaceList.push_back(SurfNum);
2599 6217 : if (surf.ExtSolar) {
2600 6201 : state.dataSurface->AllExtSolWindowSurfaceList.push_back(SurfNum);
2601 6201 : if (surf.FrameDivider > 0) {
2602 381 : state.dataSurface->AllExtSolWinWithFrameSurfaceList.push_back(SurfNum);
2603 : }
2604 : }
2605 : } else {
2606 38173 : state.dataSurface->AllHTNonWindowSurfaceList.push_back(SurfNum);
2607 38173 : surfZone.ZoneHTNonWindowSurfaceList.push_back(SurfNum);
2608 : }
2609 44390 : int const surfExtBoundCond(surf.ExtBoundCond);
2610 : // Build zone and interzone surface lists
2611 44390 : if ((surfExtBoundCond > 0) && (surfExtBoundCond != SurfNum)) {
2612 17806 : state.dataSurface->AllIZSurfaceList.push_back(SurfNum);
2613 17806 : surfZone.ZoneIZSurfaceList.push_back(SurfNum);
2614 17806 : auto &adjZone(state.dataHeatBal->Zone(state.dataSurface->Surface(surfExtBoundCond).Zone));
2615 17806 : adjZone.ZoneHTSurfaceList.push_back(SurfNum);
2616 17806 : adjZone.ZoneIZSurfaceList.push_back(SurfNum);
2617 : // Sort window vs non-window surfaces
2618 17806 : if (surf.Class == DataSurfaces::SurfaceClass::Window) {
2619 14 : adjZone.ZoneHTWindowSurfaceList.push_back(SurfNum);
2620 : } else {
2621 17792 : adjZone.ZoneHTNonWindowSurfaceList.push_back(SurfNum);
2622 : }
2623 : }
2624 : }
2625 :
2626 : // Exclude non-exterior heat transfer surfaces (but not OtherSideCondModeledExt = -4 CR7640)
2627 46044 : if (surf.HeatTransSurf && surf.ExtBoundCond > 0) continue;
2628 21964 : if (surf.HeatTransSurf && surf.ExtBoundCond == Ground) continue;
2629 19763 : if (surf.HeatTransSurf && surf.ExtBoundCond == KivaFoundation) {
2630 38 : state.dataSurface->AllHTKivaSurfaceList.push_back(SurfNum);
2631 38 : if (!ErrorsFound) state.dataSurfaceGeometry->kivaManager.foundationInputs[surf.OSCPtr].surfaces.push_back(SurfNum);
2632 38 : continue;
2633 : }
2634 19725 : if (surf.HeatTransSurf && surf.ExtBoundCond == OtherSideCoefNoCalcExt) continue;
2635 19693 : if (surf.HeatTransSurf && surf.ExtBoundCond == OtherSideCoefCalcExt) continue;
2636 : // Exclude windows and doors, i.e., consider only their base surfaces as possible obstructions
2637 19692 : if (surf.Class == SurfaceClass::Window || surf.Class == SurfaceClass::Door) continue;
2638 : // Exclude duplicate shading surfaces
2639 13091 : if (surf.MirroredSurf) continue;
2640 : // Exclude air boundary surfaces
2641 12273 : if (surf.IsAirBoundarySurf) continue;
2642 :
2643 12255 : surf.IsShadowPossibleObstruction = true;
2644 12255 : state.dataSurface->AllShadowPossObstrSurfaceList.push_back(SurfNum);
2645 : }
2646 :
2647 : // Check for IRT surfaces in invalid places.
2648 796 : iTmp1 = 0;
2649 796 : if (std::any_of(state.dataConstruction->Construct.begin(),
2650 796 : state.dataConstruction->Construct.end(),
2651 6022 : [](Construction::ConstructionProps const &e) { return e.TypeIsIRT; })) {
2652 76 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
2653 74 : auto &surf = state.dataSurface->Surface(SurfNum);
2654 74 : if (!surf.HeatTransSurf) continue; // ignore shading surfaces
2655 74 : if (surf.ExtBoundCond > 0 && surf.ExtBoundCond != SurfNum) continue; // interzone, not adiabatic surface
2656 46 : if (!state.dataConstruction->Construct(surf.Construction).TypeIsIRT) {
2657 46 : continue;
2658 : }
2659 0 : if (!state.dataGlobal->DisplayExtraWarnings) {
2660 0 : ++iTmp1;
2661 : } else {
2662 0 : ShowWarningError(state,
2663 0 : format("{}Surface=\"{}\" uses InfraredTransparent construction in a non-interzone surface. (illegal use)",
2664 : RoutineName,
2665 0 : surf.Name));
2666 : }
2667 : }
2668 2 : if (iTmp1 > 0) {
2669 0 : ShowWarningError(
2670 : state,
2671 0 : format("{}Surfaces use InfraredTransparent constructions {} in non-interzone surfaces. (illegal use)", RoutineName, iTmp1));
2672 0 : ShowContinueError(state, "For explicit details on each use, use Output:Diagnostics,DisplayExtraWarnings;");
2673 : }
2674 : }
2675 :
2676 : // Populate SurfaceFilter lists
2677 8756 : for (int iSurfaceFilter = 1; iSurfaceFilter < static_cast<int>(SurfaceFilter::Num); ++iSurfaceFilter)
2678 7960 : state.dataSurface->SurfaceFilterLists[iSurfaceFilter].reserve(state.dataSurface->TotSurfaces);
2679 :
2680 46840 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
2681 46044 : auto const &surf = state.dataSurface->Surface(SurfNum);
2682 46044 : if (!surf.HeatTransSurf) continue;
2683 44390 : if (surf.ExtBoundCond > 0) {
2684 24080 : state.dataSurface->SurfaceFilterLists[static_cast<int>(SurfaceFilter::AllInteriorSurfaces)].push_back(SurfNum);
2685 24080 : if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) {
2686 14 : state.dataSurface->SurfaceFilterLists[static_cast<int>(SurfaceFilter::AllInteriorWindows)].push_back(SurfNum);
2687 24066 : } else if (surf.Class == SurfaceClass::Wall) {
2688 13478 : state.dataSurface->SurfaceFilterLists[static_cast<int>(SurfaceFilter::AllInteriorWalls)].push_back(SurfNum);
2689 10588 : } else if (surf.Class == SurfaceClass::Floor) {
2690 4548 : state.dataSurface->SurfaceFilterLists[static_cast<int>(SurfaceFilter::AllInteriorFloors)].push_back(SurfNum);
2691 6040 : } else if (surf.Class == SurfaceClass::Roof) {
2692 3578 : state.dataSurface->SurfaceFilterLists[static_cast<int>(SurfaceFilter::AllInteriorRoofs)].push_back(SurfNum);
2693 3578 : state.dataSurface->SurfaceFilterLists[static_cast<int>(SurfaceFilter::AllInteriorCeilings)].push_back(SurfNum);
2694 : }
2695 : } else {
2696 20310 : state.dataSurface->SurfaceFilterLists[static_cast<int>(SurfaceFilter::AllExteriorSurfaces)].push_back(SurfNum);
2697 20310 : if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) {
2698 6205 : state.dataSurface->SurfaceFilterLists[static_cast<int>(SurfaceFilter::AllExteriorWindows)].push_back(SurfNum);
2699 14105 : } else if (surf.Class == SurfaceClass::Wall) {
2700 9125 : state.dataSurface->SurfaceFilterLists[static_cast<int>(SurfaceFilter::AllExteriorWalls)].push_back(SurfNum);
2701 4980 : } else if (surf.Class == SurfaceClass::Floor) {
2702 2342 : state.dataSurface->SurfaceFilterLists[static_cast<int>(SurfaceFilter::AllExteriorFloors)].push_back(SurfNum);
2703 2638 : } else if (surf.Class == SurfaceClass::Roof) {
2704 2223 : state.dataSurface->SurfaceFilterLists[static_cast<int>(SurfaceFilter::AllExteriorRoofs)].push_back(SurfNum);
2705 2223 : state.dataSurface->SurfaceFilterLists[static_cast<int>(SurfaceFilter::AllInteriorCeilings)].push_back(SurfNum);
2706 : }
2707 : }
2708 : }
2709 :
2710 : // Note, could do same for Window Area and detecting if Interzone Surface in Zone
2711 :
2712 796 : if (state.dataSurfaceGeometry->Warning1Count > 0) {
2713 10 : ShowWarningMessage(state,
2714 10 : format("{}Window dimensions differ from Window 5/6 data file dimensions, {} times.",
2715 : RoutineName,
2716 5 : state.dataSurfaceGeometry->Warning1Count));
2717 5 : ShowContinueError(state, "This will affect the frame heat transfer calculation if the frame in the Data File entry");
2718 5 : ShowContinueError(state, "is not uniform, i.e., has sections with different geometry and/or thermal properties.");
2719 5 : ShowContinueError(state, "For explicit details on each window, use Output:Diagnostics,DisplayExtraWarnings;");
2720 : }
2721 796 : if (state.dataSurfaceGeometry->Warning2Count > 0) {
2722 0 : ShowWarningMessage(state,
2723 0 : format("{}Exterior Windows have been replaced with Window 5/6 two glazing systems, {} times.",
2724 : RoutineName,
2725 0 : state.dataSurfaceGeometry->Warning2Count));
2726 0 : ShowContinueError(state, "Note that originally entered dimensions are overridden.");
2727 0 : ShowContinueError(state, "For explicit details on each window, use Output:Diagnostics,DisplayExtraWarnings;");
2728 : }
2729 796 : if (state.dataSurfaceGeometry->Warning3Count > 0) {
2730 0 : ShowWarningMessage(state,
2731 0 : format("{}Interior Windows have been replaced with Window 5/6 two glazing systems, {} times.",
2732 : RoutineName,
2733 0 : state.dataSurfaceGeometry->Warning3Count));
2734 0 : ShowContinueError(state, "Note that originally entered dimensions are overridden.");
2735 0 : ShowContinueError(state, "For explicit details on each window, use Output:Diagnostics,DisplayExtraWarnings;");
2736 : }
2737 :
2738 796 : if (state.dataErrTracking->TotalMultipliedWindows > 0) {
2739 2 : ShowWarningMessage(state,
2740 2 : format("{}There are {} window/glass door(s) that may cause inaccurate shadowing due to Solar Distribution.",
2741 : RoutineName,
2742 1 : state.dataErrTracking->TotalMultipliedWindows));
2743 1 : ShowContinueError(state, "For explicit details on each window, use Output:Diagnostics,DisplayExtraWarnings;");
2744 1 : state.dataErrTracking->TotalWarningErrors += state.dataErrTracking->TotalMultipliedWindows;
2745 : }
2746 796 : if (state.dataErrTracking->TotalCoincidentVertices > 0) {
2747 0 : ShowWarningMessage(state,
2748 0 : format("{}There are {} coincident/collinear vertices; These have been deleted unless the deletion would bring the "
2749 : "number of surface sides < 3.",
2750 : RoutineName,
2751 0 : state.dataErrTracking->TotalCoincidentVertices));
2752 0 : ShowContinueError(state, "For explicit details on each problem surface, use Output:Diagnostics,DisplayExtraWarnings;");
2753 0 : state.dataErrTracking->TotalWarningErrors += state.dataErrTracking->TotalCoincidentVertices;
2754 : }
2755 796 : if (state.dataErrTracking->TotalDegenerateSurfaces > 0) {
2756 0 : ShowSevereMessage(state,
2757 0 : format("{}There are {} degenerate surfaces; Degenerate surfaces are those with number of sides < 3.",
2758 : RoutineName,
2759 0 : state.dataErrTracking->TotalDegenerateSurfaces));
2760 0 : ShowContinueError(state, "These surfaces should be deleted.");
2761 0 : ShowContinueError(state, "For explicit details on each problem surface, use Output:Diagnostics,DisplayExtraWarnings;");
2762 0 : state.dataErrTracking->TotalSevereErrors += state.dataErrTracking->TotalDegenerateSurfaces;
2763 : }
2764 :
2765 796 : GetHTSurfExtVentedCavityData(state, ErrorsFound);
2766 :
2767 796 : state.dataSurfaceGeometry->exposedFoundationPerimeter.getData(state, ErrorsFound);
2768 :
2769 796 : GetSurfaceHeatTransferAlgorithmOverrides(state, ErrorsFound);
2770 :
2771 : // Set up enclosures, process Air Boundaries if any
2772 796 : SetupEnclosuresAndAirBoundaries(state, state.dataViewFactor->EnclRadInfo, SurfaceGeometry::enclosureType::RadiantEnclosures, ErrorsFound);
2773 :
2774 796 : GetSurfaceGroundSurfsData(state, ErrorsFound);
2775 :
2776 796 : GetSurfaceSrdSurfsData(state, ErrorsFound);
2777 :
2778 796 : GetSurfaceLocalEnvData(state, ErrorsFound);
2779 :
2780 796 : if (SurfError || ErrorsFound) {
2781 0 : ErrorsFound = true;
2782 0 : ShowFatalError(state, format("{}Errors discovered, program terminates.", RoutineName));
2783 : }
2784 :
2785 796 : int TotShadSurf = TotDetachedFixed + TotDetachedBldg + TotRectDetachedFixed + TotRectDetachedBldg + TotShdSubs + TotOverhangs +
2786 796 : TotOverhangsProjection + TotFins + TotFinsProjection;
2787 796 : int NumDElightCmplxFen = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Daylighting:DElight:ComplexFenestration");
2788 796 : if (TotShadSurf > 0 && (NumDElightCmplxFen > 0 || Dayltg::doesDayLightingUseDElight(state))) {
2789 0 : ShowWarningError(state,
2790 0 : format("{}When using DElight daylighting the presence of exterior shading surfaces is ignored.", RoutineName));
2791 : }
2792 :
2793 46840 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; SurfNum++) {
2794 46044 : auto &surf = state.dataSurface->Surface(SurfNum);
2795 : // Initialize run time surface arrays
2796 46044 : state.dataSurface->SurfActiveConstruction(SurfNum) = surf.Construction;
2797 46044 : surf.RepresentativeCalcSurfNum = SurfNum;
2798 : }
2799 :
2800 : // Representative surface calculations: Assign representative heat transfer surfaces
2801 797 : if (state.dataSurface->UseRepresentativeSurfaceCalculations &&
2802 797 : state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "ZoneProperty:UserViewFactors:BySurfaceName") == 0) {
2803 47 : for (int zoneNum = 1; zoneNum <= state.dataGlobal->NumOfZones; ++zoneNum) {
2804 92 : for (int spaceNum : state.dataHeatBal->Zone(zoneNum).spaceIndexes) {
2805 46 : auto &thisSpace = state.dataHeatBal->space(spaceNum);
2806 625 : for (int surfNum = thisSpace.HTSurfaceFirst; surfNum <= thisSpace.HTSurfaceLast; surfNum++) {
2807 579 : auto &surface(state.dataSurface->Surface(surfNum));
2808 : // Conditions where surface always needs to be unique
2809 : bool forceUniqueSurface =
2810 1158 : surface.HasShadeControl ||
2811 579 : state.dataSurface->SurfWinAirflowSource(surfNum) != DataSurfaces::WindowAirFlowSource::Invalid ||
2812 579 : state.dataConstruction->Construct(surface.Construction).SourceSinkPresent ||
2813 1737 : surface.Class == SurfaceClass::TDD_Dome ||
2814 579 : (surface.Class == SurfaceClass::Window &&
2815 178 : (surface.OriginalClass == SurfaceClass::TDD_Diffuser ||
2816 178 : state.dataSurface->SurfWinWindowModelType(surfNum) != WindowModel::Detailed ||
2817 178 : state.dataWindowManager->inExtWindowModel->isExternalLibraryModel() ||
2818 178 : state.dataConstruction->Construct(surface.Construction).TCFlag == 1));
2819 579 : if (!forceUniqueSurface) {
2820 579 : state.dataSurface->Surface(surfNum).set_representative_surface(state, surfNum);
2821 : }
2822 : }
2823 46 : }
2824 : }
2825 : }
2826 : // Initialize surface with movable insulation index list
2827 46840 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; SurfNum++) {
2828 46044 : if (state.dataSurface->SurfMaterialMovInsulExt(SurfNum) > 0 || state.dataSurface->SurfMaterialMovInsulInt(SurfNum) > 0) {
2829 5 : state.dataHeatBalSurf->SurfMovInsulIndexList.push_back(SurfNum);
2830 : }
2831 : }
2832 : }
2833 796 : if (SurfError || ErrorsFound) {
2834 0 : ErrorsFound = true;
2835 0 : ShowFatalError(state, format("{}Errors discovered, program terminates.", RoutineName));
2836 : }
2837 796 : }
2838 :
2839 796 : void CreateMissingSpaces(EnergyPlusData &state, Array1D<SurfaceGeometry::SurfaceData> &Surfaces)
2840 : {
2841 : // Scan surfaces to see if Space was assigned in input
2842 796 : EPVector<bool> anySurfacesWithSpace; // True if any surfaces in a zone do not have a space assigned in input
2843 796 : EPVector<bool> anySurfacesWithoutSpace; // True if any surfaces in a zone have a space assigned in input
2844 796 : anySurfacesWithSpace.resize(state.dataGlobal->NumOfZones, false);
2845 796 : anySurfacesWithoutSpace.resize(state.dataGlobal->NumOfZones, false);
2846 :
2847 46840 : for (int surfNum = 1; surfNum <= state.dataSurface->TotSurfaces; ++surfNum) {
2848 46044 : auto &thisSurf = Surfaces(surfNum);
2849 46044 : if (!thisSurf.HeatTransSurf) continue; // ignore shading surfaces
2850 44408 : if (thisSurf.Class == DataSurfaces::SurfaceClass::IntMass) continue; // skip internal mass surfaces for this check
2851 42010 : if (thisSurf.BaseSurf != surfNum) {
2852 : // Set space for subsurfaces
2853 6698 : thisSurf.spaceNum = Surfaces(thisSurf.BaseSurf).spaceNum;
2854 : }
2855 42010 : if (thisSurf.spaceNum > 0) {
2856 69 : anySurfacesWithSpace(thisSurf.Zone) = true;
2857 : } else {
2858 41941 : anySurfacesWithoutSpace(thisSurf.Zone) = true;
2859 : }
2860 : }
2861 :
2862 : // Create any missing Spaces
2863 5852 : for (int zoneNum = 1; zoneNum <= state.dataGlobal->NumOfZones; ++zoneNum) {
2864 5056 : auto &thisZone = state.dataHeatBal->Zone(zoneNum);
2865 5056 : if (anySurfacesWithoutSpace(zoneNum)) {
2866 : // If any surfaces in the zone are not assigned to a space, may need to create a new space
2867 : // Every zone has at least one space, created in HeatBalanceManager::GetSpaceData
2868 : // If no surfaces have a space assigned, then the default space will be used, otherwise, create a new space
2869 5052 : if (anySurfacesWithSpace(zoneNum)) {
2870 : // Add new space
2871 3 : ++state.dataGlobal->numSpaces;
2872 3 : state.dataHeatBal->space(state.dataGlobal->numSpaces).zoneNum = zoneNum;
2873 : // Add to zone's list of spaces
2874 3 : thisZone.spaceIndexes.emplace_back(state.dataGlobal->numSpaces);
2875 3 : ++state.dataHeatBal->Zone(zoneNum).numSpaces;
2876 3 : assert(state.dataHeatBal->Zone(zoneNum).numSpaces == int(state.dataHeatBal->Zone(zoneNum).spaceIndexes.size()));
2877 : // If some surfaces in the zone are assigned to a space, the new space is the remainder of the zone
2878 3 : state.dataHeatBal->space(state.dataGlobal->numSpaces).Name =
2879 6 : thisZone.Name + "-REMAINDER"; // Make UPPERcase so it can be referenced in input
2880 3 : state.dataHeatBal->space(state.dataGlobal->numSpaces).isRemainderSpace = true;
2881 3 : state.dataHeatBal->space(state.dataGlobal->numSpaces).spaceType = "GENERAL";
2882 3 : state.dataHeatBal->space(state.dataGlobal->numSpaces).spaceTypeNum = HeatBalanceManager::GetGeneralSpaceTypeNum(state);
2883 : }
2884 : }
2885 : }
2886 :
2887 : // Assign Spaces to surfaces without one
2888 46840 : for (int surfNum = 1; surfNum <= state.dataSurface->TotSurfaces; ++surfNum) {
2889 46044 : auto &thisSurf = Surfaces(surfNum);
2890 46044 : if (!thisSurf.HeatTransSurf) continue; // ignore shading surfaces
2891 44408 : if (thisSurf.spaceNum == 0) {
2892 44329 : int const numSpaces = state.dataHeatBal->Zone(thisSurf.Zone).numSpaces;
2893 44329 : int const lastSpaceForZone = state.dataHeatBal->Zone(thisSurf.Zone).spaceIndexes(numSpaces);
2894 44329 : thisSurf.spaceNum = lastSpaceForZone;
2895 : }
2896 : }
2897 796 : }
2898 :
2899 796 : void createSpaceSurfaceLists(EnergyPlusData &state)
2900 : {
2901 : static constexpr std::string_view RoutineName("createSpaceSurfaceLists: ");
2902 : // Build Space surface lists now that all of the surface sorting is complete
2903 46840 : for (int surfNum = 1; surfNum <= state.dataSurface->TotSurfaces; ++surfNum) {
2904 46044 : auto &thisSurf = state.dataSurface->Surface(surfNum);
2905 46044 : if (!thisSurf.HeatTransSurf) continue; // ignore shading surfaces
2906 : // Add to Space's list of surfaces
2907 44408 : state.dataHeatBal->space(thisSurf.spaceNum).surfaces.emplace_back(surfNum);
2908 : }
2909 5864 : for (int spaceNum = 1; spaceNum <= state.dataGlobal->numSpaces; ++spaceNum) {
2910 5068 : if (int(state.dataHeatBal->space(spaceNum).surfaces.size()) == 0) {
2911 0 : ShowWarningError(state, format("{}Space={} has no surfaces.", RoutineName, state.dataHeatBal->space(spaceNum).Name));
2912 : }
2913 : }
2914 796 : }
2915 :
2916 796 : void setSurfaceFirstLast(EnergyPlusData &state)
2917 : {
2918 : // Set Zone and Space Surface First/Last Pointers
2919 : // Space surface lists have been built earlier in createSpaceSurfaceLists
2920 5852 : for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
2921 10124 : for (int spaceNum : state.dataHeatBal->Zone(ZoneNum).spaceIndexes) {
2922 5068 : auto &thisSpace = state.dataHeatBal->space(spaceNum);
2923 49476 : for (int SurfNum : thisSpace.surfaces) {
2924 44408 : auto &surf = state.dataSurface->Surface(SurfNum);
2925 44408 : if (thisSpace.AllSurfaceFirst == 0) {
2926 5068 : thisSpace.AllSurfaceFirst = SurfNum;
2927 : }
2928 44408 : thisSpace.AllSurfaceLast = SurfNum;
2929 :
2930 44408 : if (surf.IsAirBoundarySurf) {
2931 18 : surf.HeatTransSurf = false;
2932 18 : continue;
2933 : }
2934 : // Non window surfaces are grouped next within each space
2935 44390 : if (thisSpace.HTSurfaceFirst == 0) {
2936 5068 : thisSpace.HTSurfaceFirst = SurfNum;
2937 5068 : thisSpace.OpaqOrIntMassSurfaceFirst = SurfNum;
2938 5068 : thisSpace.OpaqOrWinSurfaceFirst = SurfNum;
2939 : }
2940 44390 : thisSpace.HTSurfaceLast = SurfNum;
2941 :
2942 : // Window surfaces are grouped next within each space
2943 44390 : if ((surf.Class == DataSurfaces::SurfaceClass::Window) || (surf.Class == DataSurfaces::SurfaceClass::GlassDoor) ||
2944 38175 : (surf.Class == DataSurfaces::SurfaceClass::TDD_Diffuser)) {
2945 6217 : if (thisSpace.WindowSurfaceFirst == 0) {
2946 3153 : thisSpace.WindowSurfaceFirst = SurfNum;
2947 : }
2948 6217 : thisSpace.WindowSurfaceLast = SurfNum;
2949 38173 : } else if (surf.Class != DataSurfaces::SurfaceClass::TDD_Dome) {
2950 38171 : thisSpace.OpaqOrIntMassSurfaceLast = SurfNum;
2951 : }
2952 :
2953 : // TDDDome surfaces are grouped last within each space
2954 44390 : if (surf.Class == DataSurfaces::SurfaceClass::TDD_Dome) {
2955 2 : if (thisSpace.TDDDomeFirst == 0) {
2956 1 : thisSpace.TDDDomeFirst = SurfNum;
2957 : }
2958 2 : thisSpace.TDDDomeLast = SurfNum;
2959 : } else {
2960 44388 : thisSpace.OpaqOrWinSurfaceLast = SurfNum;
2961 : }
2962 5068 : }
2963 5068 : state.dataHeatBal->Zone(ZoneNum).AllSurfaceLast = thisSpace.AllSurfaceLast;
2964 5056 : }
2965 5056 : int firstSpaceNum = state.dataHeatBal->Zone(ZoneNum).spaceIndexes(1);
2966 5056 : state.dataHeatBal->Zone(ZoneNum).AllSurfaceFirst = state.dataHeatBal->space(firstSpaceNum).AllSurfaceFirst;
2967 : }
2968 796 : }
2969 :
2970 6698 : void checkSubSurfAzTiltNorm(EnergyPlusData &state,
2971 : SurfaceData &baseSurface, // Base surface data (in)
2972 : SurfaceData &subSurface, // Subsurface data (in)
2973 : bool &surfaceError // True if surface azimuths or tilts differ by more than error tolerance
2974 : )
2975 : {
2976 6698 : bool sameSurfNormal(false); // True if surface has the same surface normal within tolerance
2977 6698 : bool baseSurfHoriz(false); // True if base surface is near horizontal
2978 6698 : Real64 constexpr warningTolerance(30.0);
2979 6698 : Real64 constexpr errorTolerance(90.0);
2980 :
2981 6698 : surfaceError = false;
2982 :
2983 : // Check if base surface and subsurface have the same normal
2984 6698 : Vectors::CompareTwoVectors(baseSurface.NewellSurfaceNormalVector, subSurface.NewellSurfaceNormalVector, sameSurfNormal, 0.001);
2985 6698 : if (sameSurfNormal) { // copy lcs vectors
2986 : // Prior logic tested for azimuth difference < 30 and then skipped this - this caused large diffs in
2987 : // CmplxGlz_MeasuredDeflectionAndShading Restoring that check here but will require further investigation (MJW Dec 2015)
2988 : // if (std::abs(baseSurface.Azimuth - subSurface.Azimuth) > warningTolerance) {
2989 6697 : subSurface.lcsx = baseSurface.lcsx;
2990 6697 : subSurface.lcsy = baseSurface.lcsy;
2991 6697 : subSurface.lcsz = baseSurface.lcsz;
2992 : // }
2993 : } else {
2994 : // // Not sure what this does, but keeping for now (MJW Dec 2015)
2995 : // if (std::abs(subSurface.Azimuth - 360.0) < 0.01) {
2996 : // subSurface.Azimuth = 360.0 - subSurface.Azimuth;
2997 : // }
2998 : // if (std::abs(baseSurface.Azimuth - 360.0) < 0.01) {
2999 : // baseSurface.Azimuth = 360.0 - baseSurface.Azimuth;
3000 : // }
3001 :
3002 : // Is base surface horizontal? If so, ignore azimuth differences
3003 1 : if (std::abs(baseSurface.Tilt) <= 1.0e-5 || std::abs(baseSurface.Tilt - 180.0) <= 1.0e-5) baseSurfHoriz = true;
3004 :
3005 2 : if (((General::rotAzmDiffDeg(baseSurface.Azimuth, subSurface.Azimuth) > errorTolerance) && !baseSurfHoriz) ||
3006 1 : (std::abs(baseSurface.Tilt - subSurface.Tilt) > errorTolerance)) {
3007 0 : surfaceError = true;
3008 0 : ShowSevereError(
3009 : state,
3010 0 : format("checkSubSurfAzTiltNorm: Outward facing angle of subsurface differs more than {:.1R} degrees from base surface.",
3011 : errorTolerance));
3012 0 : ShowContinueError(state,
3013 0 : format("Subsurface=\"{}\" Tilt = {:.1R} Azimuth = {:.1R}", subSurface.Name, subSurface.Tilt, subSurface.Azimuth));
3014 0 : ShowContinueError(
3015 0 : state, format("Base surface=\"{}\" Tilt = {:.1R} Azimuth = {:.1R}", baseSurface.Name, baseSurface.Tilt, baseSurface.Azimuth));
3016 2 : } else if (((General::rotAzmDiffDeg(baseSurface.Azimuth, subSurface.Azimuth) > warningTolerance) && !baseSurfHoriz) ||
3017 1 : (std::abs(baseSurface.Tilt - subSurface.Tilt) > warningTolerance)) {
3018 0 : ++state.dataSurfaceGeometry->checkSubSurfAzTiltNormErrCount;
3019 0 : if (state.dataSurfaceGeometry->checkSubSurfAzTiltNormErrCount == 1 && !state.dataGlobal->DisplayExtraWarnings) {
3020 0 : ShowWarningError(state,
3021 0 : format("checkSubSurfAzTiltNorm: Some Outward Facing angles of subsurfaces differ more than {:.1R} "
3022 : "degrees from base surface.",
3023 : warningTolerance));
3024 0 : ShowContinueError(state, "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on individual surfaces.");
3025 : }
3026 0 : if (state.dataGlobal->DisplayExtraWarnings) {
3027 0 : ShowWarningError(
3028 : state,
3029 0 : format("checkSubSurfAzTiltNorm: Outward facing angle of subsurface differs more than {:.1R} degrees from base surface.",
3030 : warningTolerance));
3031 0 : ShowContinueError(
3032 0 : state, format("Subsurface=\"{}\" Tilt = {:.1R} Azimuth = {:.1R}", subSurface.Name, subSurface.Tilt, subSurface.Azimuth));
3033 0 : ShowContinueError(
3034 : state,
3035 0 : format("Base surface=\"{}\" Tilt = {:.1R} Azimuth = {:.1R}", baseSurface.Name, baseSurface.Tilt, baseSurface.Azimuth));
3036 : }
3037 : }
3038 : }
3039 6698 : }
3040 :
3041 796 : void GetGeometryParameters(EnergyPlusData &state, bool &ErrorsFound) // set to true if errors found during input
3042 : {
3043 :
3044 : // SUBROUTINE INFORMATION:
3045 : // AUTHOR Linda Lawrie
3046 : // DATE WRITTEN May 2000
3047 : // MODIFIED na
3048 : // RE-ENGINEERED na
3049 :
3050 : // PURPOSE OF THIS SUBROUTINE:
3051 : // This subroutine reads in the "Surface Geometry" parameters, verifies them,
3052 : // and sets "global" variables that will tell other routines how the surface
3053 : // vertices are expected in input.
3054 :
3055 : // METHODOLOGY EMPLOYED:
3056 : // na
3057 :
3058 : // REFERENCES:
3059 : // GlobalGeometryRules Definition
3060 : // GlobalGeometryRules,
3061 : // \required-object
3062 : // \unique-object
3063 : // A1, \field Starting Vertex Position
3064 : // \required-field
3065 : // \note Specified as entry for a 4 sided surface/rectangle
3066 : // \note Surfaces are specified as viewed from outside the surface
3067 : // \note Shading surfaces as viewed from behind. (towards what they are shading)
3068 : // \type choice
3069 : // \key UpperLeftCorner
3070 : // \key LowerLeftCorner
3071 : // \key UpperRightCorner
3072 : // \key LowerRightCorner
3073 : // A2, \field Vertex Entry Direction
3074 : // \required-field
3075 : // \type choice
3076 : // \key Counterclockwise
3077 : // \key Clockwise
3078 : // A3, \field Coordinate System
3079 : // \required-field
3080 : // \note relative -- coordinates are entered relative to zone origin
3081 : // \note world -- all coordinates entered are "absolute" for this facility
3082 : // \note absolute -- same as world
3083 : // \type choice
3084 : // \key Relative
3085 : // \key World
3086 : // \key Absolute
3087 : // A4, \field Daylighting Reference Point Coordinate System
3088 : // \type choice
3089 : // \key Relative
3090 : // \default Relative
3091 : // \note Relative -- coordinates are entered relative to zone origin
3092 : // \key World
3093 : // \note World -- all coordinates entered are "absolute" for this facility
3094 : // \key Absolute
3095 : // \note absolute -- same as world
3096 : // A5; \field Rectangular Surface Coordinate System
3097 : // \type choice
3098 : // \key Relative
3099 : // \default Relative
3100 : // \note Relative -- Starting corner is entered relative to zone origin
3101 : // \key World
3102 : // \note World -- Starting corner is entered in "absolute"
3103 : // \key Absolute
3104 : // \note absolute -- same as world
3105 :
3106 : // Using/Aliasing
3107 :
3108 : // SUBROUTINE PARAMETER DEFINITIONS:
3109 796 : static Array1D_string const FlCorners(4, {"UpperLeftCorner", "LowerLeftCorner", "LowerRightCorner", "UpperRightCorner"});
3110 :
3111 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
3112 : int NumStmt;
3113 796 : Array1D_string GAlphas(5);
3114 : int NAlphas;
3115 796 : Array1D<Real64> GNum(1);
3116 : int NNum;
3117 : int IOStat;
3118 : bool OK;
3119 : int Found;
3120 796 : std::string OutMsg;
3121 : int ZoneNum; // For loop counter
3122 796 : bool RelWarning(false);
3123 796 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
3124 :
3125 796 : cCurrentModuleObject = "GlobalGeometryRules";
3126 796 : NumStmt = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
3127 796 : OutMsg = " Surface Geometry,";
3128 :
3129 : {
3130 796 : int const SELECT_CASE_var = NumStmt;
3131 :
3132 796 : if (SELECT_CASE_var == 1) {
3133 : // This is the valid case
3134 1592 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
3135 : cCurrentModuleObject,
3136 : 1,
3137 : GAlphas,
3138 : NAlphas,
3139 : GNum,
3140 : NNum,
3141 : IOStat,
3142 796 : state.dataIPShortCut->lNumericFieldBlanks,
3143 796 : state.dataIPShortCut->lAlphaFieldBlanks,
3144 796 : state.dataIPShortCut->cAlphaFieldNames,
3145 796 : state.dataIPShortCut->cNumericFieldNames);
3146 :
3147 : // Even though these will be validated, set defaults in case error here -- wont
3148 : // cause aborts in later surface gets (hopefully)
3149 796 : state.dataSurface->Corner = UpperLeftCorner;
3150 796 : state.dataSurface->WorldCoordSystem = true;
3151 796 : state.dataSurface->CCW = true;
3152 :
3153 796 : OK = false;
3154 796 : Found = Util::FindItem(GAlphas(1), FlCorners, 4);
3155 796 : if (Found == 0) {
3156 0 : ShowSevereError(state, format("{}: Invalid {}={}", cCurrentModuleObject, state.dataIPShortCut->cAlphaFieldNames(1), GAlphas(1)));
3157 0 : ErrorsFound = true;
3158 : } else {
3159 796 : state.dataSurface->Corner = Found;
3160 796 : OK = true;
3161 796 : OutMsg += FlCorners(state.dataSurface->Corner) + ',';
3162 : }
3163 :
3164 796 : OK = false;
3165 796 : if (Util::SameString(GAlphas(2), "CCW") || Util::SameString(GAlphas(2), "Counterclockwise")) {
3166 793 : state.dataSurface->CCW = true;
3167 793 : OutMsg += "Counterclockwise,";
3168 793 : OK = true;
3169 : }
3170 796 : if (Util::SameString(GAlphas(2), "CW") || Util::SameString(GAlphas(2), "Clockwise")) {
3171 3 : state.dataSurface->CCW = false;
3172 3 : OutMsg += "Clockwise,";
3173 3 : OK = true;
3174 : }
3175 796 : if (!OK) {
3176 0 : ShowSevereError(state, format("{}: Invalid {}={}", cCurrentModuleObject, state.dataIPShortCut->cAlphaFieldNames(2), GAlphas(2)));
3177 0 : ErrorsFound = true;
3178 : }
3179 :
3180 796 : OK = false;
3181 796 : if (Util::SameString(GAlphas(3), "World") || Util::SameString(GAlphas(3), "Absolute")) {
3182 357 : state.dataSurface->WorldCoordSystem = true;
3183 357 : OutMsg += "WorldCoordinateSystem,";
3184 357 : OK = true;
3185 : }
3186 796 : if (Util::SameString(GAlphas(3), "Relative")) {
3187 439 : state.dataSurface->WorldCoordSystem = false;
3188 439 : OutMsg += "RelativeCoordinateSystem,";
3189 439 : OK = true;
3190 : }
3191 796 : if (!OK) {
3192 0 : ShowWarningError(state, format("{}: Invalid {}={}", cCurrentModuleObject, state.dataIPShortCut->cAlphaFieldNames(3), GAlphas(3)));
3193 0 : ShowContinueError(state, format("{} defaults to \"WorldCoordinateSystem\"", state.dataIPShortCut->cAlphaFieldNames(3)));
3194 0 : state.dataSurface->WorldCoordSystem = true;
3195 0 : OutMsg += "WorldCoordinateSystem,";
3196 : }
3197 :
3198 796 : OK = false;
3199 796 : if (Util::SameString(GAlphas(4), "World") || Util::SameString(GAlphas(4), "Absolute")) {
3200 8 : state.dataSurface->DaylRefWorldCoordSystem = true;
3201 8 : OutMsg += "WorldCoordinateSystem,";
3202 8 : OK = true;
3203 : }
3204 796 : if (Util::SameString(GAlphas(4), "Relative") || GAlphas(4).empty()) {
3205 788 : state.dataSurface->DaylRefWorldCoordSystem = false;
3206 788 : OutMsg += "RelativeCoordinateSystem,";
3207 788 : OK = true;
3208 : }
3209 796 : if (!OK) {
3210 0 : ShowWarningError(state, format("{}: Invalid {}={}", cCurrentModuleObject, state.dataIPShortCut->cAlphaFieldNames(4), GAlphas(4)));
3211 0 : ShowContinueError(state, format("{} defaults to \"RelativeToZoneOrigin\"", state.dataIPShortCut->cAlphaFieldNames(4)));
3212 0 : state.dataSurface->DaylRefWorldCoordSystem = false;
3213 0 : OutMsg += "RelativeToZoneOrigin,";
3214 : }
3215 :
3216 796 : OK = false;
3217 796 : if (Util::SameString(GAlphas(5), "World") || Util::SameString(GAlphas(5), "Absolute")) {
3218 18 : state.dataSurfaceGeometry->RectSurfRefWorldCoordSystem = true;
3219 18 : OutMsg += "WorldCoordinateSystem";
3220 18 : OK = true;
3221 : }
3222 796 : if (Util::SameString(GAlphas(5), "Relative") || GAlphas(5).empty()) {
3223 778 : state.dataSurfaceGeometry->RectSurfRefWorldCoordSystem = false;
3224 778 : OutMsg += "RelativeToZoneOrigin";
3225 778 : OK = true;
3226 : }
3227 796 : if (!OK) {
3228 0 : ShowWarningError(state, format("{}: Invalid {}={}", cCurrentModuleObject, state.dataIPShortCut->cAlphaFieldNames(5), GAlphas(5)));
3229 0 : ShowContinueError(state, format("{} defaults to \"RelativeToZoneOrigin\"", state.dataIPShortCut->cAlphaFieldNames(5)));
3230 0 : state.dataSurfaceGeometry->RectSurfRefWorldCoordSystem = false;
3231 0 : OutMsg += "RelativeToZoneOrigin";
3232 : }
3233 :
3234 0 : } else if (SELECT_CASE_var == 0) {
3235 :
3236 0 : ShowSevereError(state, format("{}: Required object not found.", cCurrentModuleObject));
3237 0 : OutMsg += "None found in input";
3238 0 : ErrorsFound = true;
3239 :
3240 : } else {
3241 :
3242 0 : ShowSevereError(state, format("{}: Too many objects entered. Only one allowed.", cCurrentModuleObject));
3243 0 : ErrorsFound = true;
3244 : }
3245 : }
3246 :
3247 796 : if (!state.dataSurface->WorldCoordSystem) {
3248 439 : if (state.dataSurface->DaylRefWorldCoordSystem) {
3249 0 : ShowWarningError(state, format("{}: Potential mismatch of coordinate specifications.", cCurrentModuleObject));
3250 0 : ShowContinueError(state, format("{}=\"{}\"; while ", state.dataIPShortCut->cAlphaFieldNames(3), GAlphas(3)));
3251 0 : ShowContinueError(state, format("{}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(4), GAlphas(4)));
3252 : }
3253 439 : if (state.dataSurfaceGeometry->RectSurfRefWorldCoordSystem) {
3254 0 : ShowWarningError(state, format("{}: Potential mismatch of coordinate specifications.", cCurrentModuleObject));
3255 0 : ShowContinueError(state, format("{}=\"{}\"; while ", state.dataIPShortCut->cAlphaFieldNames(3), GAlphas(3)));
3256 0 : ShowContinueError(state, format("{}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(5), GAlphas(5)));
3257 : }
3258 : } else {
3259 357 : RelWarning = false;
3260 1392 : for (ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
3261 1035 : if (state.dataHeatBal->Zone(ZoneNum).OriginX != 0.0) RelWarning = true;
3262 1035 : if (state.dataHeatBal->Zone(ZoneNum).OriginY != 0.0) RelWarning = true;
3263 1035 : if (state.dataHeatBal->Zone(ZoneNum).OriginZ != 0.0) RelWarning = true;
3264 : }
3265 357 : if (RelWarning && !state.dataSurfaceGeometry->RectSurfRefWorldCoordSystem) {
3266 0 : ShowWarningError(state,
3267 0 : format("{}: Potential mismatch of coordinate specifications. Note that the rectangular surfaces are relying on the "
3268 : "default SurfaceGeometry for 'Relative to zone' coordinate.",
3269 : cCurrentModuleObject));
3270 0 : ShowContinueError(state, format("{}=\"{}\"; while ", state.dataIPShortCut->cAlphaFieldNames(3), GAlphas(3)));
3271 0 : if (GAlphas(5) == "RELATIVE") {
3272 0 : ShowContinueError(state, format("{}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(5), GAlphas(5)));
3273 0 : } else if (GAlphas(5) != "ABSOLUTE") {
3274 0 : ShowContinueError(state, format("{}=\"defaults to RELATIVE\".", state.dataIPShortCut->cAlphaFieldNames(5)));
3275 : }
3276 : }
3277 : }
3278 :
3279 796 : print(state.files.eio,
3280 : "! <Surface Geometry>,Starting Corner,Vertex Input Direction,Coordinate System,Daylight Reference "
3281 : "Point Coordinate System,Rectangular (Simple) Surface Coordinate System\n");
3282 796 : print(state.files.eio, "{}\n", OutMsg);
3283 796 : }
3284 :
3285 796 : void GetDetShdSurfaceData(EnergyPlusData &state,
3286 : bool &ErrorsFound, // Error flag indicator (true if errors found)
3287 : int &SurfNum, // Count of Current SurfaceNumber
3288 : int const TotDetachedFixed, // Number of Fixed Detached Shading Surfaces to obtain
3289 : int const TotDetachedBldg // Number of Building Detached Shading Surfaces to obtain
3290 : )
3291 : {
3292 : // SUBROUTINE INFORMATION:
3293 : // AUTHOR Linda Lawrie
3294 : // DATE WRITTEN May 2000
3295 :
3296 : // PURPOSE OF THIS SUBROUTINE:
3297 : // This subroutine gets the Detached Shading Surface Data,
3298 : // checks it for errors, etc.
3299 :
3300 : // Using/Aliasing
3301 : using ScheduleManager::CheckScheduleValueMinMax;
3302 : using ScheduleManager::GetScheduleIndex;
3303 : using ScheduleManager::GetScheduleMaxValue;
3304 : using ScheduleManager::GetScheduleMinValue;
3305 :
3306 : // SUBROUTINE PARAMETER DEFINITIONS:
3307 796 : static Array1D_string const cModuleObjects(2, {"Shading:Site:Detailed", "Shading:Building:Detailed"});
3308 :
3309 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
3310 : int IOStat; // IO Status when calling get input subroutine
3311 : int NumAlphas; // Number of material alpha names being passed
3312 : int NumNumbers; // Number of material properties being passed
3313 : int Loop;
3314 : int Item;
3315 : int ItemsToGet;
3316 : SurfaceClass ClassItem;
3317 : int numSides;
3318 : Real64 SchedMinValue;
3319 : Real64 SchedMaxValue;
3320 :
3321 796 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
3322 :
3323 796 : if ((TotDetachedFixed + TotDetachedBldg) > 0 && state.dataHeatBal->SolarDistribution == DataHeatBalance::Shadowing::Minimal) {
3324 0 : ShowWarningError(state, "Detached shading effects are ignored when Solar Distribution = MinimalShadowing");
3325 : }
3326 :
3327 796 : if ((TotDetachedFixed + TotDetachedBldg) == 0) return;
3328 :
3329 60 : for (Item = 1; Item <= 2; ++Item) {
3330 :
3331 40 : cCurrentModuleObject = cModuleObjects(Item);
3332 40 : if (Item == 1) {
3333 20 : ItemsToGet = TotDetachedFixed;
3334 20 : ClassItem = SurfaceClass::Detached_F;
3335 : } else { // IF (Item == 2) THEN
3336 20 : ItemsToGet = TotDetachedBldg;
3337 20 : ClassItem = SurfaceClass::Detached_B;
3338 : }
3339 :
3340 40 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, Loop, NumAlphas, NumNumbers);
3341 40 : if (NumAlphas != 2) {
3342 0 : ShowSevereError(
3343 0 : state, format("{}: Object Definition indicates not = 2 Alpha Objects, Number Indicated={}", cCurrentModuleObject, NumAlphas));
3344 0 : ErrorsFound = true;
3345 : }
3346 :
3347 96 : for (Loop = 1; Loop <= ItemsToGet; ++Loop) {
3348 112 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
3349 : cCurrentModuleObject,
3350 : Loop,
3351 56 : state.dataIPShortCut->cAlphaArgs,
3352 : NumAlphas,
3353 56 : state.dataIPShortCut->rNumericArgs,
3354 : NumNumbers,
3355 : IOStat,
3356 56 : state.dataIPShortCut->lNumericFieldBlanks,
3357 56 : state.dataIPShortCut->lAlphaFieldBlanks,
3358 56 : state.dataIPShortCut->cAlphaFieldNames,
3359 56 : state.dataIPShortCut->cNumericFieldNames);
3360 :
3361 112 : if (GlobalNames::VerifyUniqueInterObjectName(state,
3362 56 : state.dataSurfaceGeometry->UniqueSurfaceNames,
3363 56 : state.dataIPShortCut->cAlphaArgs(1),
3364 : cCurrentModuleObject,
3365 56 : state.dataIPShortCut->cAlphaFieldNames(1),
3366 : ErrorsFound)) {
3367 0 : continue;
3368 : }
3369 :
3370 56 : ++SurfNum;
3371 56 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name = state.dataIPShortCut->cAlphaArgs(1); // Set the Surface Name in the Derived Type
3372 56 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class = ClassItem;
3373 56 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).HeatTransSurf = false;
3374 56 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtSolar = true;
3375 : // Base transmittance of a shadowing (sub)surface
3376 56 : if (!state.dataIPShortCut->lAlphaFieldBlanks(2)) {
3377 : // Schedule for a shadowing (sub)surface
3378 26 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).SchedShadowSurfIndex =
3379 26 : GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(2));
3380 26 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).SchedShadowSurfIndex == 0) {
3381 0 : ShowSevereError(state,
3382 0 : format("{}=\"{}\", {} not found={}",
3383 : cCurrentModuleObject,
3384 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
3385 0 : state.dataIPShortCut->cAlphaFieldNames(2),
3386 0 : state.dataIPShortCut->cAlphaArgs(2)));
3387 0 : ErrorsFound = true;
3388 : }
3389 : } else {
3390 30 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).SchedShadowSurfIndex = 0;
3391 : }
3392 56 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).SchedShadowSurfIndex != 0) {
3393 26 : if (!CheckScheduleValueMinMax(state, state.dataSurfaceGeometry->SurfaceTmp(SurfNum).SchedShadowSurfIndex, ">=", 0.0, "<=", 1.0)) {
3394 0 : ShowSevereError(state,
3395 0 : format("{}=\"{}\", {}=\"{}\", values not in range [0,1].",
3396 : cCurrentModuleObject,
3397 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
3398 0 : state.dataIPShortCut->cAlphaFieldNames(2),
3399 0 : state.dataIPShortCut->cAlphaArgs(2)));
3400 0 : ErrorsFound = true;
3401 : }
3402 26 : SchedMinValue = GetScheduleMinValue(state, state.dataSurfaceGeometry->SurfaceTmp(SurfNum).SchedShadowSurfIndex);
3403 26 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).SchedMinValue = SchedMinValue;
3404 26 : SchedMaxValue = GetScheduleMaxValue(state, state.dataSurfaceGeometry->SurfaceTmp(SurfNum).SchedShadowSurfIndex);
3405 26 : if (SchedMinValue == 1.0) {
3406 : // Set transparent for now, check for EMS actuators later in SolarShading::resetShadingSurfaceTransparency
3407 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).IsTransparent = true;
3408 : }
3409 26 : if (SchedMinValue < 0.0) {
3410 0 : ShowSevereError(state,
3411 0 : format("{}=\"{}\", {}=\"{}\", has schedule values < 0.",
3412 : cCurrentModuleObject,
3413 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
3414 0 : state.dataIPShortCut->cAlphaFieldNames(2),
3415 0 : state.dataIPShortCut->cAlphaArgs(2)));
3416 0 : ShowContinueError(state, "...Schedule values < 0 have no meaning for shading elements.");
3417 : }
3418 26 : if (SchedMaxValue > 0.0) {
3419 26 : state.dataSolarShading->anyScheduledShadingSurface = true;
3420 : }
3421 26 : if (SchedMaxValue > 1.0) {
3422 0 : ShowSevereError(state,
3423 0 : format("{}=\"{}\", {}=\"{}\", has schedule values > 1.",
3424 : cCurrentModuleObject,
3425 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
3426 0 : state.dataIPShortCut->cAlphaFieldNames(2),
3427 0 : state.dataIPShortCut->cAlphaArgs(2)));
3428 0 : ShowContinueError(state, "...Schedule values > 1 have no meaning for shading elements.");
3429 : }
3430 26 : if (std::abs(SchedMinValue - SchedMaxValue) > Constant::OneMillionth) {
3431 0 : state.dataSurface->ShadingTransmittanceVaries = true;
3432 : }
3433 : }
3434 56 : if (state.dataIPShortCut->lNumericFieldBlanks(1) || state.dataIPShortCut->rNumericArgs(1) == Constant::AutoCalculate) {
3435 0 : numSides = (NumNumbers - 1) / 3;
3436 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides = numSides;
3437 0 : if (mod(NumNumbers - 1, 3) != 0) {
3438 0 : ShowWarningError(state,
3439 0 : format("{}=\"{}\", {}",
3440 : cCurrentModuleObject,
3441 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
3442 0 : format("{} not even multiple of 3. Will read in {}",
3443 0 : state.dataIPShortCut->cNumericFieldNames(1),
3444 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides)));
3445 : }
3446 0 : if (numSides < 3) {
3447 0 : ShowSevereError(state,
3448 0 : format("{}=\"{}\", {} (autocalculate) must be >= 3. Only {} provided.",
3449 : cCurrentModuleObject,
3450 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
3451 0 : state.dataIPShortCut->cNumericFieldNames(1),
3452 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides));
3453 0 : ErrorsFound = true;
3454 0 : continue;
3455 : }
3456 : } else {
3457 56 : numSides = (NumNumbers - 1) / 3;
3458 56 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides = state.dataIPShortCut->rNumericArgs(1);
3459 56 : if (numSides > state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides) {
3460 0 : ShowWarningError(state,
3461 0 : format("{}=\"{}\", field {}={}",
3462 : cCurrentModuleObject,
3463 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
3464 0 : state.dataIPShortCut->cNumericFieldNames(1),
3465 0 : fmt::to_string(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides)));
3466 0 : ShowContinueError(state,
3467 0 : format("...but {} were entered. Only the indicated {} will be used.",
3468 : numSides,
3469 0 : state.dataIPShortCut->cNumericFieldNames(1)));
3470 : }
3471 : }
3472 56 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex.allocate(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides);
3473 168 : GetVertices(state, SurfNum, state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides, state.dataIPShortCut->rNumericArgs({2, _}));
3474 56 : CheckConvexity(state, SurfNum, state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides);
3475 56 : if (state.dataReportFlag->MakeMirroredDetachedShading) {
3476 56 : MakeMirrorSurface(state, SurfNum);
3477 : }
3478 : }
3479 :
3480 : } // Item Loop
3481 : }
3482 :
3483 796 : void GetRectDetShdSurfaceData(EnergyPlusData &state,
3484 : bool &ErrorsFound, // Error flag indicator (true if errors found)
3485 : int &SurfNum, // Count of Current SurfaceNumber
3486 : int const TotRectDetachedFixed, // Number of Fixed Detached Shading Surfaces to obtain
3487 : int const TotRectDetachedBldg // Number of Building Detached Shading Surfaces to obtain
3488 : )
3489 : {
3490 :
3491 : // SUBROUTINE INFORMATION:
3492 : // AUTHOR Linda Lawrie
3493 : // DATE WRITTEN January 2009
3494 : // MODIFIED na
3495 : // RE-ENGINEERED na
3496 :
3497 : // PURPOSE OF THIS SUBROUTINE:
3498 : // Gets the simple, rectangular detached surfaces.
3499 :
3500 : // Using/Aliasing
3501 :
3502 : // SUBROUTINE PARAMETER DEFINITIONS:
3503 796 : static Array1D_string const cModuleObjects(2, {"Shading:Site", "Shading:Building"});
3504 :
3505 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
3506 : int IOStat; // IO Status when calling get input subroutine
3507 : int NumAlphas; // Number of material alpha names being passed
3508 : int NumNumbers; // Number of material properties being passed
3509 : int Loop;
3510 : int Item;
3511 : int ItemsToGet;
3512 : SurfaceClass ClassItem;
3513 :
3514 796 : if ((TotRectDetachedFixed + TotRectDetachedBldg) > 0 && state.dataHeatBal->SolarDistribution == DataHeatBalance::Shadowing::Minimal) {
3515 0 : ShowWarningError(state, "Detached shading effects are ignored when Solar Distribution = MinimalShadowing");
3516 : }
3517 :
3518 796 : if (TotRectDetachedFixed + TotRectDetachedBldg == 0) return;
3519 6 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
3520 18 : for (Item = 1; Item <= 2; ++Item) {
3521 :
3522 12 : cCurrentModuleObject = cModuleObjects(Item);
3523 12 : if (Item == 1) {
3524 6 : ItemsToGet = TotRectDetachedFixed;
3525 6 : ClassItem = SurfaceClass::Detached_F;
3526 : } else { // IF (Item == 2) THEN
3527 6 : ItemsToGet = TotRectDetachedBldg;
3528 6 : ClassItem = SurfaceClass::Detached_B;
3529 : }
3530 :
3531 12 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, Loop, NumAlphas, NumNumbers);
3532 12 : if (NumAlphas != 1) {
3533 0 : ShowSevereError(
3534 0 : state, format("{}: Object Definition indicates not = 1 Alpha Objects, Number Indicated={}", cCurrentModuleObject, NumAlphas));
3535 0 : ErrorsFound = true;
3536 : }
3537 :
3538 32 : for (Loop = 1; Loop <= ItemsToGet; ++Loop) {
3539 40 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
3540 : cCurrentModuleObject,
3541 : Loop,
3542 20 : state.dataIPShortCut->cAlphaArgs,
3543 : NumAlphas,
3544 20 : state.dataIPShortCut->rNumericArgs,
3545 : NumNumbers,
3546 : IOStat,
3547 20 : state.dataIPShortCut->lNumericFieldBlanks,
3548 20 : state.dataIPShortCut->lAlphaFieldBlanks,
3549 20 : state.dataIPShortCut->cAlphaFieldNames,
3550 20 : state.dataIPShortCut->cNumericFieldNames);
3551 :
3552 40 : if (GlobalNames::VerifyUniqueInterObjectName(state,
3553 20 : state.dataSurfaceGeometry->UniqueSurfaceNames,
3554 20 : state.dataIPShortCut->cAlphaArgs(1),
3555 : cCurrentModuleObject,
3556 20 : state.dataIPShortCut->cAlphaFieldNames(1),
3557 : ErrorsFound)) {
3558 0 : continue;
3559 : }
3560 :
3561 20 : ++SurfNum;
3562 20 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name = state.dataIPShortCut->cAlphaArgs(1); // Set the Surface Name in the Derived Type
3563 20 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class = ClassItem;
3564 20 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).HeatTransSurf = false;
3565 20 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtSolar = true;
3566 :
3567 20 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Azimuth = state.dataIPShortCut->rNumericArgs(1);
3568 20 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == SurfaceClass::Detached_B && !state.dataSurface->WorldCoordSystem) {
3569 4 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Azimuth += state.dataHeatBal->BuildingAzimuth;
3570 : }
3571 20 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == SurfaceClass::Detached_B) {
3572 6 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Azimuth += state.dataHeatBal->BuildingRotationAppendixG;
3573 : }
3574 20 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Tilt = state.dataIPShortCut->rNumericArgs(2);
3575 20 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).convOrientation =
3576 20 : Convect::GetSurfConvOrientation(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Tilt);
3577 :
3578 20 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides = 4;
3579 20 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex.allocate(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides);
3580 :
3581 120 : MakeRectangularVertices(state,
3582 : SurfNum,
3583 20 : state.dataIPShortCut->rNumericArgs(3),
3584 20 : state.dataIPShortCut->rNumericArgs(4),
3585 20 : state.dataIPShortCut->rNumericArgs(5),
3586 20 : state.dataIPShortCut->rNumericArgs(6),
3587 20 : state.dataIPShortCut->rNumericArgs(7),
3588 20 : state.dataSurfaceGeometry->RectSurfRefWorldCoordSystem);
3589 :
3590 20 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Area <= 0.0) {
3591 0 : ShowSevereError(state,
3592 0 : format("{}=\"{}\", Surface Area <= 0.0; Entered Area={:.2T}",
3593 : cCurrentModuleObject,
3594 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
3595 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Area));
3596 0 : ErrorsFound = true;
3597 : }
3598 :
3599 20 : if (state.dataReportFlag->MakeMirroredDetachedShading) {
3600 20 : MakeMirrorSurface(state, SurfNum);
3601 : }
3602 : }
3603 :
3604 : } // Item Loop
3605 : }
3606 :
3607 796 : void GetHTSurfaceData(EnergyPlusData &state,
3608 : bool &ErrorsFound, // Error flag indicator (true if errors found)
3609 : int &SurfNum, // Count of Current SurfaceNumber
3610 : int const TotHTSurfs, // Number of Heat Transfer Base Surfaces to obtain
3611 : int const TotDetailedWalls, // Number of Wall:Detailed items to obtain
3612 : int const TotDetailedRoofs, // Number of RoofCeiling:Detailed items to obtain
3613 : int const TotDetailedFloors, // Number of Floor:Detailed items to obtain
3614 : const Array1D_string &BaseSurfCls, // Valid Classes for Base Surfaces
3615 : const Array1D<SurfaceClass> &BaseSurfIDs,
3616 : int &NeedToAddSurfaces // Number of surfaces to add, based on unentered IZ surfaces
3617 : )
3618 : {
3619 :
3620 : // SUBROUTINE INFORMATION:
3621 : // AUTHOR Linda Lawrie
3622 : // DATE WRITTEN May 2000
3623 : // MODIFIED na
3624 : // RE-ENGINEERED na
3625 :
3626 : // PURPOSE OF THIS SUBROUTINE:
3627 : // This subroutine gets the HeatTransfer Surface Data,
3628 : // checks it for errors, etc.
3629 :
3630 : // METHODOLOGY EMPLOYED:
3631 : // na
3632 :
3633 : // REFERENCES:
3634 : // Heat Transfer Surface Definition
3635 : // BuildingSurface:Detailed,
3636 : // \extensible:3 -- duplicate last set of x,y,z coordinates (last 3 fields), remembering to remove ; from "inner" fields.
3637 : // \format vertices
3638 : // A1 , \field Name
3639 : // \required-field
3640 : // \type alpha
3641 : // \reference SurfaceNames
3642 : // \reference SurfAndSubSurfNames
3643 : // \reference AllHeatTranSurfNames
3644 : // \reference HeatTranBaseSurfNames
3645 : // \reference OutFaceEnvNames
3646 : // \reference AllHeatTranAngFacNames
3647 : // \reference RadGroupAndSurfNames
3648 : // \reference SurfGroupAndHTSurfNames
3649 : // \reference AllShadingAndHTSurfNames
3650 : // A2 , \field Surface Type
3651 : // \required-field
3652 : // \type choice
3653 : // \key Floor
3654 : // \key Wall
3655 : // \key Ceiling
3656 : // \key Roof
3657 : // A3 , \field Construction Name
3658 : // \required-field
3659 : // \note To be matched with a construction in this input file
3660 : // \type object-list
3661 : // \object-list ConstructionNames
3662 : // A4 , \field Zone Name
3663 : // \required-field
3664 : // \note Zone the surface is a part of
3665 : // \type object-list
3666 : // \object-list ZoneNames
3667 : // A5 , \field Outside Boundary Condition
3668 : // \required-field
3669 : // \type choice
3670 : // \key Adiabatic
3671 : // \key Surface
3672 : // \key Zone
3673 : // \key Outdoors
3674 : // \key Ground
3675 : // \key GroundFCfactorMethod
3676 : // \key OtherSideCoefficients
3677 : // \key OtherSideConditionsModel
3678 : // \key GroundSlabPreprocessorAverage
3679 : // \key GroundSlabPreprocessorCore
3680 : // \key GroundSlabPreprocessorPerimeter
3681 : // \key GroundBasementPreprocessorAverageWall
3682 : // \key GroundBasementPreprocessorAverageFloor
3683 : // \key GroundBasementPreprocessorUpperWall
3684 : // \key GroundBasementPreprocessorLowerWall
3685 : // A6, \field Outside Boundary Condition Object
3686 : // \type object-list
3687 : // \object-list OutFaceEnvNames
3688 : // \note Non-blank only if the field Outside Boundary Condition is Surface,
3689 : // \note Zone, OtherSideCoefficients or OtherSideConditionsModel
3690 : // \note If Surface, specify name of corresponding surface in adjacent zone or
3691 : // \note specify current surface name for internal partition separating like zones
3692 : // \note If Zone, specify the name of the corresponding zone and
3693 : // \note the program will generate the corresponding interzone surface
3694 : // \note If OtherSideCoefficients, specify name of SurfaceProperty:OtherSideCoefficients
3695 : // \note If OtherSideConditionsModel, specify name of SurfaceProperty:OtherSideConditionsModel
3696 : // A7 , \field Sun Exposure
3697 : // \required-field
3698 : // \type choice
3699 : // \key SunExposed
3700 : // \key NoSun
3701 : // \default SunExposed
3702 : // A8, \field Wind Exposure
3703 : // \required-field
3704 : // \type choice
3705 : // \key WindExposed
3706 : // \key NoWind
3707 : // \default WindExposed
3708 : // N1, \field View Factor to Ground
3709 : // \type real
3710 : // \note From the exterior of the surface
3711 : // \note Unused if one uses the "reflections" options in Solar Distribution in Building input
3712 : // \note unless a DaylightingDevice:Shelf or DaylightingDevice:Tubular object has been specified.
3713 : // \note autocalculate will automatically calculate this value from the tilt of the surface
3714 : // \autocalculatable
3715 : // \minimum 0.0
3716 : // \maximum 1.0
3717 : // \default autocalculate
3718 : // N2 , \field Number of Vertices
3719 : // \note shown with 120 vertex coordinates -- extensible object
3720 : // \note "extensible" -- duplicate last set of x,y,z coordinates (last 3 fields),
3721 : // \note remembering to remove ; from "inner" fields.
3722 : // \note for clarity in any error messages, renumber the fields as well.
3723 : // \note (and changing z terminator to a comma "," for all but last one which needs a semi-colon ";")
3724 : // \autocalculatable
3725 : // \minimum 3
3726 : // \default autocalculate
3727 : // \note vertices are given in GlobalGeometryRules coordinates -- if relative, all surface coordinates
3728 : // \note are "relative" to the Zone Origin. If world, then building and zone origins are used
3729 : // \note for some internal calculations, but all coordinates are given in an "absolute" system.
3730 : // N3-xx as indicated by the N3 value
3731 :
3732 : // Using/Aliasing
3733 :
3734 : // SUBROUTINE PARAMETER DEFINITIONS:
3735 796 : static Array1D_string const cModuleObjects(4, {"BuildingSurface:Detailed", "Wall:Detailed", "Floor:Detailed", "RoofCeiling:Detailed"});
3736 :
3737 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
3738 : int IOStat; // IO Status when calling get input subroutine
3739 : int SurfaceNumAlpha; // Number of material alpha names being passed
3740 : int SurfaceNumProp; // Number of material properties being passed
3741 : int ZoneNum; // DO loop counter (zones)
3742 : int Found; // For matching interzone surfaces
3743 : int Loop;
3744 : int Item;
3745 : int ItemsToGet;
3746 : int ClassItem;
3747 : int ArgPointer;
3748 : int numSides;
3749 :
3750 796 : GetOSCData(state, ErrorsFound);
3751 796 : GetOSCMData(state, ErrorsFound);
3752 796 : GetFoundationData(state, ErrorsFound);
3753 :
3754 796 : NeedToAddSurfaces = 0;
3755 796 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
3756 3980 : for (Item = 1; Item <= 4; ++Item) {
3757 :
3758 3184 : cCurrentModuleObject = cModuleObjects(Item);
3759 3184 : if (Item == 1) {
3760 796 : ItemsToGet = TotHTSurfs;
3761 796 : ClassItem = 0;
3762 2388 : } else if (Item == 2) {
3763 796 : ItemsToGet = TotDetailedWalls;
3764 796 : ClassItem = 1;
3765 1592 : } else if (Item == 3) {
3766 796 : ItemsToGet = TotDetailedFloors;
3767 796 : ClassItem = 2;
3768 : } else { // IF (Item == 4) THEN
3769 796 : ItemsToGet = TotDetailedRoofs;
3770 796 : ClassItem = 3;
3771 : }
3772 :
3773 3184 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, Loop, SurfaceNumAlpha, SurfaceNumProp);
3774 3184 : if (Item == 1) {
3775 796 : if (SurfaceNumAlpha != 9) {
3776 0 : ShowSevereError(
3777 : state,
3778 0 : format("{}: Object Definition indicates not = 9 Alpha Objects, Number Indicated={}", cCurrentModuleObject, SurfaceNumAlpha));
3779 0 : ErrorsFound = true;
3780 : }
3781 : } else {
3782 2388 : if (SurfaceNumAlpha != 8) {
3783 0 : ShowSevereError(
3784 : state,
3785 0 : format("{}: Object Definition indicates not = 8 Alpha Objects, Number Indicated={}", cCurrentModuleObject, SurfaceNumAlpha));
3786 0 : ErrorsFound = true;
3787 : }
3788 : }
3789 :
3790 38011 : for (Loop = 1; Loop <= ItemsToGet; ++Loop) {
3791 69654 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
3792 : cCurrentModuleObject,
3793 : Loop,
3794 34827 : state.dataIPShortCut->cAlphaArgs,
3795 : SurfaceNumAlpha,
3796 34827 : state.dataIPShortCut->rNumericArgs,
3797 : SurfaceNumProp,
3798 : IOStat,
3799 34827 : state.dataIPShortCut->lNumericFieldBlanks,
3800 34827 : state.dataIPShortCut->lAlphaFieldBlanks,
3801 34827 : state.dataIPShortCut->cAlphaFieldNames,
3802 34827 : state.dataIPShortCut->cNumericFieldNames);
3803 :
3804 69654 : if (GlobalNames::VerifyUniqueInterObjectName(state,
3805 34827 : state.dataSurfaceGeometry->UniqueSurfaceNames,
3806 34827 : state.dataIPShortCut->cAlphaArgs(1),
3807 : cCurrentModuleObject,
3808 34827 : state.dataIPShortCut->cAlphaFieldNames(1),
3809 : ErrorsFound)) {
3810 0 : continue;
3811 : }
3812 :
3813 34827 : ++SurfNum;
3814 34827 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name = state.dataIPShortCut->cAlphaArgs(1); // Set the Surface Name in the Derived Type
3815 34827 : ArgPointer = 2;
3816 34827 : if (Item == 1) {
3817 34803 : if (state.dataIPShortCut->cAlphaArgs(2) == "CEILING") state.dataIPShortCut->cAlphaArgs(2) = "ROOF";
3818 34803 : ClassItem = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(2), BaseSurfCls, 3);
3819 34803 : if (ClassItem == 0) {
3820 0 : ShowSevereError(state,
3821 0 : format("{}=\"{}\", invalid {}=\"{}",
3822 : cCurrentModuleObject,
3823 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
3824 0 : state.dataIPShortCut->cAlphaFieldNames(2),
3825 0 : state.dataIPShortCut->cAlphaArgs(2)));
3826 0 : ErrorsFound = true;
3827 : } else {
3828 34803 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class = BaseSurfIDs(ClassItem);
3829 : }
3830 34803 : ++ArgPointer;
3831 : } else {
3832 24 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class = BaseSurfIDs(ClassItem);
3833 : }
3834 :
3835 34827 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction = Util::FindItemInList(
3836 34827 : state.dataIPShortCut->cAlphaArgs(ArgPointer), state.dataConstruction->Construct, state.dataHeatBal->TotConstructs);
3837 :
3838 34827 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction == 0) {
3839 0 : ErrorsFound = true;
3840 0 : ShowSevereError(state,
3841 0 : format("{}=\"{}\", invalid {}=\"{}\".",
3842 : cCurrentModuleObject,
3843 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
3844 0 : state.dataIPShortCut->cAlphaFieldNames(ArgPointer),
3845 0 : state.dataIPShortCut->cAlphaArgs(ArgPointer)));
3846 34827 : } else if (state.dataConstruction->Construct(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction).TypeIsWindow) {
3847 0 : ErrorsFound = true;
3848 0 : ShowSevereError(state,
3849 0 : format("{}=\"{}\", invalid {}=\"{}\" - has Window materials.",
3850 : cCurrentModuleObject,
3851 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
3852 0 : state.dataIPShortCut->cAlphaFieldNames(ArgPointer),
3853 0 : state.dataIPShortCut->cAlphaArgs(ArgPointer)));
3854 0 : if (Item == 1) {
3855 0 : ShowContinueError(state,
3856 0 : format("...because {}={}", state.dataIPShortCut->cAlphaFieldNames(2), state.dataIPShortCut->cAlphaArgs(2)));
3857 : } else {
3858 0 : ShowContinueError(state, format("...because Surface Type={}", BaseSurfCls(ClassItem)));
3859 : }
3860 : } else {
3861 34827 : state.dataConstruction->Construct(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction).IsUsed = true;
3862 34827 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ConstructionStoredInputValue =
3863 34827 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction;
3864 : }
3865 34827 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).HeatTransSurf = true;
3866 34827 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).BaseSurf = SurfNum;
3867 34827 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).BaseSurfName = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name;
3868 :
3869 34827 : ++ArgPointer;
3870 34827 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ZoneName = state.dataIPShortCut->cAlphaArgs(ArgPointer);
3871 34827 : ZoneNum = Util::FindItemInList(
3872 34827 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ZoneName, state.dataHeatBal->Zone, state.dataGlobal->NumOfZones);
3873 :
3874 34827 : if (ZoneNum != 0) {
3875 34827 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Zone = ZoneNum;
3876 : } else {
3877 0 : ShowSevereError(state,
3878 0 : format("{}=\"{}\", invalid {}=\"{}\".",
3879 : cCurrentModuleObject,
3880 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
3881 0 : state.dataIPShortCut->cAlphaFieldNames(ArgPointer),
3882 0 : state.dataIPShortCut->cAlphaArgs(ArgPointer)));
3883 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class = SurfaceClass::Invalid;
3884 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ZoneName = "Unknown Zone";
3885 0 : ErrorsFound = true;
3886 : }
3887 :
3888 34827 : ++ArgPointer;
3889 34827 : if (!state.dataIPShortCut->lAlphaFieldBlanks(ArgPointer)) {
3890 63 : int spaceNum = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(ArgPointer), state.dataHeatBal->space);
3891 :
3892 63 : if (spaceNum != 0) {
3893 63 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).spaceNum = spaceNum;
3894 63 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Zone != state.dataHeatBal->space(spaceNum).zoneNum) {
3895 0 : ShowSevereError(state,
3896 0 : format("{}=\"{}\", invalid {}=\"{}\" is not in the same zone as the surface.",
3897 : cCurrentModuleObject,
3898 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
3899 0 : state.dataIPShortCut->cAlphaFieldNames(ArgPointer),
3900 0 : state.dataIPShortCut->cAlphaArgs(ArgPointer)));
3901 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class = SurfaceClass::Invalid;
3902 0 : ErrorsFound = true;
3903 : }
3904 : } else {
3905 0 : ShowSevereError(state,
3906 0 : format("{}=\"{}\", invalid {}=\"{}\" not found.",
3907 : cCurrentModuleObject,
3908 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
3909 0 : state.dataIPShortCut->cAlphaFieldNames(ArgPointer),
3910 0 : state.dataIPShortCut->cAlphaArgs(ArgPointer)));
3911 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class = SurfaceClass::Invalid;
3912 0 : ErrorsFound = true;
3913 : }
3914 : }
3915 : // Get the ExteriorBoundaryCondition flag from input There are 4 conditions that
3916 : // can take place. The conditions are set with a 0, -1, or -2, or all of the
3917 : // zone names have to be looked at and generate the interzone array number
3918 34827 : ++ArgPointer;
3919 34827 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCondName = state.dataIPShortCut->cAlphaArgs(ArgPointer + 1);
3920 :
3921 34827 : if (Util::SameString(state.dataIPShortCut->cAlphaArgs(ArgPointer), "Outdoors")) {
3922 11130 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond = ExternalEnvironment;
3923 :
3924 23697 : } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(ArgPointer), "Adiabatic")) {
3925 1270 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond = UnreconciledZoneSurface;
3926 1270 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCondName = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name;
3927 :
3928 22427 : } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(ArgPointer), "Ground")) {
3929 2194 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond = Ground;
3930 :
3931 2194 : if (state.dataSurfaceGeometry->NoGroundTempObjWarning) {
3932 436 : if (!state.dataEnvrn->GroundTempInputs[(int)DataEnvironment::GroundTempType::BuildingSurface]) {
3933 2 : ShowWarningError(state,
3934 : "GetHTSurfaceData: Surfaces with interface to Ground found but no \"Ground Temperatures\" were input.");
3935 2 : ShowContinueError(state, format("Found first in surface={}", state.dataIPShortCut->cAlphaArgs(1)));
3936 4 : ShowContinueError(state,
3937 4 : format("Defaults, constant throughout the year of ({:.1R}) will be used.",
3938 2 : state.dataEnvrn->GroundTemp[(int)DataEnvironment::GroundTempType::BuildingSurface]));
3939 : }
3940 436 : state.dataSurfaceGeometry->NoGroundTempObjWarning = false;
3941 : }
3942 :
3943 : // Added for FCfactor method
3944 20233 : } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(ArgPointer), "GroundFCfactorMethod")) {
3945 184 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond = GroundFCfactorMethod;
3946 184 : if (state.dataSurfaceGeometry->NoFCGroundTempObjWarning) {
3947 184 : if (!state.dataEnvrn->GroundTempInputs[(int)DataEnvironment::GroundTempType::FCFactorMethod]) {
3948 0 : ShowSevereError(state,
3949 : "GetHTSurfaceData: Surfaces with interface to GroundFCfactorMethod found but no \"FC Ground "
3950 : "Temperatures\" were input.");
3951 0 : ShowContinueError(state, format("Found first in surface={}", state.dataIPShortCut->cAlphaArgs(1)));
3952 0 : ShowContinueError(state,
3953 : "Either add a \"Site:GroundTemperature:FCfactorMethod\" object or use a weather file with "
3954 : "Ground Temperatures.");
3955 0 : ErrorsFound = true;
3956 0 : state.dataSurfaceGeometry->NoFCGroundTempObjWarning = false;
3957 : }
3958 : }
3959 184 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction > 0) {
3960 218 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == SurfaceClass::Wall &&
3961 34 : !state.dataConstruction->Construct(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction).TypeIsCfactorWall) {
3962 0 : ShowSevereError(state,
3963 0 : format("{}=\"{}\", invalid {}",
3964 : cCurrentModuleObject,
3965 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
3966 0 : state.dataIPShortCut->cAlphaFieldNames(ArgPointer)));
3967 0 : ShowContinueError(
3968 : state,
3969 0 : format("Construction=\"{}\" is not type Construction:CfactorUndergroundWall.",
3970 0 : state.dataConstruction->Construct(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction).Name));
3971 0 : ErrorsFound = true;
3972 : }
3973 334 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == SurfaceClass::Floor &&
3974 150 : !state.dataConstruction->Construct(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction).TypeIsFfactorFloor) {
3975 0 : ShowSevereError(state,
3976 0 : format("{}=\"{}\", invalid {}",
3977 : cCurrentModuleObject,
3978 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
3979 0 : state.dataIPShortCut->cAlphaFieldNames(ArgPointer)));
3980 0 : ShowContinueError(
3981 : state,
3982 0 : format("Construction=\"{}\" is not type Construction:FfactorGroundFloor.",
3983 0 : state.dataConstruction->Construct(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction).Name));
3984 0 : ErrorsFound = true;
3985 : }
3986 : }
3987 :
3988 20049 : } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(ArgPointer), "OtherSideCoefficients")) {
3989 17 : Found = Util::FindItemInList(
3990 17 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCondName, state.dataSurface->OSC, state.dataSurface->TotOSC);
3991 17 : if (Found == 0) {
3992 0 : ShowSevereError(state,
3993 0 : format("{}=\"{}\", invalid {}=\"{}\".",
3994 : cCurrentModuleObject,
3995 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
3996 0 : state.dataIPShortCut->cAlphaFieldNames(ArgPointer + 1),
3997 0 : state.dataIPShortCut->cAlphaArgs(ArgPointer + 1)));
3998 0 : ShowContinueError(state, " no OtherSideCoefficients of that name.");
3999 0 : ErrorsFound = true;
4000 : } else {
4001 17 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).OSCPtr = Found;
4002 17 : if (state.dataSurface->OSC(Found).SurfFilmCoef > 0.0) {
4003 1 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond = OtherSideCoefCalcExt;
4004 : } else {
4005 16 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond = OtherSideCoefNoCalcExt;
4006 : }
4007 : }
4008 :
4009 20032 : } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(ArgPointer), "Surface")) {
4010 : // it has to be another surface which needs to be found
4011 : // this will be found on the second pass through the surface input
4012 : // for flagging, set the value to UnreconciledZoneSurface
4013 : // name (ExtBoundCondName) will be validated later.
4014 19574 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond = UnreconciledZoneSurface;
4015 19574 : if (state.dataIPShortCut->lAlphaFieldBlanks(ArgPointer + 1)) {
4016 6 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCondName = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name;
4017 12 : ShowSevereError(state,
4018 18 : format("{}=\"{}\", invalid {}=<blank>.",
4019 : cCurrentModuleObject,
4020 6 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
4021 6 : state.dataIPShortCut->cAlphaFieldNames(ArgPointer + 1)));
4022 6 : ShowContinueError(state, format("..{}=\"Surface\" must be non-blank.", state.dataIPShortCut->cAlphaFieldNames(ArgPointer)));
4023 6 : ShowContinueError(state, "..This surface will become an adiabatic surface - no doors/windows allowed.");
4024 : }
4025 :
4026 458 : } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(ArgPointer), "Zone")) {
4027 : // This is the code for an unmatched "other surface"
4028 : // will be set up later.
4029 365 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond = UnenteredAdjacentZoneSurface;
4030 : // check OutsideFaceEnvironment for legal zone
4031 365 : Found = Util::FindItemInList(
4032 365 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCondName, state.dataHeatBal->Zone, state.dataGlobal->NumOfZones);
4033 365 : ++NeedToAddSurfaces;
4034 :
4035 365 : if (Found == 0) {
4036 0 : ShowSevereError(state,
4037 0 : format("{}=\"{}\", invalid {}=\"{}\".",
4038 : cCurrentModuleObject,
4039 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
4040 0 : state.dataIPShortCut->cAlphaFieldNames(ArgPointer),
4041 0 : state.dataIPShortCut->cAlphaArgs(ArgPointer)));
4042 0 : ShowContinueError(state, "..Referenced as Zone for this surface.");
4043 0 : ErrorsFound = true;
4044 : }
4045 :
4046 93 : } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(ArgPointer), "Foundation")) {
4047 :
4048 38 : if (!state.dataWeather->WeatherFileExists) {
4049 0 : ShowSevereError(
4050 : state,
4051 0 : format("{}=\"{}\", using \"Foundation\" type Outside Boundary Condition requires specification of a weather file",
4052 : cCurrentModuleObject,
4053 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name));
4054 0 : ShowContinueError(state,
4055 : "Either place in.epw in the working directory or specify a weather file on the command line using -w "
4056 : "/path/to/weather.epw");
4057 0 : ErrorsFound = true;
4058 : }
4059 :
4060 : // Find foundation object, if blank use default
4061 38 : if (state.dataIPShortCut->lAlphaFieldBlanks(ArgPointer + 1)) {
4062 :
4063 8 : if (!state.dataSurfaceGeometry->kivaManager.defaultAdded) {
4064 : // Add default foundation if no other foundation object specified
4065 2 : state.dataSurfaceGeometry->kivaManager.addDefaultFoundation();
4066 : }
4067 8 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).OSCPtr =
4068 8 : state.dataSurfaceGeometry->kivaManager.defaultIndex; // Reuse OSC pointer...shouldn't be used for non OSC surfaces anyway.
4069 : } else {
4070 : Found =
4071 30 : state.dataSurfaceGeometry->kivaManager.findFoundation(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCondName);
4072 30 : if (Found != (int)state.dataSurfaceGeometry->kivaManager.foundationInputs.size()) {
4073 30 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).OSCPtr = Found;
4074 : } else {
4075 0 : ShowSevereError(state,
4076 0 : format("{}=\"{}\", invalid {}=\"{}\".",
4077 : cCurrentModuleObject,
4078 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
4079 0 : state.dataIPShortCut->cAlphaFieldNames(ArgPointer + 1),
4080 0 : state.dataIPShortCut->cAlphaArgs(ArgPointer + 1)));
4081 0 : ErrorsFound = true;
4082 : }
4083 : }
4084 :
4085 38 : if (state.dataConstruction->Construct(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction).SourceSinkPresent) {
4086 0 : ShowSevereError(state,
4087 0 : format("{}=\"{}\", construction may not have an internal source/sink",
4088 : cCurrentModuleObject,
4089 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name));
4090 0 : ErrorsFound = true;
4091 : }
4092 38 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond = KivaFoundation;
4093 :
4094 55 : } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(ArgPointer), "OtherSideConditionsModel")) {
4095 55 : Found = Util::FindItemInList(
4096 55 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCondName, state.dataSurface->OSCM, state.dataSurface->TotOSCM);
4097 55 : if (Found == 0) {
4098 0 : ShowSevereError(state,
4099 0 : format("{}=\"{}\", invalid {}=\"{}\".",
4100 : cCurrentModuleObject,
4101 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
4102 0 : state.dataIPShortCut->cAlphaFieldNames(ArgPointer + 1),
4103 0 : state.dataIPShortCut->cAlphaArgs(ArgPointer + 1)));
4104 0 : ErrorsFound = true;
4105 : }
4106 55 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).OSCMPtr = Found;
4107 55 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond = OtherSideCondModeledExt;
4108 :
4109 0 : } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(ArgPointer), "GroundSlabPreprocessorAverage") ||
4110 0 : Util::SameString(state.dataIPShortCut->cAlphaArgs(ArgPointer), "GroundSlabPreprocessorCore") ||
4111 0 : Util::SameString(state.dataIPShortCut->cAlphaArgs(ArgPointer), "GroundSlabPreprocessorPerimeter") ||
4112 0 : Util::SameString(state.dataIPShortCut->cAlphaArgs(ArgPointer), "GroundBasementPreprocessorAverageFloor") ||
4113 0 : Util::SameString(state.dataIPShortCut->cAlphaArgs(ArgPointer), "GroundBasementPreprocessorAverageWall") ||
4114 0 : Util::SameString(state.dataIPShortCut->cAlphaArgs(ArgPointer), "GroundBasementPreprocessorUpperWall") ||
4115 0 : Util::SameString(state.dataIPShortCut->cAlphaArgs(ArgPointer), "GroundBasementPreprocessorLowerWall")) {
4116 0 : ShowSevereError(state,
4117 0 : format("{}=\"{}\", invalid {}=\"{}\".",
4118 : cCurrentModuleObject,
4119 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
4120 0 : state.dataIPShortCut->cAlphaFieldNames(ArgPointer),
4121 0 : state.dataIPShortCut->cAlphaArgs(ArgPointer)));
4122 0 : ShowContinueError(state, "The ExpandObjects program has not been run or is not in your EnergyPlus.exe folder.");
4123 0 : ErrorsFound = true;
4124 :
4125 : } else {
4126 0 : ShowSevereError(state,
4127 0 : format("{}=\"{}\", invalid {}=\"{}\".",
4128 : cCurrentModuleObject,
4129 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
4130 0 : state.dataIPShortCut->cAlphaFieldNames(ArgPointer),
4131 0 : state.dataIPShortCut->cAlphaArgs(ArgPointer)));
4132 0 : ShowContinueError(state,
4133 : "Should be one of \"Outdoors\", \"Adiabatic\", Ground\", \"Surface\", \"OtherSideCoefficients\", "
4134 : "\"OtherSideConditionsModel\" or \"Zone\"");
4135 0 : ErrorsFound = true;
4136 : } // ... End of the ExtBoundCond logical IF Block
4137 :
4138 34827 : ArgPointer += 2;
4139 : // Set the logical flag for the exterior solar
4140 34827 : if (Util::SameString(state.dataIPShortCut->cAlphaArgs(ArgPointer), "SunExposed")) {
4141 11064 : if ((state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond != ExternalEnvironment) &&
4142 29 : (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond != OtherSideCondModeledExt)) {
4143 0 : ShowWarningError(state,
4144 0 : format("{}=\"{}\", {}=\"{}\".",
4145 : cCurrentModuleObject,
4146 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
4147 0 : state.dataIPShortCut->cAlphaFieldNames(ArgPointer),
4148 0 : state.dataIPShortCut->cAlphaArgs(ArgPointer)));
4149 0 : ShowContinueError(state, "..This surface is not exposed to External Environment. Sun exposure has no effect.");
4150 : } else {
4151 11035 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtSolar = true;
4152 : }
4153 23792 : } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(ArgPointer), "NoSun")) {
4154 23792 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtSolar = false;
4155 : } else {
4156 0 : ShowSevereError(state,
4157 0 : format("{}=\"{}\", invalid {}=\"{}\".",
4158 : cCurrentModuleObject,
4159 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
4160 0 : state.dataIPShortCut->cAlphaFieldNames(ArgPointer),
4161 0 : state.dataIPShortCut->cAlphaArgs(ArgPointer)));
4162 0 : ErrorsFound = true;
4163 : }
4164 :
4165 34827 : ++ArgPointer;
4166 : // Set the logical flag for the exterior wind
4167 34827 : if (Util::SameString(state.dataIPShortCut->cAlphaArgs(ArgPointer), "WindExposed")) {
4168 11103 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtWind = true;
4169 23724 : } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(ArgPointer), "NoWind")) {
4170 23724 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtWind = false;
4171 : } else {
4172 0 : ShowSevereError(state,
4173 0 : format("{}=\"{}\", invalid {}=\"{}\".",
4174 : cCurrentModuleObject,
4175 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
4176 0 : state.dataIPShortCut->cAlphaFieldNames(ArgPointer),
4177 0 : state.dataIPShortCut->cAlphaArgs(ArgPointer)));
4178 0 : ErrorsFound = true;
4179 : }
4180 :
4181 : // Set the logical flag for the EcoRoof presented, this is only based on the flag in the construction type
4182 : // if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction > 0)
4183 : // state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtEcoRoof =
4184 : // state.dataConstruction->Construct(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction).TypeIsEcoRoof;
4185 :
4186 34827 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ViewFactorGround = state.dataIPShortCut->rNumericArgs(1);
4187 34827 : if (state.dataIPShortCut->lNumericFieldBlanks(1))
4188 641 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ViewFactorGround = Constant::AutoCalculate;
4189 34827 : if (state.dataIPShortCut->lNumericFieldBlanks(2) || state.dataIPShortCut->rNumericArgs(2) == Constant::AutoCalculate) {
4190 750 : numSides = (SurfaceNumProp - 2) / 3;
4191 750 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides = numSides;
4192 750 : if (mod(SurfaceNumProp - 2, 3) != 0) {
4193 0 : ShowWarningError(state,
4194 0 : format("{}=\"{}\", {}",
4195 : cCurrentModuleObject,
4196 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
4197 0 : format("{} not even multiple of 3. Will read in {}",
4198 0 : state.dataIPShortCut->cNumericFieldNames(2),
4199 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides)));
4200 : }
4201 750 : if (numSides < 3) {
4202 0 : ShowSevereError(state,
4203 0 : format("{}=\"{}\", {} (autocalculate) must be >= 3. Only {} provided.",
4204 : cCurrentModuleObject,
4205 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
4206 0 : state.dataIPShortCut->cNumericFieldNames(2),
4207 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides));
4208 0 : ErrorsFound = true;
4209 0 : continue;
4210 : }
4211 : } else {
4212 34077 : numSides = (SurfaceNumProp - 2) / 3;
4213 34077 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides = state.dataIPShortCut->rNumericArgs(2);
4214 34077 : if (numSides > state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides) {
4215 0 : ShowWarningError(state,
4216 0 : format("{}=\"{}\", field {}={}",
4217 : cCurrentModuleObject,
4218 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
4219 0 : state.dataIPShortCut->cNumericFieldNames(2),
4220 0 : fmt::to_string(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides)));
4221 0 : ShowContinueError(state,
4222 0 : format("...but {} were entered. Only the indicated {} will be used.",
4223 : numSides,
4224 0 : state.dataIPShortCut->cNumericFieldNames(2)));
4225 : }
4226 : }
4227 34827 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex.allocate(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides);
4228 34827 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).NewVertex.allocate(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides);
4229 104481 : GetVertices(state, SurfNum, state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides, state.dataIPShortCut->rNumericArgs({3, _}));
4230 34827 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Area <= 0.0) {
4231 0 : ShowSevereError(state,
4232 0 : format("{}=\"{}\", Surface Area <= 0.0; Entered Area={:.2T}",
4233 : cCurrentModuleObject,
4234 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
4235 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Area));
4236 0 : ErrorsFound = true;
4237 : }
4238 :
4239 34827 : CheckConvexity(state, SurfNum, state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides);
4240 34827 : if (Util::SameString(state.dataIPShortCut->cAlphaArgs(5), "Surface")) {
4241 16 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides !=
4242 8 : static_cast<int>(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex.size())) {
4243 0 : ShowSevereError(state,
4244 0 : format("{}=\"{}\", After CheckConvexity, mismatch between Sides ({}) and size of Vertex ({}).",
4245 : cCurrentModuleObject,
4246 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
4247 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides,
4248 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex.size()));
4249 0 : ShowContinueError(state, "CheckConvexity is used to verify the convexity of a surface and detect collinear points.");
4250 0 : ErrorsFound = true;
4251 : }
4252 : }
4253 34827 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction > 0) {
4254 : // Check wall height for the CFactor walls
4255 :
4256 57115 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == SurfaceClass::Wall &&
4257 22288 : state.dataConstruction->Construct(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction).TypeIsCfactorWall) {
4258 34 : if (std::abs(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Height -
4259 34 : state.dataConstruction->Construct(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction).Height) > 0.05) {
4260 0 : ShowWarningError(state,
4261 0 : format("{}=\"{}\", underground Wall Height = {:.2T}",
4262 : cCurrentModuleObject,
4263 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
4264 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Height));
4265 0 : ShowContinueError(state, "..which does not match its construction height.");
4266 : }
4267 : }
4268 :
4269 : // Check area and perimeter for the FFactor floors
4270 41601 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == SurfaceClass::Floor &&
4271 6774 : state.dataConstruction->Construct(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction).TypeIsFfactorFloor) {
4272 184 : if (std::abs(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Area -
4273 184 : state.dataConstruction->Construct(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction).Area) > 0.1) {
4274 0 : ShowWarningError(state,
4275 0 : format("{}=\"{}\", underground Floor Area = {:.2T}",
4276 : cCurrentModuleObject,
4277 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
4278 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Area));
4279 0 : ShowContinueError(state, "..which does not match its construction area.");
4280 : }
4281 184 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Perimeter <
4282 184 : state.dataConstruction->Construct(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction).PerimeterExposed - 0.1) {
4283 0 : ShowWarningError(state,
4284 0 : format("{}=\"{}\", underground Floor Perimeter = {:.2T}",
4285 : cCurrentModuleObject,
4286 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
4287 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Perimeter));
4288 0 : ShowContinueError(state, "..which is less than its construction exposed perimeter.");
4289 : }
4290 : }
4291 : }
4292 : }
4293 : } // Item Looop
4294 : // Check number of Vertex between base surface and Outside Boundary surface
4295 : int ExtSurfNum;
4296 35775 : for (int i = 1; i <= SurfNum; i++) {
4297 55823 : if (state.dataSurfaceGeometry->SurfaceTmp(i).ExtBoundCond == UnreconciledZoneSurface &&
4298 20844 : state.dataSurfaceGeometry->SurfaceTmp(i).ExtBoundCondName != "") {
4299 20844 : ExtSurfNum = Util::FindItemInList(state.dataSurfaceGeometry->SurfaceTmp(i).ExtBoundCondName, state.dataSurfaceGeometry->SurfaceTmp);
4300 : // If we cannot find the referenced surface
4301 20844 : if (ExtSurfNum == 0) {
4302 0 : ShowSevereError(state,
4303 0 : format("{}=\"{}\" references an outside boundary surface that cannot be found:{}",
4304 : cCurrentModuleObject,
4305 0 : state.dataSurfaceGeometry->SurfaceTmp(i).Name,
4306 0 : state.dataSurfaceGeometry->SurfaceTmp(i).ExtBoundCondName));
4307 0 : ErrorsFound = true;
4308 : // If vertex size mistmatch
4309 41688 : } else if (state.dataSurfaceGeometry->SurfaceTmp(i).Vertex.size() !=
4310 20844 : state.dataSurfaceGeometry->SurfaceTmp(ExtSurfNum).Vertex.size()) {
4311 0 : ShowSevereError(state,
4312 0 : format("{}=\"{}\", Vertex size mismatch between base surface :{} and outside boundary surface: {}",
4313 : cCurrentModuleObject,
4314 0 : state.dataSurfaceGeometry->SurfaceTmp(i).Name,
4315 0 : state.dataSurfaceGeometry->SurfaceTmp(i).Name,
4316 0 : state.dataSurfaceGeometry->SurfaceTmp(ExtSurfNum).Name));
4317 0 : ShowContinueError(state,
4318 0 : format("The vertex sizes are {} for base surface and {} for outside boundary surface. Please check inputs.",
4319 0 : state.dataSurfaceGeometry->SurfaceTmp(i).Vertex.size(),
4320 0 : state.dataSurfaceGeometry->SurfaceTmp(ExtSurfNum).Vertex.size()));
4321 0 : ErrorsFound = true;
4322 : }
4323 : }
4324 : }
4325 796 : }
4326 :
4327 796 : void GetRectSurfaces(EnergyPlusData &state,
4328 : bool &ErrorsFound, // Error flag indicator (true if errors found)
4329 : int &SurfNum, // Count of Current SurfaceNumber
4330 : int const TotRectExtWalls, // Number of Exterior Walls to obtain
4331 : int const TotRectIntWalls, // Number of Adiabatic Walls to obtain
4332 : int const TotRectIZWalls, // Number of Interzone Walls to obtain
4333 : int const TotRectUGWalls, // Number of Underground to obtain
4334 : int const TotRectRoofs, // Number of Roofs to obtain
4335 : int const TotRectCeilings, // Number of Adiabatic Ceilings to obtain
4336 : int const TotRectIZCeilings, // Number of Interzone Ceilings to obtain
4337 : int const TotRectGCFloors, // Number of Floors with Ground Contact to obtain
4338 : int const TotRectIntFloors, // Number of Adiabatic Walls to obtain
4339 : int const TotRectIZFloors, // Number of Interzone Floors to obtain
4340 : const Array1D<SurfaceClass> &BaseSurfIDs, // ID Assignments for valid surface classes
4341 : int &NeedToAddSurfaces // Number of surfaces to add, based on unentered IZ surfaces
4342 : )
4343 : {
4344 :
4345 : // SUBROUTINE INFORMATION:
4346 : // AUTHOR Linda Lawrie
4347 : // DATE WRITTEN December 2008
4348 : // MODIFIED na
4349 : // RE-ENGINEERED na
4350 :
4351 : // PURPOSE OF THIS SUBROUTINE:
4352 : // Get simple (rectangular, LLC corner specified) walls
4353 :
4354 : // Using/Aliasing
4355 :
4356 : // SUBROUTINE PARAMETER DEFINITIONS:
4357 : static Array1D_string const cModuleObjects(10,
4358 : {"Wall:Exterior",
4359 : "Wall:Adiabatic",
4360 : "Wall:Interzone",
4361 : "Wall:Underground",
4362 : "Roof",
4363 : "Ceiling:Adiabatic",
4364 : "Ceiling:Interzone",
4365 : "Floor:GroundContact",
4366 : "Floor:Adiabatic",
4367 796 : "Floor:Interzone"});
4368 :
4369 : int Item;
4370 : int ItemsToGet;
4371 : int Loop;
4372 : int NumAlphas;
4373 : int NumNumbers;
4374 : int IOStat; // IO Status when calling get input subroutine
4375 : int Found; // For matching base surfaces
4376 : bool GettingIZSurfaces;
4377 : int OtherSurfaceField;
4378 : int ExtBoundCondition;
4379 : int ClassItem;
4380 : int ZoneNum;
4381 796 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
4382 8756 : for (Item = 1; Item <= 10; ++Item) {
4383 :
4384 7960 : cCurrentModuleObject = cModuleObjects(Item);
4385 7960 : if (Item == 1) {
4386 796 : ItemsToGet = TotRectExtWalls;
4387 796 : GettingIZSurfaces = false;
4388 796 : OtherSurfaceField = 0;
4389 796 : ExtBoundCondition = ExternalEnvironment;
4390 796 : ClassItem = 1;
4391 7164 : } else if (Item == 2) {
4392 796 : ItemsToGet = TotRectIntWalls;
4393 796 : GettingIZSurfaces = false;
4394 796 : OtherSurfaceField = 0;
4395 796 : ExtBoundCondition = UnreconciledZoneSurface;
4396 796 : ClassItem = 1;
4397 6368 : } else if (Item == 3) {
4398 796 : ItemsToGet = TotRectIZWalls;
4399 796 : GettingIZSurfaces = true;
4400 796 : OtherSurfaceField = 5;
4401 796 : ExtBoundCondition = UnreconciledZoneSurface;
4402 796 : ClassItem = 1;
4403 5572 : } else if (Item == 4) {
4404 796 : ItemsToGet = TotRectUGWalls;
4405 796 : GettingIZSurfaces = false;
4406 796 : OtherSurfaceField = 0;
4407 796 : ExtBoundCondition = Ground;
4408 796 : ClassItem = 1;
4409 4776 : } else if (Item == 5) {
4410 796 : ItemsToGet = TotRectRoofs;
4411 796 : GettingIZSurfaces = false;
4412 796 : OtherSurfaceField = 0;
4413 796 : ExtBoundCondition = ExternalEnvironment;
4414 796 : ClassItem = 3;
4415 3980 : } else if (Item == 6) {
4416 796 : ItemsToGet = TotRectCeilings;
4417 796 : GettingIZSurfaces = false;
4418 796 : OtherSurfaceField = 0;
4419 796 : ExtBoundCondition = UnreconciledZoneSurface;
4420 796 : ClassItem = 3;
4421 3184 : } else if (Item == 7) {
4422 796 : ItemsToGet = TotRectIZCeilings;
4423 796 : GettingIZSurfaces = false;
4424 796 : OtherSurfaceField = 5;
4425 796 : ExtBoundCondition = UnreconciledZoneSurface;
4426 796 : ClassItem = 3;
4427 2388 : } else if (Item == 8) {
4428 796 : ItemsToGet = TotRectGCFloors;
4429 796 : GettingIZSurfaces = false;
4430 796 : OtherSurfaceField = 0;
4431 796 : ExtBoundCondition = Ground;
4432 796 : ClassItem = 2;
4433 1592 : } else if (Item == 9) {
4434 796 : ItemsToGet = TotRectIntFloors;
4435 796 : GettingIZSurfaces = false;
4436 796 : OtherSurfaceField = 0;
4437 796 : ExtBoundCondition = UnreconciledZoneSurface;
4438 796 : ClassItem = 2;
4439 : } else { // IF (Item == 10) THEN
4440 796 : ItemsToGet = TotRectIZFloors;
4441 796 : GettingIZSurfaces = true;
4442 796 : OtherSurfaceField = 5;
4443 796 : ExtBoundCondition = UnreconciledZoneSurface;
4444 796 : ClassItem = 2;
4445 : }
4446 :
4447 8079 : for (Loop = 1; Loop <= ItemsToGet; ++Loop) {
4448 238 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
4449 : cCurrentModuleObject,
4450 : Loop,
4451 119 : state.dataIPShortCut->cAlphaArgs,
4452 : NumAlphas,
4453 119 : state.dataIPShortCut->rNumericArgs,
4454 : NumNumbers,
4455 : IOStat,
4456 119 : state.dataIPShortCut->lNumericFieldBlanks,
4457 119 : state.dataIPShortCut->lAlphaFieldBlanks,
4458 119 : state.dataIPShortCut->cAlphaFieldNames,
4459 119 : state.dataIPShortCut->cNumericFieldNames);
4460 :
4461 238 : if (GlobalNames::VerifyUniqueInterObjectName(state,
4462 119 : state.dataSurfaceGeometry->UniqueSurfaceNames,
4463 119 : state.dataIPShortCut->cAlphaArgs(1),
4464 : cCurrentModuleObject,
4465 119 : state.dataIPShortCut->cAlphaFieldNames(1),
4466 : ErrorsFound)) {
4467 0 : continue;
4468 : }
4469 :
4470 119 : if (NumNumbers < 7) {
4471 0 : ShowSevereError(state,
4472 0 : format("{}=\"{}\", Too few number of numeric args=[{}].",
4473 : cCurrentModuleObject,
4474 0 : state.dataIPShortCut->cAlphaArgs(1),
4475 : NumNumbers));
4476 0 : ErrorsFound = true;
4477 : }
4478 :
4479 119 : ++SurfNum;
4480 119 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name = state.dataIPShortCut->cAlphaArgs(1); // Set the Surface Name in the Derived Type
4481 119 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class = BaseSurfIDs(ClassItem); // Set class number
4482 :
4483 119 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction =
4484 119 : Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(2), state.dataConstruction->Construct, state.dataHeatBal->TotConstructs);
4485 :
4486 119 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction == 0) {
4487 0 : ErrorsFound = true;
4488 0 : ShowSevereError(state,
4489 0 : format("{}=\"{}\", invalid {}=\"{}\".",
4490 : cCurrentModuleObject,
4491 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
4492 0 : state.dataIPShortCut->cAlphaFieldNames(2),
4493 0 : state.dataIPShortCut->cAlphaArgs(2)));
4494 119 : } else if (state.dataConstruction->Construct(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction).TypeIsWindow) {
4495 0 : ErrorsFound = true;
4496 0 : ShowSevereError(state,
4497 0 : format("{}=\"{}\", invalid {}=\"{}\" - has Window materials.",
4498 : cCurrentModuleObject,
4499 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
4500 0 : state.dataIPShortCut->cAlphaFieldNames(3),
4501 0 : state.dataIPShortCut->cAlphaArgs(2)));
4502 0 : ShowContinueError(state,
4503 0 : format("...because {}={}", state.dataIPShortCut->cAlphaFieldNames(2), state.dataIPShortCut->cAlphaArgs(2)));
4504 : } else {
4505 119 : state.dataConstruction->Construct(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction).IsUsed = true;
4506 119 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ConstructionStoredInputValue =
4507 119 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction;
4508 : }
4509 119 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).HeatTransSurf = true;
4510 119 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).BaseSurf = SurfNum;
4511 119 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).BaseSurfName = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name;
4512 :
4513 119 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ZoneName = state.dataIPShortCut->cAlphaArgs(3);
4514 119 : ZoneNum = Util::FindItemInList(
4515 119 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ZoneName, state.dataHeatBal->Zone, state.dataGlobal->NumOfZones);
4516 :
4517 119 : if (ZoneNum != 0) {
4518 119 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Zone = ZoneNum;
4519 : } else {
4520 0 : ShowSevereError(state,
4521 0 : format("{}=\"{}\", invalid {}=\"{}\".",
4522 : cCurrentModuleObject,
4523 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
4524 0 : state.dataIPShortCut->cAlphaFieldNames(3),
4525 0 : state.dataIPShortCut->cAlphaArgs(3)));
4526 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class = SurfaceClass::Invalid;
4527 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ZoneName = "Unknown Zone";
4528 0 : ErrorsFound = true;
4529 : }
4530 :
4531 119 : if (!state.dataIPShortCut->lAlphaFieldBlanks(4)) {
4532 0 : int spaceNum = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(4), state.dataHeatBal->space);
4533 :
4534 0 : if (spaceNum != 0) {
4535 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).spaceNum = spaceNum;
4536 : } else {
4537 0 : ShowSevereError(state,
4538 0 : format("{}=\"{}\", invalid {}=\"{}\".",
4539 : cCurrentModuleObject,
4540 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
4541 0 : state.dataIPShortCut->cAlphaFieldNames(4),
4542 0 : state.dataIPShortCut->cAlphaArgs(4)));
4543 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class = SurfaceClass::Invalid;
4544 0 : ErrorsFound = true;
4545 : }
4546 : }
4547 :
4548 119 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond = ExtBoundCondition;
4549 119 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction > 0) {
4550 119 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == SurfaceClass::Wall &&
4551 119 : state.dataConstruction->Construct(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction).TypeIsCfactorWall &&
4552 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond == Ground) {
4553 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond = GroundFCfactorMethod;
4554 119 : } else if (state.dataConstruction->Construct(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction).TypeIsCfactorWall) {
4555 0 : ErrorsFound = true;
4556 0 : ShowSevereError(state,
4557 0 : format("{}=\"{}\", Construction type is \"Construction:CfactorUndergroundWall\" but invalid for this object.",
4558 : cCurrentModuleObject,
4559 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name));
4560 : }
4561 119 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == SurfaceClass::Floor &&
4562 119 : state.dataConstruction->Construct(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction).TypeIsFfactorFloor &&
4563 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond == Ground) {
4564 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond = GroundFCfactorMethod;
4565 119 : } else if (state.dataConstruction->Construct(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction).TypeIsFfactorFloor) {
4566 0 : ErrorsFound = true;
4567 0 : ShowSevereError(state,
4568 0 : format("{}=\"{}\", Construction type is \"Construction:FfactorGroundFloor\" but invalid for this object.",
4569 : cCurrentModuleObject,
4570 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name));
4571 : }
4572 : }
4573 119 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtSolar = false;
4574 119 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtWind = false;
4575 119 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ViewFactorGround = Constant::AutoCalculate;
4576 :
4577 119 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond == ExternalEnvironment) {
4578 66 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtSolar = true;
4579 66 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtWind = true;
4580 :
4581 : // Set the logical flag for the EcoRoof presented, this is only based on the flag in the construction type
4582 : // if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction > 0)
4583 : // state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtEcoRoof =
4584 : // state.dataConstruction->Construct(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction).TypeIsEcoRoof;
4585 :
4586 53 : } else if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond == UnreconciledZoneSurface) {
4587 47 : if (GettingIZSurfaces) {
4588 19 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCondName = state.dataIPShortCut->cAlphaArgs(OtherSurfaceField);
4589 19 : Found = Util::FindItemInList(
4590 19 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCondName, state.dataHeatBal->Zone, state.dataGlobal->NumOfZones);
4591 : // see if match to zone, then it's an unentered other surface, else reconciled later
4592 19 : if (Found > 0) {
4593 1 : ++NeedToAddSurfaces;
4594 1 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond = UnenteredAdjacentZoneSurface;
4595 : }
4596 : } else {
4597 28 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCondName = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name;
4598 : }
4599 :
4600 6 : } else if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond == Ground) {
4601 :
4602 6 : if (state.dataSurfaceGeometry->NoGroundTempObjWarning) {
4603 1 : if (!state.dataEnvrn->GroundTempInputs[(int)DataEnvironment::GroundTempType::BuildingSurface]) {
4604 0 : ShowWarningError(state,
4605 : "GetRectSurfaces: Surfaces with interface to Ground found but no \"Ground Temperatures\" were input.");
4606 0 : ShowContinueError(state, format("Found first in surface={}", state.dataIPShortCut->cAlphaArgs(1)));
4607 0 : ShowContinueError(state,
4608 0 : format("Defaults, constant throughout the year of ({:.1R}) will be used.",
4609 0 : state.dataEnvrn->GroundTemp[(int)DataEnvironment::GroundTempType::BuildingSurface]));
4610 : }
4611 1 : state.dataSurfaceGeometry->NoGroundTempObjWarning = false;
4612 : }
4613 :
4614 0 : } else if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond == GroundFCfactorMethod) {
4615 0 : if (state.dataSurfaceGeometry->NoFCGroundTempObjWarning) {
4616 0 : if (!state.dataEnvrn->GroundTempInputs[(int)DataEnvironment::GroundTempType::FCFactorMethod]) {
4617 0 : ShowSevereError(state,
4618 : "GetRectSurfaces: Surfaces with interface to GroundFCfactorMethod found but no \"FC Ground "
4619 : "Temperatures\" were input.");
4620 0 : ShowContinueError(state, format("Found first in surface={}", state.dataIPShortCut->cAlphaArgs(1)));
4621 0 : ShowContinueError(state,
4622 : "Either add a \"Site:GroundTemperature:FCfactorMethod\" object or use a weather file with "
4623 : "Ground Temperatures.");
4624 0 : ErrorsFound = true;
4625 0 : state.dataSurfaceGeometry->NoFCGroundTempObjWarning = false;
4626 : }
4627 : }
4628 :
4629 : } // ... End of the ExtBoundCond logical IF Block
4630 :
4631 119 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Azimuth = state.dataIPShortCut->rNumericArgs(1);
4632 119 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Tilt = state.dataIPShortCut->rNumericArgs(2);
4633 119 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).convOrientation =
4634 119 : Convect::GetSurfConvOrientation(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Tilt);
4635 119 : if (!state.dataSurface->WorldCoordSystem) {
4636 95 : if (ZoneNum != 0) {
4637 95 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Azimuth +=
4638 95 : state.dataHeatBal->BuildingAzimuth + state.dataHeatBal->Zone(ZoneNum).RelNorth;
4639 : }
4640 : }
4641 119 : if (ZoneNum != 0) {
4642 119 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Azimuth += state.dataHeatBal->BuildingRotationAppendixG;
4643 : }
4644 :
4645 119 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides = 4;
4646 119 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex.allocate(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides);
4647 :
4648 714 : MakeRectangularVertices(state,
4649 : SurfNum,
4650 119 : state.dataIPShortCut->rNumericArgs(3),
4651 119 : state.dataIPShortCut->rNumericArgs(4),
4652 119 : state.dataIPShortCut->rNumericArgs(5),
4653 119 : state.dataIPShortCut->rNumericArgs(6),
4654 119 : state.dataIPShortCut->rNumericArgs(7),
4655 119 : state.dataSurfaceGeometry->RectSurfRefWorldCoordSystem);
4656 :
4657 119 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Area <= 0.0) {
4658 0 : ShowSevereError(state,
4659 0 : format("{}=\"{}\", Surface Area <= 0.0; Entered Area={:.2T}",
4660 : cCurrentModuleObject,
4661 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
4662 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Area));
4663 0 : ErrorsFound = true;
4664 : }
4665 :
4666 : // Check wall height for the CFactor walls
4667 198 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == SurfaceClass::Wall &&
4668 79 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond == GroundFCfactorMethod) {
4669 0 : if (std::abs(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Height -
4670 0 : state.dataConstruction->Construct(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction).Height) > 0.05) {
4671 0 : ShowWarningError(state,
4672 0 : format("{}=\"{}\", underground Wall Height = {:.2T}",
4673 : cCurrentModuleObject,
4674 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
4675 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Height));
4676 0 : ShowContinueError(state, "..which deos not match its construction height.");
4677 : }
4678 : }
4679 :
4680 : // Check area and perimeter for the FFactor floors
4681 139 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == SurfaceClass::Floor &&
4682 20 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond == GroundFCfactorMethod) {
4683 0 : if (std::abs(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Area -
4684 0 : state.dataConstruction->Construct(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction).Area) > 0.1) {
4685 0 : ShowWarningError(state,
4686 0 : format("{}=\"{}\", underground Floor Area = {:.2T}",
4687 : cCurrentModuleObject,
4688 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
4689 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Area));
4690 0 : ShowContinueError(state, "..which does not match its construction area.");
4691 : }
4692 0 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Perimeter <
4693 0 : state.dataConstruction->Construct(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction).PerimeterExposed - 0.1) {
4694 0 : ShowWarningError(state,
4695 0 : format("{}=\"{}\", underground Floor Perimeter = {:.2T}",
4696 : cCurrentModuleObject,
4697 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
4698 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Perimeter));
4699 0 : ShowContinueError(state, "..which is less than its construction exposed perimeter.");
4700 : }
4701 : }
4702 : } // Getting Items
4703 : }
4704 796 : }
4705 :
4706 139 : void MakeRectangularVertices(EnergyPlusData &state,
4707 : int const SurfNum,
4708 : Real64 const XCoord,
4709 : Real64 const YCoord,
4710 : Real64 const ZCoord,
4711 : Real64 const Length,
4712 : Real64 const Height,
4713 : bool const SurfWorldCoordSystem)
4714 : {
4715 :
4716 : // SUBROUTINE INFORMATION:
4717 : // AUTHOR Linda Lawrie
4718 : // DATE WRITTEN December 2008
4719 : // MODIFIED na
4720 : // RE-ENGINEERED na
4721 :
4722 : // PURPOSE OF THIS SUBROUTINE:
4723 : // This routine creates world/3d coordinates for rectangular surfaces using azimuth, tilt, LLC (X,Y,Z), length & height.
4724 :
4725 : // METHODOLOGY EMPLOYED:
4726 : // na
4727 :
4728 : // REFERENCES:
4729 : // na
4730 :
4731 : // Using/Aliasing
4732 : using namespace Vectors;
4733 :
4734 : // Locals
4735 : // SUBROUTINE ARGUMENT DEFINITIONS:
4736 :
4737 : // SUBROUTINE PARAMETER DEFINITIONS:
4738 : // na
4739 :
4740 : // INTERFACE BLOCK SPECIFICATIONS:
4741 : // na
4742 :
4743 : // DERIVED TYPE DEFINITIONS:
4744 : // na
4745 :
4746 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
4747 : Real64 SurfAzimuth; // Surface Azimuth/Facing (same as Base Surface)
4748 : Real64 SurfTilt; // Tilt (same as Base Surface)
4749 : Real64 XLLC;
4750 : Real64 YLLC;
4751 : Real64 ZLLC;
4752 : Real64 CosSurfAzimuth;
4753 : Real64 SinSurfAzimuth;
4754 : Real64 CosSurfTilt;
4755 : Real64 SinSurfTilt;
4756 139 : Array1D<Real64> XX(4);
4757 139 : Array1D<Real64> YY(4);
4758 : Real64 Xb;
4759 : Real64 Yb;
4760 : Real64 Perimeter;
4761 : int n;
4762 : int Vrt;
4763 :
4764 159 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Zone == 0 &&
4765 20 : (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class != SurfaceClass::Detached_F &&
4766 6 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class != SurfaceClass::Detached_B))
4767 0 : return;
4768 :
4769 139 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Height = Height;
4770 139 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Width = Length;
4771 :
4772 139 : SurfAzimuth = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Azimuth;
4773 139 : SurfTilt = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Tilt;
4774 139 : CosSurfAzimuth = std::cos(SurfAzimuth * Constant::DegToRadians);
4775 139 : SinSurfAzimuth = std::sin(SurfAzimuth * Constant::DegToRadians);
4776 139 : CosSurfTilt = std::cos(SurfTilt * Constant::DegToRadians);
4777 139 : SinSurfTilt = std::sin(SurfTilt * Constant::DegToRadians);
4778 139 : if (!SurfWorldCoordSystem) {
4779 111 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Zone > 0) {
4780 95 : Xb = XCoord * state.dataSurfaceGeometry->CosZoneRelNorth(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Zone) -
4781 95 : YCoord * state.dataSurfaceGeometry->SinZoneRelNorth(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Zone) +
4782 95 : state.dataHeatBal->Zone(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Zone).OriginX;
4783 95 : Yb = XCoord * state.dataSurfaceGeometry->SinZoneRelNorth(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Zone) +
4784 95 : YCoord * state.dataSurfaceGeometry->CosZoneRelNorth(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Zone) +
4785 95 : state.dataHeatBal->Zone(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Zone).OriginY;
4786 95 : XLLC = Xb * state.dataSurfaceGeometry->CosBldgRelNorth - Yb * state.dataSurfaceGeometry->SinBldgRelNorth;
4787 95 : YLLC = Xb * state.dataSurfaceGeometry->SinBldgRelNorth + Yb * state.dataSurfaceGeometry->CosBldgRelNorth;
4788 95 : ZLLC = ZCoord + state.dataHeatBal->Zone(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Zone).OriginZ;
4789 : } else {
4790 16 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == SurfaceClass::Detached_B) {
4791 5 : Xb = XCoord;
4792 5 : Yb = YCoord;
4793 5 : XLLC = Xb * state.dataSurfaceGeometry->CosBldgRelNorth - Yb * state.dataSurfaceGeometry->SinBldgRelNorth;
4794 5 : YLLC = Xb * state.dataSurfaceGeometry->SinBldgRelNorth + Yb * state.dataSurfaceGeometry->CosBldgRelNorth;
4795 5 : ZLLC = ZCoord;
4796 : } else {
4797 11 : XLLC = XCoord;
4798 11 : YLLC = YCoord;
4799 11 : ZLLC = ZCoord;
4800 : }
4801 : }
4802 : } else {
4803 : // for world coordinates, only rotate for appendix G
4804 28 : Xb = XCoord;
4805 28 : Yb = YCoord;
4806 28 : ZLLC = ZCoord;
4807 28 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class != SurfaceClass::Detached_F) {
4808 25 : XLLC = Xb * state.dataSurfaceGeometry->CosBldgRotAppGonly - Yb * state.dataSurfaceGeometry->SinBldgRotAppGonly;
4809 25 : YLLC = Xb * state.dataSurfaceGeometry->SinBldgRotAppGonly + Yb * state.dataSurfaceGeometry->CosBldgRotAppGonly;
4810 : } else {
4811 3 : XLLC = Xb;
4812 3 : YLLC = Yb;
4813 : }
4814 : }
4815 :
4816 139 : XX(1) = 0.0;
4817 139 : XX(2) = 0.0;
4818 139 : XX(3) = Length;
4819 139 : XX(4) = Length;
4820 139 : YY(1) = Height;
4821 139 : YY(4) = Height;
4822 139 : YY(3) = 0.0;
4823 139 : YY(2) = 0.0;
4824 :
4825 695 : for (n = 1; n <= state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides; ++n) {
4826 556 : Vrt = n;
4827 556 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(Vrt).x = XLLC - XX(n) * CosSurfAzimuth - YY(n) * CosSurfTilt * SinSurfAzimuth;
4828 556 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(Vrt).y = YLLC + XX(n) * SinSurfAzimuth - YY(n) * CosSurfTilt * CosSurfAzimuth;
4829 556 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(Vrt).z = ZLLC + YY(n) * SinSurfTilt;
4830 : }
4831 :
4832 139 : CreateNewellAreaVector(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex,
4833 139 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides,
4834 139 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).NewellAreaVector);
4835 139 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).GrossArea = VecLength(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).NewellAreaVector);
4836 139 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Area = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).GrossArea;
4837 139 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).NetAreaShadowCalc = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Area;
4838 139 : CreateNewellSurfaceNormalVector(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex,
4839 139 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides,
4840 139 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).NewellSurfaceNormalVector);
4841 139 : DetermineAzimuthAndTilt(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex,
4842 : SurfAzimuth,
4843 : SurfTilt,
4844 139 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).lcsx,
4845 139 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).lcsy,
4846 139 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).lcsz,
4847 139 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).NewellSurfaceNormalVector);
4848 139 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Azimuth = SurfAzimuth;
4849 139 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Tilt = SurfTilt;
4850 139 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).convOrientation =
4851 139 : Convect::GetSurfConvOrientation(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Tilt);
4852 : // Sine and cosine of azimuth and tilt
4853 139 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).SinAzim = SinSurfAzimuth;
4854 139 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).CosAzim = CosSurfAzimuth;
4855 139 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).SinTilt = SinSurfTilt;
4856 139 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).CosTilt = CosSurfTilt;
4857 139 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ViewFactorGround = 0.5 * (1.0 - state.dataSurfaceGeometry->SurfaceTmp(SurfNum).CosTilt);
4858 : // Outward normal unit vector (pointing away from room)
4859 139 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).OutNormVec = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).NewellSurfaceNormalVector;
4860 556 : for (n = 1; n <= 3; ++n) {
4861 417 : if (std::abs(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).OutNormVec(n) - 1.0) < 1.e-06)
4862 71 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).OutNormVec(n) = +1.0;
4863 417 : if (std::abs(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).OutNormVec(n) + 1.0) < 1.e-06)
4864 68 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).OutNormVec(n) = -1.0;
4865 417 : if (std::abs(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).OutNormVec(n)) < 1.e-06)
4866 278 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).OutNormVec(n) = 0.0;
4867 : }
4868 :
4869 : // Can perform tests on this surface here
4870 139 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ViewFactorSky = 0.5 * (1.0 + state.dataSurfaceGeometry->SurfaceTmp(SurfNum).CosTilt);
4871 : // The following IR view factors are modified in subr. SkyDifSolarShading if there are shadowing
4872 : // surfaces
4873 139 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ViewFactorSkyIR = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ViewFactorSky;
4874 139 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ViewFactorGroundIR = 0.5 * (1.0 - state.dataSurfaceGeometry->SurfaceTmp(SurfNum).CosTilt);
4875 :
4876 139 : Perimeter = distance(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides),
4877 139 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(1));
4878 556 : for (Vrt = 2; Vrt <= state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides; ++Vrt) {
4879 417 : Perimeter +=
4880 417 : distance(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(Vrt), state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(Vrt - 1));
4881 : }
4882 139 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Perimeter = Perimeter;
4883 :
4884 : // Call to transform vertices
4885 :
4886 139 : TransformVertsByAspect(state, SurfNum, state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides);
4887 139 : }
4888 :
4889 796 : void GetHTSubSurfaceData(EnergyPlusData &state,
4890 : bool &ErrorsFound, // Error flag indicator (true if errors found)
4891 : int &SurfNum, // Count of Current SurfaceNumber
4892 : int const TotHTSubs, // Number of Heat Transfer SubSurfaces to obtain
4893 : const Array1D_string &SubSurfCls, // Valid Classes for Sub Surfaces
4894 : const Array1D<SurfaceClass> &SubSurfIDs, // ID Assignments for valid sub surface classes
4895 : int &AddedSubSurfaces, // Subsurfaces added when windows reference Window5
4896 : int &NeedToAddSurfaces // Number of surfaces to add, based on unentered IZ surfaces
4897 : )
4898 : {
4899 :
4900 : // SUBROUTINE INFORMATION:
4901 : // AUTHOR Linda Lawrie
4902 : // DATE WRITTEN May 2000
4903 : // MODIFIED August 2012 - line up subsurfaces with base surface types
4904 : // RE-ENGINEERED na
4905 :
4906 : // PURPOSE OF THIS SUBROUTINE:
4907 : // This subroutine gets the HeatTransfer Sub Surface Data,
4908 : // checks it for errors, etc.
4909 :
4910 : // METHODOLOGY EMPLOYED:
4911 : // na
4912 :
4913 : // REFERENCES:
4914 : // Heat Transfer Subsurface Definition
4915 : // FenestrationSurface:Detailed,
4916 : // \min-fields 19
4917 : // \memo Used for windows, doors, glass doors, tubular daylighting devices
4918 : // \format vertices
4919 : // A1 , \field Name
4920 : // \required-field
4921 : // \type alpha
4922 : // A2 , \field Surface Type
4923 : // \required-field
4924 : // \type choice
4925 : // \key Window
4926 : // \key Door
4927 : // \key GlassDoor
4928 : // \key TubularDaylightDome
4929 : // \key TubularDaylightDiffuser
4930 : // A3 , \field Construction Name
4931 : // \required-field
4932 : // \note To be matched with a construction in this input file
4933 : // \type object-list
4934 : // \object-list ConstructionNames
4935 : // A4 , \field Building Surface Name
4936 : // \required-field
4937 : // \type object-list
4938 : // \object-list SurfaceNames
4939 : // A5, \field Outside Boundary Condition Object
4940 : // \type object-list
4941 : // \object-list OutFaceEnvNames
4942 : // \note Non-blank only if base surface field Outside Boundary Condition is
4943 : // \note Surface or OtherSideCoefficients
4944 : // \note If Base Surface's Surface, specify name of corresponding subsurface in adjacent zone or
4945 : // \note specify current subsurface name for internal partition separating like zones
4946 : // \note If OtherSideCoefficients, specify name of SurfaceProperty:OtherSideCoefficients
4947 : // \note or leave blank to inherit Base Surface's OtherSide Coefficients
4948 : // N1, \field View Factor to Ground
4949 : // \type real
4950 : // \note From the exterior of the surface
4951 : // \note Unused if one uses the "reflections" options in Solar Distribution in Building input
4952 : // \note unless a DaylightingDevice:Shelf or DaylightingDevice:Tubular object has been specified.
4953 : // \note autocalculate will automatically calculate this value from the tilt of the surface
4954 : // \autocalculatable
4955 : // \minimum 0.0
4956 : // \maximum 1.0
4957 : // \default autocalculate
4958 : // A6, \field Frame and Divider Name
4959 : // \note Enter the name of a WindowProperty:FrameAndDivider object
4960 : // \type object-list
4961 : // \object-list WindowFrameAndDividerNames
4962 : // \note Used only for exterior windows (rectangular) and glass doors.
4963 : // \note Unused for triangular windows.
4964 : // \note If not specified (blank), window or glass door has no frame or divider
4965 : // \note and no beam solar reflection from reveal surfaces.
4966 : // N2 , \field Multiplier
4967 : // \note Used only for Surface Type = WINDOW, GLASSDOOR or DOOR
4968 : // \note Non-integer values will be truncated to integer
4969 : // \default 1.0
4970 : // \minimum 1.0
4971 : // N3 , \field Number of Vertices
4972 : // \minimum 3
4973 : // \maximum 4
4974 : // \autocalculatable
4975 : // \default autocalculate
4976 : // \note vertices are given in GlobalGeometryRules coordinates -- if relative, all surface coordinates
4977 : // \note are "relative" to the Zone Origin. If world, then building and zone origins are used
4978 : // \note for some internal calculations, but all coordinates are given in an "absolute" system.
4979 : // N4-15 as indicated by the N3 value
4980 :
4981 : // Using/Aliasing
4982 :
4983 : // Locals
4984 : // SUBROUTINE ARGUMENT DEFINITIONS:
4985 : // data file entry with two glazing systems
4986 :
4987 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
4988 : int IOStat; // IO Status when calling get input subroutine
4989 : int SurfaceNumAlpha; // Number of material alpha names being passed
4990 : int SurfaceNumProp; // Number of material properties being passed
4991 : int Found; // For matching interzone surfaces
4992 : int Loop;
4993 : int ValidChk;
4994 : int numSides;
4995 :
4996 796 : GetWindowShadingControlData(state, ErrorsFound);
4997 796 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
4998 796 : cCurrentModuleObject = "FenestrationSurface:Detailed";
4999 796 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, Loop, SurfaceNumAlpha, SurfaceNumProp);
5000 :
5001 796 : if (SurfaceNumAlpha != 6) {
5002 0 : ShowSevereError(
5003 0 : state, format("{}: Object Definition indicates not = 6 Alpha Objects, Number Indicated={}", cCurrentModuleObject, SurfaceNumAlpha));
5004 0 : ErrorsFound = true;
5005 : }
5006 :
5007 796 : if (SurfaceNumProp != 15) {
5008 0 : ShowSevereError(
5009 0 : state, format("{}: Object Definition indicates > 15 Numeric Objects, Number Indicated={}", cCurrentModuleObject, SurfaceNumAlpha));
5010 0 : ErrorsFound = true;
5011 : }
5012 796 : NeedToAddSurfaces = 0;
5013 :
5014 7416 : for (Loop = 1; Loop <= TotHTSubs; ++Loop) {
5015 13240 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
5016 : cCurrentModuleObject,
5017 : Loop,
5018 6620 : state.dataIPShortCut->cAlphaArgs,
5019 : SurfaceNumAlpha,
5020 6620 : state.dataIPShortCut->rNumericArgs,
5021 : SurfaceNumProp,
5022 : IOStat,
5023 6620 : state.dataIPShortCut->lNumericFieldBlanks,
5024 6620 : state.dataIPShortCut->lAlphaFieldBlanks,
5025 6620 : state.dataIPShortCut->cAlphaFieldNames,
5026 6620 : state.dataIPShortCut->cNumericFieldNames);
5027 :
5028 13240 : if (GlobalNames::VerifyUniqueInterObjectName(state,
5029 6620 : state.dataSurfaceGeometry->UniqueSurfaceNames,
5030 6620 : state.dataIPShortCut->cAlphaArgs(1),
5031 : cCurrentModuleObject,
5032 6620 : state.dataIPShortCut->cAlphaFieldNames(1),
5033 : ErrorsFound)) {
5034 0 : continue;
5035 : }
5036 :
5037 6620 : if (SurfaceNumProp < 12) {
5038 0 : ShowSevereError(state,
5039 0 : format("{}=\"{}\", Too few number of numeric args=[{}].",
5040 : cCurrentModuleObject,
5041 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
5042 : SurfaceNumProp));
5043 0 : ErrorsFound = true;
5044 : }
5045 :
5046 6620 : ++SurfNum;
5047 6620 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name = state.dataIPShortCut->cAlphaArgs(1); // Set the Surface Name in the Derived Type
5048 6620 : ValidChk = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(2), SubSurfCls, 6);
5049 6620 : if (ValidChk == 0) {
5050 0 : ShowSevereError(state,
5051 0 : format("{}=\"{}\", invalid {}=\"{}",
5052 : cCurrentModuleObject,
5053 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
5054 0 : state.dataIPShortCut->cAlphaFieldNames(2),
5055 0 : state.dataIPShortCut->cAlphaArgs(2)));
5056 0 : ErrorsFound = true;
5057 : } else {
5058 6620 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class = SubSurfIDs(ValidChk); // Set class number
5059 : }
5060 :
5061 6620 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction =
5062 6620 : Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(3), state.dataConstruction->Construct, state.dataHeatBal->TotConstructs);
5063 :
5064 6620 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction == 0) {
5065 0 : ShowSevereError(state,
5066 0 : format("{}=\"{}\", invalid {}=\"{}\".",
5067 : cCurrentModuleObject,
5068 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
5069 0 : state.dataIPShortCut->cAlphaFieldNames(3),
5070 0 : state.dataIPShortCut->cAlphaArgs(3)));
5071 0 : ErrorsFound = true;
5072 0 : continue;
5073 : } else {
5074 6620 : state.dataConstruction->Construct(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction).IsUsed = true;
5075 6620 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ConstructionStoredInputValue =
5076 6620 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction;
5077 : }
5078 :
5079 6620 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == SurfaceClass::Window ||
5080 1008 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == SurfaceClass::GlassDoor ||
5081 8098 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == SurfaceClass::TDD_Diffuser ||
5082 470 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == SurfaceClass::TDD_Dome) {
5083 :
5084 6152 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction != 0) {
5085 6152 : auto &construction = state.dataConstruction->Construct(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction);
5086 6152 : if (!construction.TypeIsWindow && !construction.TypeIsAirBoundary) {
5087 0 : ErrorsFound = true;
5088 0 : ShowSevereError(state,
5089 0 : format("{}=\"{}\" has an opaque surface construction; it should have a window construction.",
5090 : cCurrentModuleObject,
5091 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name));
5092 : }
5093 6152 : if (state.dataConstruction->Construct(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction).SourceSinkPresent) {
5094 0 : ErrorsFound = true;
5095 0 : ShowSevereError(state,
5096 0 : format("{}=\"{}\": Windows are not allowed to have embedded sources/sinks",
5097 : cCurrentModuleObject,
5098 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name));
5099 : }
5100 : }
5101 :
5102 468 : } else if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction != 0) {
5103 468 : if (state.dataConstruction->Construct(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction).TypeIsWindow) {
5104 0 : ErrorsFound = true;
5105 0 : ShowSevereError(state,
5106 0 : format("{}=\"{}\", invalid {}=\"{}\" - has Window materials.",
5107 : cCurrentModuleObject,
5108 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
5109 0 : state.dataIPShortCut->cAlphaFieldNames(3),
5110 0 : state.dataIPShortCut->cAlphaArgs(3)));
5111 0 : ShowContinueError(state,
5112 0 : format("...because {}={}", state.dataIPShortCut->cAlphaFieldNames(2), state.dataIPShortCut->cAlphaArgs(2)));
5113 : }
5114 : }
5115 :
5116 6620 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).HeatTransSurf = true;
5117 :
5118 6620 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).BaseSurfName = state.dataIPShortCut->cAlphaArgs(4);
5119 : // The subsurface inherits properties from the base surface
5120 : // Exterior conditions, Zone, etc.
5121 : // We can figure out the base surface though, because they've all been entered
5122 6620 : Found = Util::FindItemInList(
5123 6620 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).BaseSurfName, state.dataSurfaceGeometry->SurfaceTmp, state.dataSurface->TotSurfaces);
5124 6620 : if (Found > 0) {
5125 6620 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).BaseSurf = Found;
5126 6620 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCond;
5127 6620 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCondName = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCondName;
5128 6620 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtSolar = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtSolar;
5129 6620 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtWind = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtWind;
5130 6620 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Zone = state.dataSurfaceGeometry->SurfaceTmp(Found).Zone;
5131 6620 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ZoneName = state.dataSurfaceGeometry->SurfaceTmp(Found).ZoneName;
5132 6620 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).OSCPtr = state.dataSurfaceGeometry->SurfaceTmp(Found).OSCPtr;
5133 6684 : if (state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCond == UnreconciledZoneSurface &&
5134 64 : state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCondName ==
5135 64 : state.dataSurfaceGeometry->SurfaceTmp(Found).Name) { // Adiabatic surface, no windows or doors allowed
5136 0 : ShowSevereError(state,
5137 0 : format("{}=\"{}\", invalid {}=\"{}\".",
5138 : cCurrentModuleObject,
5139 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
5140 0 : state.dataIPShortCut->cAlphaFieldNames(4),
5141 0 : state.dataIPShortCut->cAlphaArgs(4)));
5142 0 : ShowContinueError(state, "... adiabatic surfaces cannot have windows or doors.");
5143 0 : ShowContinueError(state,
5144 : "... no solar transmission will result for these windows or doors. You must have interior windows or doors on "
5145 : "Interzone surfaces for transmission to result.");
5146 : }
5147 : } else {
5148 0 : ShowSevereError(state,
5149 0 : format("{}=\"{}\", invalid {}=\"{}",
5150 : cCurrentModuleObject,
5151 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
5152 0 : state.dataIPShortCut->cAlphaFieldNames(4),
5153 0 : state.dataIPShortCut->cAlphaArgs(4)));
5154 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ZoneName = "Unknown Zone";
5155 0 : ErrorsFound = true;
5156 : }
5157 13238 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == SurfaceClass::TDD_Dome ||
5158 6618 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == SurfaceClass::TDD_Diffuser) {
5159 4 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond = ExternalEnvironment;
5160 : }
5161 :
5162 6620 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond == ExternalEnvironment) {
5163 6541 : if (!state.dataIPShortCut->lAlphaFieldBlanks(5)) {
5164 0 : ShowWarningError(state,
5165 0 : format("{}=\"{}\", invalid field {}",
5166 : cCurrentModuleObject,
5167 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
5168 0 : state.dataIPShortCut->cAlphaFieldNames(5)));
5169 0 : ShowContinueError(
5170 : state,
5171 0 : format("...when Base surface uses \"Outdoors\" as {}, subsurfaces need to be blank to inherit the outdoor characteristics.",
5172 0 : state.dataIPShortCut->cAlphaFieldNames(5)));
5173 0 : ShowContinueError(state, "...Surface external characteristics changed to reflect base surface.");
5174 : }
5175 : }
5176 :
5177 6620 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond == UnreconciledZoneSurface) { // "Surface" Base Surface
5178 62 : if (!state.dataIPShortCut->lAlphaFieldBlanks(5)) {
5179 62 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCondName = state.dataIPShortCut->cAlphaArgs(5);
5180 : } else {
5181 0 : ShowSevereError(state,
5182 0 : format("{}=\"{}\", invalid blank {}",
5183 : cCurrentModuleObject,
5184 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
5185 0 : state.dataIPShortCut->cAlphaFieldNames(5)));
5186 0 : ShowContinueError(
5187 : state,
5188 0 : format("...when Base surface uses \"Surface\" as {}, subsurfaces must also specify specific surfaces in the adjacent zone.",
5189 0 : state.dataIPShortCut->cAlphaFieldNames(5)));
5190 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCondName =
5191 0 : state.dataIPShortCut->cAlphaArgs(5); // putting it as blank will not confuse things later.
5192 0 : ErrorsFound = true;
5193 : }
5194 : }
5195 :
5196 6620 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond == UnenteredAdjacentZoneSurface) { // "Zone" - unmatched interior surface
5197 1 : ++NeedToAddSurfaces;
5198 : // ignoring window5datafiles for now -- will need to add.
5199 : }
5200 :
5201 13224 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond == OtherSideCoefNoCalcExt ||
5202 6604 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond == OtherSideCoefCalcExt) {
5203 16 : if (!state.dataIPShortCut->lAlphaFieldBlanks(5)) { // Otherside Coef special Name
5204 2 : Found = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(5), state.dataSurface->OSC, state.dataSurface->TotOSC);
5205 2 : if (Found == 0) {
5206 0 : ShowSevereError(state,
5207 0 : format("{}=\"{}\", invalid {}=\"{}\".",
5208 : cCurrentModuleObject,
5209 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
5210 0 : state.dataIPShortCut->cAlphaFieldNames(5),
5211 0 : state.dataIPShortCut->cAlphaArgs(5)));
5212 0 : ShowContinueError(state, "...base surface requires that this subsurface have OtherSideCoefficients -- not found.");
5213 0 : ErrorsFound = true;
5214 : } else { // found
5215 : // The following allows for a subsurface that has different characteristics than
5216 : // the base surface with OtherSide Coeff -- do we want that or is it an error?
5217 2 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).OSCPtr = Found;
5218 2 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCondName = state.dataIPShortCut->cAlphaArgs(5);
5219 2 : if (state.dataSurface->OSC(Found).SurfFilmCoef > 0.0) {
5220 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond = OtherSideCoefCalcExt;
5221 : } else {
5222 2 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond = OtherSideCoefNoCalcExt;
5223 : }
5224 : }
5225 : }
5226 : }
5227 :
5228 6620 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond == OtherSideCondModeledExt) {
5229 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond = ExternalEnvironment;
5230 : }
5231 :
5232 6620 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCondName == BlankString) {
5233 6531 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCondName = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name;
5234 : }
5235 6620 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ViewFactorGround = state.dataIPShortCut->rNumericArgs(1);
5236 6620 : if (state.dataIPShortCut->lNumericFieldBlanks(1))
5237 399 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ViewFactorGround = Constant::AutoCalculate;
5238 :
5239 6620 : if (state.dataIPShortCut->lNumericFieldBlanks(3) || state.dataIPShortCut->rNumericArgs(3) == Constant::AutoCalculate) {
5240 97 : state.dataIPShortCut->rNumericArgs(3) = (SurfaceNumProp - 3) / 3;
5241 97 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides = state.dataIPShortCut->rNumericArgs(3);
5242 97 : if (mod(SurfaceNumProp - 3, 3) != 0) {
5243 0 : ShowWarningError(state,
5244 0 : format("{}=\"{}\", {}",
5245 : cCurrentModuleObject,
5246 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
5247 0 : format("{} not even multiple of 3. Will read in {}",
5248 0 : state.dataIPShortCut->cNumericFieldNames(3),
5249 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides)));
5250 : }
5251 97 : if (state.dataIPShortCut->rNumericArgs(3) < 3) {
5252 0 : ShowSevereError(state,
5253 0 : format("{}=\"{}\", {} (autocalculate) must be >= 3. Only {} provided.",
5254 : cCurrentModuleObject,
5255 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
5256 0 : state.dataIPShortCut->cNumericFieldNames(3),
5257 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides));
5258 0 : ErrorsFound = true;
5259 0 : continue;
5260 : }
5261 : } else {
5262 6523 : numSides = (SurfaceNumProp - 2) / 3;
5263 6523 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides = state.dataIPShortCut->rNumericArgs(3);
5264 6523 : if (numSides > state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides) {
5265 0 : ShowWarningError(state,
5266 0 : format("{}=\"{}\", field {}={}",
5267 : cCurrentModuleObject,
5268 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
5269 0 : state.dataIPShortCut->cNumericFieldNames(3),
5270 0 : fmt::to_string(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides)));
5271 0 : ShowContinueError(
5272 : state,
5273 0 : format("...but {} were entered. Only the indicated {} will be used.", numSides, state.dataIPShortCut->cNumericFieldNames(3)));
5274 : }
5275 : }
5276 6620 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex.allocate(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides);
5277 6620 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == SurfaceClass::Window ||
5278 7092 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == SurfaceClass::GlassDoor ||
5279 472 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == SurfaceClass::Door)
5280 6616 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Multiplier = int(state.dataIPShortCut->rNumericArgs(2));
5281 : // Only windows, glass doors and doors can have Multiplier > 1:
5282 6620 : if ((state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class != SurfaceClass::Window &&
5283 1008 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class != SurfaceClass::GlassDoor &&
5284 7632 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class != SurfaceClass::Door) &&
5285 4 : state.dataIPShortCut->rNumericArgs(2) > 1.0) {
5286 0 : ShowWarningError(state,
5287 0 : format("{}=\"{}\", invalid {}=[{:.1T}].",
5288 : cCurrentModuleObject,
5289 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
5290 0 : state.dataIPShortCut->cNumericFieldNames(2),
5291 0 : state.dataIPShortCut->rNumericArgs(2)));
5292 0 : ShowContinueError(state,
5293 0 : format("...because {}={} multiplier will be set to 1.0.",
5294 0 : state.dataIPShortCut->cAlphaFieldNames(2),
5295 0 : state.dataIPShortCut->cAlphaArgs(2)));
5296 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Multiplier = 1.0;
5297 : }
5298 :
5299 19860 : GetVertices(state, SurfNum, state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides, state.dataIPShortCut->rNumericArgs({4, _}));
5300 :
5301 6620 : CheckConvexity(state, SurfNum, state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides);
5302 6620 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).windowShadingControlList.clear();
5303 6620 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).activeWindowShadingControl = 0;
5304 6620 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).HasShadeControl = false;
5305 :
5306 6620 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).shadedConstructionList.clear();
5307 6620 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).activeShadedConstruction = 0;
5308 6620 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).shadedStormWinConstructionList.clear();
5309 :
5310 6620 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == SurfaceClass::Window ||
5311 1008 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == SurfaceClass::GlassDoor ||
5312 8098 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == SurfaceClass::TDD_Diffuser ||
5313 470 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == SurfaceClass::TDD_Dome) {
5314 :
5315 12304 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond == OtherSideCoefNoCalcExt ||
5316 6152 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond == OtherSideCoefCalcExt) {
5317 0 : ShowSevereError(state,
5318 0 : format("{}=\"{}\", Other side coefficients are not allowed with windows.",
5319 : cCurrentModuleObject,
5320 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name));
5321 0 : ErrorsFound = true;
5322 : }
5323 :
5324 6152 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond == Ground) {
5325 0 : ShowSevereError(state,
5326 0 : format("{}=\"{}\", Exterior boundary condition = Ground is not allowed with windows.",
5327 : cCurrentModuleObject,
5328 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name));
5329 0 : ErrorsFound = true;
5330 : }
5331 :
5332 6152 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond == KivaFoundation) {
5333 0 : ShowSevereError(state,
5334 0 : format("{}=\"{}\", Exterior boundary condition = Foundation is not allowed with windows.",
5335 : cCurrentModuleObject,
5336 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name));
5337 0 : ErrorsFound = true;
5338 : }
5339 :
5340 6152 : InitialAssociateWindowShadingControlFenestration(state, ErrorsFound, SurfNum);
5341 :
5342 6152 : CheckWindowShadingControlFrameDivider(state, "GetHTSubSurfaceData", ErrorsFound, SurfNum, 6);
5343 :
5344 6152 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides == 3) { // Triangular window
5345 2 : if (!state.dataIPShortCut->cAlphaArgs(6).empty()) {
5346 0 : ShowWarningError(state,
5347 0 : format("{}=\"{}\", invalid {}=\"{}\".",
5348 : cCurrentModuleObject,
5349 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
5350 0 : state.dataIPShortCut->cAlphaFieldNames(6),
5351 0 : state.dataIPShortCut->cAlphaArgs(6)));
5352 0 : ShowContinueError(state, ".. because it is a triangular window and cannot have a frame or divider or reveal reflection.");
5353 0 : ShowContinueError(state, "Frame, divider and reveal reflection will be ignored for this window.");
5354 : }
5355 2 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).FrameDivider = 0;
5356 : } // End of check if window is triangular or rectangular
5357 :
5358 : } // check on non-opaquedoor subsurfaces
5359 :
5360 6620 : CheckSubSurfaceMiscellaneous(state,
5361 : "GetHTSubSurfaceData",
5362 : ErrorsFound,
5363 : SurfNum,
5364 6620 : state.dataIPShortCut->cAlphaArgs(1),
5365 6620 : state.dataIPShortCut->cAlphaArgs(3),
5366 : AddedSubSurfaces);
5367 :
5368 : } // End of main loop over subsurfaces
5369 796 : }
5370 :
5371 796 : void GetRectSubSurfaces(EnergyPlusData &state,
5372 : bool &ErrorsFound, // Error flag indicator (true if errors found)
5373 : int &SurfNum, // Count of Current SurfaceNumber
5374 : int const TotWindows, // Number of Window SubSurfaces to obtain
5375 : int const TotDoors, // Number of Door SubSurfaces to obtain
5376 : int const TotGlazedDoors, // Number of Glass Door SubSurfaces to obtain
5377 : int const TotIZWindows, // Number of Interzone Window SubSurfaces to obtain
5378 : int const TotIZDoors, // Number of Interzone Door SubSurfaces to obtain
5379 : int const TotIZGlazedDoors, // Number of Interzone Glass Door SubSurfaces to obtain
5380 : const Array1D<SurfaceClass> &SubSurfIDs, // ID Assignments for valid sub surface classes
5381 : int &AddedSubSurfaces, // Subsurfaces added when windows reference Window5
5382 : int &NeedToAddSubSurfaces // Number of surfaces to add, based on unentered IZ surfaces
5383 : )
5384 : {
5385 :
5386 : // SUBROUTINE INFORMATION:
5387 : // AUTHOR Linda Lawrie
5388 : // DATE WRITTEN December 2008
5389 : // MODIFIED na
5390 : // RE-ENGINEERED na
5391 :
5392 : // PURPOSE OF THIS SUBROUTINE:
5393 : // Get simple (rectangular, relative origin to base surface) windows, doors, glazed doors.
5394 :
5395 : // Using/Aliasing
5396 :
5397 : // Locals
5398 : // SUBROUTINE ARGUMENT DEFINITIONS:
5399 : // data file entry with two glazing systems
5400 :
5401 : // SUBROUTINE PARAMETER DEFINITIONS:
5402 796 : static Array1D_string const cModuleObjects(6, {"Window", "Door", "GlazedDoor", "Window:Interzone", "Door:Interzone", "GlazedDoor:Interzone"});
5403 :
5404 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
5405 : int Item;
5406 : int ItemsToGet;
5407 : int Loop;
5408 : int NumAlphas;
5409 : int NumNumbers;
5410 : int IOStat; // IO Status when calling get input subroutine
5411 : int Found; // For matching base surfaces
5412 : bool GettingIZSurfaces;
5413 : int WindowShadingField;
5414 : int FrameField;
5415 : int OtherSurfaceField;
5416 : int ClassItem;
5417 : int IZFound;
5418 796 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
5419 5572 : for (Item = 1; Item <= 6; ++Item) {
5420 :
5421 4776 : cCurrentModuleObject = cModuleObjects(Item);
5422 4776 : if (Item == 1) {
5423 796 : ItemsToGet = TotWindows;
5424 796 : GettingIZSurfaces = false;
5425 796 : WindowShadingField = 4;
5426 796 : FrameField = 5;
5427 796 : OtherSurfaceField = 0;
5428 796 : ClassItem = 1;
5429 3980 : } else if (Item == 2) {
5430 796 : ItemsToGet = TotDoors;
5431 796 : GettingIZSurfaces = false;
5432 796 : WindowShadingField = 0;
5433 796 : FrameField = 0;
5434 796 : OtherSurfaceField = 0;
5435 796 : ClassItem = 2;
5436 3184 : } else if (Item == 3) {
5437 796 : ItemsToGet = TotGlazedDoors;
5438 796 : GettingIZSurfaces = false;
5439 796 : WindowShadingField = 4;
5440 796 : FrameField = 5;
5441 796 : OtherSurfaceField = 0;
5442 796 : ClassItem = 3;
5443 2388 : } else if (Item == 4) {
5444 796 : ItemsToGet = TotIZWindows;
5445 796 : GettingIZSurfaces = true;
5446 796 : WindowShadingField = 0;
5447 796 : FrameField = 0;
5448 796 : OtherSurfaceField = 4;
5449 796 : ClassItem = 1;
5450 1592 : } else if (Item == 5) {
5451 796 : ItemsToGet = TotIZDoors;
5452 796 : GettingIZSurfaces = true;
5453 796 : WindowShadingField = 0;
5454 796 : FrameField = 0;
5455 796 : OtherSurfaceField = 4;
5456 796 : ClassItem = 2;
5457 : } else { // Item = 6
5458 796 : ItemsToGet = TotIZGlazedDoors;
5459 796 : GettingIZSurfaces = true;
5460 796 : WindowShadingField = 0;
5461 796 : FrameField = 0;
5462 796 : OtherSurfaceField = 4;
5463 796 : ClassItem = 3;
5464 : }
5465 :
5466 4850 : for (Loop = 1; Loop <= ItemsToGet; ++Loop) {
5467 148 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
5468 : cCurrentModuleObject,
5469 : Loop,
5470 74 : state.dataIPShortCut->cAlphaArgs,
5471 : NumAlphas,
5472 74 : state.dataIPShortCut->rNumericArgs,
5473 : NumNumbers,
5474 : IOStat,
5475 74 : state.dataIPShortCut->lNumericFieldBlanks,
5476 74 : state.dataIPShortCut->lAlphaFieldBlanks,
5477 74 : state.dataIPShortCut->cAlphaFieldNames,
5478 74 : state.dataIPShortCut->cNumericFieldNames);
5479 :
5480 148 : if (GlobalNames::VerifyUniqueInterObjectName(state,
5481 74 : state.dataSurfaceGeometry->UniqueSurfaceNames,
5482 74 : state.dataIPShortCut->cAlphaArgs(1),
5483 : cCurrentModuleObject,
5484 74 : state.dataIPShortCut->cAlphaFieldNames(1),
5485 : ErrorsFound)) {
5486 0 : continue;
5487 : }
5488 :
5489 74 : if (NumNumbers < 5) {
5490 0 : ShowSevereError(state,
5491 0 : format("{}=\"{}\", Too few number of numeric args=[{}].",
5492 : cCurrentModuleObject,
5493 0 : state.dataIPShortCut->cAlphaArgs(1),
5494 : NumNumbers));
5495 0 : ErrorsFound = true;
5496 : }
5497 :
5498 74 : ++SurfNum;
5499 74 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name = state.dataIPShortCut->cAlphaArgs(1); // Set the Surface Name in the Derived Type
5500 74 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class = SubSurfIDs(ClassItem); // Set class number
5501 :
5502 74 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction =
5503 74 : Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(2), state.dataConstruction->Construct, state.dataHeatBal->TotConstructs);
5504 :
5505 74 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction == 0) {
5506 0 : ErrorsFound = true;
5507 0 : ShowSevereError(state,
5508 0 : format("{}=\"{}\", invalid {}=\"{}\".",
5509 : cCurrentModuleObject,
5510 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
5511 0 : state.dataIPShortCut->cAlphaFieldNames(2),
5512 0 : state.dataIPShortCut->cAlphaArgs(2)));
5513 : } else {
5514 74 : state.dataConstruction->Construct(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction).IsUsed = true;
5515 74 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ConstructionStoredInputValue =
5516 74 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction;
5517 : }
5518 :
5519 85 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == SurfaceClass::Window ||
5520 11 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == SurfaceClass::GlassDoor) {
5521 :
5522 65 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction != 0) {
5523 65 : auto &construction = state.dataConstruction->Construct(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction);
5524 65 : if (!construction.TypeIsWindow && !construction.TypeIsAirBoundary) {
5525 0 : ErrorsFound = true;
5526 0 : ShowSevereError(state,
5527 0 : format("{}=\"{}\" has an opaque surface construction; it should have a window construction.",
5528 : cCurrentModuleObject,
5529 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name));
5530 : }
5531 65 : if (state.dataConstruction->Construct(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction).SourceSinkPresent) {
5532 0 : ErrorsFound = true;
5533 0 : ShowSevereError(state,
5534 0 : format("{}=\"{}\": Windows are not allowed to have embedded sources/sinks",
5535 : cCurrentModuleObject,
5536 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name));
5537 : }
5538 : }
5539 :
5540 9 : } else if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction != 0) {
5541 9 : if (state.dataConstruction->Construct(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction).TypeIsWindow) {
5542 0 : ErrorsFound = true;
5543 0 : ShowSevereError(state,
5544 0 : format("{}=\"{}\", invalid {}=\"{}\" - has Window materials.",
5545 : cCurrentModuleObject,
5546 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
5547 0 : state.dataIPShortCut->cAlphaFieldNames(2),
5548 0 : state.dataIPShortCut->cAlphaArgs(2)));
5549 : }
5550 : }
5551 :
5552 74 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).HeatTransSurf = true;
5553 :
5554 74 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).BaseSurfName = state.dataIPShortCut->cAlphaArgs(3);
5555 : // The subsurface inherits properties from the base surface
5556 : // Exterior conditions, Zone, etc.
5557 : // We can figure out the base surface though, because they've all been entered
5558 74 : Found = Util::FindItemInList(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).BaseSurfName,
5559 74 : state.dataSurfaceGeometry->SurfaceTmp,
5560 74 : state.dataSurface->TotSurfaces);
5561 74 : if (Found > 0) {
5562 74 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).BaseSurf = Found;
5563 74 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCond;
5564 74 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCondName = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCondName;
5565 74 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtSolar = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtSolar;
5566 74 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtWind = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtWind;
5567 74 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Tilt = state.dataSurfaceGeometry->SurfaceTmp(Found).Tilt;
5568 74 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).convOrientation =
5569 74 : Convect::GetSurfConvOrientation(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Tilt);
5570 74 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Azimuth = state.dataSurfaceGeometry->SurfaceTmp(Found).Azimuth;
5571 74 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Zone = state.dataSurfaceGeometry->SurfaceTmp(Found).Zone;
5572 74 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ZoneName = state.dataSurfaceGeometry->SurfaceTmp(Found).ZoneName;
5573 74 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).OSCPtr = state.dataSurfaceGeometry->SurfaceTmp(Found).OSCPtr;
5574 74 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ViewFactorGround = state.dataSurfaceGeometry->SurfaceTmp(Found).ViewFactorGround;
5575 74 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ViewFactorSky = state.dataSurfaceGeometry->SurfaceTmp(Found).ViewFactorSky;
5576 : } else {
5577 0 : ShowSevereError(state,
5578 0 : format("{}=\"{}\", invalid {}=\"{}",
5579 : cCurrentModuleObject,
5580 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
5581 0 : state.dataIPShortCut->cAlphaFieldNames(3),
5582 0 : state.dataIPShortCut->cAlphaArgs(3)));
5583 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ZoneName = "Unknown Zone";
5584 0 : ErrorsFound = true;
5585 0 : continue;
5586 : }
5587 82 : if (state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCond == UnreconciledZoneSurface &&
5588 8 : state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCondName ==
5589 8 : state.dataSurfaceGeometry->SurfaceTmp(Found).Name) { // Adiabatic surface, no windows or doors allowed
5590 0 : ShowSevereError(state,
5591 0 : format("{}=\"{}\", invalid {}=\"{}\".",
5592 : cCurrentModuleObject,
5593 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
5594 0 : state.dataIPShortCut->cAlphaFieldNames(3),
5595 0 : state.dataIPShortCut->cAlphaArgs(3)));
5596 0 : ShowContinueError(state, "... adiabatic surfaces cannot have windows or doors.");
5597 0 : ShowContinueError(state,
5598 : "... no solar transmission will result for these windows or doors. You must have interior windows or doors on "
5599 : "Interzone surfaces for transmission to result.");
5600 : }
5601 :
5602 74 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond == UnreconciledZoneSurface) { // "Surface" Base Surface
5603 8 : if (!GettingIZSurfaces) {
5604 0 : ShowSevereError(
5605 : state,
5606 0 : format("{}=\"{}\", invalid use of object", cCurrentModuleObject, state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name));
5607 0 : ShowContinueError(
5608 : state,
5609 0 : format(
5610 : "...when Base surface uses \"Surface\" as {}, subsurfaces must also specify specific surfaces in the adjacent zone.",
5611 0 : state.dataIPShortCut->cAlphaFieldNames(5)));
5612 0 : ShowContinueError(state, format("...Please use {}:Interzone to enter this surface.", cCurrentModuleObject));
5613 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCondName =
5614 0 : BlankString; // putting it as blank will not confuse things later.
5615 0 : ErrorsFound = true;
5616 : }
5617 : }
5618 :
5619 74 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond == UnreconciledZoneSurface) { // "Surface" Base Surface
5620 8 : if (GettingIZSurfaces) {
5621 8 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCondName = state.dataIPShortCut->cAlphaArgs(OtherSurfaceField);
5622 8 : IZFound = Util::FindItemInList(
5623 8 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCondName, state.dataHeatBal->Zone, state.dataGlobal->NumOfZones);
5624 8 : if (IZFound > 0) state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond = UnenteredAdjacentZoneSurface;
5625 : } else { // Interior Window
5626 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCondName = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name;
5627 : }
5628 : }
5629 :
5630 : // This is the parent's property:
5631 74 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond ==
5632 : UnenteredAdjacentZoneSurface) { // OtherZone - unmatched interior surface
5633 3 : if (GettingIZSurfaces) {
5634 3 : ++NeedToAddSubSurfaces;
5635 : } else { // Interior Window
5636 0 : ShowSevereError(state,
5637 0 : format("{}=\"{}\", invalid Interzone Surface, specify {}:InterZone",
5638 : cCurrentModuleObject,
5639 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
5640 : cCurrentModuleObject));
5641 0 : ShowContinueError(state, "...when base surface is an interzone surface, subsurface must also be an interzone surface.");
5642 0 : ++NeedToAddSubSurfaces;
5643 0 : ErrorsFound = true;
5644 : }
5645 : }
5646 :
5647 74 : if (GettingIZSurfaces) {
5648 11 : if (state.dataIPShortCut->lAlphaFieldBlanks(OtherSurfaceField)) {
5649 : // blank -- set it up for unentered adjacent zone
5650 0 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond ==
5651 : UnenteredAdjacentZoneSurface) { // already set but need Zone
5652 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCondName =
5653 0 : state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCondName; // base surface has it
5654 0 : } else if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond == UnreconciledZoneSurface) {
5655 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCondName =
5656 0 : state.dataSurfaceGeometry->SurfaceTmp(Found).ZoneName; // base surface has it
5657 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond = UnenteredAdjacentZoneSurface;
5658 : } else { // not correct boundary condition for interzone subsurface
5659 0 : ShowSevereError(state,
5660 0 : format("{}=\"{}\", invalid Base Surface type for Interzone Surface",
5661 : cCurrentModuleObject,
5662 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name));
5663 0 : ShowContinueError(state,
5664 : "...when base surface is not an interzone surface, subsurface must also not be an interzone surface.");
5665 0 : ErrorsFound = true;
5666 : }
5667 : }
5668 : }
5669 :
5670 74 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond == OtherSideCondModeledExt) {
5671 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond = ExternalEnvironment;
5672 : }
5673 :
5674 : // SurfaceTmp(SurfNum)%ViewFactorGround = AutoCalculate
5675 :
5676 74 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides = 4;
5677 74 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex.allocate(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides);
5678 74 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == SurfaceClass::Window ||
5679 83 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == SurfaceClass::GlassDoor ||
5680 9 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == SurfaceClass::Door)
5681 74 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Multiplier = int(state.dataIPShortCut->rNumericArgs(1));
5682 : // Only windows, glass doors and doors can have Multiplier > 1:
5683 74 : if ((state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class != SurfaceClass::Window &&
5684 11 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class != SurfaceClass::GlassDoor &&
5685 85 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class != SurfaceClass::Door) &&
5686 0 : state.dataIPShortCut->rNumericArgs(1) > 1.0) {
5687 0 : ShowWarningError(state,
5688 0 : format("{}=\"{}\", invalid {}=[{:.1T}].",
5689 : cCurrentModuleObject,
5690 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
5691 0 : state.dataIPShortCut->cNumericFieldNames(1),
5692 0 : state.dataIPShortCut->rNumericArgs(1)));
5693 0 : ShowContinueError(state,
5694 0 : format("...because {}={} multiplier will be set to 1.0.",
5695 0 : state.dataIPShortCut->cAlphaFieldNames(1),
5696 0 : state.dataIPShortCut->cAlphaArgs(1)));
5697 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Multiplier = 1.0;
5698 : }
5699 :
5700 370 : MakeRelativeRectangularVertices(state,
5701 74 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).BaseSurf,
5702 : SurfNum,
5703 74 : state.dataIPShortCut->rNumericArgs(2),
5704 74 : state.dataIPShortCut->rNumericArgs(3),
5705 74 : state.dataIPShortCut->rNumericArgs(4),
5706 74 : state.dataIPShortCut->rNumericArgs(5));
5707 :
5708 74 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Area <= 0.0) {
5709 0 : ShowSevereError(state,
5710 0 : format("{}=\"{}\", Surface Area <= 0.0; Entered Area={:.2T}",
5711 : cCurrentModuleObject,
5712 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
5713 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Area));
5714 0 : ErrorsFound = true;
5715 : }
5716 :
5717 74 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).windowShadingControlList.clear();
5718 74 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).activeWindowShadingControl = 0;
5719 74 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).HasShadeControl = false;
5720 :
5721 74 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).shadedConstructionList.clear();
5722 74 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).activeShadedConstruction = 0;
5723 74 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).shadedStormWinConstructionList.clear();
5724 :
5725 74 : InitialAssociateWindowShadingControlFenestration(state, ErrorsFound, SurfNum);
5726 :
5727 83 : if (!GettingIZSurfaces && (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == SurfaceClass::Window ||
5728 9 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == SurfaceClass::GlassDoor)) {
5729 :
5730 110 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond == OtherSideCoefNoCalcExt ||
5731 55 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond == OtherSideCoefCalcExt) {
5732 0 : ShowSevereError(state,
5733 0 : format("{}=\"{}\", Other side coefficients are not allowed with windows.",
5734 : cCurrentModuleObject,
5735 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name));
5736 0 : ErrorsFound = true;
5737 : }
5738 :
5739 55 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond == Ground) {
5740 0 : ShowSevereError(state,
5741 0 : format("{}=\"{}\", Exterior boundary condition = Ground is not allowed with windows.",
5742 : cCurrentModuleObject,
5743 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name));
5744 0 : ErrorsFound = true;
5745 : }
5746 :
5747 55 : CheckWindowShadingControlFrameDivider(state, "GetRectSubSurfaces", ErrorsFound, SurfNum, FrameField);
5748 :
5749 : } // check on non-opaquedoor subsurfaces
5750 :
5751 74 : CheckSubSurfaceMiscellaneous(state,
5752 : "GetRectSubSurfaces",
5753 : ErrorsFound,
5754 : SurfNum,
5755 74 : state.dataIPShortCut->cAlphaArgs(1),
5756 74 : state.dataIPShortCut->cAlphaArgs(2),
5757 : AddedSubSurfaces);
5758 :
5759 : } // Getting Items
5760 : }
5761 796 : }
5762 :
5763 6207 : void CheckWindowShadingControlFrameDivider(EnergyPlusData &state,
5764 : std::string_view const cRoutineName, // routine name calling this one (for error messages)
5765 : bool &ErrorsFound, // true if errors have been found or are found here
5766 : int const SurfNum, // current surface number
5767 : int const FrameField // field number for frame/divider
5768 : )
5769 : {
5770 :
5771 : // SUBROUTINE INFORMATION:
5772 : // AUTHOR Linda Lawrie
5773 : // DATE WRITTEN December 2008
5774 : // MODIFIED na
5775 : // RE-ENGINEERED na
5776 :
5777 : // PURPOSE OF THIS SUBROUTINE:
5778 : // This routine performs checks on WindowShadingControl settings and Frame/Divider Settings.
5779 :
5780 : // Using/Aliasing
5781 :
5782 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
5783 : int ConstrNumSh; // Construction number with Shade
5784 : int ConstrNum; // Construction number
5785 : int ShDevNum; // Shading Device number
5786 : int Lay; // Layer number
5787 : int TotGlassLayers; // Number of glass layers in window construction
5788 : int TotLayers; // Number of layers in unshaded construction
5789 : int TotShLayers; // Number of layers in shaded construction
5790 : int MatGap; // Gap material number
5791 : int MatGap1; // Material number of gap to left (outer side) of between-glass shade/blind
5792 : int MatGap2; // Material number of gap to right (inner side) of between-glass shade/blind
5793 : int MatSh; // Between-glass shade/blind material number
5794 : Real64 MatGapCalc; // Calculated MatGap diff for shaded vs non-shaded constructions
5795 :
5796 : // If WindowShadingControl has been specified for this window --
5797 : // Set shaded construction number if shaded construction was specified in WindowShadingControl.
5798 : // Otherwise, create shaded construction if WindowShadingControl for this window has
5799 : // interior or exterior shade/blind (but not between-glass shade/blind) specified.
5800 :
5801 6362 : for (std::size_t shadeControlIndex = 0; shadeControlIndex < state.dataSurfaceGeometry->SurfaceTmp(SurfNum).windowShadingControlList.size();
5802 : ++shadeControlIndex) {
5803 155 : int WSCPtr = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).windowShadingControlList[shadeControlIndex];
5804 155 : ConstrNumSh = 0;
5805 155 : if (!ErrorsFound && state.dataSurfaceGeometry->SurfaceTmp(SurfNum).HasShadeControl) {
5806 155 : ConstrNumSh = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).shadedConstructionList[shadeControlIndex];
5807 155 : if (ConstrNumSh > 0) {
5808 137 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).activeShadedConstruction = ConstrNumSh;
5809 : } else {
5810 18 : if (ANY_INTERIOR_SHADE_BLIND(state.dataSurface->WindowShadingControl(WSCPtr).ShadingType) ||
5811 0 : ANY_EXTERIOR_SHADE_BLIND_SCREEN(state.dataSurface->WindowShadingControl(WSCPtr).ShadingType)) {
5812 18 : ShDevNum = state.dataSurface->WindowShadingControl(WSCPtr).ShadingDevice;
5813 18 : if (ShDevNum > 0) {
5814 18 : CreateShadedWindowConstruction(state, SurfNum, WSCPtr, ShDevNum, shadeControlIndex);
5815 18 : ConstrNumSh = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).activeShadedConstruction;
5816 : }
5817 : }
5818 : }
5819 : }
5820 :
5821 : // Error checks for shades and blinds
5822 :
5823 155 : ConstrNum = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction;
5824 155 : if (!ErrorsFound && WSCPtr > 0 && ConstrNum > 0 && ConstrNumSh > 0) {
5825 :
5826 155 : if (ANY_INTERIOR_SHADE_BLIND(state.dataSurface->WindowShadingControl(WSCPtr).ShadingType)) {
5827 88 : TotLayers = state.dataConstruction->Construct(ConstrNum).TotLayers;
5828 88 : TotShLayers = state.dataConstruction->Construct(ConstrNumSh).TotLayers;
5829 88 : if (TotShLayers - 1 != TotLayers) {
5830 0 : ShowWarningError(
5831 : state,
5832 : "WindowShadingControl: Interior shade or blind: Potential problem in match of unshaded/shaded constructions, "
5833 : "shaded should have 1 more layers than unshaded.");
5834 0 : ShowContinueError(state, format("Unshaded construction={}", state.dataConstruction->Construct(ConstrNum).Name));
5835 0 : ShowContinueError(state, format("Shaded construction={}", state.dataConstruction->Construct(ConstrNumSh).Name));
5836 0 : ShowContinueError(state,
5837 : "If preceding two constructions are same name, you have likely specified a WindowShadingControl (Field #3) "
5838 : "with the Window Construction rather than a shaded construction.");
5839 : }
5840 248 : for (Lay = 1; Lay <= state.dataConstruction->Construct(ConstrNum).TotLayers; ++Lay) {
5841 160 : if (state.dataConstruction->Construct(ConstrNum).LayerPoint(Lay) !=
5842 160 : state.dataConstruction->Construct(ConstrNumSh).LayerPoint(Lay)) {
5843 0 : ErrorsFound = true;
5844 0 : ShowSevereError(state,
5845 0 : format(" The glass and gas layers in the shaded and unshaded constructions do not match for window={}",
5846 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name));
5847 0 : ShowContinueError(state, format("Unshaded construction={}", state.dataConstruction->Construct(ConstrNum).Name));
5848 0 : ShowContinueError(state, format("Shaded construction={}", state.dataConstruction->Construct(ConstrNumSh).Name));
5849 0 : break;
5850 : }
5851 : }
5852 : }
5853 :
5854 155 : if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(state.dataSurface->WindowShadingControl(WSCPtr).ShadingType)) {
5855 28 : TotLayers = state.dataConstruction->Construct(ConstrNum).TotLayers;
5856 28 : TotShLayers = state.dataConstruction->Construct(ConstrNumSh).TotLayers;
5857 28 : if (TotShLayers - 1 != TotLayers) {
5858 0 : ShowWarningError(state,
5859 : "WindowShadingControl: Exterior shade, screen or blind: Potential problem in match of unshaded/shaded "
5860 : "constructions, shaded should have 1 more layer than unshaded.");
5861 0 : ShowContinueError(state, format("Unshaded construction={}", state.dataConstruction->Construct(ConstrNum).Name));
5862 0 : ShowContinueError(state, format("Shaded construction={}", state.dataConstruction->Construct(ConstrNumSh).Name));
5863 0 : ShowContinueError(
5864 : state,
5865 : "If preceding two constructions have the same name, you have likely specified a WindowShadingControl (Field "
5866 : "#3) with the Window Construction rather than a shaded construction.");
5867 : }
5868 76 : for (Lay = 1; Lay <= state.dataConstruction->Construct(ConstrNum).TotLayers; ++Lay) {
5869 48 : if (state.dataConstruction->Construct(ConstrNum).LayerPoint(Lay) !=
5870 48 : state.dataConstruction->Construct(ConstrNumSh).LayerPoint(Lay + 1)) {
5871 0 : ErrorsFound = true;
5872 0 : ShowSevereError(state,
5873 0 : format(" The glass and gas layers in the shaded and unshaded constructions do not match for window={}",
5874 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name));
5875 0 : ShowContinueError(state, format("Unshaded construction={}", state.dataConstruction->Construct(ConstrNum).Name));
5876 0 : ShowContinueError(state, format("Shaded construction={}", state.dataConstruction->Construct(ConstrNumSh).Name));
5877 0 : break;
5878 : }
5879 : }
5880 : }
5881 :
5882 155 : if (ANY_BETWEENGLASS_SHADE_BLIND(state.dataSurface->WindowShadingControl(WSCPtr).ShadingType)) {
5883 : // Divider not allowed with between-glass shade or blind
5884 9 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).FrameDivider > 0) {
5885 0 : if (state.dataSurface->FrameDivider(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).FrameDivider).DividerWidth > 0.0) {
5886 0 : ShowWarningError(
5887 0 : state, format("A divider cannot be specified for window {}", state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name));
5888 0 : ShowContinueError(state, ", which has a between-glass shade or blind.");
5889 0 : ShowContinueError(state, "Calculation will proceed without the divider for this window.");
5890 0 : state.dataSurface->FrameDivider(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).FrameDivider).DividerWidth = 0.0;
5891 : }
5892 : }
5893 : // Check consistency of gap widths between unshaded and shaded constructions
5894 9 : TotGlassLayers = state.dataConstruction->Construct(ConstrNum).TotGlassLayers;
5895 9 : TotLayers = state.dataConstruction->Construct(ConstrNum).TotLayers;
5896 9 : TotShLayers = state.dataConstruction->Construct(ConstrNumSh).TotLayers;
5897 9 : if (TotShLayers - 2 != TotLayers) {
5898 0 : ShowWarningError(
5899 : state,
5900 : "WindowShadingControl: Between Glass Shade/Blind: Potential problem in match of unshaded/shaded constructions, "
5901 : "shaded should have 2 more layers than unshaded.");
5902 0 : ShowContinueError(state, format("Unshaded construction={}", state.dataConstruction->Construct(ConstrNum).Name));
5903 0 : ShowContinueError(state, format("Shaded construction={}", state.dataConstruction->Construct(ConstrNumSh).Name));
5904 0 : ShowContinueError(state,
5905 : "If preceding two constructions are same name, you have likely specified a WindowShadingControl (Field #3) "
5906 : "with the Window Construction rather than a shaded construction.");
5907 : }
5908 9 : if (state.dataConstruction->Construct(ConstrNum).LayerPoint(TotLayers) !=
5909 9 : state.dataConstruction->Construct(ConstrNumSh).LayerPoint(TotShLayers)) {
5910 0 : ShowSevereError(state, format("{}: Mis-match in unshaded/shaded inside layer materials. These should match.", cRoutineName));
5911 0 : ShowContinueError(
5912 : state,
5913 0 : format("Unshaded construction={}, Material={}",
5914 0 : state.dataConstruction->Construct(ConstrNum).Name,
5915 0 : state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(TotLayers))->Name));
5916 0 : ShowContinueError(
5917 : state,
5918 0 : format("Shaded construction={}, Material={}",
5919 0 : state.dataConstruction->Construct(ConstrNumSh).Name,
5920 0 : state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNumSh).LayerPoint(TotShLayers))->Name));
5921 0 : ErrorsFound = true;
5922 : }
5923 9 : if (state.dataConstruction->Construct(ConstrNum).LayerPoint(1) != state.dataConstruction->Construct(ConstrNumSh).LayerPoint(1)) {
5924 0 : ShowSevereError(state, format("{}: Mis-match in unshaded/shaded inside layer materials. These should match.", cRoutineName));
5925 0 : ShowContinueError(state,
5926 0 : format("Unshaded construction={}, Material={}",
5927 0 : state.dataConstruction->Construct(ConstrNum).Name,
5928 0 : state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(1))->Name));
5929 0 : ShowContinueError(state,
5930 0 : format("Shaded construction={}, Material={}",
5931 0 : state.dataConstruction->Construct(ConstrNumSh).Name,
5932 0 : state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNumSh).LayerPoint(1))->Name));
5933 0 : ErrorsFound = true;
5934 : }
5935 9 : if (TotGlassLayers == 2 || TotGlassLayers == 3) {
5936 9 : MatGap = state.dataConstruction->Construct(ConstrNum).LayerPoint(2 * TotGlassLayers - 2);
5937 9 : MatGap1 = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(2 * TotGlassLayers - 2);
5938 9 : MatGap2 = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(2 * TotGlassLayers);
5939 9 : MatSh = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(2 * TotGlassLayers - 1);
5940 9 : if (state.dataSurface->WindowShadingControl(WSCPtr).ShadingType == WinShadingType::BGBlind) {
5941 5 : MatGapCalc =
5942 5 : std::abs(state.dataMaterial->Material(MatGap)->Thickness -
5943 5 : (state.dataMaterial->Material(MatGap1)->Thickness + state.dataMaterial->Material(MatGap2)->Thickness));
5944 5 : if (MatGapCalc > 0.001) {
5945 0 : ShowSevereError(state,
5946 0 : format("{}: The gap width(s) for the unshaded window construction {}",
5947 : cRoutineName,
5948 0 : state.dataConstruction->Construct(ConstrNum).Name));
5949 0 : ShowContinueError(state,
5950 0 : "are inconsistent with the gap widths for shaded window construction " +
5951 0 : state.dataConstruction->Construct(ConstrNumSh).Name);
5952 0 : ShowContinueError(state,
5953 0 : "for window " + state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name +
5954 : ", which has a between-glass blind.");
5955 0 : ShowContinueError(state,
5956 0 : format("..Material={} thickness={:.3R} -",
5957 0 : state.dataMaterial->Material(MatGap)->Name,
5958 0 : state.dataMaterial->Material(MatGap)->Thickness));
5959 0 : ShowContinueError(state,
5960 0 : format("..( Material={} thickness={:.3R} +",
5961 0 : state.dataMaterial->Material(MatGap1)->Name,
5962 0 : state.dataMaterial->Material(MatGap1)->Thickness));
5963 0 : ShowContinueError(state,
5964 0 : format("..Material={} thickness={:.3R} )=[{:.3R}] >.001",
5965 0 : state.dataMaterial->Material(MatGap2)->Name,
5966 0 : state.dataMaterial->Material(MatGap2)->Thickness,
5967 : MatGapCalc));
5968 0 : ErrorsFound = true;
5969 : }
5970 : } else { // Between-glass shade
5971 4 : MatGapCalc =
5972 4 : std::abs(state.dataMaterial->Material(MatGap)->Thickness -
5973 4 : (state.dataMaterial->Material(MatGap1)->Thickness + state.dataMaterial->Material(MatGap2)->Thickness +
5974 4 : state.dataMaterial->Material(MatSh)->Thickness));
5975 4 : if (MatGapCalc > 0.001) {
5976 0 : ShowSevereError(state,
5977 0 : format("{}: The gap width(s) for the unshaded window construction {}",
5978 : cRoutineName,
5979 0 : state.dataConstruction->Construct(ConstrNum).Name));
5980 0 : ShowContinueError(state,
5981 0 : "are inconsistent with the gap widths for shaded window construction " +
5982 0 : state.dataConstruction->Construct(ConstrNumSh).Name);
5983 0 : ShowContinueError(state,
5984 0 : "for window " + state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name +
5985 : ", which has a between-glass shade.");
5986 0 : ShowContinueError(state,
5987 0 : format("..Material={} thickness={:.3R} -",
5988 0 : state.dataMaterial->Material(MatGap)->Name,
5989 0 : state.dataMaterial->Material(MatGap)->Thickness));
5990 0 : ShowContinueError(state,
5991 0 : format("...( Material={} thickness={:.3R} +",
5992 0 : state.dataMaterial->Material(MatGap1)->Name,
5993 0 : state.dataMaterial->Material(MatGap1)->Thickness));
5994 0 : ShowContinueError(state,
5995 0 : format("..Material={} thickness={:.3R} +",
5996 0 : state.dataMaterial->Material(MatGap2)->Name,
5997 0 : state.dataMaterial->Material(MatGap2)->Thickness));
5998 0 : ShowContinueError(state,
5999 0 : format("..Material={} thickness={:.3R} )=[{:.3R}] >.001",
6000 0 : state.dataMaterial->Material(MatSh)->Name,
6001 0 : state.dataMaterial->Material(MatSh)->Thickness,
6002 : MatGapCalc));
6003 0 : ErrorsFound = true;
6004 : }
6005 : }
6006 : }
6007 : }
6008 : }
6009 : }
6010 6207 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
6011 6207 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides != 3) { // Rectangular Window
6012 : // Initialize the FrameDivider number for this window. W5FrameDivider will be positive if
6013 : // this window's construction came from the Window5 data file and that construction had an
6014 : // associated frame or divider. It will be zero if the window's construction is not from the
6015 : // Window5 data file, or the construction is from the data file, but the construction has no
6016 : // associated frame or divider. Note that if there is a FrameDivider candidate for this
6017 : // window from the Window5 data file it is used instead of the window's input FrameDivider.
6018 :
6019 6205 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction != 0) {
6020 6205 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).FrameDivider =
6021 6205 : state.dataConstruction->Construct(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction).W5FrameDivider;
6022 :
6023 : // Warning if FrameAndDivider for this window is over-ridden by one from Window5 Data File
6024 6205 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).FrameDivider > 0 && !state.dataIPShortCut->lAlphaFieldBlanks(FrameField)) {
6025 0 : ShowSevereError(state,
6026 0 : format("{}=\"{}\", {}=\"{}\"",
6027 : cCurrentModuleObject,
6028 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
6029 0 : state.dataIPShortCut->cAlphaFieldNames(FrameField),
6030 0 : state.dataIPShortCut->cAlphaArgs(FrameField)));
6031 0 : ShowContinueError(state,
6032 0 : format("will be replaced with FrameAndDivider from Window5 Data File entry {}",
6033 0 : state.dataConstruction->Construct(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction).Name));
6034 : }
6035 :
6036 6205 : if (!state.dataIPShortCut->lAlphaFieldBlanks(FrameField) && state.dataSurfaceGeometry->SurfaceTmp(SurfNum).FrameDivider == 0) {
6037 373 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).FrameDivider =
6038 373 : Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(FrameField), state.dataSurface->FrameDivider);
6039 373 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).FrameDivider == 0) {
6040 0 : if (!state.dataConstruction->Construct(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction).WindowTypeEQL) {
6041 0 : ShowSevereError(state,
6042 0 : format("{}=\"{}\", invalid {}=\"{}\"",
6043 : cCurrentModuleObject,
6044 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
6045 0 : state.dataIPShortCut->cAlphaFieldNames(FrameField),
6046 0 : state.dataIPShortCut->cAlphaArgs(FrameField)));
6047 0 : ErrorsFound = true;
6048 : } else {
6049 0 : ShowSevereError(state,
6050 0 : format("{}=\"{}\", invalid {}=\"{}\"",
6051 : cCurrentModuleObject,
6052 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
6053 0 : state.dataIPShortCut->cAlphaFieldNames(FrameField),
6054 0 : state.dataIPShortCut->cAlphaArgs(FrameField)));
6055 0 : ShowContinueError(state, "...Frame/Divider is not supported in Equivalent Layer Window model.");
6056 : }
6057 : }
6058 : // Divider not allowed with between-glass shade or blind
6059 414 : for (int WSCPtr : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).windowShadingControlList) {
6060 41 : if (!ErrorsFound && WSCPtr > 0 && ConstrNumSh > 0) {
6061 41 : if (ANY_BETWEENGLASS_SHADE_BLIND(state.dataSurface->WindowShadingControl(WSCPtr).ShadingType)) {
6062 1 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).FrameDivider > 0) {
6063 1 : if (state.dataSurface->FrameDivider(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).FrameDivider).DividerWidth >
6064 : 0.0) {
6065 0 : ShowSevereError(state,
6066 0 : format("{}=\"{}\", invalid {}=\"{}\"",
6067 : cCurrentModuleObject,
6068 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
6069 0 : state.dataIPShortCut->cAlphaFieldNames(FrameField),
6070 0 : state.dataIPShortCut->cAlphaArgs(FrameField)));
6071 0 : ShowContinueError(state,
6072 : "Divider cannot be specified because the construction has a between-glass shade or blind.");
6073 0 : ShowContinueError(state, "Calculation will proceed without the divider for this window.");
6074 0 : ShowContinueError(
6075 : state,
6076 0 : format("Divider width = [{:.2R}].",
6077 0 : state.dataSurface->FrameDivider(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).FrameDivider)
6078 0 : .DividerWidth));
6079 0 : state.dataSurface->FrameDivider(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).FrameDivider).DividerWidth =
6080 : 0.0;
6081 : }
6082 : } // End of check if window has divider
6083 : } // End of check if window has a between-glass shade or blind
6084 : } // End of check if window has a shaded construction
6085 373 : } // end of looping through window shading controls of window
6086 : } // End of check if window has an associated FrameAndDivider
6087 : } // End of check if window has a construction
6088 : }
6089 :
6090 6207 : if (state.dataConstruction->Construct(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction).WindowTypeEQL) {
6091 3 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).FrameDivider > 0) {
6092 : // Equivalent Layer window does not have frame/divider model
6093 0 : ShowSevereError(state,
6094 0 : format("{}=\"{}\", invalid {}=\"{}\"",
6095 : cCurrentModuleObject,
6096 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
6097 0 : state.dataIPShortCut->cAlphaFieldNames(FrameField),
6098 0 : state.dataIPShortCut->cAlphaArgs(FrameField)));
6099 0 : ShowContinueError(state, "Frame/Divider is not supported in Equivalent Layer Window model.");
6100 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).FrameDivider = 0;
6101 : }
6102 : }
6103 6207 : }
6104 :
6105 6694 : void CheckSubSurfaceMiscellaneous(EnergyPlusData &state,
6106 : std::string_view const cRoutineName, // routine name calling this one (for error messages)
6107 : bool &ErrorsFound, // true if errors have been found or are found here
6108 : int const SurfNum, // current surface number
6109 : std::string const &SubSurfaceName, // name of the surface
6110 : std::string const &SubSurfaceConstruction, // name of the construction
6111 : int &AddedSubSurfaces)
6112 : {
6113 :
6114 : // SUBROUTINE INFORMATION:
6115 : // AUTHOR Linda Lawrie
6116 : // DATE WRITTEN December 2008
6117 : // MODIFIED na
6118 : // RE-ENGINEERED na
6119 :
6120 : // PURPOSE OF THIS SUBROUTINE:
6121 : // This routine performs miscellaneous checks on subsurfaces: Windows, GlassDoors, Doors, Tubular Devices.
6122 :
6123 : // Using/Aliasing
6124 :
6125 : using namespace DataErrorTracking;
6126 :
6127 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
6128 : int NumShades; // count on number of shading layers
6129 : int Lay; // Layer number
6130 : int LayerPtr; // Layer pointer
6131 : int ConstrNum; // Construction number
6132 : int Found; // when item is found
6133 :
6134 : // Warning if window has multiplier > 1 and SolarDistribution = FullExterior or FullInteriorExterior
6135 :
6136 6694 : if ((state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == SurfaceClass::Window ||
6137 1019 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == SurfaceClass::GlassDoor) &&
6138 13127 : static_cast<int>(state.dataHeatBal->SolarDistribution) > static_cast<int>(DataHeatBalance::Shadowing::Minimal) &&
6139 5414 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Multiplier > 1.0) {
6140 6 : if (state.dataGlobal->DisplayExtraWarnings) {
6141 0 : ShowWarningError(
6142 : state,
6143 0 : format("{}: A Multiplier > 1.0 for window/glass door {}", cRoutineName, state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name));
6144 0 : ShowContinueError(state, "in conjunction with SolarDistribution = FullExterior or FullInteriorExterior");
6145 0 : ShowContinueError(state, "can cause inaccurate shadowing on the window and/or");
6146 0 : ShowContinueError(state, "inaccurate interior solar distribution from the window.");
6147 : }
6148 6 : ++state.dataErrTracking->TotalMultipliedWindows;
6149 : }
6150 :
6151 : // Require that a construction referenced by a surface that is a window
6152 : // NOT have a shading device layer; use WindowShadingControl to specify a shading device.
6153 6694 : ConstrNum = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction;
6154 6694 : if (ConstrNum > 0) {
6155 6694 : NumShades = 0;
6156 17582 : for (Lay = 1; Lay <= state.dataConstruction->Construct(ConstrNum).TotLayers; ++Lay) {
6157 10888 : LayerPtr = state.dataConstruction->Construct(ConstrNum).LayerPoint(Lay);
6158 10888 : if (LayerPtr == 0) continue; // Error is caught already, will terminate later
6159 10888 : if (state.dataMaterial->Material(LayerPtr)->group == Material::Group::Shade ||
6160 21776 : state.dataMaterial->Material(LayerPtr)->group == Material::Group::WindowBlind ||
6161 10888 : state.dataMaterial->Material(LayerPtr)->group == Material::Group::Screen)
6162 0 : ++NumShades;
6163 : }
6164 6694 : if (NumShades != 0) {
6165 0 : ShowSevereError(state, format("{}: Window \"{}\" must not directly reference", cRoutineName, SubSurfaceName));
6166 0 : ShowContinueError(state, format("a Construction (i.e, \"{}\") with a shading device.", SubSurfaceConstruction));
6167 0 : ShowContinueError(state, "Use WindowShadingControl to specify a shading device for a window.");
6168 0 : ErrorsFound = true;
6169 : }
6170 : }
6171 :
6172 : // Disallow glass transmittance dirt factor for interior windows and glass doors
6173 :
6174 6785 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond != ExternalEnvironment &&
6175 91 : (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == SurfaceClass::Window ||
6176 80 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == SurfaceClass::GlassDoor)) {
6177 12 : ConstrNum = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction;
6178 12 : if (ConstrNum > 0) {
6179 24 : for (Lay = 1; Lay <= state.dataConstruction->Construct(ConstrNum).TotLayers; ++Lay) {
6180 12 : LayerPtr = state.dataConstruction->Construct(ConstrNum).LayerPoint(Lay);
6181 12 : auto const *thisMaterial = dynamic_cast<Material::MaterialChild *>(state.dataMaterial->Material(LayerPtr));
6182 12 : assert(thisMaterial != nullptr);
6183 12 : if (thisMaterial->group == Material::Group::WindowGlass && thisMaterial->GlassTransDirtFactor < 1.0) {
6184 0 : ShowSevereError(state, format("{}: Interior Window or GlassDoor {} has a glass layer with", cRoutineName, SubSurfaceName));
6185 0 : ShowContinueError(state, "Dirt Correction Factor for Solar and Visible Transmittance < 1.0");
6186 0 : ShowContinueError(state, "A value less than 1.0 for this factor is only allowed for exterior windows and glass doors.");
6187 0 : ErrorsFound = true;
6188 : }
6189 : }
6190 : }
6191 : }
6192 :
6193 : // If this is a window with a construction from the Window5DataFile, call routine that will
6194 : // (1) if one glazing system on Data File, give warning message if window height or width
6195 : // differ by more than 10% from those of the glazing system on the Data File;
6196 : // (2) if two glazing systems (separated by a mullion) on Data File, create a second window
6197 : // and adjust the dimensions of the original and second windows to those on the Data File
6198 :
6199 6694 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction != 0) {
6200 :
6201 6694 : if (state.dataConstruction->Construct(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction).FromWindow5DataFile) {
6202 :
6203 8 : ModifyWindow(state, SurfNum, ErrorsFound, AddedSubSurfaces);
6204 :
6205 : } else {
6206 : // Calculate net area for base surface (note that ModifyWindow, above, adjusts net area of
6207 : // base surface for case where window construction is from Window5 Data File
6208 : // In case there is in error in this window's base surface (i.e. none)..
6209 6686 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).BaseSurf > 0) {
6210 6686 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).BaseSurf).Area -=
6211 6686 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Area;
6212 :
6213 : // Subtract TDD:DIFFUSER area from other side interzone surface
6214 6688 : if ((state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == SurfaceClass::TDD_Diffuser) &&
6215 2 : not_blank(state.dataSurfaceGeometry->SurfaceTmp(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).BaseSurf)
6216 : .ExtBoundCondName)) { // Base surface is an interzone surface
6217 : // Lookup interzone surface of the base surface
6218 : // (Interzone surfaces have not been assigned yet, but all base surfaces should already be loaded.)
6219 2 : Found = Util::FindItemInList(
6220 2 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).BaseSurf).ExtBoundCondName,
6221 2 : state.dataSurfaceGeometry->SurfaceTmp,
6222 : SurfNum);
6223 2 : if (Found != 0) state.dataSurfaceGeometry->SurfaceTmp(Found).Area -= state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Area;
6224 : }
6225 6686 : if (state.dataSurfaceGeometry->SurfaceTmp(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).BaseSurf).Area <= 0.0) {
6226 0 : ShowSevereError(state,
6227 0 : format("{}: Surface Openings have too much area for base surface={}",
6228 : cRoutineName,
6229 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).BaseSurf).Name));
6230 0 : ShowContinueError(state, format("Opening Surface creating error={}", state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name));
6231 0 : ErrorsFound = true;
6232 : }
6233 : // Net area of base surface with unity window multipliers (used in shadowing checks)
6234 : // For Windows, Glass Doors and Doors, just one area is subtracted. For the rest, should be
6235 : // full area.
6236 7705 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == SurfaceClass::Window ||
6237 1019 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == SurfaceClass::GlassDoor) {
6238 6205 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).BaseSurf).NetAreaShadowCalc -=
6239 6205 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Area / state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Multiplier;
6240 481 : } else if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == SurfaceClass::Door) { // Door, TDD:Diffuser, TDD:DOME
6241 477 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).BaseSurf).NetAreaShadowCalc -=
6242 477 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Area / state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Multiplier;
6243 : } else {
6244 4 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).BaseSurf).NetAreaShadowCalc -=
6245 4 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Area;
6246 : }
6247 : }
6248 : }
6249 : }
6250 6694 : }
6251 :
6252 118 : void MakeRelativeRectangularVertices(EnergyPlusData &state,
6253 : int const BaseSurfNum, // Base surface
6254 : int const SurfNum,
6255 : Real64 const XCoord,
6256 : Real64 const ZCoord,
6257 : Real64 const Length,
6258 : Real64 const Height)
6259 : {
6260 :
6261 : // SUBROUTINE INFORMATION:
6262 : // AUTHOR Linda Lawrie
6263 : // DATE WRITTEN December 2008
6264 : // MODIFIED na
6265 : // RE-ENGINEERED na
6266 :
6267 : // PURPOSE OF THIS SUBROUTINE:
6268 : // This routine creates world/3d coordinates for rectangular surfaces using relative X and Z, length & height.
6269 :
6270 : // METHODOLOGY EMPLOYED:
6271 : // na
6272 :
6273 : // REFERENCES:
6274 : // na
6275 :
6276 : // Using/Aliasing
6277 : using namespace Vectors;
6278 :
6279 : // Locals
6280 : // SUBROUTINE ARGUMENT DEFINITIONS:
6281 :
6282 : // SUBROUTINE PARAMETER DEFINITIONS:
6283 : // na
6284 :
6285 : // INTERFACE BLOCK SPECIFICATIONS:
6286 : // na
6287 :
6288 : // DERIVED TYPE DEFINITIONS:
6289 : // na
6290 :
6291 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
6292 : Real64 SurfAzimuth; // Surface Azimuth/Facing (same as Base Surface)
6293 : Real64 SurfTilt; // Tilt (same as Base Surface)
6294 : Real64 XLLC;
6295 : Real64 YLLC;
6296 : Real64 ZLLC;
6297 : Real64 CosSurfAzimuth;
6298 : Real64 SinSurfAzimuth;
6299 : Real64 CosSurfTilt;
6300 : Real64 SinSurfTilt;
6301 : Real64 BaseCosSurfAzimuth;
6302 : Real64 BaseSinSurfAzimuth;
6303 : Real64 BaseCosSurfTilt;
6304 : Real64 BaseSinSurfTilt;
6305 118 : Array1D<Real64> XX(4);
6306 118 : Array1D<Real64> YY(4);
6307 : Real64 Perimeter;
6308 : int n;
6309 : int Vrt;
6310 :
6311 118 : if (BaseSurfNum == 0) return; // invalid base surface, don't bother
6312 :
6313 : // Tilt and Facing (Azimuth) will be same as the Base Surface
6314 :
6315 118 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Height = Height;
6316 118 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Width = Length;
6317 :
6318 118 : SurfAzimuth = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Azimuth;
6319 118 : SurfTilt = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Tilt;
6320 118 : CosSurfAzimuth = std::cos(SurfAzimuth * Constant::DegToRadians);
6321 118 : SinSurfAzimuth = std::sin(SurfAzimuth * Constant::DegToRadians);
6322 118 : CosSurfTilt = std::cos(SurfTilt * Constant::DegToRadians);
6323 118 : SinSurfTilt = std::sin(SurfTilt * Constant::DegToRadians);
6324 118 : BaseCosSurfAzimuth = state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosAzim;
6325 118 : BaseSinSurfAzimuth = state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).SinAzim;
6326 118 : BaseCosSurfTilt = state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosTilt;
6327 118 : BaseSinSurfTilt = state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).SinTilt;
6328 :
6329 118 : XLLC = state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).x - XCoord * BaseCosSurfAzimuth -
6330 118 : ZCoord * BaseCosSurfTilt * BaseSinSurfAzimuth;
6331 118 : YLLC = state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).y + XCoord * BaseSinSurfAzimuth -
6332 118 : ZCoord * BaseCosSurfTilt * BaseCosSurfAzimuth;
6333 118 : ZLLC = state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).z + ZCoord * BaseSinSurfTilt;
6334 :
6335 118 : XX(1) = 0.0;
6336 118 : XX(2) = 0.0;
6337 118 : XX(3) = Length;
6338 118 : XX(4) = Length;
6339 118 : YY(1) = Height;
6340 118 : YY(4) = Height;
6341 118 : YY(3) = 0.0;
6342 118 : YY(2) = 0.0;
6343 :
6344 590 : for (n = 1; n <= state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides; ++n) {
6345 472 : Vrt = n;
6346 472 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(Vrt).x = XLLC - XX(n) * CosSurfAzimuth - YY(n) * CosSurfTilt * SinSurfAzimuth;
6347 472 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(Vrt).y = YLLC + XX(n) * SinSurfAzimuth - YY(n) * CosSurfTilt * CosSurfAzimuth;
6348 472 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(Vrt).z = ZLLC + YY(n) * SinSurfTilt;
6349 : }
6350 :
6351 118 : CreateNewellAreaVector(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex,
6352 118 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides,
6353 118 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).NewellAreaVector);
6354 118 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).GrossArea = VecLength(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).NewellAreaVector);
6355 118 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Area = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).GrossArea;
6356 118 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).NetAreaShadowCalc = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Area;
6357 118 : CreateNewellSurfaceNormalVector(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex,
6358 118 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides,
6359 118 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).NewellSurfaceNormalVector);
6360 118 : DetermineAzimuthAndTilt(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex,
6361 : SurfAzimuth,
6362 : SurfTilt,
6363 118 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).lcsx,
6364 118 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).lcsy,
6365 118 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).lcsz,
6366 118 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).NewellSurfaceNormalVector);
6367 118 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Azimuth = SurfAzimuth;
6368 118 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Tilt = SurfTilt;
6369 118 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).convOrientation =
6370 118 : Convect::GetSurfConvOrientation(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Tilt);
6371 : // Sine and cosine of azimuth and tilt
6372 118 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).SinAzim = SinSurfAzimuth;
6373 118 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).CosAzim = CosSurfAzimuth;
6374 118 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).SinTilt = SinSurfTilt;
6375 118 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).CosTilt = CosSurfTilt;
6376 118 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class != SurfaceClass::Window &&
6377 171 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class != SurfaceClass::GlassDoor &&
6378 53 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class != SurfaceClass::Door)
6379 44 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ViewFactorGround = 0.5 * (1.0 - state.dataSurfaceGeometry->SurfaceTmp(SurfNum).CosTilt);
6380 : // Outward normal unit vector (pointing away from room)
6381 118 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).OutNormVec = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).NewellSurfaceNormalVector;
6382 472 : for (n = 1; n <= 3; ++n) {
6383 354 : if (std::abs(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).OutNormVec(n) - 1.0) < 1.e-06)
6384 27 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).OutNormVec(n) = +1.0;
6385 354 : if (std::abs(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).OutNormVec(n) + 1.0) < 1.e-06)
6386 91 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).OutNormVec(n) = -1.0;
6387 354 : if (std::abs(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).OutNormVec(n)) < 1.e-06)
6388 236 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).OutNormVec(n) = 0.0;
6389 : }
6390 :
6391 : // IF (SurfaceTmp(SurfNum)%Class == SurfaceClass::Roof .and. SurfTilt > 80.) THEN
6392 : // WRITE(TiltString,'(F5.1)') SurfTilt
6393 : // TiltString=ADJUSTL(TiltString)
6394 : // CALL ShowWarningError(state, format("Roof/Ceiling Tilt={}{}{}{}{}{}{}{}{}{} for Surface={}{}{}, in
6395 : // Zone={}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}", //TRIM(TiltString)//',,
6396 : // much, greater, than, expected, tilt, of, 0,'//, &, //, //TRIM(SurfaceTmp(SurfNum)%Name)//, &, //, //TRIM(SurfaceTmp(SurfNum)%ZoneName)),
6397 : // //, ENDIF, //, IF, (SurfaceTmp(SurfNum)%Class, ==, SurfaceClass::Floor, .and., SurfTilt, <, 170.), THEN, //, WRITE(TiltString,'(F5.1)'),
6398 : // SurfTilt, //, TiltString=ADJUSTL(TiltString), //, CALL, ShowWarningError(state, 'Floor Tilt='//TRIM(TiltString)//', much less than
6399 : // expected tilt of 180,'// &
6400 : // ' for Surface='//TRIM(SurfaceTmp(SurfNum)%Name)// &
6401 : // ', in Zone='//TRIM(SurfaceTmp(SurfNum)%ZoneName)), //, ENDIF, if,
6402 : // (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class, ==, SurfaceClass::Window, ||,
6403 : // state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class, ==, SurfaceClass::GlassDoor, ||,
6404 : // state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class, ==, SurfaceClass::Door),
6405 : // state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Area, *=,
6406 : // state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Multiplier;, //, Can, perform, tests, on, this, surface, here,
6407 : // state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ViewFactorSky, =, 0.5, *, (1.0,
6408 : // state.dataSurfaceGeometry->SurfaceTmp(SurfNum).CosTilt));
6409 : // The following IR view factors are modified in subr. SkyDifSolarShading if there are shadowing
6410 : // surfaces
6411 118 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ViewFactorSkyIR = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ViewFactorSky;
6412 118 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ViewFactorGroundIR = 0.5 * (1.0 - state.dataSurfaceGeometry->SurfaceTmp(SurfNum).CosTilt);
6413 :
6414 118 : Perimeter = distance(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides),
6415 118 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(1));
6416 472 : for (Vrt = 2; Vrt <= state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides; ++Vrt) {
6417 354 : Perimeter +=
6418 354 : distance(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(Vrt), state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(Vrt - 1));
6419 : }
6420 118 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Perimeter = Perimeter;
6421 :
6422 : // Call to transform vertices
6423 :
6424 118 : TransformVertsByAspect(state, SurfNum, state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides);
6425 118 : }
6426 :
6427 796 : void GetAttShdSurfaceData(EnergyPlusData &state,
6428 : bool &ErrorsFound, // Error flag indicator (true if errors found)
6429 : int &SurfNum, // Count of Current SurfaceNumber
6430 : int const TotShdSubs // Number of Attached Shading SubSurfaces to obtain
6431 : )
6432 : {
6433 : // SUBROUTINE INFORMATION:
6434 : // AUTHOR Linda Lawrie
6435 : // DATE WRITTEN May 2000
6436 :
6437 : // PURPOSE OF THIS SUBROUTINE:
6438 : // This subroutine gets the HeatTransfer Surface Data,
6439 : // checks it for errors, etc.
6440 :
6441 : // Using/Aliasing
6442 : using ScheduleManager::CheckScheduleValueMinMax;
6443 : using ScheduleManager::GetScheduleIndex;
6444 : using ScheduleManager::GetScheduleMaxValue;
6445 : using ScheduleManager::GetScheduleMinValue;
6446 :
6447 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
6448 : int IOStat; // IO Status when calling get input subroutine
6449 : int NumAlphas; // Number of alpha names being passed
6450 : int NumNumbers; // Number of properties being passed
6451 : int Found; // For matching interzone surfaces
6452 : int Loop;
6453 : Real64 SchedMinValue;
6454 : Real64 SchedMaxValue;
6455 :
6456 796 : if (TotShdSubs > 0 && state.dataHeatBal->SolarDistribution == DataHeatBalance::Shadowing::Minimal) {
6457 1 : ShowWarningError(state, "Shading effects of Fins and Overhangs are ignored when Solar Distribution = MinimalShadowing");
6458 : }
6459 796 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
6460 796 : cCurrentModuleObject = "Shading:Zone:Detailed";
6461 796 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, Loop, NumAlphas, NumNumbers);
6462 796 : if (NumAlphas != 3) {
6463 0 : ShowSevereError(state,
6464 0 : format("{}: Object Definition indicates not = 3 Alpha Objects, Number Indicated={}", cCurrentModuleObject, NumAlphas));
6465 0 : ErrorsFound = true;
6466 : }
6467 :
6468 1494 : for (Loop = 1; Loop <= TotShdSubs; ++Loop) {
6469 1396 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
6470 : cCurrentModuleObject,
6471 : Loop,
6472 698 : state.dataIPShortCut->cAlphaArgs,
6473 : NumAlphas,
6474 698 : state.dataIPShortCut->rNumericArgs,
6475 : NumNumbers,
6476 : IOStat,
6477 698 : state.dataIPShortCut->lNumericFieldBlanks,
6478 698 : state.dataIPShortCut->lAlphaFieldBlanks,
6479 698 : state.dataIPShortCut->cAlphaFieldNames,
6480 698 : state.dataIPShortCut->cNumericFieldNames);
6481 :
6482 1396 : if (GlobalNames::VerifyUniqueInterObjectName(state,
6483 698 : state.dataSurfaceGeometry->UniqueSurfaceNames,
6484 698 : state.dataIPShortCut->cAlphaArgs(1),
6485 : cCurrentModuleObject,
6486 698 : state.dataIPShortCut->cAlphaFieldNames(1),
6487 : ErrorsFound)) {
6488 0 : continue;
6489 : }
6490 :
6491 698 : ++SurfNum;
6492 698 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name = state.dataIPShortCut->cAlphaArgs(1); // Set the Surface Name in the Derived Type
6493 698 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class = SurfaceClass::Shading;
6494 698 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).HeatTransSurf = false;
6495 698 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).BaseSurfName = state.dataIPShortCut->cAlphaArgs(2);
6496 : // The subsurface inherits properties from the base surface
6497 : // Exterior conditions, Zone, etc.
6498 : // We can figure out the base surface though, because they've all been entered
6499 698 : Found = Util::FindItemInList(
6500 698 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).BaseSurfName, state.dataSurfaceGeometry->SurfaceTmp, state.dataSurface->TotSurfaces);
6501 698 : if (Found > 0) {
6502 : // SurfaceTmp(SurfNum)%BaseSurf=Found
6503 698 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCond;
6504 698 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtSolar = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtSolar;
6505 698 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtWind = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtWind;
6506 698 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Zone =
6507 698 : state.dataSurfaceGeometry->SurfaceTmp(Found).Zone; // Necessary to do relative coordinates in GetVertices below
6508 698 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ZoneName =
6509 1396 : state.dataSurfaceGeometry->SurfaceTmp(Found).ZoneName; // Necessary to have surface drawn in OutputReports
6510 : } else {
6511 0 : ShowSevereError(state,
6512 0 : format("{}=\"{}\", invalid {}=\"{}",
6513 : cCurrentModuleObject,
6514 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
6515 0 : state.dataIPShortCut->cAlphaFieldNames(2),
6516 0 : state.dataIPShortCut->cAlphaArgs(2)));
6517 0 : ErrorsFound = true;
6518 : }
6519 698 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond == UnenteredAdjacentZoneSurface) {
6520 0 : ShowSevereError(state,
6521 0 : format("{}=\"{}\", invalid {}=\"{}",
6522 : cCurrentModuleObject,
6523 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
6524 0 : state.dataIPShortCut->cAlphaFieldNames(2),
6525 0 : state.dataIPShortCut->cAlphaArgs(2)));
6526 0 : ShowContinueError(state, "...trying to attach a shading device to an interzone surface.");
6527 0 : ErrorsFound = true;
6528 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond =
6529 : ExternalEnvironment; // reset so program won't crash during "add surfaces"
6530 : }
6531 698 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond == UnreconciledZoneSurface) {
6532 0 : ShowSevereError(state,
6533 0 : format("{}=\"{}\", invalid {}=\"{}",
6534 : cCurrentModuleObject,
6535 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
6536 0 : state.dataIPShortCut->cAlphaFieldNames(2),
6537 0 : state.dataIPShortCut->cAlphaArgs(2)));
6538 0 : ShowContinueError(state, "...trying to attach a shading device to an interior surface.");
6539 0 : ErrorsFound = true;
6540 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond =
6541 : ExternalEnvironment; // reset so program won't crash during "add surfaces"
6542 : }
6543 :
6544 698 : if (!state.dataIPShortCut->lAlphaFieldBlanks(3)) {
6545 635 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).SchedShadowSurfIndex = GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(3));
6546 635 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).SchedShadowSurfIndex == 0) {
6547 0 : ShowSevereError(state,
6548 0 : format("{}=\"{}\", {} not found=\"{}",
6549 : cCurrentModuleObject,
6550 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
6551 0 : state.dataIPShortCut->cAlphaFieldNames(3),
6552 0 : state.dataIPShortCut->cAlphaArgs(3)));
6553 0 : ErrorsFound = true;
6554 : }
6555 : } else {
6556 63 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).SchedShadowSurfIndex = 0;
6557 : }
6558 698 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).SchedShadowSurfIndex != 0) {
6559 635 : if (!CheckScheduleValueMinMax(state, state.dataSurfaceGeometry->SurfaceTmp(SurfNum).SchedShadowSurfIndex, ">=", 0.0, "<=", 1.0)) {
6560 0 : ShowSevereError(state,
6561 0 : format("{}=\"{}\", {}=\"{}\", values not in range [0,1].",
6562 : cCurrentModuleObject,
6563 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
6564 0 : state.dataIPShortCut->cAlphaFieldNames(3),
6565 0 : state.dataIPShortCut->cAlphaArgs(3)));
6566 0 : ErrorsFound = true;
6567 : }
6568 635 : SchedMinValue = GetScheduleMinValue(state, state.dataSurfaceGeometry->SurfaceTmp(SurfNum).SchedShadowSurfIndex);
6569 635 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).SchedMinValue = SchedMinValue;
6570 635 : SchedMaxValue = GetScheduleMaxValue(state, state.dataSurfaceGeometry->SurfaceTmp(SurfNum).SchedShadowSurfIndex);
6571 635 : if (SchedMinValue == 1.0) {
6572 : // Set transparent for now, check for EMS actuators later in SolarShading::resetShadingSurfaceTransparency
6573 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).IsTransparent = true;
6574 : }
6575 635 : if (SchedMinValue < 0.0) {
6576 0 : ShowSevereError(state,
6577 0 : format("{}=\"{}\", {}=\"{}\", has schedule values < 0.",
6578 : cCurrentModuleObject,
6579 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
6580 0 : state.dataIPShortCut->cAlphaFieldNames(2),
6581 0 : state.dataIPShortCut->cAlphaArgs(2)));
6582 0 : ShowContinueError(state, "...Schedule values < 0 have no meaning for shading elements.");
6583 : }
6584 635 : if (SchedMaxValue > 0.0) {
6585 8 : state.dataSolarShading->anyScheduledShadingSurface = true;
6586 : }
6587 635 : if (SchedMaxValue > 1.0) {
6588 0 : ShowSevereError(state,
6589 0 : format("{}=\"{}\", {}=\"{}\", has schedule values > 1.",
6590 : cCurrentModuleObject,
6591 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
6592 0 : state.dataIPShortCut->cAlphaFieldNames(2),
6593 0 : state.dataIPShortCut->cAlphaArgs(2)));
6594 0 : ShowContinueError(state, "...Schedule values > 1 have no meaning for shading elements.");
6595 : }
6596 635 : if (std::abs(SchedMinValue - SchedMaxValue) > Constant::OneMillionth) {
6597 0 : state.dataSurface->ShadingTransmittanceVaries = true;
6598 : }
6599 : }
6600 698 : if (state.dataIPShortCut->lNumericFieldBlanks(1) || state.dataIPShortCut->rNumericArgs(1) == Constant::AutoCalculate) {
6601 2 : state.dataIPShortCut->rNumericArgs(1) = (NumNumbers - 1) / 3;
6602 2 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides = state.dataIPShortCut->rNumericArgs(1);
6603 2 : if (mod(NumNumbers - 1, 3) != 0) {
6604 0 : ShowWarningError(state,
6605 0 : format("{}=\"{}\", {}",
6606 : cCurrentModuleObject,
6607 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
6608 0 : format("{} not even multiple of 3. Will read in {}",
6609 0 : state.dataIPShortCut->cNumericFieldNames(1),
6610 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides)));
6611 : }
6612 2 : if (state.dataIPShortCut->rNumericArgs(1) < 3) {
6613 0 : ShowSevereError(state,
6614 0 : format("{}=\"{}\", {} (autocalculate) must be >= 3. Only {} provided.",
6615 : cCurrentModuleObject,
6616 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
6617 0 : state.dataIPShortCut->cNumericFieldNames(1),
6618 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides));
6619 0 : ErrorsFound = true;
6620 0 : continue;
6621 : }
6622 : } else {
6623 696 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides = state.dataIPShortCut->rNumericArgs(1);
6624 : }
6625 698 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex.allocate(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides);
6626 2094 : GetVertices(state, SurfNum, state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides, state.dataIPShortCut->rNumericArgs({2, _}));
6627 698 : CheckConvexity(state, SurfNum, state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides);
6628 : // IF (SurfaceTmp(SurfNum)%Sides == 3) THEN
6629 : // CALL ShowWarningError(state, TRIM(cCurrentModuleObject)//'="'//TRIM(SurfaceTmp(SurfNum)%Name)// &
6630 : // ' should not be triangular.')
6631 : // CALL ShowContinueError(state, '...Check results carefully.')
6632 : // ErrorsFound=.TRUE.
6633 : // ENDIF
6634 : // Reset surface to be "detached"
6635 698 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).BaseSurf = 0;
6636 : // SurfaceTmp(SurfNum)%BaseSurfName=' '
6637 698 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Zone = 0;
6638 : // SurfaceTmp(SurfNum)%ZoneName=' '
6639 698 : if (state.dataReportFlag->MakeMirroredAttachedShading) {
6640 698 : MakeMirrorSurface(state, SurfNum);
6641 : }
6642 : }
6643 796 : }
6644 :
6645 796 : void GetSimpleShdSurfaceData(EnergyPlusData &state,
6646 : bool &ErrorsFound, // Error flag indicator (true if errors found)
6647 : int &SurfNum, // Count of Current SurfaceNumber
6648 : int const TotOverhangs, // Number of Overhangs to obtain
6649 : int const TotOverhangsProjection, // Number of Overhangs (projection) to obtain
6650 : int const TotFins, // Number of Fins to obtain
6651 : int const TotFinsProjection // Number of Fins (projection) to obtain
6652 : )
6653 : {
6654 :
6655 : // SUBROUTINE INFORMATION:
6656 : // AUTHOR Linda Lawrie
6657 : // DATE WRITTEN January 2009
6658 : // MODIFIED na
6659 : // RE-ENGINEERED na
6660 :
6661 : // PURPOSE OF THIS SUBROUTINE:
6662 : // Get simple overhang and fin descriptions.
6663 :
6664 : // Using/Aliasing
6665 : using namespace Vectors;
6666 :
6667 : // SUBROUTINE PARAMETER DEFINITIONS:
6668 796 : static Array1D_string const cModuleObjects(4, {"Shading:Overhang", "Shading:Overhang:Projection", "Shading:Fin", "Shading:Fin:Projection"});
6669 :
6670 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
6671 : int Item;
6672 : int ItemsToGet;
6673 : int Loop;
6674 : int NumAlphas;
6675 : int NumNumbers;
6676 : int IOStat; // IO Status when calling get input subroutine
6677 : int Found; // For matching base surfaces
6678 : Real64 Depth;
6679 : Real64 Length;
6680 : Real64 Xp;
6681 : Real64 Yp;
6682 : Real64 Zp;
6683 : Real64 XLLC;
6684 : Real64 YLLC;
6685 : int BaseSurfNum;
6686 : Real64 TiltAngle;
6687 : bool MakeFin;
6688 :
6689 805 : if ((TotOverhangs + TotOverhangsProjection + TotFins + TotFinsProjection) > 0 &&
6690 9 : state.dataHeatBal->SolarDistribution == DataHeatBalance::Shadowing::Minimal) {
6691 0 : ShowWarningError(state, "Shading effects of Fins and Overhangs are ignored when Solar Distribution = MinimalShadowing");
6692 : }
6693 796 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
6694 3980 : for (Item = 1; Item <= 4; ++Item) {
6695 :
6696 3184 : cCurrentModuleObject = cModuleObjects(Item);
6697 3184 : if (Item == 1) {
6698 796 : ItemsToGet = TotOverhangs;
6699 2388 : } else if (Item == 2) {
6700 796 : ItemsToGet = TotOverhangsProjection;
6701 1592 : } else if (Item == 3) {
6702 796 : ItemsToGet = TotFins;
6703 : } else { // ! (Item == 4) THEN
6704 796 : ItemsToGet = TotFinsProjection;
6705 : }
6706 :
6707 3219 : for (Loop = 1; Loop <= ItemsToGet; ++Loop) {
6708 70 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
6709 : cCurrentModuleObject,
6710 : Loop,
6711 35 : state.dataIPShortCut->cAlphaArgs,
6712 : NumAlphas,
6713 35 : state.dataIPShortCut->rNumericArgs,
6714 : NumNumbers,
6715 : IOStat,
6716 35 : state.dataIPShortCut->lNumericFieldBlanks,
6717 35 : state.dataIPShortCut->lAlphaFieldBlanks,
6718 35 : state.dataIPShortCut->cAlphaFieldNames,
6719 35 : state.dataIPShortCut->cNumericFieldNames);
6720 :
6721 70 : if (GlobalNames::VerifyUniqueInterObjectName(state,
6722 35 : state.dataSurfaceGeometry->UniqueSurfaceNames,
6723 35 : state.dataIPShortCut->cAlphaArgs(1),
6724 : cCurrentModuleObject,
6725 35 : state.dataIPShortCut->cAlphaFieldNames(1),
6726 : ErrorsFound)) {
6727 0 : continue;
6728 : }
6729 :
6730 35 : ++SurfNum;
6731 35 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name = state.dataIPShortCut->cAlphaArgs(1); // Set the Surface Name in the Derived Type
6732 35 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class = SurfaceClass::Shading;
6733 35 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).HeatTransSurf = false;
6734 : // this object references a window or door....
6735 : Found =
6736 35 : Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(2), state.dataSurfaceGeometry->SurfaceTmp, state.dataSurface->TotSurfaces);
6737 35 : if (Found > 0) {
6738 35 : BaseSurfNum = state.dataSurfaceGeometry->SurfaceTmp(Found).BaseSurf;
6739 35 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).BaseSurfName = state.dataSurfaceGeometry->SurfaceTmp(Found).BaseSurfName;
6740 35 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCond;
6741 35 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtSolar = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtSolar;
6742 35 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtWind = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtWind;
6743 35 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Zone =
6744 35 : state.dataSurfaceGeometry->SurfaceTmp(Found).Zone; // Necessary to do relative coordinates in GetVertices below
6745 35 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ZoneName =
6746 70 : state.dataSurfaceGeometry->SurfaceTmp(Found).ZoneName; // Necessary to have surface drawn in OutputReports
6747 : } else {
6748 0 : ShowSevereError(state,
6749 0 : format("{}=\"{}\", invalid {}=\"{}",
6750 : cCurrentModuleObject,
6751 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
6752 0 : state.dataIPShortCut->cAlphaFieldNames(2),
6753 0 : state.dataIPShortCut->cAlphaArgs(2)));
6754 0 : ErrorsFound = true;
6755 0 : continue;
6756 : }
6757 35 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond == UnenteredAdjacentZoneSurface) {
6758 0 : ShowSevereError(state,
6759 0 : format("{}=\"{}\", invalid {}=\"{}",
6760 : cCurrentModuleObject,
6761 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
6762 0 : state.dataIPShortCut->cAlphaFieldNames(2),
6763 0 : state.dataIPShortCut->cAlphaArgs(2)));
6764 0 : ShowContinueError(state, "...trying to attach a shading device to an interzone surface.");
6765 0 : ErrorsFound = true;
6766 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond =
6767 : ExternalEnvironment; // reset so program won't crash during "add surfaces"
6768 : }
6769 35 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond == UnreconciledZoneSurface) {
6770 0 : ShowSevereError(state,
6771 0 : format("{}=\"{}\", invalid {}=\"{}",
6772 : cCurrentModuleObject,
6773 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
6774 0 : state.dataIPShortCut->cAlphaFieldNames(2),
6775 0 : state.dataIPShortCut->cAlphaArgs(2)));
6776 0 : ShowContinueError(state, "...trying to attach a shading device to an interior surface.");
6777 0 : ErrorsFound = true;
6778 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond =
6779 : ExternalEnvironment; // reset so program won't crash during "add surfaces"
6780 : }
6781 :
6782 35 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).SchedShadowSurfIndex = 0;
6783 :
6784 : //===== Overhang =====
6785 :
6786 35 : if (Item < 3) {
6787 : // Found is the surface window or door.
6788 : // N1, \field Height above Window or Door
6789 : // \units m
6790 : // N2, \field Tilt Angle from Window/Door
6791 : // \units deg
6792 : // \default 90
6793 : // \minimum 0
6794 : // \maximum 180
6795 : // N3, \field Left extension from Window/Door Width
6796 : // \units m
6797 : // N4, \field Right extension from Window/Door Width
6798 : // \note N3 + N4 + Window/Door Width is Overhang Length
6799 : // \units m
6800 : // N5; \field Depth
6801 : // \units m
6802 : // for projection option:
6803 : // N5; \field Depth as Fraction of Window/Door Height
6804 : // \units m
6805 26 : Length = state.dataIPShortCut->rNumericArgs(3) + state.dataIPShortCut->rNumericArgs(4) +
6806 26 : state.dataSurfaceGeometry->SurfaceTmp(Found).Width;
6807 26 : if (Item == 1) {
6808 25 : Depth = state.dataIPShortCut->rNumericArgs(5);
6809 1 : } else if (Item == 2) {
6810 1 : Depth = state.dataIPShortCut->rNumericArgs(5) * state.dataSurfaceGeometry->SurfaceTmp(Found).Height;
6811 : }
6812 :
6813 26 : if (Length * Depth <= 0.0) {
6814 0 : ShowSevereError(state,
6815 0 : format("{}=\"{}\", illegal surface area=[{:.2R}]. Surface will NOT be entered.",
6816 : cCurrentModuleObject,
6817 0 : state.dataIPShortCut->cAlphaArgs(1),
6818 0 : Length * Depth));
6819 0 : continue;
6820 : }
6821 :
6822 26 : TiltAngle = state.dataSurfaceGeometry->SurfaceTmp(Found).Tilt + state.dataIPShortCut->rNumericArgs(2);
6823 26 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Tilt = TiltAngle;
6824 26 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).convOrientation =
6825 26 : Convect::GetSurfConvOrientation(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Tilt);
6826 26 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Azimuth = state.dataSurfaceGeometry->SurfaceTmp(Found).Azimuth;
6827 :
6828 : // Make it relative to surface origin.....
6829 26 : Xp = state.dataSurfaceGeometry->SurfaceTmp(Found).Vertex(2).x - state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).x;
6830 26 : Yp = state.dataSurfaceGeometry->SurfaceTmp(Found).Vertex(2).y - state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).y;
6831 26 : Zp = state.dataSurfaceGeometry->SurfaceTmp(Found).Vertex(2).z - state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).z;
6832 :
6833 26 : XLLC = -Xp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosAzim +
6834 26 : Yp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).SinAzim;
6835 :
6836 26 : YLLC =
6837 26 : -Xp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).SinAzim *
6838 26 : state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosTilt -
6839 26 : Yp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosAzim * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosTilt +
6840 26 : Zp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).SinTilt;
6841 :
6842 26 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides = 4;
6843 26 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex.allocate(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides);
6844 :
6845 52 : MakeRelativeRectangularVertices(state,
6846 : BaseSurfNum,
6847 : SurfNum,
6848 26 : XLLC - state.dataIPShortCut->rNumericArgs(3),
6849 26 : YLLC + state.dataSurfaceGeometry->SurfaceTmp(Found).Height +
6850 26 : state.dataIPShortCut->rNumericArgs(1),
6851 : Length,
6852 : Depth);
6853 :
6854 : // Reset surface to be "detached"
6855 : // SurfaceTmp(SurfNum)%BaseSurfName=' '
6856 : // SurfaceTmp(SurfNum)%ZoneName=' '
6857 :
6858 26 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).BaseSurf = 0;
6859 26 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Zone = 0;
6860 :
6861 : // and mirror
6862 26 : if (state.dataReportFlag->MakeMirroredAttachedShading) {
6863 26 : MakeMirrorSurface(state, SurfNum);
6864 : }
6865 :
6866 : } else { // Fins
6867 :
6868 : //===== Fins =====
6869 :
6870 : //===== Left Fin =====
6871 :
6872 : // N1, \field Left Extension from Window/Door
6873 : // \units m
6874 : // N2, \field Left Distance Above Top of Window
6875 : // \units m
6876 : // N3, \field Left Distance Below Bottom of Window
6877 : // \units m
6878 : // \note N2 + N3 + height of Window/Door is height of Fin
6879 : // N4, \field Left Tilt Angle from Window/Door
6880 : // \units deg
6881 : // \default 90
6882 : // \minimum 0
6883 : // \maximum 180
6884 : // N5, \field Left Depth
6885 : // \units m
6886 : // for projection option:
6887 : // N5, \field Left Depth as Fraction of Window/Door Width
6888 : // \units m
6889 9 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name + " Left";
6890 9 : Length = state.dataIPShortCut->rNumericArgs(2) + state.dataIPShortCut->rNumericArgs(3) +
6891 9 : state.dataSurfaceGeometry->SurfaceTmp(Found).Height;
6892 9 : if (Item == 3) {
6893 8 : Depth = state.dataIPShortCut->rNumericArgs(5);
6894 1 : } else if (Item == 4) {
6895 1 : Depth = state.dataIPShortCut->rNumericArgs(5) * state.dataSurfaceGeometry->SurfaceTmp(Found).Width;
6896 : }
6897 :
6898 9 : MakeFin = true;
6899 9 : if (Length * Depth <= 0.0) {
6900 0 : ShowWarningError(state,
6901 0 : format("{}=Left Fin of \"{}\", illegal surface area=[{:.2R}]. Surface will NOT be entered.",
6902 : cCurrentModuleObject,
6903 0 : state.dataIPShortCut->cAlphaArgs(1),
6904 0 : Length * Depth));
6905 0 : MakeFin = false;
6906 : }
6907 :
6908 9 : if (MakeFin) {
6909 9 : TiltAngle = state.dataSurfaceGeometry->SurfaceTmp(Found).Tilt;
6910 9 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Tilt = TiltAngle;
6911 9 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).convOrientation =
6912 9 : Convect::GetSurfConvOrientation(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Tilt);
6913 9 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Azimuth =
6914 9 : state.dataSurfaceGeometry->SurfaceTmp(Found).Azimuth - (180.0 - state.dataIPShortCut->rNumericArgs(4));
6915 :
6916 : // Make it relative to surface origin.....
6917 :
6918 9 : Xp =
6919 9 : state.dataSurfaceGeometry->SurfaceTmp(Found).Vertex(2).x - state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).x;
6920 9 : Yp =
6921 9 : state.dataSurfaceGeometry->SurfaceTmp(Found).Vertex(2).y - state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).y;
6922 9 : Zp =
6923 9 : state.dataSurfaceGeometry->SurfaceTmp(Found).Vertex(2).z - state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).z;
6924 :
6925 9 : XLLC = -Xp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosAzim +
6926 9 : Yp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).SinAzim;
6927 :
6928 9 : YLLC = -Xp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).SinAzim *
6929 9 : state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosTilt -
6930 9 : Yp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosAzim *
6931 9 : state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosTilt +
6932 9 : Zp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).SinTilt;
6933 :
6934 9 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).CosAzim =
6935 9 : std::cos(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Azimuth * Constant::DegToRadians);
6936 9 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).SinAzim =
6937 9 : std::sin(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Azimuth * Constant::DegToRadians);
6938 9 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).CosTilt =
6939 9 : std::cos(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Tilt * Constant::DegToRadians);
6940 9 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).SinTilt =
6941 9 : std::sin(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Tilt * Constant::DegToRadians);
6942 :
6943 9 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides = 4;
6944 9 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex.allocate(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides);
6945 :
6946 27 : MakeRelativeRectangularVertices(state,
6947 : BaseSurfNum,
6948 : SurfNum,
6949 9 : XLLC - state.dataIPShortCut->rNumericArgs(1),
6950 9 : YLLC - state.dataIPShortCut->rNumericArgs(3),
6951 : -Depth,
6952 : Length);
6953 :
6954 : // Reset surface to be "detached"
6955 : // SurfaceTmp(SurfNum)%BaseSurfName=' '
6956 : // SurfaceTmp(SurfNum)%ZoneName=' '
6957 :
6958 9 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).BaseSurf = 0;
6959 9 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Zone = 0;
6960 :
6961 : // and mirror
6962 9 : if (state.dataReportFlag->MakeMirroredAttachedShading) {
6963 9 : MakeMirrorSurface(state, SurfNum);
6964 : }
6965 : } else {
6966 0 : --SurfNum;
6967 : }
6968 :
6969 : //===== Right Fin =====
6970 :
6971 : // N6, \field Right Extension from Window/Door
6972 : // \units m
6973 : // N7, \field Right Distance Above Top of Window
6974 : // \units m
6975 : // N8, \field Right Distance Below Bottom of Window
6976 : // \note N7 + N8 + height of Window/Door is height of Fin
6977 : // \units m
6978 : // N9, \field Right Tilt Angle from Window/Door
6979 : // \units deg
6980 : // \default 90
6981 : // \minimum 0
6982 : // \maximum 180
6983 : // N10; \field Right Depth
6984 : // \units m
6985 : // for projection option:
6986 : // N10; \field Right Depth as Fraction of Window/Door Width
6987 : // \units m
6988 :
6989 9 : ++SurfNum;
6990 9 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name =
6991 18 : state.dataIPShortCut->cAlphaArgs(1) + " Right"; // Set the Surface Name in the Derived Type
6992 9 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class = SurfaceClass::Shading;
6993 9 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).HeatTransSurf = false;
6994 9 : BaseSurfNum = state.dataSurfaceGeometry->SurfaceTmp(Found).BaseSurf;
6995 9 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).BaseSurfName = state.dataSurfaceGeometry->SurfaceTmp(Found).BaseSurfName;
6996 9 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCond;
6997 9 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtSolar = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtSolar;
6998 9 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtWind = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtWind;
6999 9 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Zone =
7000 9 : state.dataSurfaceGeometry->SurfaceTmp(Found).Zone; // Necessary to do relative coordinates in GetVertices below
7001 9 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ZoneName =
7002 18 : state.dataSurfaceGeometry->SurfaceTmp(Found).ZoneName; // Necessary to have surface drawn in OutputReports
7003 :
7004 9 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).SchedShadowSurfIndex = 0;
7005 9 : Length = state.dataIPShortCut->rNumericArgs(7) + state.dataIPShortCut->rNumericArgs(8) +
7006 9 : state.dataSurfaceGeometry->SurfaceTmp(Found).Height;
7007 9 : if (Item == 3) {
7008 8 : Depth = state.dataIPShortCut->rNumericArgs(10);
7009 1 : } else if (Item == 4) {
7010 1 : Depth = state.dataIPShortCut->rNumericArgs(10) * state.dataSurfaceGeometry->SurfaceTmp(Found).Width;
7011 : }
7012 :
7013 9 : MakeFin = true;
7014 9 : if (Length * Depth <= 0.0) {
7015 0 : ShowWarningError(state,
7016 0 : format("{}=Right Fin of \"{}\", illegal surface area=[{:.2R}]. Surface will NOT be entered.",
7017 : cCurrentModuleObject,
7018 0 : state.dataIPShortCut->cAlphaArgs(1),
7019 0 : Length * Depth));
7020 0 : MakeFin = false;
7021 : }
7022 :
7023 9 : if (MakeFin) {
7024 : // Make it relative to surface origin.....
7025 :
7026 9 : Xp =
7027 9 : state.dataSurfaceGeometry->SurfaceTmp(Found).Vertex(2).x - state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).x;
7028 9 : Yp =
7029 9 : state.dataSurfaceGeometry->SurfaceTmp(Found).Vertex(2).y - state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).y;
7030 9 : Zp =
7031 9 : state.dataSurfaceGeometry->SurfaceTmp(Found).Vertex(2).z - state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).z;
7032 :
7033 9 : XLLC = -Xp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosAzim +
7034 9 : Yp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).SinAzim;
7035 :
7036 9 : YLLC = -Xp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).SinAzim *
7037 9 : state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosTilt -
7038 9 : Yp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosAzim *
7039 9 : state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosTilt +
7040 9 : Zp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).SinTilt;
7041 :
7042 9 : TiltAngle = state.dataSurfaceGeometry->SurfaceTmp(Found).Tilt;
7043 9 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Tilt = TiltAngle;
7044 9 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).convOrientation =
7045 9 : Convect::GetSurfConvOrientation(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Tilt);
7046 9 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Azimuth =
7047 9 : state.dataSurfaceGeometry->SurfaceTmp(Found).Azimuth - (180.0 - state.dataIPShortCut->rNumericArgs(9));
7048 9 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).CosAzim =
7049 9 : std::cos(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Azimuth * Constant::DegToRadians);
7050 9 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).SinAzim =
7051 9 : std::sin(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Azimuth * Constant::DegToRadians);
7052 9 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).CosTilt =
7053 9 : std::cos(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Tilt * Constant::DegToRadians);
7054 9 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).SinTilt =
7055 9 : std::sin(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Tilt * Constant::DegToRadians);
7056 :
7057 9 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides = 4;
7058 9 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex.allocate(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides);
7059 :
7060 27 : MakeRelativeRectangularVertices(state,
7061 : BaseSurfNum,
7062 : SurfNum,
7063 9 : XLLC + state.dataSurfaceGeometry->SurfaceTmp(Found).Width +
7064 9 : state.dataIPShortCut->rNumericArgs(6),
7065 9 : YLLC - state.dataIPShortCut->rNumericArgs(8),
7066 : -Depth,
7067 : Length);
7068 :
7069 : // Reset surface to be "detached"
7070 : // SurfaceTmp(SurfNum)%BaseSurfName=' '
7071 : // SurfaceTmp(SurfNum)%ZoneName=' '
7072 :
7073 9 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).BaseSurf = 0;
7074 9 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Zone = 0;
7075 :
7076 : // and mirror
7077 9 : if (state.dataReportFlag->MakeMirroredAttachedShading) {
7078 9 : MakeMirrorSurface(state, SurfNum);
7079 : }
7080 : } else {
7081 0 : --SurfNum;
7082 : }
7083 : }
7084 : }
7085 : }
7086 796 : }
7087 :
7088 796 : void GetIntMassSurfaceData(EnergyPlusData &state,
7089 : bool &ErrorsFound, // Error flag indicator (true if errors found)
7090 : int &SurfNum // Count of Current SurfaceNumber
7091 : )
7092 : {
7093 :
7094 : // SUBROUTINE INFORMATION:
7095 : // AUTHOR Linda Lawrie
7096 : // DATE WRITTEN May 2000
7097 : // MODIFIED na
7098 : // RE-ENGINEERED na
7099 :
7100 : // PURPOSE OF THIS SUBROUTINE:
7101 : // This subroutine gets the Internal Surface Data,
7102 : // checks it for errors, etc.
7103 :
7104 : // METHODOLOGY EMPLOYED:
7105 : // na
7106 :
7107 : // REFERENCES:
7108 : // Internal Mass Surface Definition
7109 : // Surface:HeatTransfer:InternalMass,
7110 : // \note used to describe internal zone surface area that does not need to be part of geometric representation
7111 : // A1 , \field User Supplied Surface Name
7112 : // \type alpha
7113 : // \reference SurfaceNames
7114 : // A2 , \field Construction Name of the Surface
7115 : // \note To be matched with a construction in this input file
7116 : // \type object-list
7117 : // \object-list ConstructionNames
7118 : // A3 , \field Interior Environment
7119 : // \note Zone the surface is a part of
7120 : // \type object-list
7121 : // \object-list ZoneNames
7122 : // N1, \field View factor to Person (to people?)
7123 : // \type real
7124 : // \note from the interior of the surface
7125 : // N2 ; \field Surface area
7126 : // \units m2
7127 :
7128 : // Using/Aliasing
7129 : using namespace Vectors;
7130 : using General::CheckCreatedZoneItemName;
7131 :
7132 : // SUBROUTINE PARAMETER DEFINITIONS:
7133 : static constexpr std::string_view RoutineName("GetIntMassSurfaceData: ");
7134 :
7135 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
7136 : int IOStat; // IO Status when calling get input subroutine
7137 : int SurfaceNumAlpha; // Number of material alpha names being passed
7138 : int SurfaceNumArg; // Number of material properties being passed
7139 : int ZoneNum; // index to a zone
7140 796 : int NumIntMassSurfaces(0); // total count of internal mass surfaces
7141 : bool errFlag; // local error flag
7142 796 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
7143 796 : cCurrentModuleObject = "InternalMass";
7144 796 : int TotIntMass = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
7145 796 : if (TotIntMass == 0) return;
7146 :
7147 170 : state.dataSurface->IntMassObjects.allocate(TotIntMass);
7148 :
7149 : // scan for use of Zone lists in InternalMass objects
7150 170 : errFlag = false;
7151 170 : NumIntMassSurfaces = 0;
7152 2555 : for (int Item = 1; Item <= TotIntMass; ++Item) {
7153 4770 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
7154 : cCurrentModuleObject,
7155 : Item,
7156 2385 : state.dataIPShortCut->cAlphaArgs,
7157 : SurfaceNumAlpha,
7158 2385 : state.dataIPShortCut->rNumericArgs,
7159 : SurfaceNumArg,
7160 : IOStat,
7161 2385 : state.dataIPShortCut->lNumericFieldBlanks,
7162 2385 : state.dataIPShortCut->lAlphaFieldBlanks,
7163 2385 : state.dataIPShortCut->cAlphaFieldNames,
7164 2385 : state.dataIPShortCut->cNumericFieldNames);
7165 :
7166 4770 : if (GlobalNames::VerifyUniqueInterObjectName(state,
7167 2385 : state.dataSurfaceGeometry->UniqueSurfaceNames,
7168 2385 : state.dataIPShortCut->cAlphaArgs(1),
7169 : cCurrentModuleObject,
7170 2385 : state.dataIPShortCut->cAlphaFieldNames(1),
7171 : ErrorsFound)) {
7172 0 : continue;
7173 : }
7174 :
7175 2385 : state.dataSurface->IntMassObjects(Item).Name = state.dataIPShortCut->cAlphaArgs(1);
7176 2385 : state.dataSurface->IntMassObjects(Item).GrossArea = state.dataIPShortCut->rNumericArgs(1);
7177 2385 : state.dataSurface->IntMassObjects(Item).Construction =
7178 2385 : Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(2), state.dataConstruction->Construct, state.dataHeatBal->TotConstructs);
7179 2385 : state.dataSurface->IntMassObjects(Item).ZoneOrZoneListName = state.dataIPShortCut->cAlphaArgs(3);
7180 2385 : int Item1 = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(3), state.dataHeatBal->Zone, state.dataGlobal->NumOfZones);
7181 2385 : int ZLItem = 0;
7182 2385 : if (Item1 == 0 && state.dataHeatBal->NumOfZoneLists > 0)
7183 5 : ZLItem = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(3), state.dataHeatBal->ZoneList);
7184 2385 : if (Item1 > 0) {
7185 2380 : if (state.dataIPShortCut->lAlphaFieldBlanks(4)) {
7186 2380 : ++NumIntMassSurfaces;
7187 : }
7188 2380 : state.dataSurface->IntMassObjects(Item).NumOfZones = 1;
7189 2380 : state.dataSurface->IntMassObjects(Item).ZoneListActive = false;
7190 2380 : state.dataSurface->IntMassObjects(Item).ZoneOrZoneListPtr = Item1;
7191 5 : } else if (ZLItem > 0) {
7192 2 : NumIntMassSurfaces += state.dataHeatBal->ZoneList(ZLItem).NumOfZones;
7193 2 : state.dataSurface->IntMassObjects(Item).NumOfZones = state.dataHeatBal->ZoneList(ZLItem).NumOfZones;
7194 2 : state.dataSurface->IntMassObjects(Item).ZoneListActive = true;
7195 2 : state.dataSurface->IntMassObjects(Item).ZoneOrZoneListPtr = ZLItem;
7196 3 : } else if (state.dataIPShortCut->lAlphaFieldBlanks(4)) {
7197 : // If Space or SpaceList Name is blank, then throw error.
7198 0 : ShowSevereError(state,
7199 0 : format("{}=\"{}\" invalid {}=\"{}\" not found.",
7200 : cCurrentModuleObject,
7201 0 : state.dataIPShortCut->cAlphaArgs(1),
7202 0 : state.dataIPShortCut->cAlphaFieldNames(3),
7203 0 : state.dataIPShortCut->cAlphaArgs(3)));
7204 0 : ++SurfNum;
7205 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class = SurfaceClass::Invalid;
7206 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ZoneName = "Unknown Zone";
7207 0 : ErrorsFound = true;
7208 0 : errFlag = true;
7209 : }
7210 :
7211 2385 : if (!state.dataIPShortCut->lAlphaFieldBlanks(4)) {
7212 3 : state.dataSurface->IntMassObjects(Item).spaceOrSpaceListName = state.dataIPShortCut->cAlphaArgs(4);
7213 3 : int Item1 = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(4), state.dataHeatBal->space);
7214 3 : int SLItem = 0;
7215 3 : if (Item1 == 0 && int(state.dataHeatBal->spaceList.size()) > 0)
7216 1 : SLItem = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(4), state.dataHeatBal->spaceList);
7217 3 : if (Item1 > 0) {
7218 2 : ++NumIntMassSurfaces;
7219 2 : state.dataSurface->IntMassObjects(Item).numOfSpaces = 1;
7220 2 : state.dataSurface->IntMassObjects(Item).spaceListActive = false;
7221 2 : state.dataSurface->IntMassObjects(Item).spaceOrSpaceListPtr = Item1;
7222 2 : state.dataSurface->IntMassObjects(Item).NumOfZones = 1;
7223 2 : state.dataSurface->IntMassObjects(Item).ZoneListActive = false;
7224 2 : state.dataSurface->IntMassObjects(Item).ZoneOrZoneListPtr = state.dataHeatBal->space(Item1).zoneNum;
7225 1 : } else if (SLItem > 0) {
7226 1 : int numOfSpaces = int(state.dataHeatBal->spaceList(SLItem).numListSpaces);
7227 1 : NumIntMassSurfaces += numOfSpaces;
7228 1 : state.dataSurface->IntMassObjects(Item).numOfSpaces = numOfSpaces;
7229 1 : state.dataSurface->IntMassObjects(Item).spaceListActive = true;
7230 1 : state.dataSurface->IntMassObjects(Item).spaceOrSpaceListPtr = SLItem;
7231 : } else {
7232 0 : ShowSevereError(state,
7233 0 : format("{}=\"{}\" invalid {}=\"{}\" not found.",
7234 : cCurrentModuleObject,
7235 0 : state.dataIPShortCut->cAlphaArgs(1),
7236 0 : state.dataIPShortCut->cAlphaFieldNames(4),
7237 0 : state.dataIPShortCut->cAlphaArgs(4)));
7238 0 : ++SurfNum;
7239 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class = SurfaceClass::Invalid;
7240 0 : ErrorsFound = true;
7241 0 : errFlag = true;
7242 : }
7243 : }
7244 :
7245 2385 : if (errFlag) {
7246 0 : ShowSevereError(state, format("{}Errors with invalid names in {} objects.", RoutineName, cCurrentModuleObject));
7247 0 : ShowContinueError(state, "...These will not be read in. Other errors may occur.");
7248 0 : NumIntMassSurfaces = 0;
7249 : }
7250 :
7251 2385 : if (state.dataSurface->IntMassObjects(Item).Construction == 0) {
7252 0 : ErrorsFound = true;
7253 0 : ShowSevereError(state,
7254 0 : format("{}=\"{}\", {} not found={}",
7255 : cCurrentModuleObject,
7256 0 : state.dataIPShortCut->cAlphaArgs(1),
7257 0 : state.dataIPShortCut->cAlphaFieldNames(2),
7258 0 : state.dataIPShortCut->cAlphaArgs(2)));
7259 2385 : } else if (state.dataConstruction->Construct(state.dataSurface->IntMassObjects(Item).Construction).TypeIsWindow) {
7260 0 : ErrorsFound = true;
7261 0 : ShowSevereError(state,
7262 0 : format("{}=\"{}\", invalid {}=\"{}\" - has Window materials.",
7263 : cCurrentModuleObject,
7264 0 : state.dataIPShortCut->cAlphaArgs(1),
7265 0 : state.dataIPShortCut->cAlphaFieldNames(2),
7266 0 : state.dataIPShortCut->cAlphaArgs(2)));
7267 : } else {
7268 2385 : state.dataConstruction->Construct(state.dataSurface->IntMassObjects(Item).Construction).IsUsed = true;
7269 : }
7270 : }
7271 :
7272 170 : if (NumIntMassSurfaces > 0) {
7273 170 : int spaceNum = 0;
7274 2555 : for (int Loop = 1; Loop <= TotIntMass; ++Loop) {
7275 2385 : int numberOfZonesOrSpaces = 1;
7276 2385 : if (state.dataSurface->IntMassObjects(Loop).ZoneListActive) {
7277 2 : numberOfZonesOrSpaces = state.dataSurface->IntMassObjects(Loop).NumOfZones;
7278 2383 : } else if (state.dataSurface->IntMassObjects(Loop).spaceListActive) {
7279 1 : numberOfZonesOrSpaces = state.dataSurface->IntMassObjects(Loop).numOfSpaces;
7280 : }
7281 :
7282 4783 : for (int Item1 = 1; Item1 <= numberOfZonesOrSpaces; ++Item1) {
7283 :
7284 2398 : ++SurfNum;
7285 :
7286 2398 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction = state.dataSurface->IntMassObjects(Loop).Construction;
7287 2398 : if (!state.dataSurface->IntMassObjects(Loop).ZoneListActive && !state.dataSurface->IntMassObjects(Loop).spaceListActive) {
7288 2382 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Zone = state.dataSurface->IntMassObjects(Loop).ZoneOrZoneListPtr;
7289 2382 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).spaceNum = state.dataSurface->IntMassObjects(Loop).spaceOrSpaceListPtr;
7290 2382 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name = state.dataSurface->IntMassObjects(Loop).Name;
7291 2382 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class = SurfaceClass::IntMass;
7292 2382 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ZoneName = state.dataSurface->IntMassObjects(Loop).ZoneOrZoneListName;
7293 2382 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).HeatTransSurf = true;
7294 : } else {
7295 16 : if (state.dataSurface->IntMassObjects(Loop).ZoneListActive) {
7296 24 : CheckCreatedZoneItemName(
7297 : state,
7298 : RoutineName,
7299 : cCurrentModuleObject,
7300 : state.dataHeatBal
7301 8 : ->Zone(state.dataHeatBal->ZoneList(state.dataSurface->IntMassObjects(Loop).ZoneOrZoneListPtr).Zone(Item1))
7302 8 : .Name,
7303 8 : state.dataHeatBal->ZoneList(state.dataSurface->IntMassObjects(Loop).ZoneOrZoneListPtr).MaxZoneNameLength,
7304 8 : state.dataSurface->IntMassObjects(Loop).Name,
7305 8 : state.dataSurfaceGeometry->SurfaceTmp,
7306 8 : SurfNum - 1,
7307 8 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
7308 : errFlag);
7309 :
7310 8 : ZoneNum = state.dataHeatBal->ZoneList(state.dataSurface->IntMassObjects(Loop).ZoneOrZoneListPtr).Zone(Item1);
7311 8 : } else if (state.dataSurface->IntMassObjects(Loop).spaceListActive) {
7312 8 : spaceNum = state.dataHeatBal->spaceList(state.dataSurface->IntMassObjects(Loop).spaceOrSpaceListPtr).spaces(Item1);
7313 8 : ZoneNum = state.dataHeatBal->space(spaceNum).zoneNum;
7314 8 : const std::string spaceName = state.dataHeatBal->space(spaceNum).Name;
7315 8 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name = spaceName + ' ' + state.dataSurface->IntMassObjects(Loop).Name;
7316 8 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).spaceNum = spaceNum;
7317 8 : }
7318 16 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Zone = ZoneNum;
7319 16 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class = SurfaceClass::IntMass;
7320 16 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ZoneName = state.dataHeatBal->Zone(ZoneNum).Name;
7321 16 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).HeatTransSurf = true;
7322 16 : if (errFlag) ErrorsFound = true;
7323 : }
7324 :
7325 2398 : if (state.dataSurface->IntMassObjects(Loop).Construction > 0) {
7326 2398 : if (state.dataConstruction->Construct(state.dataSurface->IntMassObjects(Loop).Construction).IsUsed) {
7327 2398 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ConstructionStoredInputValue =
7328 2398 : state.dataSurface->IntMassObjects(Loop).Construction;
7329 : }
7330 : }
7331 2398 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).GrossArea = state.dataSurface->IntMassObjects(Loop).GrossArea;
7332 2398 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Area = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).GrossArea;
7333 2398 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).NetAreaShadowCalc = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Area;
7334 2398 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Width = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Area;
7335 2398 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Height = 1.0;
7336 2398 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Tilt = 90.0;
7337 2398 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).convOrientation =
7338 2398 : Convect::GetSurfConvOrientation(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Tilt);
7339 2398 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).CosTilt = 0.0; // Tuned Was std::cos( 90.0 * DegToRadians )
7340 2398 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).SinTilt = 1.0; // Tuned Was std::sin( 90.0 * DegToRadians )
7341 2398 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Azimuth = 0.0;
7342 2398 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).CosAzim = 1.0; // Tuned Was std::cos( 0.0 )
7343 2398 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).SinAzim = 0.0; // Tuned Was std::sin( 0.0 )
7344 : // Outward normal unit vector (pointing away from room)
7345 2398 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).OutNormVec = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).lcsz;
7346 2398 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ViewFactorSky = 0.5;
7347 2398 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtSolar = false;
7348 2398 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtWind = false;
7349 2398 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).BaseSurf = SurfNum;
7350 2398 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).BaseSurfName = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name;
7351 2398 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCondName = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name;
7352 2398 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond = UnreconciledZoneSurface;
7353 : }
7354 : }
7355 : }
7356 : }
7357 :
7358 796 : int GetNumIntMassSurfaces(EnergyPlusData &state) // Number of Internal Mass Surfaces to obtain
7359 :
7360 : {
7361 : // Counts internal mass surfaces applied to zones and zone lists
7362 :
7363 : // Using/Aliasing
7364 :
7365 : int IOStat; // IO Status when calling get input subroutine
7366 : int SurfaceNumAlpha; // Number of material alpha names being passed
7367 : int SurfaceNumArg; // Number of material properties being passed
7368 : int NumIntMassSurf; // total count of internal mass surfaces
7369 :
7370 796 : NumIntMassSurf = 0;
7371 796 : int TotIntMass = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "InternalMass");
7372 :
7373 796 : if (TotIntMass == 0) return NumIntMassSurf;
7374 170 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
7375 170 : cCurrentModuleObject = "InternalMass";
7376 : // scan for zones and zone lists in InternalMass objects
7377 2555 : for (int Item = 1; Item <= TotIntMass; ++Item) {
7378 4770 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
7379 : cCurrentModuleObject,
7380 : Item,
7381 2385 : state.dataIPShortCut->cAlphaArgs,
7382 : SurfaceNumAlpha,
7383 2385 : state.dataIPShortCut->rNumericArgs,
7384 : SurfaceNumArg,
7385 : IOStat,
7386 2385 : state.dataIPShortCut->lNumericFieldBlanks,
7387 2385 : state.dataIPShortCut->lAlphaFieldBlanks,
7388 2385 : state.dataIPShortCut->cAlphaFieldNames,
7389 2385 : state.dataIPShortCut->cNumericFieldNames);
7390 :
7391 2385 : int Item1 = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(3), state.dataHeatBal->Zone, state.dataGlobal->NumOfZones);
7392 2385 : int ZLItem = 0;
7393 2385 : if (Item1 == 0 && state.dataHeatBal->NumOfZoneLists > 0)
7394 5 : ZLItem = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(3), state.dataHeatBal->ZoneList);
7395 2385 : if (Item1 > 0) {
7396 2380 : if (state.dataIPShortCut->lAlphaFieldBlanks(4)) {
7397 2380 : ++NumIntMassSurf;
7398 : }
7399 5 : } else if (ZLItem > 0) {
7400 2 : NumIntMassSurf += state.dataHeatBal->ZoneList(ZLItem).NumOfZones;
7401 : }
7402 :
7403 2385 : if (!state.dataIPShortCut->lAlphaFieldBlanks(4)) {
7404 3 : int Item1 = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(4), state.dataHeatBal->space);
7405 3 : int SLItem = 0;
7406 3 : if (Item1 == 0 && int(state.dataHeatBal->spaceList.size()) > 0)
7407 1 : SLItem = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(4), state.dataHeatBal->spaceList);
7408 3 : if (Item1 > 0) {
7409 2 : ++NumIntMassSurf;
7410 1 : } else if (SLItem > 0) {
7411 1 : int numOfSpaces = int(state.dataHeatBal->spaceList(SLItem).numListSpaces);
7412 1 : NumIntMassSurf += numOfSpaces;
7413 : }
7414 : }
7415 : }
7416 170 : NumIntMassSurf = max(NumIntMassSurf, TotIntMass);
7417 170 : return NumIntMassSurf;
7418 : }
7419 :
7420 9 : void GetShadingSurfReflectanceData(EnergyPlusData &state, bool &ErrorsFound) // If errors found in input
7421 : {
7422 :
7423 : // SUBROUTINE INFORMATION:
7424 : // AUTHOR Fred Winkelmann
7425 : // DATE WRITTEN Sept 2003
7426 : // MODIFIED na
7427 : // RE-ENGINEERED na
7428 :
7429 : // PURPOSE OF THIS SUBROUTINE:
7430 : // Gets data for a Shading Surface Reflectance object. This is only called when the
7431 : // Solar Distribution is to be calculated for reflectances.
7432 :
7433 : // Using/Aliasing
7434 :
7435 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
7436 :
7437 : int IOStat; // IO Status when calling get input subroutine
7438 : int NumAlpha; // Number of alpha names being passed
7439 : int NumProp; // Number of properties being passed
7440 : int TotShadingSurfaceReflectance; // Total Shading Surface Refleftance statements
7441 : int Loop; // DO loop index
7442 : int SurfNum; // Surface number
7443 : int GlConstrNum; // Glazing construction number
7444 : bool WrongSurfaceType;
7445 :
7446 : // For shading surfaces, initialize value of reflectance values to default values. These values
7447 : // may be overridden below for shading surfaces with an associated Shading Surface Reflectance object.
7448 101 : for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
7449 92 : auto const &surf = state.dataSurface->Surface(SurfNum);
7450 92 : if (!(surf.Class == SurfaceClass::Shading || surf.Class == SurfaceClass::Detached_F || surf.Class == SurfaceClass::Detached_B ||
7451 86 : surf.Class == SurfaceClass::Overhang || surf.Class == SurfaceClass::Fin))
7452 86 : continue;
7453 6 : state.dataSurface->SurfShadowDiffuseSolRefl(SurfNum) = 0.2;
7454 6 : state.dataSurface->SurfShadowDiffuseVisRefl(SurfNum) = 0.2;
7455 6 : state.dataSurface->SurfShadowGlazingFrac(SurfNum) = 0.0;
7456 6 : state.dataSurface->SurfShadowGlazingConstruct(SurfNum) = 0;
7457 : }
7458 :
7459 : // Get the total number of Shading Surface Reflectance objects
7460 9 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
7461 9 : cCurrentModuleObject = "ShadingProperty:Reflectance";
7462 9 : TotShadingSurfaceReflectance = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
7463 : // IF(TotShadingSurfaceReflectance.EQ.0) RETURN
7464 :
7465 10 : for (Loop = 1; Loop <= TotShadingSurfaceReflectance; ++Loop) {
7466 :
7467 2 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
7468 : cCurrentModuleObject,
7469 : Loop,
7470 1 : state.dataIPShortCut->cAlphaArgs,
7471 : NumAlpha,
7472 1 : state.dataIPShortCut->rNumericArgs,
7473 : NumProp,
7474 : IOStat,
7475 1 : state.dataIPShortCut->lNumericFieldBlanks,
7476 1 : state.dataIPShortCut->lAlphaFieldBlanks,
7477 1 : state.dataIPShortCut->cAlphaFieldNames,
7478 1 : state.dataIPShortCut->cNumericFieldNames);
7479 1 : SurfNum = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(1), state.dataSurface->Surface, state.dataSurface->TotSurfaces);
7480 1 : if (SurfNum == 0) {
7481 0 : ShowWarningError(state, format("{}=\"{}\", invalid specification", cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
7482 0 : ShowContinueError(state,
7483 0 : format(".. not found {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(1), state.dataIPShortCut->cAlphaArgs(1)));
7484 : // ErrorsFound =.TRUE.
7485 0 : continue;
7486 : }
7487 :
7488 : // Check that associated surface is a shading surface
7489 1 : WrongSurfaceType = false;
7490 1 : if (SurfNum != 0) {
7491 1 : auto const &surf = state.dataSurface->Surface(SurfNum);
7492 1 : if (!(surf.Class == SurfaceClass::Shading || surf.Class == SurfaceClass::Detached_F || surf.Class == SurfaceClass::Detached_B ||
7493 0 : surf.Class == SurfaceClass::Overhang || surf.Class == SurfaceClass::Fin))
7494 0 : WrongSurfaceType = true;
7495 1 : if (WrongSurfaceType) {
7496 0 : ShowSevereError(
7497 : state,
7498 0 : format("GetShadingSurfReflectanceData: {}=\"{}\", surface is not a shading surface.", cCurrentModuleObject, surf.Name));
7499 0 : ErrorsFound = true;
7500 0 : continue;
7501 : }
7502 : }
7503 :
7504 : // If associated surface is a shading surface, set reflectance values
7505 1 : state.dataSurface->SurfShadowGlazingFrac(SurfNum) = state.dataIPShortCut->rNumericArgs(3);
7506 1 : state.dataSurface->SurfShadowDiffuseSolRefl(SurfNum) =
7507 1 : (1.0 - state.dataIPShortCut->rNumericArgs(3)) * state.dataIPShortCut->rNumericArgs(1);
7508 1 : state.dataSurface->SurfShadowDiffuseVisRefl(SurfNum) =
7509 1 : (1.0 - state.dataIPShortCut->rNumericArgs(3)) * state.dataIPShortCut->rNumericArgs(2);
7510 1 : if (state.dataIPShortCut->rNumericArgs(3) > 0.0) {
7511 : GlConstrNum =
7512 1 : Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(2), state.dataConstruction->Construct, state.dataHeatBal->TotConstructs);
7513 1 : if (GlConstrNum == 0) {
7514 0 : ShowSevereError(state,
7515 0 : format("{}=\"{}\", {} not found={}",
7516 : cCurrentModuleObject,
7517 0 : state.dataSurface->Surface(SurfNum).Name,
7518 0 : state.dataIPShortCut->cAlphaFieldNames(2),
7519 0 : state.dataIPShortCut->cAlphaArgs(2)));
7520 0 : ErrorsFound = true;
7521 : } else {
7522 1 : state.dataConstruction->Construct(GlConstrNum).IsUsed = true;
7523 : }
7524 1 : state.dataSurface->SurfShadowGlazingConstruct(SurfNum) = GlConstrNum;
7525 : }
7526 1 : SurfNum = Util::FindItemInList("Mir-" + state.dataIPShortCut->cAlphaArgs(1), state.dataSurface->Surface, state.dataSurface->TotSurfaces);
7527 1 : if (SurfNum == 0) continue;
7528 1 : state.dataSurface->SurfShadowGlazingFrac(SurfNum) = state.dataIPShortCut->rNumericArgs(3);
7529 1 : state.dataSurface->SurfShadowDiffuseSolRefl(SurfNum) =
7530 1 : (1.0 - state.dataIPShortCut->rNumericArgs(3)) * state.dataIPShortCut->rNumericArgs(1);
7531 1 : state.dataSurface->SurfShadowDiffuseVisRefl(SurfNum) =
7532 1 : (1.0 - state.dataIPShortCut->rNumericArgs(3)) * state.dataIPShortCut->rNumericArgs(2);
7533 1 : if (state.dataIPShortCut->rNumericArgs(3) > 0.0) {
7534 : GlConstrNum =
7535 1 : Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(2), state.dataConstruction->Construct, state.dataHeatBal->TotConstructs);
7536 1 : if (GlConstrNum != 0) {
7537 1 : state.dataConstruction->Construct(GlConstrNum).IsUsed = true;
7538 : }
7539 1 : state.dataSurface->SurfShadowGlazingConstruct(SurfNum) = GlConstrNum;
7540 : }
7541 :
7542 : } // End of loop over Shading Surface Reflectance objects
7543 :
7544 : // Write reflectance values to .eio file.
7545 9 : print(state.files.eio,
7546 : "! <ShadingProperty Reflectance>,Shading Surface Name,Shading Type,Diffuse Solar Reflectance, Diffuse "
7547 : "Visible Reflectance,Surface Glazing Fraction,Surface Glazing Contruction\n");
7548 :
7549 101 : for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
7550 92 : auto const &surf = state.dataSurface->Surface(SurfNum);
7551 92 : if (!(surf.Class == SurfaceClass::Shading || surf.Class == SurfaceClass::Detached_F || surf.Class == SurfaceClass::Detached_B ||
7552 86 : surf.Class == SurfaceClass::Overhang || surf.Class == SurfaceClass::Fin))
7553 86 : continue;
7554 :
7555 6 : constexpr std::string_view fmt = "ShadingProperty Reflectance,{},{},{:.2R},{:.2R},{:.2R}, {}\n";
7556 6 : if (state.dataSurface->SurfShadowGlazingConstruct(SurfNum) != 0) {
7557 6 : print(state.files.eio,
7558 : fmt,
7559 2 : surf.Name,
7560 4 : cSurfaceClass(surf.Class),
7561 2 : state.dataSurface->SurfShadowDiffuseSolRefl(SurfNum),
7562 2 : state.dataSurface->SurfShadowDiffuseVisRefl(SurfNum),
7563 2 : state.dataSurface->SurfShadowGlazingFrac(SurfNum),
7564 2 : state.dataConstruction->Construct(state.dataSurface->SurfShadowGlazingConstruct(SurfNum)).Name);
7565 : } else {
7566 12 : print(state.files.eio,
7567 : fmt,
7568 4 : surf.Name,
7569 8 : cSurfaceClass(surf.Class),
7570 4 : state.dataSurface->SurfShadowDiffuseSolRefl(SurfNum),
7571 4 : state.dataSurface->SurfShadowDiffuseVisRefl(SurfNum),
7572 4 : state.dataSurface->SurfShadowGlazingFrac(SurfNum),
7573 : "N/A");
7574 : }
7575 : }
7576 9 : }
7577 :
7578 796 : void GetHTSurfExtVentedCavityData(EnergyPlusData &state, bool &ErrorsFound) // Error flag indicator (true if errors found)
7579 : {
7580 :
7581 : // SUBROUTINE INFORMATION:
7582 : // AUTHOR BGriffith
7583 : // DATE WRITTEN January 2005
7584 : // MODIFIED na
7585 : // RE-ENGINEERED na
7586 :
7587 : // PURPOSE OF THIS SUBROUTINE:
7588 : // load input data for Exterior Vented Cavity Special case for heat transfer surfaces
7589 :
7590 : // METHODOLOGY EMPLOYED:
7591 : // usual E+ input processes
7592 :
7593 : // REFERENCES:
7594 : // derived from SUBROUTINE GetTranspiredCollectorInput
7595 :
7596 : // Using/Aliasing
7597 :
7598 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
7599 :
7600 : int Item; // Item to be "gotten"
7601 : int NumAlphas; // Number of Alphas for each GetObjectItem call
7602 : int NumNumbers; // Number of Numbers for each GetObjectItem call
7603 : int MaxNumAlphas; // argument for call to GetObjectDefMaxArgs
7604 : int MaxNumNumbers; // argument for call to GetObjectDefMaxArgs
7605 : int Dummy; // argument for call to GetObjectDefMaxArgs
7606 : int IOStatus; // Used in GetObjectItem
7607 : int Found;
7608 : int AlphaOffset; // local temp var
7609 796 : std::string Roughness;
7610 : int ThisSurf; // do loop counter
7611 : Real64 AvgAzimuth; // temp for error checking
7612 : Real64 AvgTilt; // temp for error checking
7613 796 : constexpr Real64 AZITOL = 15.0; // Degree Azimuth Angle Tolerance
7614 796 : constexpr Real64 TILTOL = 10.0; // Degree Tilt Angle Tolerance
7615 : int SurfID; // local surface "pointer"
7616 : bool IsBlank;
7617 : bool ErrorInName;
7618 796 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
7619 796 : cCurrentModuleObject = "SurfaceProperty:ExteriorNaturalVentedCavity";
7620 796 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, Dummy, MaxNumAlphas, MaxNumNumbers);
7621 :
7622 796 : if (MaxNumNumbers != 8) {
7623 0 : ShowSevereError(
7624 0 : state, format("{}: Object Definition indicates not = 8 Number Objects, Number Indicated={}", cCurrentModuleObject, MaxNumNumbers));
7625 0 : ErrorsFound = true;
7626 : }
7627 :
7628 796 : state.dataSurface->TotExtVentCav = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
7629 :
7630 796 : state.dataHeatBal->ExtVentedCavity.allocate(state.dataSurface->TotExtVentCav);
7631 :
7632 801 : for (Item = 1; Item <= state.dataSurface->TotExtVentCav; ++Item) {
7633 10 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
7634 : cCurrentModuleObject,
7635 : Item,
7636 5 : state.dataIPShortCut->cAlphaArgs,
7637 : NumAlphas,
7638 5 : state.dataIPShortCut->rNumericArgs,
7639 : NumNumbers,
7640 : IOStatus,
7641 5 : state.dataIPShortCut->lNumericFieldBlanks,
7642 5 : state.dataIPShortCut->lAlphaFieldBlanks,
7643 5 : state.dataIPShortCut->cAlphaFieldNames,
7644 5 : state.dataIPShortCut->cNumericFieldNames);
7645 : // first handle cAlphaArgs
7646 5 : ErrorInName = false;
7647 5 : IsBlank = false;
7648 :
7649 10 : Util::VerifyName(state,
7650 5 : state.dataIPShortCut->cAlphaArgs(1),
7651 5 : state.dataHeatBal->ExtVentedCavity,
7652 : Item - 1,
7653 : ErrorInName,
7654 : IsBlank,
7655 10 : cCurrentModuleObject + " Name");
7656 5 : if (ErrorInName) {
7657 0 : ShowContinueError(state, "...cannot not duplicate other names");
7658 0 : ErrorsFound = true;
7659 0 : continue;
7660 : }
7661 5 : state.dataHeatBal->ExtVentedCavity(Item).Name = state.dataIPShortCut->cAlphaArgs(1);
7662 :
7663 5 : state.dataHeatBal->ExtVentedCavity(Item).OSCMName = state.dataIPShortCut->cAlphaArgs(2);
7664 5 : if (!state.dataIPShortCut->lAlphaFieldBlanks(2)) {
7665 5 : Found = Util::FindItemInList(state.dataHeatBal->ExtVentedCavity(Item).OSCMName, state.dataSurface->OSCM, state.dataSurface->TotOSCM);
7666 5 : if (Found == 0) {
7667 0 : ShowSevereError(state,
7668 0 : format("{}=\"{}\", invalid {}=\"{}\".",
7669 : cCurrentModuleObject,
7670 0 : state.dataHeatBal->ExtVentedCavity(Item).Name,
7671 0 : state.dataIPShortCut->cAlphaFieldNames(2),
7672 0 : state.dataIPShortCut->cAlphaArgs(2)));
7673 0 : ErrorsFound = true;
7674 : }
7675 : } else {
7676 0 : Found = 0;
7677 0 : ShowSevereError(state,
7678 0 : format("{}=\"{}\", invalid {} cannot be blank.",
7679 : cCurrentModuleObject,
7680 0 : state.dataHeatBal->ExtVentedCavity(Item).Name,
7681 0 : state.dataIPShortCut->cAlphaFieldNames(2)));
7682 0 : ErrorsFound = true;
7683 : }
7684 5 : state.dataHeatBal->ExtVentedCavity(Item).OSCMPtr = Found;
7685 :
7686 5 : Roughness = state.dataIPShortCut->cAlphaArgs(3);
7687 : // Select the correct Number for the associated ascii name for the roughness type
7688 5 : if (Util::SameString(Roughness, "VerySmooth")) {
7689 0 : state.dataHeatBal->ExtVentedCavity(Item).BaffleRoughness = Material::SurfaceRoughness::VerySmooth;
7690 5 : } else if (Util::SameString(Roughness, "Smooth")) {
7691 5 : state.dataHeatBal->ExtVentedCavity(Item).BaffleRoughness = Material::SurfaceRoughness::Smooth;
7692 0 : } else if (Util::SameString(Roughness, "MediumSmooth")) {
7693 0 : state.dataHeatBal->ExtVentedCavity(Item).BaffleRoughness = Material::SurfaceRoughness::MediumSmooth;
7694 0 : } else if (Util::SameString(Roughness, "MediumRough")) {
7695 0 : state.dataHeatBal->ExtVentedCavity(Item).BaffleRoughness = Material::SurfaceRoughness::MediumRough;
7696 0 : } else if (Util::SameString(Roughness, "Rough")) {
7697 0 : state.dataHeatBal->ExtVentedCavity(Item).BaffleRoughness = Material::SurfaceRoughness::Rough;
7698 0 : } else if (Util::SameString(Roughness, "VeryRough")) {
7699 0 : state.dataHeatBal->ExtVentedCavity(Item).BaffleRoughness = Material::SurfaceRoughness::VeryRough;
7700 : } // TODO: fix this after creating FindEnumeratedValueIndex()
7701 :
7702 : // Was it set?
7703 5 : if (state.dataHeatBal->ExtVentedCavity(Item).BaffleRoughness == Material::SurfaceRoughness::Invalid) {
7704 0 : ShowSevereError(state,
7705 0 : format("{}=\"{}\", invalid {}=\"{}",
7706 : cCurrentModuleObject,
7707 0 : state.dataHeatBal->ExtVentedCavity(Item).Name,
7708 0 : state.dataIPShortCut->cAlphaFieldNames(3),
7709 0 : state.dataIPShortCut->cAlphaArgs(3)));
7710 0 : ErrorsFound = true;
7711 : }
7712 :
7713 5 : AlphaOffset = 3;
7714 5 : state.dataHeatBal->ExtVentedCavity(Item).NumSurfs = NumAlphas - AlphaOffset;
7715 5 : if (state.dataHeatBal->ExtVentedCavity(Item).NumSurfs == 0) {
7716 0 : ShowSevereError(state,
7717 0 : format("{}=\"{}\", no underlying surfaces specified. Must have at least one.",
7718 : cCurrentModuleObject,
7719 0 : state.dataHeatBal->ExtVentedCavity(Item).Name));
7720 0 : ErrorsFound = true;
7721 0 : continue;
7722 : }
7723 5 : state.dataHeatBal->ExtVentedCavity(Item).SurfPtrs.allocate(state.dataHeatBal->ExtVentedCavity(Item).NumSurfs);
7724 5 : state.dataHeatBal->ExtVentedCavity(Item).SurfPtrs = 0;
7725 10 : for (ThisSurf = 1; ThisSurf <= state.dataHeatBal->ExtVentedCavity(Item).NumSurfs; ++ThisSurf) {
7726 5 : Found = Util::FindItemInList(
7727 5 : state.dataIPShortCut->cAlphaArgs(ThisSurf + AlphaOffset), state.dataSurface->Surface, state.dataSurface->TotSurfaces);
7728 5 : if (Found == 0) {
7729 0 : ShowSevereError(state,
7730 0 : format("{}=\"{}\", invalid {}=\"{}",
7731 : cCurrentModuleObject,
7732 0 : state.dataHeatBal->ExtVentedCavity(Item).Name,
7733 0 : state.dataIPShortCut->cAlphaFieldNames(ThisSurf + AlphaOffset),
7734 0 : state.dataIPShortCut->cAlphaArgs(ThisSurf + AlphaOffset)));
7735 0 : ErrorsFound = true;
7736 0 : continue;
7737 : }
7738 : // check that surface is appropriate, Heat transfer, Sun, Wind,
7739 5 : if (!state.dataSurface->Surface(Found).HeatTransSurf) {
7740 0 : ShowSevereError(state,
7741 0 : format("{}=\"{}\", invalid {}=\"{}",
7742 : cCurrentModuleObject,
7743 0 : state.dataHeatBal->ExtVentedCavity(Item).Name,
7744 0 : state.dataIPShortCut->cAlphaFieldNames(ThisSurf + AlphaOffset),
7745 0 : state.dataIPShortCut->cAlphaArgs(ThisSurf + AlphaOffset)));
7746 0 : ShowContinueError(state, "...because it is not a Heat Transfer Surface.");
7747 0 : ErrorsFound = true;
7748 0 : continue;
7749 : }
7750 5 : if (!state.dataSurface->Surface(Found).ExtSolar) {
7751 0 : ShowSevereError(state,
7752 0 : format("{}=\"{}\", invalid {}=\"{}",
7753 : cCurrentModuleObject,
7754 0 : state.dataHeatBal->ExtVentedCavity(Item).Name,
7755 0 : state.dataIPShortCut->cAlphaFieldNames(ThisSurf + AlphaOffset),
7756 0 : state.dataIPShortCut->cAlphaArgs(ThisSurf + AlphaOffset)));
7757 0 : ShowContinueError(state, "...because it is not exposed to Sun.");
7758 0 : ErrorsFound = true;
7759 0 : continue;
7760 : }
7761 5 : if (!state.dataSurface->Surface(Found).ExtWind) {
7762 0 : ShowSevereError(state,
7763 0 : format("{}=\"{}\", invalid {}=\"{}",
7764 : cCurrentModuleObject,
7765 0 : state.dataHeatBal->ExtVentedCavity(Item).Name,
7766 0 : state.dataIPShortCut->cAlphaFieldNames(ThisSurf + AlphaOffset),
7767 0 : state.dataIPShortCut->cAlphaArgs(ThisSurf + AlphaOffset)));
7768 0 : ShowContinueError(state, "...because it is not exposed to Wind.");
7769 0 : ErrorsFound = true;
7770 0 : continue;
7771 : }
7772 5 : if (state.dataSurface->Surface(Found).ExtBoundCond != OtherSideCondModeledExt) {
7773 0 : ShowSevereError(state, format("{}=\"{}\", is invalid", cCurrentModuleObject, state.dataHeatBal->ExtVentedCavity(Item).Name));
7774 0 : ShowContinueError(state,
7775 0 : format("...because {}=\"{}\".",
7776 0 : state.dataIPShortCut->cAlphaFieldNames(ThisSurf + AlphaOffset),
7777 0 : state.dataIPShortCut->cAlphaArgs(ThisSurf + AlphaOffset)));
7778 0 : ShowContinueError(state, "...is not an OtherSideConditionedModel surface.");
7779 0 : ErrorsFound = true;
7780 0 : continue;
7781 : }
7782 5 : state.dataHeatBal->ExtVentedCavity(Item).SurfPtrs(ThisSurf) = Found;
7783 :
7784 : // now set info in Surface structure
7785 5 : state.dataSurface->SurfExtCavNum(Found) = Item;
7786 5 : state.dataSurface->SurfExtCavityPresent(Found) = true;
7787 : }
7788 :
7789 5 : if (ErrorsFound) continue; // previous inner do loop may have detected problems that need to be cycle'd again to avoid crash
7790 :
7791 : // now that we should have all the surfaces, do some preperations and checks.
7792 :
7793 : // are they all similar tilt and azimuth? Issue warnings so people can do it if they really want
7794 5 : Real64 const surfaceArea(sum_sub(state.dataSurface->Surface, &SurfaceData::Area, state.dataHeatBal->ExtVentedCavity(Item).SurfPtrs));
7795 : // AvgAzimuth = sum( Surface( ExtVentedCavity( Item ).SurfPtrs ).Azimuth * Surface( ExtVentedCavity( Item ).SurfPtrs
7796 : //).Area
7797 : //)
7798 : /// sum( Surface( ExtVentedCavity( Item ).SurfPtrs ).Area ); //Autodesk:F2C++ Array subscript usage: Replaced by below
7799 5 : AvgAzimuth = sum_product_sub(state.dataSurface->Surface,
7800 : &SurfaceData::Azimuth,
7801 : &SurfaceData::Area,
7802 5 : state.dataHeatBal->ExtVentedCavity(Item).SurfPtrs) /
7803 : surfaceArea; // Autodesk:F2C++ Functions handle array subscript usage
7804 : // AvgTilt = sum( Surface( ExtVentedCavity( Item ).SurfPtrs ).Tilt * Surface( ExtVentedCavity( Item ).SurfPtrs ).Area )
7805 : // /
7806 : // sum( Surface( ExtVentedCavity( Item ).SurfPtrs ).Area ); //Autodesk:F2C++ Array subscript usage: Replaced by below
7807 10 : AvgTilt = sum_product_sub(
7808 5 : state.dataSurface->Surface, &SurfaceData::Tilt, &SurfaceData::Area, state.dataHeatBal->ExtVentedCavity(Item).SurfPtrs) /
7809 : surfaceArea; // Autodesk:F2C++ Functions handle array subscript usage
7810 10 : for (ThisSurf = 1; ThisSurf <= state.dataHeatBal->ExtVentedCavity(Item).NumSurfs; ++ThisSurf) {
7811 5 : SurfID = state.dataHeatBal->ExtVentedCavity(Item).SurfPtrs(ThisSurf);
7812 5 : if (General::rotAzmDiffDeg(state.dataSurface->Surface(SurfID).Azimuth, AvgAzimuth) > AZITOL) {
7813 0 : ShowWarningError(state,
7814 0 : format("{}=\"{}, Surface {} has Azimuth different from others in the associated group.",
7815 : cCurrentModuleObject,
7816 0 : state.dataHeatBal->ExtVentedCavity(Item).Name,
7817 0 : state.dataSurface->Surface(SurfID).Name));
7818 : }
7819 5 : if (std::abs(state.dataSurface->Surface(SurfID).Tilt - AvgTilt) > TILTOL) {
7820 0 : ShowWarningError(state,
7821 0 : format("{}=\"{}, Surface {} has Tilt different from others in the associated group.",
7822 : cCurrentModuleObject,
7823 0 : state.dataHeatBal->ExtVentedCavity(Item).Name,
7824 0 : state.dataSurface->Surface(SurfID).Name));
7825 : }
7826 :
7827 : // test that there are no windows. Now allow windows
7828 : // If (Surface(SurfID)%GrossArea > Surface(SurfID)%Area) Then
7829 : // Call ShowWarningError(state, 'Surface '//TRIM(Surface(SurfID)%name)//' has a subsurface whose area is not being ' &
7830 : // //'subtracted in the group of surfaces associated with '//TRIM(ExtVentedCavity(Item)%Name))
7831 : // endif
7832 : }
7833 5 : state.dataHeatBal->ExtVentedCavity(Item).Tilt = AvgTilt;
7834 5 : state.dataHeatBal->ExtVentedCavity(Item).Azimuth = AvgAzimuth;
7835 :
7836 : // find area weighted centroid.
7837 : // ExtVentedCavity( Item ).Centroid.z = sum( Surface( ExtVentedCavity( Item ).SurfPtrs ).Centroid.z * Surface(
7838 : // ExtVentedCavity( Item
7839 : //).SurfPtrs ).Area ) / sum( Surface( ExtVentedCavity( Item ).SurfPtrs ).Area ); //Autodesk:F2C++ Array subscript usage: Replaced
7840 : // by below
7841 10 : state.dataHeatBal->ExtVentedCavity(Item).Centroid.z = sum_product_sub(state.dataSurface->Surface,
7842 : &SurfaceData::Centroid,
7843 : &Vector::z,
7844 5 : state.dataSurface->Surface,
7845 : &SurfaceData::Area,
7846 10 : state.dataHeatBal->ExtVentedCavity(Item).SurfPtrs) /
7847 : surfaceArea; // Autodesk:F2C++ Functions handle array subscript usage
7848 :
7849 : // now handle rNumericArgs from input object
7850 5 : state.dataHeatBal->ExtVentedCavity(Item).Porosity = state.dataIPShortCut->rNumericArgs(1);
7851 5 : state.dataHeatBal->ExtVentedCavity(Item).LWEmitt = state.dataIPShortCut->rNumericArgs(2);
7852 5 : state.dataHeatBal->ExtVentedCavity(Item).SolAbsorp = state.dataIPShortCut->rNumericArgs(3);
7853 5 : state.dataHeatBal->ExtVentedCavity(Item).HdeltaNPL = state.dataIPShortCut->rNumericArgs(4);
7854 5 : state.dataHeatBal->ExtVentedCavity(Item).PlenGapThick = state.dataIPShortCut->rNumericArgs(5);
7855 5 : if (state.dataHeatBal->ExtVentedCavity(Item).PlenGapThick <= 0.0) {
7856 0 : ShowSevereError(state, format("{}=\"{}\", invalid .", cCurrentModuleObject, state.dataHeatBal->ExtVentedCavity(Item).Name));
7857 0 : ErrorsFound = true;
7858 0 : ShowContinueError(state,
7859 0 : format("...because field \"{}\" must be greater than Zero=[{:.2T}].",
7860 0 : state.dataIPShortCut->cNumericFieldNames(5),
7861 0 : state.dataIPShortCut->rNumericArgs(5)));
7862 0 : continue;
7863 : }
7864 5 : state.dataHeatBal->ExtVentedCavity(Item).AreaRatio = state.dataIPShortCut->rNumericArgs(6);
7865 5 : state.dataHeatBal->ExtVentedCavity(Item).Cv = state.dataIPShortCut->rNumericArgs(7);
7866 5 : state.dataHeatBal->ExtVentedCavity(Item).Cd = state.dataIPShortCut->rNumericArgs(8);
7867 :
7868 : // Fill out data we now know
7869 : // sum areas of HT surface areas
7870 : // ExtVentedCavity( Item ).ProjArea = sum( Surface( ExtVentedCavity( Item ).SurfPtrs ).Area ); //Autodesk:F2C++ Array
7871 : // subscript usage: Replaced by below
7872 5 : state.dataHeatBal->ExtVentedCavity(Item).ProjArea = surfaceArea;
7873 5 : if (state.dataHeatBal->ExtVentedCavity(Item).ProjArea <= 0.0) {
7874 0 : ShowSevereError(state, format("{}=\"{}\", invalid .", cCurrentModuleObject, state.dataHeatBal->ExtVentedCavity(Item).Name));
7875 0 : ErrorsFound = true;
7876 0 : ShowContinueError(state,
7877 0 : format("...because gross area of underlying surfaces must be greater than Zero=[{:.2T}].",
7878 0 : state.dataHeatBal->ExtVentedCavity(Item).ProjArea));
7879 0 : continue;
7880 : }
7881 5 : state.dataHeatBal->ExtVentedCavity(Item).ActualArea =
7882 5 : state.dataHeatBal->ExtVentedCavity(Item).ProjArea * state.dataHeatBal->ExtVentedCavity(Item).AreaRatio;
7883 :
7884 10 : SetupOutputVariable(state,
7885 : "Surface Exterior Cavity Baffle Surface Temperature",
7886 : Constant::Units::C,
7887 5 : state.dataHeatBal->ExtVentedCavity(Item).Tbaffle,
7888 : OutputProcessor::TimeStepType::System,
7889 : OutputProcessor::StoreType::Average,
7890 5 : state.dataHeatBal->ExtVentedCavity(Item).Name);
7891 10 : SetupOutputVariable(state,
7892 : "Surface Exterior Cavity Air Drybulb Temperature",
7893 : Constant::Units::C,
7894 5 : state.dataHeatBal->ExtVentedCavity(Item).TAirCav,
7895 : OutputProcessor::TimeStepType::System,
7896 : OutputProcessor::StoreType::Average,
7897 5 : state.dataHeatBal->ExtVentedCavity(Item).Name);
7898 10 : SetupOutputVariable(state,
7899 : "Surface Exterior Cavity Total Natural Ventilation Air Change Rate",
7900 : Constant::Units::ach,
7901 5 : state.dataHeatBal->ExtVentedCavity(Item).PassiveACH,
7902 : OutputProcessor::TimeStepType::System,
7903 : OutputProcessor::StoreType::Average,
7904 5 : state.dataHeatBal->ExtVentedCavity(Item).Name);
7905 10 : SetupOutputVariable(state,
7906 : "Surface Exterior Cavity Total Natural Ventilation Mass Flow Rate",
7907 : Constant::Units::kg_s,
7908 5 : state.dataHeatBal->ExtVentedCavity(Item).PassiveMdotVent,
7909 : OutputProcessor::TimeStepType::System,
7910 : OutputProcessor::StoreType::Average,
7911 5 : state.dataHeatBal->ExtVentedCavity(Item).Name);
7912 10 : SetupOutputVariable(state,
7913 : "Surface Exterior Cavity Natural Ventilation from Wind Mass Flow Rate",
7914 : Constant::Units::kg_s,
7915 5 : state.dataHeatBal->ExtVentedCavity(Item).PassiveMdotWind,
7916 : OutputProcessor::TimeStepType::System,
7917 : OutputProcessor::StoreType::Average,
7918 5 : state.dataHeatBal->ExtVentedCavity(Item).Name);
7919 10 : SetupOutputVariable(state,
7920 : "Surface Exterior Cavity Natural Ventilation from Buoyancy Mass Flow Rate",
7921 : Constant::Units::kg_s,
7922 5 : state.dataHeatBal->ExtVentedCavity(Item).PassiveMdotTherm,
7923 : OutputProcessor::TimeStepType::System,
7924 : OutputProcessor::StoreType::Average,
7925 5 : state.dataHeatBal->ExtVentedCavity(Item).Name);
7926 : }
7927 796 : }
7928 :
7929 796 : void ExposedFoundationPerimeter::getData(EnergyPlusData &state, bool &ErrorsFound)
7930 : {
7931 :
7932 : int IOStatus; // Used in GetObjectItem
7933 : int NumAlphas;
7934 : int NumNumbers;
7935 :
7936 796 : Real64 constexpr tolerance = 1e-6;
7937 :
7938 796 : constexpr std::string_view cCurrentModuleObject = "SurfaceProperty:ExposedFoundationPerimeter";
7939 796 : int numObjects = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
7940 :
7941 819 : for (int obj = 1; obj <= numObjects; ++obj) {
7942 23 : int alpF = 1;
7943 23 : int numF = 1;
7944 46 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
7945 : cCurrentModuleObject,
7946 : obj,
7947 23 : state.dataIPShortCut->cAlphaArgs,
7948 : NumAlphas,
7949 23 : state.dataIPShortCut->rNumericArgs,
7950 : NumNumbers,
7951 : IOStatus,
7952 23 : state.dataIPShortCut->lNumericFieldBlanks,
7953 23 : state.dataIPShortCut->lAlphaFieldBlanks,
7954 23 : state.dataIPShortCut->cAlphaFieldNames,
7955 23 : state.dataIPShortCut->cNumericFieldNames);
7956 23 : int Found = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(alpF), state.dataSurface->Surface, state.dataSurface->TotSurfaces);
7957 23 : if (Found == 0) {
7958 0 : ShowSevereError(state, format("{}=\"{}\", did not find matching surface", cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
7959 0 : ErrorsFound = true;
7960 : }
7961 23 : alpF++;
7962 23 : if (state.dataSurface->Surface(Found).Class != SurfaceClass::Floor) {
7963 0 : ShowWarningError(state,
7964 0 : format("{}: {}, surface is not a floor surface", cCurrentModuleObject, state.dataSurface->Surface(Found).Name));
7965 0 : ShowContinueError(state, format("{} will not be used", cCurrentModuleObject));
7966 0 : continue;
7967 : }
7968 :
7969 : // Choose calculation method
7970 :
7971 : enum class CalculationMethod
7972 : {
7973 : Invalid = -1,
7974 : TotalExposedPerimeter,
7975 : ExposedPerimeterFraction,
7976 : Bysegment,
7977 : Num
7978 : };
7979 :
7980 23 : constexpr std::array<std::string_view, static_cast<int>(CalculationMethod::Num)> CalculationMethodUC = {
7981 : "TOTALEXPOSEDPERIMETER", "EXPOSEDPERIMETERFRACTION", "BYSEGMENT"};
7982 : CalculationMethod calculationMethod =
7983 23 : static_cast<CalculationMethod>(getEnumValue(CalculationMethodUC, state.dataIPShortCut->cAlphaArgs(alpF)));
7984 23 : if (calculationMethod != CalculationMethod::TotalExposedPerimeter && calculationMethod != CalculationMethod::ExposedPerimeterFraction &&
7985 19 : calculationMethod != CalculationMethod::Bysegment) {
7986 0 : ShowSevereError(state,
7987 0 : format("{}=\"{}\", {} is not a valid choice for {}",
7988 : cCurrentModuleObject,
7989 0 : state.dataIPShortCut->cAlphaArgs(1),
7990 : calculationMethod,
7991 0 : state.dataIPShortCut->cAlphaFieldNames(alpF)));
7992 0 : ErrorsFound = true;
7993 : }
7994 23 : alpF++;
7995 :
7996 23 : Data data;
7997 23 : data.useDetailedExposedPerimeter = true;
7998 :
7999 23 : if (!state.dataIPShortCut->lNumericFieldBlanks(numF)) {
8000 1 : if (calculationMethod == CalculationMethod::TotalExposedPerimeter) {
8001 1 : data.exposedFraction = state.dataIPShortCut->rNumericArgs(numF) / state.dataSurface->Surface(Found).Perimeter;
8002 1 : if (data.exposedFraction > 1 + tolerance) {
8003 0 : ShowWarningError(state,
8004 0 : format("{}: {}, {} is greater than the perimeter of {}",
8005 : cCurrentModuleObject,
8006 0 : state.dataSurface->Surface(Found).Name,
8007 0 : state.dataIPShortCut->cNumericFieldNames(numF),
8008 0 : state.dataSurface->Surface(Found).Name));
8009 0 : ShowContinueError(state,
8010 0 : format("{} perimeter = {}, {} exposed perimeter = {}",
8011 0 : state.dataSurface->Surface(Found).Name,
8012 0 : state.dataSurface->Surface(Found).Perimeter,
8013 : cCurrentModuleObject,
8014 0 : state.dataIPShortCut->rNumericArgs(numF)));
8015 0 : ShowContinueError(state,
8016 0 : format("{} will be set equal to {} perimeter",
8017 0 : state.dataIPShortCut->cNumericFieldNames(numF),
8018 0 : state.dataSurface->Surface(Found).Name));
8019 0 : data.exposedFraction = 1.0;
8020 : }
8021 :
8022 1 : data.useDetailedExposedPerimeter = false;
8023 : } else {
8024 0 : ShowWarningError(state,
8025 0 : format("{}: {}, {} set as calculation method, but a value has been set for {}. This value will be ignored.",
8026 : cCurrentModuleObject,
8027 0 : state.dataSurface->Surface(Found).Name,
8028 : calculationMethod,
8029 0 : state.dataIPShortCut->cNumericFieldNames(numF)));
8030 : }
8031 : } else {
8032 22 : if (calculationMethod == CalculationMethod::TotalExposedPerimeter) {
8033 0 : ShowSevereError(state,
8034 0 : format("{}: {}, {} set as calculation method, but no value has been set for {}",
8035 : cCurrentModuleObject,
8036 0 : state.dataSurface->Surface(Found).Name,
8037 : calculationMethod,
8038 0 : state.dataIPShortCut->cNumericFieldNames(numF)));
8039 0 : ErrorsFound = true;
8040 : }
8041 : }
8042 23 : numF++;
8043 :
8044 23 : if (!state.dataIPShortCut->lNumericFieldBlanks(numF)) {
8045 3 : if (calculationMethod == CalculationMethod::ExposedPerimeterFraction) {
8046 3 : data.exposedFraction = state.dataIPShortCut->rNumericArgs(numF);
8047 3 : data.useDetailedExposedPerimeter = false;
8048 : } else {
8049 0 : ShowWarningError(state,
8050 0 : format("{}: {}, {} set as calculation method, but a value has been set for {}. This value will be ignored.",
8051 : cCurrentModuleObject,
8052 0 : state.dataSurface->Surface(Found).Name,
8053 : calculationMethod,
8054 0 : state.dataIPShortCut->cNumericFieldNames(numF)));
8055 : }
8056 : } else {
8057 20 : if (calculationMethod == CalculationMethod::ExposedPerimeterFraction) {
8058 0 : ShowSevereError(state,
8059 0 : format("{}: {}, {} set as calculation method, but no value has been set for {}",
8060 : cCurrentModuleObject,
8061 0 : state.dataSurface->Surface(Found).Name,
8062 : calculationMethod,
8063 0 : state.dataIPShortCut->cNumericFieldNames(numF)));
8064 0 : ErrorsFound = true;
8065 : }
8066 : }
8067 23 : numF++;
8068 :
8069 23 : int numRemainingFields = NumAlphas - (alpF - 1) + NumNumbers - (numF - 1);
8070 23 : if (numRemainingFields > 0) {
8071 19 : if (calculationMethod == CalculationMethod::Bysegment) {
8072 19 : if (numRemainingFields != (int)state.dataSurface->Surface(Found).Vertex.size()) {
8073 0 : ShowSevereError(state,
8074 0 : format("{}: {}, must have equal number of segments as the floor has vertices.{}\" and \"{}\"",
8075 : cCurrentModuleObject,
8076 0 : state.dataSurface->Surface(Found).Name,
8077 0 : state.dataIPShortCut->cAlphaFieldNames(alpF),
8078 0 : state.dataIPShortCut->cNumericFieldNames(numF - 1)));
8079 0 : ShowContinueError(state,
8080 0 : format("{} number of vertices = {}, {} number of segments = {}",
8081 0 : state.dataSurface->Surface(Found).Name,
8082 0 : state.dataSurface->Surface(Found).Vertex.size(),
8083 : cCurrentModuleObject,
8084 : numRemainingFields));
8085 0 : ErrorsFound = true;
8086 : }
8087 95 : for (int segNum = 0; segNum < numRemainingFields; segNum++) {
8088 76 : if (Util::SameString(state.dataIPShortCut->cAlphaArgs(alpF), "YES")) {
8089 28 : data.isExposedPerimeter.push_back(true);
8090 48 : } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(alpF), "NO")) {
8091 48 : data.isExposedPerimeter.push_back(false);
8092 0 : } else if (state.dataIPShortCut->lAlphaFieldBlanks(alpF)) {
8093 0 : ShowSevereError(
8094 : state,
8095 0 : format("{}: {}, {} set as calculation method, but no value has been set for {}. Must be \"Yes\" or \"No\".",
8096 : cCurrentModuleObject,
8097 0 : state.dataSurface->Surface(Found).Name,
8098 : calculationMethod,
8099 0 : state.dataIPShortCut->cAlphaFieldNames(alpF)));
8100 0 : ErrorsFound = true;
8101 : } else {
8102 0 : ShowSevereError(state,
8103 0 : format("{}: {}, {} invalid [{}]. Must be \"Yes\" or \"No\".",
8104 : cCurrentModuleObject,
8105 0 : state.dataSurface->Surface(Found).Name,
8106 0 : state.dataIPShortCut->cAlphaFieldNames(alpF),
8107 0 : state.dataIPShortCut->cAlphaArgs(alpF)));
8108 0 : ErrorsFound = true;
8109 : }
8110 76 : alpF++;
8111 : }
8112 : }
8113 : } else {
8114 4 : if (calculationMethod == CalculationMethod::Bysegment) {
8115 0 : ShowSevereError(state,
8116 0 : format("{}: {}, {} set as calculation method, but no values have been set for Surface Segments Exposed",
8117 : cCurrentModuleObject,
8118 0 : state.dataSurface->Surface(Found).Name,
8119 : calculationMethod));
8120 0 : ErrorsFound = true;
8121 : }
8122 : }
8123 23 : surfaceMap[Found] = data;
8124 23 : }
8125 796 : }
8126 :
8127 796 : void GetSurfaceLocalEnvData(EnergyPlusData &state, bool &ErrorsFound) // Error flag indicator (true if errors found)
8128 : {
8129 : // SUBROUTINE INFORMATION:
8130 : // AUTHOR X LUO
8131 : // DATE WRITTEN July 2017
8132 : // MODIFIED na
8133 : // RE-ENGINEERED na
8134 :
8135 : // PURPOSE OF THIS SUBROUTINE:
8136 : // load input data for Outdoor Air Node for exterior surfaces
8137 :
8138 : // Using/Aliasing
8139 : using namespace DataErrorTracking;
8140 : using DataLoopNode::ObjectIsParent;
8141 : using NodeInputManager::GetOnlySingleNode;
8142 : using OutAirNodeManager::CheckOutAirNodeNumber;
8143 : using ScheduleManager::GetScheduleIndex;
8144 :
8145 : // SUBROUTINE PARAMETER DEFINITIONS:
8146 : static constexpr std::string_view RoutineName("GetSurfaceLocalEnvData: ");
8147 :
8148 : // INTERFACE BLOCK SPECIFICATIONS:na
8149 : // DERIVED TYPE DEFINITIONS:na
8150 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
8151 : int NumAlpha;
8152 : int NumNumeric;
8153 : int IOStat;
8154 :
8155 : //-----------------------------------------------------------------------
8156 : // SurfaceProperty:LocalEnvironment
8157 : //-----------------------------------------------------------------------
8158 796 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
8159 796 : cCurrentModuleObject = "SurfaceProperty:LocalEnvironment";
8160 796 : state.dataSurface->TotSurfLocalEnv = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
8161 :
8162 796 : if (state.dataSurface->TotSurfLocalEnv > 0) {
8163 :
8164 4 : state.dataGlobal->AnyLocalEnvironmentsInModel = true;
8165 :
8166 4 : if (!allocated(state.dataSurface->SurfLocalEnvironment)) {
8167 4 : state.dataSurface->SurfLocalEnvironment.allocate(state.dataSurface->TotSurfLocalEnv);
8168 : }
8169 :
8170 126 : for (int Loop = 1; Loop <= state.dataSurface->TotSurfLocalEnv; ++Loop) {
8171 :
8172 122 : auto &SurfLocalEnv = state.dataSurface->SurfLocalEnvironment(Loop);
8173 :
8174 244 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
8175 : cCurrentModuleObject,
8176 : Loop,
8177 122 : state.dataIPShortCut->cAlphaArgs,
8178 : NumAlpha,
8179 122 : state.dataIPShortCut->rNumericArgs,
8180 : NumNumeric,
8181 : IOStat,
8182 122 : state.dataIPShortCut->lNumericFieldBlanks,
8183 122 : state.dataIPShortCut->lAlphaFieldBlanks,
8184 122 : state.dataIPShortCut->cAlphaFieldNames,
8185 122 : state.dataIPShortCut->cNumericFieldNames);
8186 122 : Util::IsNameEmpty(state, state.dataIPShortCut->cAlphaArgs(1), cCurrentModuleObject, ErrorsFound);
8187 :
8188 122 : SurfLocalEnv.Name = state.dataIPShortCut->cAlphaArgs(1);
8189 :
8190 : // Assign surface number
8191 122 : int SurfNum = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(2), state.dataSurface->Surface);
8192 122 : if (SurfNum == 0) {
8193 0 : ShowSevereError(state,
8194 0 : format("{} {} = \"{}\", object. Illegal value for \"{}\" has been found.",
8195 : RoutineName,
8196 : cCurrentModuleObject,
8197 0 : SurfLocalEnv.Name,
8198 0 : state.dataIPShortCut->cAlphaFieldNames(2)));
8199 0 : ShowContinueError(state,
8200 0 : format("{} entered value = \"{}\", no corresponding surface (ref BuildingSurface:Detailed) has been "
8201 : "found in the input file.",
8202 0 : state.dataIPShortCut->cAlphaFieldNames(2),
8203 0 : state.dataIPShortCut->cAlphaArgs(2)));
8204 0 : ErrorsFound = true;
8205 : } else {
8206 122 : SurfLocalEnv.SurfPtr = SurfNum;
8207 : }
8208 :
8209 : // Assign Sunlit Fraction Schedule number
8210 122 : if (!state.dataIPShortCut->lAlphaFieldBlanks(3)) {
8211 102 : int SunlitFracSchedNum = GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(3));
8212 102 : if (SunlitFracSchedNum == 0) {
8213 0 : ShowSevereError(state,
8214 0 : format("{} {} = \"{}\", object. Illegal value for \"{}\" has been found.",
8215 : RoutineName,
8216 : cCurrentModuleObject,
8217 0 : SurfLocalEnv.Name,
8218 0 : state.dataIPShortCut->cAlphaFieldNames(3)));
8219 0 : ShowContinueError(
8220 : state,
8221 0 : format("{} entered value = \"{}\", no corresponding sunlit fraction schedule has been found in the input file.",
8222 0 : state.dataIPShortCut->cAlphaFieldNames(3),
8223 0 : state.dataIPShortCut->cAlphaArgs(3)));
8224 0 : ErrorsFound = true;
8225 : } else {
8226 102 : SurfLocalEnv.SunlitFracSchedPtr = SunlitFracSchedNum;
8227 : }
8228 : }
8229 :
8230 : // Assign surrounding surfaces object number;
8231 122 : if (!state.dataIPShortCut->lAlphaFieldBlanks(4)) {
8232 6 : int SurroundingSurfsNum = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(4), state.dataSurface->SurroundingSurfsProperty);
8233 6 : if (SurroundingSurfsNum == 0) {
8234 0 : ShowSevereError(state,
8235 0 : format("{} {} = \"{}\", object. Illegal value for \"{}\" has been found.",
8236 : RoutineName,
8237 : cCurrentModuleObject,
8238 0 : SurfLocalEnv.Name,
8239 0 : state.dataIPShortCut->cAlphaFieldNames(4)));
8240 0 : ShowContinueError(state,
8241 0 : format("{} entered value = \"{}\", no corresponding surrounding surfaces properties has been found "
8242 : "in the input file.",
8243 0 : state.dataIPShortCut->cAlphaFieldNames(4),
8244 0 : state.dataIPShortCut->cAlphaArgs(4)));
8245 0 : ErrorsFound = true;
8246 : } else {
8247 6 : SurfLocalEnv.SurroundingSurfsPtr = SurroundingSurfsNum;
8248 : }
8249 : }
8250 :
8251 : // Assign outdoor air node number;
8252 122 : if (!state.dataIPShortCut->lAlphaFieldBlanks(5)) {
8253 2 : int NodeNum = GetOnlySingleNode(state,
8254 2 : state.dataIPShortCut->cAlphaArgs(5),
8255 : ErrorsFound,
8256 : DataLoopNode::ConnectionObjectType::SurfacePropertyLocalEnvironment,
8257 2 : SurfLocalEnv.Name,
8258 : DataLoopNode::NodeFluidType::Air,
8259 : DataLoopNode::ConnectionType::Inlet,
8260 : NodeInputManager::CompFluidStream::Primary,
8261 : ObjectIsParent);
8262 2 : if (NodeNum == 0 && CheckOutAirNodeNumber(state, NodeNum)) {
8263 0 : ShowSevereError(state,
8264 0 : format("{} {} = \"{}\", object. Illegal value for \"{}\" has been found.",
8265 : RoutineName,
8266 : cCurrentModuleObject,
8267 0 : SurfLocalEnv.Name,
8268 0 : state.dataIPShortCut->cAlphaFieldNames(5)));
8269 0 : ShowContinueError(state,
8270 0 : format("{} entered value = \"{}\", no corresponding outdoor air node has been found in the input file.",
8271 0 : state.dataIPShortCut->cAlphaFieldNames(5),
8272 0 : state.dataIPShortCut->cAlphaArgs(5)));
8273 0 : ErrorsFound = true;
8274 : } else {
8275 2 : SurfLocalEnv.OutdoorAirNodePtr = NodeNum;
8276 : }
8277 : }
8278 :
8279 : // get ground surfaces object number;
8280 122 : if (!state.dataIPShortCut->lAlphaFieldBlanks(6)) {
8281 13 : int GndSurfsNum = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(6), state.dataSurface->GroundSurfsProperty);
8282 13 : if (GndSurfsNum == 0) {
8283 0 : ShowSevereError(state,
8284 0 : format("{} {} = \"{}\", object. Illegal value for \"{}\" has been found.",
8285 : RoutineName,
8286 : cCurrentModuleObject,
8287 0 : SurfLocalEnv.Name,
8288 0 : state.dataIPShortCut->cAlphaFieldNames(6)));
8289 0 : ShowContinueError(
8290 : state,
8291 0 : format("{} entered value = \"{}\", no corresponding ground surfaces object has been found in the input file.",
8292 0 : state.dataIPShortCut->cAlphaFieldNames(6),
8293 0 : state.dataIPShortCut->cAlphaArgs(6)));
8294 0 : ErrorsFound = true;
8295 : } else {
8296 13 : SurfLocalEnv.GroundSurfsPtr = GndSurfsNum;
8297 : }
8298 : }
8299 : }
8300 : }
8301 : // Link surface properties to surface object
8302 46840 : for (int SurfLoop = 1; SurfLoop <= state.dataSurface->TotSurfaces; ++SurfLoop) {
8303 59550 : for (int Loop = 1; Loop <= state.dataSurface->TotSurfLocalEnv; ++Loop) {
8304 13506 : auto &SurfLocalEnv = state.dataSurface->SurfLocalEnvironment(Loop);
8305 13506 : if (SurfLocalEnv.SurfPtr == SurfLoop) {
8306 122 : auto &surface = state.dataSurface->Surface(SurfLoop);
8307 122 : if (SurfLocalEnv.OutdoorAirNodePtr != 0) {
8308 2 : surface.SurfLinkedOutAirNode = SurfLocalEnv.OutdoorAirNodePtr;
8309 : }
8310 122 : if (SurfLocalEnv.SunlitFracSchedPtr != 0) {
8311 102 : surface.SurfSchedExternalShadingFrac = true;
8312 102 : surface.SurfExternalShadingSchInd = SurfLocalEnv.SunlitFracSchedPtr;
8313 : }
8314 122 : if (SurfLocalEnv.SurroundingSurfsPtr != 0) {
8315 6 : surface.SurfHasSurroundingSurfProperty = true;
8316 6 : surface.SurfSurroundingSurfacesNum = SurfLocalEnv.SurroundingSurfsPtr;
8317 6 : surface.ViewFactorSrdSurfs =
8318 6 : state.dataSurface->SurroundingSurfsProperty(surface.SurfSurroundingSurfacesNum).SurfsViewFactorSum;
8319 6 : if (surface.ViewFactorSrdSurfs == 0.0) {
8320 0 : surface.SurfHasSurroundingSurfProperty = false;
8321 : }
8322 : }
8323 122 : if (SurfLocalEnv.GroundSurfsPtr != 0) {
8324 13 : surface.IsSurfPropertyGndSurfacesDefined = true;
8325 13 : surface.UseSurfPropertyGndSurfTemp = true;
8326 13 : surface.UseSurfPropertyGndSurfRefl = true;
8327 13 : surface.SurfPropertyGndSurfIndex = SurfLocalEnv.GroundSurfsPtr;
8328 : }
8329 : }
8330 : }
8331 : }
8332 796 : }
8333 :
8334 796 : void GetSurfaceSrdSurfsData(EnergyPlusData &state, bool &ErrorsFound) // Error flag indicator (true if errors found)
8335 : {
8336 : // SUBROUTINE INFORMATION:
8337 : // AUTHOR X LUO
8338 : // DATE WRITTEN July 2017
8339 : // MODIFIED na
8340 : // RE-ENGINEERED na
8341 :
8342 : // PURPOSE OF THIS SUBROUTINE:
8343 : // load input data for surrounding surfaces properties for exterior surfaces
8344 :
8345 : // Using/Aliasing
8346 : using namespace DataErrorTracking;
8347 : using DataLoopNode::ObjectIsParent;
8348 : using NodeInputManager::GetOnlySingleNode;
8349 : using OutAirNodeManager::CheckOutAirNodeNumber;
8350 : using ScheduleManager::GetScheduleIndex;
8351 :
8352 : // INTERFACE BLOCK SPECIFICATIONS:na
8353 : // DERIVED TYPE DEFINITIONS:na
8354 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
8355 : int NumAlpha;
8356 : int NumNumeric;
8357 : int IOStat;
8358 : int TotSrdSurfProperties;
8359 :
8360 : //-----------------------------------------------------------------------
8361 : // SurfaceProperty:SurroundingSurfaces
8362 : //-----------------------------------------------------------------------
8363 796 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
8364 796 : cCurrentModuleObject = "SurfaceProperty:SurroundingSurfaces";
8365 796 : TotSrdSurfProperties = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
8366 :
8367 796 : if (TotSrdSurfProperties > 0) {
8368 :
8369 2 : if (!allocated(state.dataSurface->SurroundingSurfsProperty)) {
8370 2 : state.dataSurface->SurroundingSurfsProperty.allocate(TotSrdSurfProperties);
8371 : }
8372 :
8373 8 : for (int Loop = 1; Loop <= TotSrdSurfProperties; ++Loop) {
8374 :
8375 6 : auto &SrdSurfsProp = state.dataSurface->SurroundingSurfsProperty(Loop);
8376 :
8377 12 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
8378 : cCurrentModuleObject,
8379 : Loop,
8380 6 : state.dataIPShortCut->cAlphaArgs,
8381 : NumAlpha,
8382 6 : state.dataIPShortCut->rNumericArgs,
8383 : NumNumeric,
8384 : IOStat,
8385 6 : state.dataIPShortCut->lNumericFieldBlanks,
8386 6 : state.dataIPShortCut->lAlphaFieldBlanks,
8387 6 : state.dataIPShortCut->cAlphaFieldNames,
8388 6 : state.dataIPShortCut->cNumericFieldNames);
8389 6 : Util::IsNameEmpty(state, state.dataIPShortCut->cAlphaArgs(1), cCurrentModuleObject, ErrorsFound);
8390 :
8391 : // A1: Name
8392 6 : SrdSurfsProp.Name = state.dataIPShortCut->cAlphaArgs(1);
8393 :
8394 : // N1: sky view factor
8395 6 : if (!state.dataIPShortCut->lNumericFieldBlanks(1)) {
8396 6 : SrdSurfsProp.SkyViewFactor = state.dataIPShortCut->rNumericArgs(1);
8397 6 : SrdSurfsProp.IsSkyViewFactorSet = true;
8398 : }
8399 :
8400 : // A2: sky temp sch name
8401 6 : if (!state.dataIPShortCut->lAlphaFieldBlanks(2)) {
8402 0 : SrdSurfsProp.SkyTempSchNum = GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(2));
8403 : }
8404 :
8405 : // N2: ground view factor
8406 6 : if (!state.dataIPShortCut->lNumericFieldBlanks(2)) {
8407 3 : SrdSurfsProp.GroundViewFactor = state.dataIPShortCut->rNumericArgs(2);
8408 3 : SrdSurfsProp.IsGroundViewFactorSet = true;
8409 : }
8410 :
8411 : // A3: ground temp sch name
8412 6 : if (!state.dataIPShortCut->lAlphaFieldBlanks(3)) {
8413 0 : SrdSurfsProp.GroundTempSchNum = GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(3));
8414 : }
8415 :
8416 : // The object requires at least one srd surface input, each surface requires a set of 3 fields (2 Alpha fields Name and Temp
8417 : // Sch Name and 1 Num fields View Factor)
8418 6 : if (NumAlpha < 5) {
8419 0 : ShowSevereError(state, format("{} = \"{}\" is not defined correctly.", cCurrentModuleObject, SrdSurfsProp.Name));
8420 0 : ShowContinueError(state, "At lease one set of surrounding surface properties should be defined.");
8421 0 : ErrorsFound = true;
8422 0 : continue;
8423 : }
8424 6 : if ((NumAlpha - 3) / 2 != (NumNumeric - 2)) {
8425 0 : ShowSevereError(state, format("{} = \"{}\" is not defined correctly.", cCurrentModuleObject, SrdSurfsProp.Name));
8426 0 : ShowContinueError(state, "Check number of input fields for each surrounding surface.");
8427 0 : ErrorsFound = true;
8428 0 : continue;
8429 : }
8430 : // Read surrounding surfaces properties
8431 6 : SrdSurfsProp.TotSurroundingSurface = NumNumeric - 2;
8432 6 : SrdSurfsProp.SurroundingSurfs.allocate(SrdSurfsProp.TotSurroundingSurface);
8433 14 : for (int SurfLoop = 1; SurfLoop <= SrdSurfsProp.TotSurroundingSurface; ++SurfLoop) {
8434 8 : SrdSurfsProp.SurroundingSurfs(SurfLoop).Name = state.dataIPShortCut->cAlphaArgs(SurfLoop * 2 + 2);
8435 8 : SrdSurfsProp.SurroundingSurfs(SurfLoop).ViewFactor = state.dataIPShortCut->rNumericArgs(SurfLoop + 2);
8436 8 : SrdSurfsProp.SurroundingSurfs(SurfLoop).TempSchNum = GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(SurfLoop * 2 + 3));
8437 8 : SrdSurfsProp.SurfsViewFactorSum += SrdSurfsProp.SurroundingSurfs(SurfLoop).ViewFactor;
8438 : }
8439 : }
8440 : }
8441 796 : }
8442 :
8443 796 : void GetSurfaceGroundSurfsData(EnergyPlusData &state, bool &ErrorsFound)
8444 : {
8445 :
8446 796 : std::string const cCurrentModuleObject = "SurfaceProperty:GroundSurfaces";
8447 796 : state.dataSurface->TotSurfPropGndSurfs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
8448 796 : auto const instances = state.dataInputProcessing->inputProcessor->epJSON.find(cCurrentModuleObject);
8449 796 : if (instances == state.dataInputProcessing->inputProcessor->epJSON.end()) {
8450 795 : if (state.dataSurface->TotSurfPropGndSurfs > 0) ErrorsFound = true;
8451 795 : return;
8452 : } else {
8453 1 : auto &instancesValue = instances.value();
8454 6 : for (auto instance = instancesValue.begin(); instance != instancesValue.end(); ++instance) {
8455 5 : auto const &fields = instance.value();
8456 5 : std::string const &thisObjectName = instance.key();
8457 5 : GroundSurfacesProperty thisGndSurfsObj;
8458 5 : thisGndSurfsObj.Name = Util::makeUPPER(thisObjectName);
8459 5 : state.dataInputProcessing->inputProcessor->markObjectAsUsed(cCurrentModuleObject, thisObjectName);
8460 5 : auto groundSurfaces = fields.find("ground_surfaces");
8461 5 : if (groundSurfaces != fields.end()) {
8462 5 : auto &groundSurfacesArray = groundSurfaces.value();
8463 5 : thisGndSurfsObj.NumGndSurfs = groundSurfacesArray.size();
8464 16 : for (auto &groundSurface : groundSurfacesArray) {
8465 11 : GroundSurfacesData thisGndSurf;
8466 11 : auto GndSurfName = groundSurface.find("ground_surface_name");
8467 11 : if (GndSurfName != groundSurface.end()) {
8468 11 : std::string ground_surf_name = GndSurfName.value().get<std::string>();
8469 11 : if (!ground_surf_name.empty()) {
8470 11 : thisGndSurf.Name = Util::makeUPPER(ground_surf_name);
8471 : }
8472 11 : }
8473 11 : auto groundSurfViewFactor = groundSurface.find("ground_surface_view_factor");
8474 11 : if (groundSurfViewFactor != groundSurface.end()) {
8475 11 : thisGndSurf.ViewFactor = groundSurfViewFactor.value().get<Real64>();
8476 11 : thisGndSurfsObj.IsGroundViewFactorSet = true;
8477 : }
8478 11 : auto TempSchName = groundSurface.find("ground_surface_temperature_schedule_name");
8479 11 : if (TempSchName != groundSurface.end()) {
8480 10 : std::string gnd_surf_TempSchName = TempSchName.value().get<std::string>();
8481 10 : if (!gnd_surf_TempSchName.empty()) {
8482 10 : thisGndSurf.TempSchPtr = ScheduleManager::GetScheduleIndex(state, Util::makeUPPER(gnd_surf_TempSchName));
8483 : }
8484 10 : }
8485 11 : auto ReflSchName = groundSurface.find("ground_surface_reflectance_schedule_name");
8486 11 : if (ReflSchName != groundSurface.end()) {
8487 10 : std::string gnd_surf_ReflSchName = ReflSchName.value().get<std::string>();
8488 10 : if (!gnd_surf_ReflSchName.empty()) {
8489 10 : thisGndSurf.ReflSchPtr = ScheduleManager::GetScheduleIndex(state, Util::makeUPPER(gnd_surf_ReflSchName));
8490 : }
8491 10 : }
8492 11 : thisGndSurfsObj.GndSurfs.push_back(thisGndSurf);
8493 16 : }
8494 : }
8495 16 : for (int gSurfNum = 1; gSurfNum <= thisGndSurfsObj.NumGndSurfs; gSurfNum++) {
8496 11 : thisGndSurfsObj.SurfsViewFactorSum += thisGndSurfsObj.GndSurfs(gSurfNum).ViewFactor;
8497 : }
8498 5 : state.dataSurface->GroundSurfsProperty.push_back(thisGndSurfsObj);
8499 6 : }
8500 : }
8501 : // set report variables
8502 1 : if (state.dataSurface->TotSurfPropGndSurfs > 0) {
8503 6 : for (int Loop = 1; Loop <= state.dataSurface->TotSurfPropGndSurfs; Loop++) {
8504 5 : bool SetTempSchReportVar = true;
8505 5 : bool SetReflSchReportVar = true;
8506 5 : auto &thisGndSurfsObj = state.dataSurface->GroundSurfsProperty(Loop);
8507 16 : for (int gSurfNum = 1; gSurfNum <= thisGndSurfsObj.NumGndSurfs; gSurfNum++) {
8508 11 : if (thisGndSurfsObj.GndSurfs(gSurfNum).TempSchPtr != 0 && SetTempSchReportVar) {
8509 8 : SetupOutputVariable(state,
8510 : "Surfaces Property Ground Surfaces Average Temperature",
8511 : Constant::Units::C,
8512 4 : thisGndSurfsObj.SurfsTempAvg,
8513 : OutputProcessor::TimeStepType::Zone,
8514 : OutputProcessor::StoreType::Average,
8515 4 : thisGndSurfsObj.Name);
8516 4 : SetTempSchReportVar = false;
8517 : }
8518 11 : if (thisGndSurfsObj.GndSurfs(gSurfNum).ReflSchPtr != 0 && SetReflSchReportVar) {
8519 8 : SetupOutputVariable(state,
8520 : "Surfaces Property Ground Surfaces Average Reflectance",
8521 : Constant::Units::None,
8522 4 : thisGndSurfsObj.SurfsReflAvg,
8523 : OutputProcessor::TimeStepType::Zone,
8524 : OutputProcessor::StoreType::Average,
8525 4 : thisGndSurfsObj.Name);
8526 4 : SetReflSchReportVar = false;
8527 : }
8528 : }
8529 : }
8530 : }
8531 1591 : }
8532 :
8533 796 : void GetSurfaceHeatTransferAlgorithmOverrides(EnergyPlusData &state, bool &ErrorsFound)
8534 : {
8535 :
8536 : // SUBROUTINE INFORMATION:
8537 : // AUTHOR B. Griffith, portions from ApplyConvectionValue by Linda Lawrie
8538 : // DATE WRITTEN July 2012
8539 : // MODIFIED na
8540 : // RE-ENGINEERED na
8541 :
8542 : // PURPOSE OF THIS SUBROUTINE:
8543 : // <description>
8544 :
8545 : // Using/Aliasing
8546 :
8547 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
8548 : int CountHTAlgoObjectsSingleSurf;
8549 : int CountHTAlgoObjectsMultiSurf;
8550 : int CountHTAlgoObjectsSurfList;
8551 : int IOStatus; // Used in GetObjectItem
8552 796 : bool ErrorsFoundSingleSurf(false);
8553 796 : bool ErrorsFoundMultiSurf(false);
8554 796 : bool ErrorsFoundSurfList(false);
8555 796 : bool ErrorsFoundByConstruct(false);
8556 : DataSurfaces::HeatTransferModel tmpAlgoInput;
8557 : int Item;
8558 : int Item1;
8559 : int NumAlphas;
8560 : int NumNumbers;
8561 : int Found;
8562 : bool SurfacesOfType;
8563 : int SurfNum;
8564 : // INTEGER :: Index
8565 : int NumEMPDMat;
8566 : int NumPCMat;
8567 : int NumVTCMat;
8568 : int NumHAMTMat1;
8569 : int NumHAMTMat2;
8570 : int NumHAMTMat3;
8571 : int NumHAMTMat4;
8572 : int NumHAMTMat5;
8573 : int NumHAMTMat6;
8574 : int SumHAMTMat;
8575 : bool msgneeded;
8576 :
8577 796 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
8578 796 : cCurrentModuleObject = "SurfaceProperty:HeatBalanceSourceTerm";
8579 796 : int CountAddHeatSourceSurf = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
8580 :
8581 800 : for (Item = 1; Item <= CountAddHeatSourceSurf; ++Item) {
8582 8 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
8583 : cCurrentModuleObject,
8584 : Item,
8585 4 : state.dataIPShortCut->cAlphaArgs,
8586 : NumAlphas,
8587 4 : state.dataIPShortCut->rNumericArgs,
8588 : NumNumbers,
8589 : IOStatus,
8590 4 : state.dataIPShortCut->lNumericFieldBlanks,
8591 4 : state.dataIPShortCut->lAlphaFieldBlanks,
8592 4 : state.dataIPShortCut->cAlphaFieldNames,
8593 4 : state.dataIPShortCut->cNumericFieldNames);
8594 4 : Found = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(1), state.dataSurface->Surface, state.dataSurface->TotSurfaces);
8595 :
8596 4 : if (Found == 0) {
8597 0 : ShowSevereError(state,
8598 0 : format("{}=\"{}\", did not find matching surface.", cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
8599 0 : ErrorsFound = true;
8600 8 : } else if (state.dataSurface->Surface(Found).InsideHeatSourceTermSchedule ||
8601 4 : state.dataSurface->Surface(Found).OutsideHeatSourceTermSchedule) {
8602 0 : ShowSevereError(state,
8603 0 : format("{}=\"{}\", multiple SurfaceProperty:HeatBalanceSourceTerm objects applied to the same surface.",
8604 : cCurrentModuleObject,
8605 0 : state.dataIPShortCut->cAlphaArgs(1)));
8606 0 : ErrorsFound = true;
8607 : }
8608 :
8609 4 : if (!state.dataIPShortCut->lAlphaFieldBlanks(2)) {
8610 1 : state.dataSurface->Surface(Found).InsideHeatSourceTermSchedule =
8611 1 : ScheduleManager::GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(2));
8612 1 : if (state.dataSurface->Surface(Found).InsideHeatSourceTermSchedule == 0) {
8613 0 : ShowSevereError(state,
8614 0 : format("{}=\"{}\", cannot find the matching Schedule: {}=\"{}",
8615 : cCurrentModuleObject,
8616 0 : state.dataIPShortCut->cAlphaArgs(1),
8617 0 : state.dataIPShortCut->cAlphaFieldNames(2),
8618 0 : state.dataIPShortCut->cAlphaArgs(2)));
8619 0 : ErrorsFound = true;
8620 : } else {
8621 1 : state.dataSurface->allInsideSourceSurfaceList.emplace_back(Found);
8622 : }
8623 : }
8624 :
8625 4 : if (!state.dataIPShortCut->lAlphaFieldBlanks(3)) {
8626 3 : state.dataSurface->Surface(Found).OutsideHeatSourceTermSchedule =
8627 3 : ScheduleManager::GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(3));
8628 3 : if (state.dataSurface->Surface(Found).OutsideHeatSourceTermSchedule == 0) {
8629 0 : ShowSevereError(state,
8630 0 : format("{}=\"{}\", cannot find the matching Schedule: {}=\"{}",
8631 : cCurrentModuleObject,
8632 0 : state.dataIPShortCut->cAlphaArgs(1),
8633 0 : state.dataIPShortCut->cAlphaFieldNames(3),
8634 0 : state.dataIPShortCut->cAlphaArgs(3)));
8635 0 : ErrorsFound = true;
8636 3 : } else if (state.dataSurface->Surface(Found).OSCPtr > 0) {
8637 0 : ShowSevereError(state,
8638 0 : format("{}=\"SurfaceProperty:HeatBalanceSourceTerm\", cannot be specified for OtherSideCoefficient Surface={}",
8639 : cCurrentModuleObject,
8640 0 : state.dataIPShortCut->cAlphaArgs(1)));
8641 0 : ErrorsFound = true;
8642 : } else {
8643 3 : state.dataSurface->allOutsideSourceSurfaceList.emplace_back(Found);
8644 : }
8645 : }
8646 :
8647 5 : if (state.dataSurface->Surface(Found).OutsideHeatSourceTermSchedule == 0 &&
8648 1 : state.dataSurface->Surface(Found).InsideHeatSourceTermSchedule == 0) {
8649 0 : ShowSevereError(
8650 : state,
8651 0 : format("{}=\"{}\", no schedule defined for additional heat source.", cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
8652 0 : ErrorsFound = true;
8653 : }
8654 : }
8655 :
8656 : // first initialize each heat transfer surface with the overall model type, array assignment
8657 46840 : for (auto &e : state.dataSurface->Surface)
8658 46840 : e.HeatTransferAlgorithm = state.dataHeatBal->OverallHeatTransferSolutionAlgo;
8659 :
8660 796 : cCurrentModuleObject = "SurfaceProperty:HeatTransferAlgorithm";
8661 796 : CountHTAlgoObjectsSingleSurf = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
8662 :
8663 796 : cCurrentModuleObject = "SurfaceProperty:HeatTransferAlgorithm";
8664 798 : for (Item = 1; Item <= CountHTAlgoObjectsSingleSurf; ++Item) {
8665 4 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
8666 : cCurrentModuleObject,
8667 : Item,
8668 2 : state.dataIPShortCut->cAlphaArgs,
8669 : NumAlphas,
8670 2 : state.dataIPShortCut->rNumericArgs,
8671 : NumNumbers,
8672 : IOStatus,
8673 2 : state.dataIPShortCut->lNumericFieldBlanks,
8674 2 : state.dataIPShortCut->lAlphaFieldBlanks,
8675 2 : state.dataIPShortCut->cAlphaFieldNames,
8676 2 : state.dataIPShortCut->cNumericFieldNames);
8677 2 : ErrorsFoundSingleSurf = false;
8678 2 : Found = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(1), state.dataSurface->Surface, state.dataSurface->TotSurfaces);
8679 :
8680 2 : if (Found == 0) {
8681 0 : ShowSevereError(state,
8682 0 : format("{}=\"{}\", did not find matching surface.", cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
8683 0 : ErrorsFoundSingleSurf = true;
8684 : }
8685 :
8686 : {
8687 2 : std::string const &SELECT_CASE_var = state.dataIPShortCut->cAlphaArgs(2);
8688 :
8689 2 : if (SELECT_CASE_var == "CONDUCTIONTRANSFERFUNCTION") {
8690 0 : tmpAlgoInput = DataSurfaces::HeatTransferModel::CTF;
8691 0 : state.dataHeatBal->AnyCTF = true;
8692 2 : } else if (SELECT_CASE_var == "MOISTUREPENETRATIONDEPTHCONDUCTIONTRANSFERFUNCTION") {
8693 1 : tmpAlgoInput = DataSurfaces::HeatTransferModel::EMPD;
8694 1 : state.dataHeatBal->AnyEMPD = true;
8695 1 : } else if (SELECT_CASE_var == "COMBINEDHEATANDMOISTUREFINITEELEMENT") {
8696 0 : tmpAlgoInput = DataSurfaces::HeatTransferModel::HAMT;
8697 0 : state.dataHeatBal->AnyHAMT = true;
8698 1 : } else if (SELECT_CASE_var == "CONDUCTIONFINITEDIFFERENCE") {
8699 1 : tmpAlgoInput = DataSurfaces::HeatTransferModel::CondFD;
8700 1 : state.dataHeatBal->AnyCondFD = true;
8701 : } else {
8702 0 : ShowSevereError(state,
8703 0 : format("{}=\"{}\", invalid {}=\"{}",
8704 : cCurrentModuleObject,
8705 0 : state.dataIPShortCut->cAlphaArgs(1),
8706 0 : state.dataIPShortCut->cAlphaFieldNames(2),
8707 0 : state.dataIPShortCut->cAlphaArgs(2)));
8708 0 : ErrorsFoundSingleSurf = true;
8709 : }
8710 : }
8711 :
8712 2 : if (!ErrorsFoundSingleSurf) {
8713 2 : state.dataSurface->Surface(Found).HeatTransferAlgorithm = tmpAlgoInput;
8714 : } else {
8715 0 : ErrorsFound = true;
8716 : }
8717 : } // single surface heat transfer algorithm override
8718 :
8719 796 : cCurrentModuleObject = "SurfaceProperty:HeatTransferAlgorithm:MultipleSurface";
8720 796 : CountHTAlgoObjectsMultiSurf = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
8721 :
8722 796 : for (Item = 1; Item <= CountHTAlgoObjectsMultiSurf; ++Item) {
8723 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
8724 : cCurrentModuleObject,
8725 : Item,
8726 0 : state.dataIPShortCut->cAlphaArgs,
8727 : NumAlphas,
8728 0 : state.dataIPShortCut->rNumericArgs,
8729 : NumNumbers,
8730 : IOStatus,
8731 0 : state.dataIPShortCut->lNumericFieldBlanks,
8732 0 : state.dataIPShortCut->lAlphaFieldBlanks,
8733 0 : state.dataIPShortCut->cAlphaFieldNames,
8734 0 : state.dataIPShortCut->cNumericFieldNames);
8735 0 : ErrorsFoundMultiSurf = false;
8736 : {
8737 0 : std::string const &SELECT_CASE_var = state.dataIPShortCut->cAlphaArgs(3);
8738 :
8739 0 : if (SELECT_CASE_var == "CONDUCTIONTRANSFERFUNCTION") {
8740 0 : tmpAlgoInput = DataSurfaces::HeatTransferModel::CTF;
8741 0 : state.dataHeatBal->AnyCTF = true;
8742 0 : } else if (SELECT_CASE_var == "MOISTUREPENETRATIONDEPTHCONDUCTIONTRANSFERFUNCTION") {
8743 0 : tmpAlgoInput = DataSurfaces::HeatTransferModel::EMPD;
8744 0 : state.dataHeatBal->AnyEMPD = true;
8745 0 : } else if (SELECT_CASE_var == "COMBINEDHEATANDMOISTUREFINITEELEMENT") {
8746 0 : tmpAlgoInput = DataSurfaces::HeatTransferModel::HAMT;
8747 0 : state.dataHeatBal->AnyHAMT = true;
8748 0 : } else if (SELECT_CASE_var == "CONDUCTIONFINITEDIFFERENCE") {
8749 0 : tmpAlgoInput = DataSurfaces::HeatTransferModel::CondFD;
8750 0 : state.dataHeatBal->AnyCondFD = true;
8751 : } else {
8752 0 : ShowSevereError(state,
8753 0 : format("{}=\"{}\", invalid {}=\"{}",
8754 : cCurrentModuleObject,
8755 0 : state.dataIPShortCut->cAlphaArgs(1),
8756 0 : state.dataIPShortCut->cAlphaFieldNames(3),
8757 0 : state.dataIPShortCut->cAlphaArgs(3)));
8758 0 : ErrorsFoundMultiSurf = true;
8759 : }
8760 : }
8761 :
8762 : {
8763 0 : std::string const &SELECT_CASE_var = state.dataIPShortCut->cAlphaArgs(2);
8764 :
8765 0 : if (SELECT_CASE_var == "ALLEXTERIORSURFACES") {
8766 0 : SurfacesOfType = false;
8767 0 : for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
8768 0 : auto &surf = state.dataSurface->Surface(SurfNum);
8769 0 : if (!surf.HeatTransSurf) continue;
8770 0 : if (surf.ExtBoundCond > 0) continue; // Interior surfaces
8771 0 : if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) continue;
8772 0 : SurfacesOfType = true;
8773 0 : surf.HeatTransferAlgorithm = tmpAlgoInput;
8774 : }
8775 :
8776 0 : } else if (SELECT_CASE_var == "ALLEXTERIORWALLS") {
8777 0 : SurfacesOfType = false;
8778 0 : for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
8779 0 : auto &surf = state.dataSurface->Surface(SurfNum);
8780 0 : if (!surf.HeatTransSurf) continue;
8781 0 : if (surf.ExtBoundCond > 0) continue; // Interior surfaces
8782 :
8783 0 : if (surf.Class != SurfaceClass::Wall) continue;
8784 0 : if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) continue;
8785 0 : SurfacesOfType = true;
8786 0 : surf.HeatTransferAlgorithm = tmpAlgoInput;
8787 : }
8788 :
8789 0 : } else if (SELECT_CASE_var == "ALLEXTERIORROOFS") {
8790 0 : SurfacesOfType = false;
8791 0 : for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
8792 0 : auto &surf = state.dataSurface->Surface(SurfNum);
8793 0 : if (!surf.HeatTransSurf) continue;
8794 0 : if (surf.ExtBoundCond > 0) continue; // Interior surfaces
8795 0 : if (surf.Class != SurfaceClass::Roof) continue;
8796 0 : if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) continue;
8797 0 : SurfacesOfType = true;
8798 0 : surf.HeatTransferAlgorithm = tmpAlgoInput;
8799 : }
8800 :
8801 0 : } else if (SELECT_CASE_var == "ALLEXTERIORFLOORS") {
8802 0 : SurfacesOfType = false;
8803 0 : for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
8804 0 : auto &surf = state.dataSurface->Surface(SurfNum);
8805 0 : if (!surf.HeatTransSurf) continue;
8806 0 : if (surf.ExtBoundCond > 0) continue; // Interior surfaces
8807 0 : if (surf.Class != SurfaceClass::Floor) continue;
8808 0 : if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) continue;
8809 0 : SurfacesOfType = true;
8810 0 : surf.HeatTransferAlgorithm = tmpAlgoInput;
8811 : }
8812 :
8813 0 : } else if (SELECT_CASE_var == "ALLGROUNDCONTACTSURFACES") {
8814 0 : SurfacesOfType = false;
8815 0 : for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
8816 0 : auto &surf = state.dataSurface->Surface(SurfNum);
8817 0 : if (!surf.HeatTransSurf) continue;
8818 0 : if (surf.ExtBoundCond != Ground) continue; // ground BC
8819 0 : if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) continue;
8820 0 : SurfacesOfType = true;
8821 0 : surf.HeatTransferAlgorithm = tmpAlgoInput;
8822 : }
8823 0 : } else if (SELECT_CASE_var == "ALLINTERIORSURFACES") {
8824 0 : SurfacesOfType = false;
8825 0 : for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
8826 0 : auto &surf = state.dataSurface->Surface(SurfNum);
8827 0 : if (!surf.HeatTransSurf) continue;
8828 0 : if (surf.ExtBoundCond <= 0) continue; // Exterior surfaces
8829 0 : if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) continue;
8830 0 : SurfacesOfType = true;
8831 0 : surf.HeatTransferAlgorithm = tmpAlgoInput;
8832 : }
8833 :
8834 0 : } else if (SELECT_CASE_var == "ALLINTERIORWALLS") {
8835 0 : SurfacesOfType = false;
8836 0 : for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
8837 0 : auto &surf = state.dataSurface->Surface(SurfNum);
8838 0 : if (!surf.HeatTransSurf) continue;
8839 0 : if (surf.ExtBoundCond <= 0) continue; // Exterior surfaces
8840 0 : if (surf.Class != SurfaceClass::Wall) continue;
8841 0 : if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) continue;
8842 0 : SurfacesOfType = true;
8843 0 : surf.HeatTransferAlgorithm = tmpAlgoInput;
8844 : }
8845 :
8846 0 : } else if ((SELECT_CASE_var == "ALLINTERIORROOFS") || (SELECT_CASE_var == "ALLINTERIORCEILINGS")) {
8847 0 : SurfacesOfType = false;
8848 0 : for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
8849 0 : auto &surf = state.dataSurface->Surface(SurfNum);
8850 0 : if (!surf.HeatTransSurf) continue;
8851 0 : if (surf.ExtBoundCond <= 0) continue; // Exterior surfaces
8852 0 : if (surf.Class != SurfaceClass::Roof) continue;
8853 0 : if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) continue;
8854 0 : SurfacesOfType = true;
8855 0 : surf.HeatTransferAlgorithm = tmpAlgoInput;
8856 : }
8857 :
8858 0 : } else if (SELECT_CASE_var == "ALLINTERIORFLOORS") {
8859 0 : SurfacesOfType = false;
8860 0 : for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
8861 0 : auto &surf = state.dataSurface->Surface(SurfNum);
8862 0 : if (!surf.HeatTransSurf) continue;
8863 0 : if (surf.ExtBoundCond <= 0) continue; // Exterior surfaces
8864 0 : if (surf.Class != SurfaceClass::Floor) continue;
8865 0 : if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) continue;
8866 0 : SurfacesOfType = true;
8867 0 : surf.HeatTransferAlgorithm = tmpAlgoInput;
8868 : }
8869 : } else {
8870 0 : SurfacesOfType = false;
8871 0 : ShowSevereError(state,
8872 0 : format("{}=\"{}\", invalid {}=\"{}",
8873 : cCurrentModuleObject,
8874 0 : state.dataIPShortCut->cAlphaArgs(1),
8875 0 : state.dataIPShortCut->cAlphaFieldNames(2),
8876 0 : state.dataIPShortCut->cAlphaArgs(2)));
8877 0 : ErrorsFoundMultiSurf = true;
8878 : }
8879 : }
8880 :
8881 0 : if (!SurfacesOfType) {
8882 0 : ShowWarningError(
8883 : state,
8884 0 : format("In {}=\"{}\", for Multiple Surface Assignment=\"{}\", there were no surfaces of that type found for assignment.",
8885 : cCurrentModuleObject,
8886 0 : state.dataIPShortCut->cAlphaArgs(1),
8887 0 : state.dataIPShortCut->cAlphaArgs(2)));
8888 : }
8889 0 : if (ErrorsFoundMultiSurf) ErrorsFound = true;
8890 :
8891 : } // multi surface heat transfer algo override
8892 :
8893 796 : cCurrentModuleObject = "SurfaceProperty:HeatTransferAlgorithm:SurfaceList";
8894 796 : CountHTAlgoObjectsSurfList = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
8895 797 : for (Item = 1; Item <= CountHTAlgoObjectsSurfList; ++Item) {
8896 2 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
8897 : cCurrentModuleObject,
8898 : Item,
8899 1 : state.dataIPShortCut->cAlphaArgs,
8900 : NumAlphas,
8901 1 : state.dataIPShortCut->rNumericArgs,
8902 : NumNumbers,
8903 : IOStatus,
8904 1 : state.dataIPShortCut->lNumericFieldBlanks,
8905 1 : state.dataIPShortCut->lAlphaFieldBlanks,
8906 1 : state.dataIPShortCut->cAlphaFieldNames,
8907 1 : state.dataIPShortCut->cNumericFieldNames);
8908 1 : ErrorsFoundSurfList = false;
8909 : {
8910 1 : std::string const &SELECT_CASE_var = state.dataIPShortCut->cAlphaArgs(2);
8911 :
8912 1 : if (SELECT_CASE_var == "CONDUCTIONTRANSFERFUNCTION") {
8913 0 : tmpAlgoInput = DataSurfaces::HeatTransferModel::CTF;
8914 0 : state.dataHeatBal->AnyCTF = true;
8915 1 : } else if (SELECT_CASE_var == "MOISTUREPENETRATIONDEPTHCONDUCTIONTRANSFERFUNCTION") {
8916 1 : tmpAlgoInput = DataSurfaces::HeatTransferModel::EMPD;
8917 1 : state.dataHeatBal->AnyEMPD = true;
8918 0 : } else if (SELECT_CASE_var == "COMBINEDHEATANDMOISTUREFINITEELEMENT") {
8919 0 : tmpAlgoInput = DataSurfaces::HeatTransferModel::HAMT;
8920 0 : state.dataHeatBal->AnyHAMT = true;
8921 0 : } else if (SELECT_CASE_var == "CONDUCTIONFINITEDIFFERENCE") {
8922 0 : tmpAlgoInput = DataSurfaces::HeatTransferModel::CondFD;
8923 0 : state.dataHeatBal->AnyCondFD = true;
8924 : } else {
8925 0 : ShowSevereError(state,
8926 0 : format("{}=\"{}\", invalid {}=\"{}",
8927 : cCurrentModuleObject,
8928 0 : state.dataIPShortCut->cAlphaArgs(1),
8929 0 : state.dataIPShortCut->cAlphaFieldNames(2),
8930 0 : state.dataIPShortCut->cAlphaArgs(2)));
8931 0 : ErrorsFoundSurfList = true;
8932 : }
8933 : }
8934 :
8935 3 : for (Item1 = 3; Item1 <= NumAlphas; ++Item1) {
8936 :
8937 2 : Found = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(Item1), state.dataSurface->Surface, state.dataSurface->TotSurfaces);
8938 :
8939 2 : if (Found == 0) {
8940 0 : ShowSevereError(state,
8941 0 : format("{}=\"{}\", did not find matching surface.", cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
8942 0 : ShowContinueError(state, format("Name of surface not found = \"{}\"", state.dataIPShortCut->cAlphaArgs(Item1)));
8943 0 : ErrorsFoundSurfList = true;
8944 : }
8945 :
8946 2 : if (!ErrorsFoundSurfList) {
8947 2 : state.dataSurface->Surface(Found).HeatTransferAlgorithm = tmpAlgoInput;
8948 : } else {
8949 0 : ErrorsFound = true;
8950 : }
8951 : }
8952 : }
8953 :
8954 796 : cCurrentModuleObject = "SurfaceProperty:HeatTransferAlgorithm:Construction";
8955 796 : CountHTAlgoObjectsSurfList = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
8956 797 : for (Item = 1; Item <= CountHTAlgoObjectsSurfList; ++Item) {
8957 2 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
8958 : cCurrentModuleObject,
8959 : Item,
8960 1 : state.dataIPShortCut->cAlphaArgs,
8961 : NumAlphas,
8962 1 : state.dataIPShortCut->rNumericArgs,
8963 : NumNumbers,
8964 : IOStatus,
8965 1 : state.dataIPShortCut->lNumericFieldBlanks,
8966 1 : state.dataIPShortCut->lAlphaFieldBlanks,
8967 1 : state.dataIPShortCut->cAlphaFieldNames,
8968 1 : state.dataIPShortCut->cNumericFieldNames);
8969 1 : ErrorsFoundByConstruct = false;
8970 : {
8971 1 : std::string const &SELECT_CASE_var = state.dataIPShortCut->cAlphaArgs(2);
8972 :
8973 1 : if (SELECT_CASE_var == "CONDUCTIONTRANSFERFUNCTION") {
8974 0 : tmpAlgoInput = DataSurfaces::HeatTransferModel::CTF;
8975 0 : state.dataHeatBal->AnyCTF = true;
8976 1 : } else if (SELECT_CASE_var == "MOISTUREPENETRATIONDEPTHCONDUCTIONTRANSFERFUNCTION") {
8977 0 : tmpAlgoInput = DataSurfaces::HeatTransferModel::EMPD;
8978 0 : state.dataHeatBal->AnyEMPD = true;
8979 1 : } else if (SELECT_CASE_var == "COMBINEDHEATANDMOISTUREFINITEELEMENT") {
8980 1 : tmpAlgoInput = DataSurfaces::HeatTransferModel::HAMT;
8981 1 : state.dataHeatBal->AnyHAMT = true;
8982 0 : } else if (SELECT_CASE_var == "CONDUCTIONFINITEDIFFERENCE") {
8983 0 : tmpAlgoInput = DataSurfaces::HeatTransferModel::CondFD;
8984 0 : state.dataHeatBal->AnyCondFD = true;
8985 : } else {
8986 0 : ShowSevereError(state,
8987 0 : format("{}=\"{}\", invalid {}=\"{}",
8988 : cCurrentModuleObject,
8989 0 : state.dataIPShortCut->cAlphaArgs(1),
8990 0 : state.dataIPShortCut->cAlphaFieldNames(2),
8991 0 : state.dataIPShortCut->cAlphaArgs(2)));
8992 0 : ErrorsFoundByConstruct = true;
8993 : }
8994 : }
8995 :
8996 1 : Found = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(3), state.dataConstruction->Construct, state.dataHeatBal->TotConstructs);
8997 1 : if (Found == 0) {
8998 0 : ShowSevereError(state,
8999 0 : format("{}=\"{}\", invalid {}=\"{}",
9000 : cCurrentModuleObject,
9001 0 : state.dataIPShortCut->cAlphaArgs(1),
9002 0 : state.dataIPShortCut->cAlphaFieldNames(3),
9003 0 : state.dataIPShortCut->cAlphaArgs(3)));
9004 0 : ErrorsFoundByConstruct = true;
9005 : }
9006 :
9007 1 : if (!ErrorsFoundByConstruct) {
9008 7 : for (Item1 = 1; Item1 <= state.dataSurface->TotSurfaces; ++Item1) {
9009 6 : if (state.dataSurface->Surface(Item1).Construction == Found) {
9010 1 : state.dataSurface->Surface(Item1).HeatTransferAlgorithm = tmpAlgoInput;
9011 : }
9012 : }
9013 : }
9014 : }
9015 :
9016 : // Change algorithm for Kiva and air boundary foundation surfaces
9017 46840 : for (auto &surf : state.dataSurface->Surface) {
9018 46044 : if (surf.ExtBoundCond == KivaFoundation) {
9019 38 : surf.HeatTransferAlgorithm = DataSurfaces::HeatTransferModel::Kiva;
9020 38 : state.dataHeatBal->AnyKiva = true;
9021 : }
9022 796 : }
9023 :
9024 : // test for missing materials for algorithms selected
9025 796 : NumEMPDMat = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "MaterialProperty:MoisturePenetrationDepth:Settings");
9026 796 : NumPCMat = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "MaterialProperty:PhaseChange") +
9027 796 : state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "MaterialProperty:PhaseChangeHysteresis");
9028 796 : NumVTCMat = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "MaterialProperty:VariableThermalConductivity");
9029 796 : NumHAMTMat1 = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "MaterialProperty:HeatAndMoistureTransfer:Settings");
9030 : NumHAMTMat2 =
9031 796 : state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "MaterialProperty:HeatAndMoistureTransfer:SorptionIsotherm");
9032 796 : NumHAMTMat3 = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "MaterialProperty:HeatAndMoistureTransfer:Suction");
9033 796 : NumHAMTMat4 = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "MaterialProperty:HeatAndMoistureTransfer:Redistribution");
9034 796 : NumHAMTMat5 = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "MaterialProperty:HeatAndMoistureTransfer:Diffusion");
9035 : NumHAMTMat6 =
9036 796 : state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "MaterialProperty:HeatAndMoistureTransfer:ThermalConductivity");
9037 796 : SumHAMTMat = NumHAMTMat1 + NumHAMTMat2 + NumHAMTMat3 + NumHAMTMat4 + NumHAMTMat5 + NumHAMTMat6;
9038 796 : msgneeded = false;
9039 :
9040 796 : if (NumEMPDMat > 0 && !state.dataHeatBal->AnyEMPD) {
9041 0 : ShowWarningError(state,
9042 0 : format("The input file includes {} MaterialProperty:MoisturePenetrationDepth:Settings objects but the moisture "
9043 : "penetration depth algorithm is not used anywhere.",
9044 : NumEMPDMat));
9045 0 : msgneeded = true;
9046 : }
9047 796 : if (NumPCMat > 0 && !state.dataHeatBal->AnyCondFD) {
9048 0 : ShowWarningError(state,
9049 0 : format("The input file includes {} MaterialProperty:PhaseChange objects but the conduction finite difference algorithm "
9050 : "is not used anywhere.",
9051 : NumPCMat));
9052 0 : msgneeded = true;
9053 : }
9054 796 : if (NumVTCMat > 0 && !state.dataHeatBal->AnyCondFD) {
9055 0 : ShowWarningError(state,
9056 0 : format("The input file includes {} MaterialProperty:VariableThermalConductivity objects but the conduction finite "
9057 : "difference algorithm is not used anywhere.",
9058 : NumVTCMat));
9059 0 : msgneeded = true;
9060 : }
9061 796 : if (SumHAMTMat > 0 && !state.dataHeatBal->AnyHAMT) {
9062 0 : ShowWarningError(state,
9063 0 : format("The input file includes {} MaterialProperty:HeatAndMoistureTransfer:* objects but the combined heat and "
9064 : "moisture finite difference algorithm is not used anywhere.",
9065 : SumHAMTMat));
9066 0 : msgneeded = true;
9067 : }
9068 796 : if (msgneeded) {
9069 0 : ShowContinueError(state, "Previous materials will be ignored due to HeatBalanceAlgorithm choice.");
9070 : }
9071 796 : msgneeded = false;
9072 796 : if (NumEMPDMat == 0 && state.dataHeatBal->AnyEMPD) {
9073 0 : ShowWarningError(state,
9074 : "The moisture penetration depth conduction transfer function algorithm is used but the input file includes no "
9075 : "MaterialProperty:MoisturePenetrationDepth:Settings objects.");
9076 0 : msgneeded = true;
9077 : }
9078 796 : if (SumHAMTMat == 0 && state.dataHeatBal->AnyHAMT) {
9079 0 : ShowWarningError(state,
9080 : "The combined heat and moisture finite element algorithm is used but the input file includes no "
9081 : "MaterialProperty:HeatAndMoistureTransfer:* objects.");
9082 0 : msgneeded = true;
9083 : }
9084 796 : if (msgneeded) {
9085 0 : ShowContinueError(state,
9086 : "Certain materials objects are necessary to achieve proper results with the heat transfer algorithm(s) selected.");
9087 : }
9088 :
9089 : // Write Solution Algorithm to the initialization output file for User Verification
9090 796 : print(state.files.eio,
9091 : "{}\n",
9092 : "! <Surface Heat Transfer Algorithm>, Value {CTF - ConductionTransferFunction | EMPD - "
9093 : "MoisturePenetrationDepthConductionTransferFunction | CondFD - ConductionFiniteDifference | HAMT - "
9094 : "CombinedHeatAndMoistureFiniteElement} - Description,Inside Surface Max Temperature Limit{C}, Surface "
9095 : "Convection Coefficient Lower Limit {W/m2-K}, Surface Convection Coefficient Upper Limit {W/m2-K}");
9096 :
9097 796 : int numberOfHeatTransferAlgosUsed = 0;
9098 : // Formats
9099 : static constexpr std::string_view Format_725("Surface Heat Transfer Algorithm, {},{:.0R},{:.2R},{:.1R}\n");
9100 :
9101 796 : if (state.dataHeatBal->AnyCTF) {
9102 782 : constexpr std::string_view AlgoName = "CTF - ConductionTransferFunction";
9103 782 : ++numberOfHeatTransferAlgosUsed;
9104 782 : print(state.files.eio,
9105 : Format_725,
9106 : AlgoName,
9107 782 : state.dataHeatBalSurf->MaxSurfaceTempLimit,
9108 782 : state.dataHeatBal->LowHConvLimit,
9109 782 : state.dataHeatBal->HighHConvLimit);
9110 : }
9111 796 : if (state.dataHeatBal->AnyEMPD) {
9112 2 : state.dataHeatBal->AllCTF = false;
9113 2 : constexpr std::string_view AlgoName = "EMPD - MoisturePenetrationDepthConductionTransferFunction";
9114 2 : ++numberOfHeatTransferAlgosUsed;
9115 2 : print(state.files.eio,
9116 : Format_725,
9117 : AlgoName,
9118 2 : state.dataHeatBalSurf->MaxSurfaceTempLimit,
9119 2 : state.dataHeatBal->LowHConvLimit,
9120 2 : state.dataHeatBal->HighHConvLimit);
9121 2 : if (state.dataHeatBal->doSpaceHeatBalanceSimulation || state.dataHeatBal->doSpaceHeatBalanceSizing) {
9122 0 : ShowSevereError(
9123 : state,
9124 : "MoisturePenetrationDepthConductionTransferFunction is not supported with ZoneAirHeatBalanceAlgorithm Space Heat Balance.");
9125 0 : ErrorsFound = true;
9126 : }
9127 : }
9128 796 : if (state.dataHeatBal->AnyCondFD) {
9129 12 : state.dataHeatBal->AllCTF = false;
9130 12 : constexpr std::string_view AlgoName = "CondFD - ConductionFiniteDifference";
9131 12 : ++numberOfHeatTransferAlgosUsed;
9132 12 : print(state.files.eio,
9133 : Format_725,
9134 : AlgoName,
9135 12 : state.dataHeatBalSurf->MaxSurfaceTempLimit,
9136 12 : state.dataHeatBal->LowHConvLimit,
9137 12 : state.dataHeatBal->HighHConvLimit);
9138 : }
9139 796 : if (state.dataHeatBal->AnyHAMT) {
9140 3 : state.dataHeatBal->AllCTF = false;
9141 3 : constexpr std::string_view AlgoName = "HAMT - CombinedHeatAndMoistureFiniteElement";
9142 3 : ++numberOfHeatTransferAlgosUsed;
9143 3 : print(state.files.eio,
9144 : Format_725,
9145 : AlgoName,
9146 3 : state.dataHeatBalSurf->MaxSurfaceTempLimit,
9147 3 : state.dataHeatBal->LowHConvLimit,
9148 3 : state.dataHeatBal->HighHConvLimit);
9149 3 : if (state.dataHeatBal->doSpaceHeatBalanceSimulation || state.dataHeatBal->doSpaceHeatBalanceSizing) {
9150 0 : ShowSevereError(state, "CombinedHeatAndMoistureFiniteElement is not supported with ZoneAirHeatBalanceAlgorithm Space Heat Balance.");
9151 0 : ErrorsFound = true;
9152 : }
9153 : }
9154 796 : if (state.dataHeatBal->AnyKiva) {
9155 9 : state.dataHeatBal->AllCTF = false;
9156 9 : constexpr std::string_view AlgoName = "KivaFoundation - TwoDimensionalFiniteDifference";
9157 9 : ++numberOfHeatTransferAlgosUsed;
9158 9 : print(state.files.eio,
9159 : Format_725,
9160 : AlgoName,
9161 9 : state.dataHeatBalSurf->MaxSurfaceTempLimit,
9162 9 : state.dataHeatBal->LowHConvLimit,
9163 9 : state.dataHeatBal->HighHConvLimit);
9164 : }
9165 :
9166 : // Check HeatTransferAlgorithm for interior surfaces
9167 796 : if (numberOfHeatTransferAlgosUsed > 1) {
9168 : int ExtSurfNum;
9169 506 : for (Item = 1; Item <= state.dataSurface->TotSurfaces; ++Item) {
9170 496 : auto &surf = state.dataSurface->Surface(Item);
9171 496 : if (surf.ExtBoundCond > 0) {
9172 280 : if ((surf.HeatTransferAlgorithm == DataSurfaces::HeatTransferModel::Invalid) ||
9173 280 : (surf.HeatTransferAlgorithm == DataSurfaces::HeatTransferModel::None))
9174 0 : continue;
9175 280 : ExtSurfNum = surf.ExtBoundCond;
9176 280 : auto &extSurf = state.dataSurface->Surface(ExtSurfNum);
9177 280 : if (surf.HeatTransferAlgorithm != extSurf.HeatTransferAlgorithm) {
9178 0 : ShowWarningError(state,
9179 : "An interior surface is defined as two surfaces with reverse constructions. The HeatTransferAlgorithm in "
9180 : "both constructions should be same.");
9181 0 : ShowContinueError(state,
9182 0 : format("The HeatTransferAlgorithm of Surface: {}, is {}",
9183 0 : surf.Name,
9184 0 : DataSurfaces::HeatTransAlgoStrs[static_cast<int>(surf.HeatTransferAlgorithm)]));
9185 0 : ShowContinueError(state,
9186 0 : format("The HeatTransferAlgorithm of Surface: {}, is {}",
9187 0 : extSurf.Name,
9188 0 : DataSurfaces::HeatTransAlgoStrs[static_cast<int>(extSurf.HeatTransferAlgorithm)]));
9189 0 : if (surf.HeatTransferAlgorithm > extSurf.HeatTransferAlgorithm) {
9190 0 : ShowContinueError(state,
9191 0 : format("The HeatTransferAlgorithm of Surface: {}, is assigned to {}. Simulation continues.",
9192 0 : extSurf.Name,
9193 0 : DataSurfaces::HeatTransAlgoStrs[static_cast<int>(surf.HeatTransferAlgorithm)]));
9194 0 : extSurf.HeatTransferAlgorithm = surf.HeatTransferAlgorithm;
9195 : } else {
9196 0 : ShowContinueError(state,
9197 0 : format("The HeatTransferAlgorithm of Surface: {}, is assigned to {}. Simulation continues.",
9198 0 : surf.Name,
9199 0 : DataSurfaces::HeatTransAlgoStrs[static_cast<int>(extSurf.HeatTransferAlgorithm)]));
9200 0 : surf.HeatTransferAlgorithm = extSurf.HeatTransferAlgorithm;
9201 : }
9202 : }
9203 : }
9204 : }
9205 : }
9206 :
9207 : // Assign model type to windows, shading surfaces, and TDDs
9208 46840 : for (Item = 1; Item <= state.dataSurface->TotSurfaces; ++Item) {
9209 46044 : if (state.dataSurface->Surface(Item).Class == SurfaceClass::Window || state.dataSurface->Surface(Item).Class == SurfaceClass::GlassDoor) {
9210 : // todo, add complex fenestration switch HeatTransferModel_ComplexFenestration
9211 6217 : if (state.dataSurface->SurfWinWindowModelType(Item) == WindowModel::BSDF) {
9212 0 : state.dataSurface->Surface(Item).HeatTransferAlgorithm = DataSurfaces::HeatTransferModel::ComplexFenestration;
9213 : } else {
9214 6217 : state.dataSurface->Surface(Item).HeatTransferAlgorithm = DataSurfaces::HeatTransferModel::Window5;
9215 : }
9216 : }
9217 46044 : if (state.dataSurface->Surface(Item).Class == SurfaceClass::Detached_B ||
9218 46002 : state.dataSurface->Surface(Item).Class == SurfaceClass::Detached_F ||
9219 136454 : state.dataSurface->Surface(Item).Class == SurfaceClass::Shading || state.dataSurface->Surface(Item).Class == SurfaceClass::Overhang ||
9220 44408 : state.dataSurface->Surface(Item).Class == SurfaceClass::Fin) {
9221 1636 : state.dataSurface->Surface(Item).HeatTransferAlgorithm = DataSurfaces::HeatTransferModel::None;
9222 : }
9223 92088 : if (state.dataSurface->Surface(Item).Class == SurfaceClass::TDD_Diffuser ||
9224 46044 : state.dataSurface->Surface(Item).Class == SurfaceClass::TDD_Dome) {
9225 2 : state.dataSurface->Surface(Item).HeatTransferAlgorithm = DataSurfaces::HeatTransferModel::TDD;
9226 : }
9227 :
9228 54130 : if (state.dataSurface->Surface(Item).HeatTransferAlgorithm == DataSurfaces::HeatTransferModel::CTF ||
9229 8086 : state.dataSurface->Surface(Item).HeatTransferAlgorithm == DataSurfaces::HeatTransferModel::EMPD) {
9230 38001 : state.dataConstruction->Construct(state.dataSurface->Surface(Item).Construction).IsUsedCTF = true;
9231 : }
9232 : }
9233 796 : }
9234 :
9235 : struct PopCoincidentVertexReturn
9236 : {
9237 : double perimeter;
9238 : int poppedVertexPos = -1; // This is a STL vector position, 0-indexed
9239 : int keptVertexPos = -1;
9240 : };
9241 :
9242 42201 : PopCoincidentVertexReturn checkPopCoincidentVertex(const Array1D<Vector> &vertices)
9243 : {
9244 :
9245 42201 : size_t const nSides = vertices.size();
9246 :
9247 : // Pass one: Vector of distance from this vertex to the next one
9248 42201 : std::vector<Real64> distances(nSides);
9249 42201 : size_t index = 0;
9250 42201 : double min_distance = std::numeric_limits<Real64>::max();
9251 42201 : double perimeter = 0.0;
9252 211868 : for (auto it = vertices.begin(); it != vertices.end(); ++it) {
9253 169667 : auto itnext = std::next(it);
9254 169667 : if (itnext == std::end(vertices)) {
9255 42201 : itnext = std::begin(vertices);
9256 : }
9257 169667 : const auto dist = distance(*it, *itnext);
9258 169667 : distances[index++] = dist;
9259 169667 : min_distance = std::min(min_distance, dist);
9260 169667 : perimeter += dist;
9261 : }
9262 : // Return early if nothing to be popped
9263 42201 : if (min_distance >= Constant::OneCentimeter) {
9264 42201 : return {perimeter};
9265 : }
9266 :
9267 : // Pass two: figure out the vertex that is coincident with its previous and/or next vertex and
9268 : // that minimizes the (distanceThisToNext + distanceThisToPrev).
9269 0 : Real64 min_weight = std::numeric_limits<Real64>::max();
9270 0 : int poppedVertexPos = -1;
9271 0 : int keptVertexPos = -1;
9272 :
9273 0 : for (size_t index = 0; index < nSides; ++index) {
9274 0 : size_t const prevIndex = (index == 0) ? nSides - 1 : index - 1;
9275 0 : Real64 &distanceThisToNext = distances[index];
9276 0 : Real64 &distanceThisToPrev = distances[prevIndex];
9277 0 : if ((distanceThisToNext >= Constant::OneCentimeter) && (distanceThisToPrev >= Constant::OneCentimeter)) {
9278 0 : continue;
9279 : }
9280 0 : Real64 const weight = distanceThisToNext + distanceThisToPrev;
9281 0 : if (weight < min_weight) {
9282 0 : min_weight = weight;
9283 0 : poppedVertexPos = static_cast<int>(index);
9284 0 : if (distanceThisToPrev < distanceThisToNext) {
9285 0 : keptVertexPos = prevIndex;
9286 : } else {
9287 0 : keptVertexPos = static_cast<int>((index == nSides - 1) ? 0 : index + 1);
9288 : }
9289 : }
9290 : }
9291 :
9292 : // Return the keptVertexPos (which can be the previous or the next), so we can print the displayExtraWarning correctly
9293 0 : return {perimeter, poppedVertexPos, keptVertexPos};
9294 42201 : }
9295 :
9296 42201 : void GetVertices(EnergyPlusData &state,
9297 : int const SurfNum, // Current surface number
9298 : int const NSides, // Number of sides to figure
9299 : Array1S<Real64> const Vertices // Vertices, in specified order
9300 : )
9301 : {
9302 :
9303 : // SUBROUTINE INFORMATION:
9304 : // AUTHOR Linda Lawrie
9305 : // DATE WRITTEN May 2000
9306 : // MODIFIED na
9307 : // RE-ENGINEERED na
9308 :
9309 : // PURPOSE OF THIS SUBROUTINE:
9310 : // This subroutine gets the surface vertices from the arrays
9311 : // passed by the calling routine. These had previously been obtained
9312 : // from the InputProcessor (GetObjectItem). This routine will provide
9313 : // a standard place for determining various properties of the surface
9314 : // from the vertices.
9315 :
9316 : // METHODOLOGY EMPLOYED:
9317 : // na
9318 :
9319 : // REFERENCES:
9320 : // na
9321 :
9322 : // Using/Aliasing
9323 : using namespace Vectors;
9324 :
9325 : using namespace DataErrorTracking;
9326 :
9327 : // SUBROUTINE ARGUMENT DEFINITIONS:
9328 :
9329 : // SUBROUTINE PARAMETER DEFINITIONS:
9330 : static constexpr std::string_view RoutineName("GetVertices: ");
9331 :
9332 : // INTERFACE BLOCK SPECIFICATIONS
9333 : // na
9334 :
9335 : // DERIVED TYPE DEFINITIONS
9336 : // na
9337 :
9338 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
9339 : int Ptr; // Pointer into Vertice array
9340 : int n; // Loop counter
9341 : int NSrc; // Used for CW -> CCW transformation
9342 : int NTar; // Used for CW -> CCW transformation
9343 : Real64 SurfWorldAz;
9344 : Real64 SurfTilt;
9345 : Real64 Perimeter; // Perimeter length of the surface
9346 : Real64 Xb; // Intermediate calculation
9347 : Real64 Yb; // Intermediate calculation
9348 : int ZoneNum;
9349 : int ThisCorner;
9350 42201 : std::string TiltString;
9351 : Real64 ThisWidth;
9352 : Real64 ThisHeight;
9353 : // unused REAL(r64) :: ccwtest
9354 : // unused LOGICAL :: SurfaceCCW
9355 : Real64 dotp;
9356 :
9357 : // Object Data
9358 42201 : Vector const TestVector(0.0, 0.0, 1.0);
9359 42201 : Vector temp;
9360 :
9361 42201 : if (NSides > state.dataSurface->MaxVerticesPerSurface) state.dataSurface->MaxVerticesPerSurface = NSides;
9362 42201 : Ptr = 1;
9363 211868 : for (n = 1; n <= NSides; ++n) {
9364 169667 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(n).x = Vertices(Ptr);
9365 169667 : ++Ptr;
9366 169667 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(n).y = Vertices(Ptr);
9367 169667 : ++Ptr;
9368 169667 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(n).z = Vertices(Ptr);
9369 169667 : ++Ptr;
9370 : }
9371 :
9372 : // Address changing vertices if they were put in in CW order rather than CCW
9373 42201 : if (!state.dataSurface->CCW) {
9374 : // If even number of sides, this will transfer appropriately
9375 : // If odd number, will leave the "odd" one, which is what you want.
9376 195 : NSrc = NSides;
9377 195 : NTar = 2;
9378 390 : for (n = 1; n <= (NSides - 1) / 2; ++n) {
9379 195 : temp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(NSrc);
9380 195 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(NSrc) = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(NTar);
9381 195 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(NTar) = temp;
9382 195 : --NSrc;
9383 195 : ++NTar;
9384 : }
9385 : }
9386 : // Now address which "Corner" has been put in first. Note: the azimuth and tilt and area
9387 : // calculations do not care which corner is put in first.
9388 : // 2/2011 - don't think the shading calculations have a corner preference. Will keep this for
9389 : // consistency (for now)
9390 42201 : ThisCorner = state.dataSurface->Corner;
9391 45348 : while (ThisCorner != UpperLeftCorner) {
9392 3147 : if (NSides < 4) {
9393 12 : if (ThisCorner == UpperRightCorner) {
9394 0 : ThisCorner = UpperLeftCorner;
9395 0 : break;
9396 : }
9397 : }
9398 3147 : NTar = ThisCorner;
9399 3147 : NSrc = ThisCorner + 1;
9400 3147 : if (NSrc > NSides) NSrc = 1;
9401 12860 : for (n = 1; n <= NSides - 1; ++n) {
9402 9713 : temp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(NTar);
9403 9713 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(NTar) = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(NSrc);
9404 9713 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(NSrc) = temp;
9405 9713 : ++NTar;
9406 9713 : ++NSrc;
9407 9713 : if (NTar > NSides) NTar = 1;
9408 9713 : if (NSrc > NSides) NSrc = 1;
9409 : }
9410 3147 : ++ThisCorner;
9411 3147 : if (ThisCorner > NSides) ThisCorner = 1;
9412 : } // Corners
9413 42201 : if (!state.dataSurface->WorldCoordSystem) {
9414 : // Input in "relative" coordinates, use Building and Zone North Axes and Origins
9415 : // to translate each point (including rotation for Appendix G)
9416 33602 : ZoneNum = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Zone;
9417 33602 : if (ZoneNum > 0) {
9418 168443 : for (n = 1; n <= NSides; ++n) {
9419 134875 : Xb = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(n).x * state.dataSurfaceGeometry->CosZoneRelNorth(ZoneNum) -
9420 134875 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(n).y * state.dataSurfaceGeometry->SinZoneRelNorth(ZoneNum) +
9421 134875 : state.dataHeatBal->Zone(ZoneNum).OriginX;
9422 134875 : Yb = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(n).x * state.dataSurfaceGeometry->SinZoneRelNorth(ZoneNum) +
9423 134875 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(n).y * state.dataSurfaceGeometry->CosZoneRelNorth(ZoneNum) +
9424 134875 : state.dataHeatBal->Zone(ZoneNum).OriginY;
9425 134875 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(n).x =
9426 134875 : Xb * state.dataSurfaceGeometry->CosBldgRelNorth - Yb * state.dataSurfaceGeometry->SinBldgRelNorth;
9427 134875 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(n).y =
9428 134875 : Xb * state.dataSurfaceGeometry->SinBldgRelNorth + Yb * state.dataSurfaceGeometry->CosBldgRelNorth;
9429 134875 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(n).z += state.dataHeatBal->Zone(ZoneNum).OriginZ;
9430 : }
9431 34 : } else if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == SurfaceClass::Detached_B) {
9432 67 : for (n = 1; n <= NSides; ++n) {
9433 52 : Xb = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(n).x;
9434 52 : Yb = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(n).y;
9435 52 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(n).x =
9436 52 : Xb * state.dataSurfaceGeometry->CosBldgRelNorth - Yb * state.dataSurfaceGeometry->SinBldgRelNorth;
9437 52 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(n).y =
9438 52 : Xb * state.dataSurfaceGeometry->SinBldgRelNorth + Yb * state.dataSurfaceGeometry->CosBldgRelNorth;
9439 : }
9440 : }
9441 : } else {
9442 : // if world coordinate only need to rotate for Appendix G
9443 8599 : ZoneNum = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Zone;
9444 8599 : if (ZoneNum > 0) {
9445 43167 : for (n = 1; n <= NSides; ++n) {
9446 34590 : Xb = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(n).x;
9447 34590 : Yb = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(n).y;
9448 34590 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(n).x =
9449 34590 : Xb * state.dataSurfaceGeometry->CosBldgRotAppGonly - Yb * state.dataSurfaceGeometry->SinBldgRotAppGonly;
9450 34590 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(n).y =
9451 34590 : Xb * state.dataSurfaceGeometry->SinBldgRotAppGonly + Yb * state.dataSurfaceGeometry->CosBldgRotAppGonly;
9452 : }
9453 22 : } else if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == SurfaceClass::Detached_B) {
9454 0 : for (n = 1; n <= NSides; ++n) {
9455 0 : Xb = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(n).x;
9456 0 : Yb = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(n).y;
9457 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(n).x =
9458 0 : Xb * state.dataSurfaceGeometry->CosBldgRotAppGonly - Yb * state.dataSurfaceGeometry->SinBldgRotAppGonly;
9459 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(n).y =
9460 0 : Xb * state.dataSurfaceGeometry->SinBldgRotAppGonly + Yb * state.dataSurfaceGeometry->CosBldgRotAppGonly;
9461 : }
9462 : }
9463 : }
9464 :
9465 42201 : if (NSides > 2) {
9466 42201 : auto &surface = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
9467 42201 : auto &vertices = surface.Vertex;
9468 42201 : auto &nSides = surface.Sides;
9469 :
9470 : while (true) {
9471 42201 : PopCoincidentVertexReturn const popResult = checkPopCoincidentVertex(vertices);
9472 42201 : Perimeter = popResult.perimeter;
9473 42201 : if (popResult.poppedVertexPos < 0) {
9474 : // No pop needed, we're done
9475 42201 : break;
9476 : }
9477 :
9478 : // Grab the popped one, and the kept one (regardless of whether it's previous or next)
9479 0 : auto it = vertices.begin();
9480 0 : std::advance(it, popResult.poppedVertexPos);
9481 0 : int const poppedVertexIndex = popResult.poppedVertexPos + 1;
9482 :
9483 0 : auto itKept = vertices.begin();
9484 0 : std::advance(itKept, popResult.keptVertexPos);
9485 0 : int const keptVertexIndex = popResult.keptVertexPos + 1;
9486 :
9487 0 : if (state.dataGlobal->DisplayExtraWarnings) {
9488 0 : ShowWarningError(state,
9489 0 : format("{}Distance between two vertices < .01, possibly coincident. for Surface={}, in Zone={}",
9490 : RoutineName,
9491 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
9492 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ZoneName));
9493 :
9494 0 : bool const printPoppedFirst = (poppedVertexIndex < keptVertexIndex) ? !(poppedVertexIndex == 1 && keptVertexIndex == nSides)
9495 0 : : (poppedVertexIndex == nSides && keptVertexIndex == 1);
9496 :
9497 0 : if (printPoppedFirst) {
9498 0 : ShowContinueError(state, format("Vertex [{}]=({:.2R},{:.2R},{:.2R})", poppedVertexIndex, it->x, it->y, it->z));
9499 0 : ShowContinueError(state, format("Vertex [{}]=({:.2R},{:.2R},{:.2R})", keptVertexIndex, itKept->x, itKept->y, itKept->z));
9500 : } else {
9501 0 : ShowContinueError(state, format("Vertex [{}]=({:.2R},{:.2R},{:.2R})", keptVertexIndex, itKept->x, itKept->y, itKept->z));
9502 0 : ShowContinueError(state, format("Vertex [{}]=({:.2R},{:.2R},{:.2R})", poppedVertexIndex, it->x, it->y, it->z));
9503 : }
9504 : }
9505 0 : ++state.dataErrTracking->TotalCoincidentVertices;
9506 0 : if (nSides <= 3) {
9507 0 : if (state.dataGlobal->DisplayExtraWarnings) {
9508 0 : ShowContinueError(state,
9509 0 : format("Cannot Drop Vertex [{}]; Number of Surface Sides at minimum. This surface is now a "
9510 : "degenerate surface.",
9511 : poppedVertexIndex));
9512 : }
9513 0 : ++state.dataErrTracking->TotalDegenerateSurfaces;
9514 : // If degenerate, we won't be able to pop now nor later, so exit
9515 : // mark degenerate surface?
9516 0 : break;
9517 : }
9518 :
9519 0 : if (state.dataGlobal->DisplayExtraWarnings) {
9520 0 : ShowContinueError(state, format("Dropping Vertex [{}].", poppedVertexIndex));
9521 : }
9522 0 : --nSides;
9523 0 : vertices.erase(it);
9524 : // No need to recompute perimeter, because it'll be done in the next iteration, until no popping or degenerate happens
9525 0 : }
9526 :
9527 42201 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Perimeter = Perimeter;
9528 :
9529 42201 : CreateNewellSurfaceNormalVector(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex,
9530 42201 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides,
9531 42201 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).NewellSurfaceNormalVector);
9532 42201 : CreateNewellAreaVector(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex,
9533 42201 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides,
9534 42201 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).NewellAreaVector);
9535 : // For surfaces with subsurfaces, the following two areas are turned into net areas later by
9536 : // subtracting subsurface areas
9537 42201 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).GrossArea = VecLength(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).NewellAreaVector);
9538 42201 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Area = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).GrossArea;
9539 42201 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).NetAreaShadowCalc = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Area;
9540 42201 : DetermineAzimuthAndTilt(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex,
9541 : SurfWorldAz,
9542 : SurfTilt,
9543 42201 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).lcsx,
9544 42201 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).lcsy,
9545 42201 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).lcsz,
9546 42201 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).NewellSurfaceNormalVector);
9547 42201 : dotp = dot(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).NewellSurfaceNormalVector, TestVector);
9548 42201 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == SurfaceClass::Roof && dotp < -0.000001) {
9549 0 : TiltString = format("{:.1R}", SurfTilt);
9550 0 : ShowWarningError(state,
9551 0 : format("{}Roof/Ceiling is upside down! Tilt angle=[{}], should be near 0, Surface=\"{}\", in Zone=\"{}\".",
9552 : RoutineName,
9553 : TiltString,
9554 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
9555 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ZoneName));
9556 0 : ShowContinueError(state, "Automatic fix is attempted.");
9557 0 : ReverseAndRecalculate(state, SurfNum, state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides, SurfWorldAz, SurfTilt);
9558 42201 : } else if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == SurfaceClass::Roof && SurfTilt > 80.0) {
9559 0 : TiltString = format("{:.1R}", SurfTilt);
9560 0 : ShowWarningError(
9561 : state,
9562 0 : format("{}Roof/Ceiling is not oriented correctly! Tilt angle=[{}], should be near 0, Surface=\"{}\", in Zone=\"{}\".",
9563 : RoutineName,
9564 : TiltString,
9565 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
9566 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ZoneName));
9567 : }
9568 42201 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == SurfaceClass::Floor && dotp > 0.000001) {
9569 0 : TiltString = format("{:.1R}", SurfTilt);
9570 0 : ShowWarningError(state,
9571 0 : format("{}Floor is upside down! Tilt angle=[{}], should be near 180, Surface=\"{}\", in Zone=\"{}\".",
9572 : RoutineName,
9573 : TiltString,
9574 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
9575 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ZoneName));
9576 0 : ShowContinueError(state, "Automatic fix is attempted.");
9577 0 : ReverseAndRecalculate(state, SurfNum, state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides, SurfWorldAz, SurfTilt);
9578 42201 : } else if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == SurfaceClass::Floor && SurfTilt < 158.2) { // slope/grade = 40%!
9579 0 : TiltString = format("{:.1R}", SurfTilt);
9580 0 : ShowWarningError(state,
9581 0 : format("{}Floor is not oriented correctly! Tilt angle=[{}], should be near 180, Surface=\"{}\", in Zone=\"{}\".",
9582 : RoutineName,
9583 : TiltString,
9584 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
9585 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ZoneName));
9586 : }
9587 42201 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Azimuth = SurfWorldAz;
9588 42201 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Tilt = SurfTilt;
9589 42201 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).convOrientation =
9590 42201 : Convect::GetSurfConvOrientation(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Tilt);
9591 :
9592 : // Sine and cosine of azimuth and tilt
9593 42201 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).SinAzim = std::sin(SurfWorldAz * Constant::DegToRadians);
9594 42201 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).CosAzim = std::cos(SurfWorldAz * Constant::DegToRadians);
9595 42201 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).SinTilt = std::sin(SurfTilt * Constant::DegToRadians);
9596 42201 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).CosTilt = std::cos(SurfTilt * Constant::DegToRadians);
9597 42201 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ViewFactorGround == Constant::AutoCalculate) {
9598 19942 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ViewFactorGround =
9599 19942 : 0.5 * (1.0 - state.dataSurfaceGeometry->SurfaceTmp(SurfNum).CosTilt);
9600 : }
9601 : // Outward normal unit vector (pointing away from room)
9602 42201 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).OutNormVec = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).NewellSurfaceNormalVector;
9603 168804 : for (n = 1; n <= 3; ++n) {
9604 126603 : if (std::abs(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).OutNormVec(n) - 1.0) < 1.e-06)
9605 15855 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).OutNormVec(n) = +1.0;
9606 126603 : if (std::abs(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).OutNormVec(n) + 1.0) < 1.e-06)
9607 18046 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).OutNormVec(n) = -1.0;
9608 126603 : if (std::abs(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).OutNormVec(n)) < 1.e-06)
9609 76068 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).OutNormVec(n) = 0.0;
9610 : }
9611 :
9612 42201 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == SurfaceClass::Window ||
9613 78254 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == SurfaceClass::GlassDoor ||
9614 36053 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == SurfaceClass::Door)
9615 6616 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Area *= state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Multiplier;
9616 : // Can perform tests on this surface here
9617 42201 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ViewFactorSky = 0.5 * (1.0 + state.dataSurfaceGeometry->SurfaceTmp(SurfNum).CosTilt);
9618 : // The following IR view factors are modified in subr. SkyDifSolarShading if there are shadowing
9619 : // surfaces
9620 42201 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ViewFactorSkyIR = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ViewFactorSky;
9621 42201 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ViewFactorGroundIR = 0.5 * (1.0 - state.dataSurfaceGeometry->SurfaceTmp(SurfNum).CosTilt);
9622 :
9623 : // Call to transform vertices
9624 :
9625 42201 : TransformVertsByAspect(state, SurfNum, state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides);
9626 :
9627 : } else {
9628 0 : ShowFatalError(state,
9629 0 : format("{}Called with less than 2 sides, Surface={}", RoutineName, state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name));
9630 : }
9631 :
9632 : // Preliminary Height/Width
9633 42201 : temp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(3) - state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(2);
9634 42201 : ThisWidth = VecLength(temp);
9635 42201 : temp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(2) - state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(1);
9636 42201 : ThisHeight = VecLength(temp);
9637 42201 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Height = ThisHeight;
9638 42201 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Width = ThisWidth;
9639 42201 : }
9640 :
9641 0 : void ReverseAndRecalculate(EnergyPlusData &state,
9642 : int const SurfNum, // Surface number for the surface
9643 : int const NSides, // number of sides to surface
9644 : Real64 &SurfAzimuth, // Surface Facing angle (will be 0 for roofs/floors)
9645 : Real64 &SurfTilt // Surface tilt (
9646 : )
9647 : {
9648 :
9649 : // SUBROUTINE INFORMATION:
9650 : // AUTHOR Linda Lawrie
9651 : // DATE WRITTEN February 2011
9652 : // MODIFIED na
9653 : // RE-ENGINEERED na
9654 :
9655 : // PURPOSE OF THIS SUBROUTINE:
9656 : // This routine reverses the vertices for a surface (needed when roof/floor is upside down)
9657 : // and recalculates the azimuth, etc for the surface.
9658 :
9659 : // METHODOLOGY EMPLOYED:
9660 : // na
9661 :
9662 : // REFERENCES:
9663 : // na
9664 :
9665 : // Using/Aliasing
9666 : using namespace Vectors;
9667 :
9668 : // SUBROUTINE ARGUMENT DEFINITIONS:
9669 :
9670 : // SUBROUTINE PARAMETER DEFINITIONS:
9671 : static constexpr std::string_view RoutineName("ReverseAndRecalculate: ");
9672 :
9673 : // INTERFACE BLOCK SPECIFICATIONS:
9674 : // na
9675 :
9676 : // DERIVED TYPE DEFINITIONS:
9677 : // na
9678 :
9679 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
9680 : int n; // Loop Control
9681 : int RevPtr; // pointer for reversing vertices
9682 0 : std::string TiltString;
9683 :
9684 : // Object Data
9685 0 : Array1D<Vector> Vertices(NSides); // Vertices, in specified order
9686 :
9687 0 : for (n = 1; n <= NSides; ++n) {
9688 0 : Vertices(n) = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(n);
9689 : }
9690 0 : RevPtr = NSides;
9691 0 : for (n = 1; n <= NSides; ++n) {
9692 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(n) = Vertices(RevPtr);
9693 0 : --RevPtr;
9694 : }
9695 :
9696 0 : print(state.files.debug, "Reversing Surface Name={}\n", state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name);
9697 0 : for (n = 1; n <= NSides; ++n) {
9698 0 : print(state.files.debug,
9699 : "side={:5} abs coord vertex= {:18.13F} {:18.13F} {:18.13F}\n",
9700 : n,
9701 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(n).x,
9702 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(n).y,
9703 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(n).z);
9704 : }
9705 :
9706 0 : CreateNewellSurfaceNormalVector(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex,
9707 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides,
9708 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).NewellSurfaceNormalVector);
9709 0 : DetermineAzimuthAndTilt(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex,
9710 : SurfAzimuth,
9711 : SurfTilt,
9712 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).lcsx,
9713 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).lcsy,
9714 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).lcsz,
9715 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).NewellSurfaceNormalVector);
9716 0 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == SurfaceClass::Roof && SurfTilt > 80.0) {
9717 0 : TiltString = format("{:.1R}", SurfTilt);
9718 0 : ShowWarningError(
9719 : state,
9720 0 : format("{}Roof/Ceiling is still upside down! Tilt angle=[{}], should be near 0, please fix manually.", RoutineName, TiltString));
9721 : }
9722 0 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == SurfaceClass::Floor && SurfTilt < 158.2) { // 40% grade!
9723 0 : ShowWarningError(
9724 0 : state, format("{}Floor is still upside down! Tilt angle=[{}], should be near 180, please fix manually.", RoutineName, TiltString));
9725 : }
9726 0 : }
9727 :
9728 818 : void MakeMirrorSurface(EnergyPlusData &state, int &SurfNum) // In=>Surface to Mirror, Out=>new Surface index
9729 : {
9730 :
9731 : // SUBROUTINE INFORMATION:
9732 : // AUTHOR Linda Lawrie
9733 : // DATE WRITTEN June 2002
9734 :
9735 : // PURPOSE OF THIS SUBROUTINE:
9736 : // This subroutine creates a "mirror" surface using the indicated surface.
9737 : // This is the simple approach for bi-directional shading devices. If, perchance,
9738 : // the user has already taken care of this (e.g. fins in middle of wall), there will
9739 : // be extra shading devices shown.
9740 :
9741 818 : auto &origSurface = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
9742 818 : auto &newSurface = state.dataSurfaceGeometry->SurfaceTmp(SurfNum + 1);
9743 818 : newSurface = origSurface;
9744 :
9745 818 : int nVert = origSurface.Sides;
9746 : // Reverse the vertices in the original surface. Add "MIR-" to name.
9747 4068 : for (int Vert = 1; Vert <= state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides; ++Vert) {
9748 3250 : newSurface.Vertex(Vert) = origSurface.Vertex(nVert);
9749 3250 : --nVert;
9750 : }
9751 818 : newSurface.Name = "Mir-" + origSurface.Name;
9752 818 : newSurface.MirroredSurf = true;
9753 :
9754 818 : if (newSurface.Sides > 2) {
9755 818 : Vectors::CreateNewellAreaVector(newSurface.Vertex, newSurface.Sides, newSurface.NewellAreaVector);
9756 818 : newSurface.GrossArea = Vectors::VecLength(newSurface.NewellAreaVector);
9757 818 : newSurface.Area = newSurface.GrossArea;
9758 818 : newSurface.NetAreaShadowCalc = newSurface.Area;
9759 818 : Vectors::CreateNewellSurfaceNormalVector(newSurface.Vertex, newSurface.Sides, newSurface.NewellSurfaceNormalVector);
9760 818 : Real64 SurfWorldAz = 0.0;
9761 818 : Real64 SurfTilt = 0.0;
9762 818 : Vectors::DetermineAzimuthAndTilt(
9763 818 : newSurface.Vertex, SurfWorldAz, SurfTilt, newSurface.lcsx, newSurface.lcsy, newSurface.lcsz, newSurface.NewellSurfaceNormalVector);
9764 818 : newSurface.Azimuth = SurfWorldAz;
9765 818 : newSurface.Tilt = SurfTilt;
9766 818 : newSurface.convOrientation = Convect::GetSurfConvOrientation(newSurface.Tilt);
9767 :
9768 : // Sine and cosine of azimuth and tilt
9769 818 : newSurface.SinAzim = std::sin(SurfWorldAz * Constant::DegToRadians);
9770 818 : newSurface.CosAzim = std::cos(SurfWorldAz * Constant::DegToRadians);
9771 818 : newSurface.SinTilt = std::sin(SurfTilt * Constant::DegToRadians);
9772 818 : newSurface.CosTilt = std::cos(SurfTilt * Constant::DegToRadians);
9773 : // Outward normal unit vector (pointing away from room)
9774 818 : newSurface.OutNormVec = newSurface.NewellSurfaceNormalVector;
9775 3272 : for (int n = 1; n <= 3; ++n) {
9776 2454 : if (std::abs(newSurface.OutNormVec(n) - 1.0) < 1.e-06) newSurface.OutNormVec(n) = +1.0;
9777 2454 : if (std::abs(newSurface.OutNormVec(n) + 1.0) < 1.e-06) newSurface.OutNormVec(n) = -1.0;
9778 2454 : if (std::abs(newSurface.OutNormVec(n)) < 1.e-06) newSurface.OutNormVec(n) = 0.0;
9779 : }
9780 :
9781 : // Can perform tests on this surface here
9782 818 : newSurface.ViewFactorSky = 0.5 * (1.0 + newSurface.CosTilt);
9783 : // The following IR view factors are modified in subr. SkyDifSolarShading if there are shadowing surfaces
9784 818 : newSurface.ViewFactorSkyIR = newSurface.ViewFactorSky;
9785 818 : newSurface.ViewFactorGroundIR = 0.5 * (1.0 - newSurface.CosTilt);
9786 818 : ++SurfNum; // Calling function expects incremented argument on return
9787 : }
9788 818 : }
9789 :
9790 796 : void GetWindowShadingControlData(EnergyPlusData &state, bool &ErrorsFound) // If errors found in input
9791 : {
9792 :
9793 : // SUBROUTINE INFORMATION:
9794 : // AUTHOR Fred Winkelmann
9795 : // DATE WRITTEN November 1998
9796 : // MODIFIED Aug 2001 (FW): add handling of new ShadingControlIsScheduled
9797 : // and GlareControlIsActive fields
9798 : // Nov 2001 (FW): add ShadingDevice as alternative to ShadedConstruction
9799 : // Dec 2001 (FW): add slat angle controls for blinds
9800 : // Aug 2002 (FW): add Setpoint2; check that specified control type is legal
9801 : // Feb 2003 (FW): add error if Material Name of Shading Device is used with
9802 : // Shading Type = BetweenGlassShade or BetweenGlassBlind
9803 : // Dec 2003 (FW): improve BetweenGlassBlind error messages
9804 : // Feb 2009 (BG): improve error checking for OnIfScheduleAllows
9805 : // RE-ENGINEERED na
9806 :
9807 : // PURPOSE OF THIS SUBROUTINE:
9808 : // Reads in the window shading control information
9809 : // from the input data file, interprets it and puts it in the derived type
9810 :
9811 : // Using/Aliasing
9812 : using ScheduleManager::GetScheduleIndex;
9813 :
9814 : // SUBROUTINE PARAMETER DEFINITIONS:
9815 :
9816 796 : int constexpr NumValidShadingTypes(9);
9817 : static Array1D_string const cValidShadingTypes(NumValidShadingTypes,
9818 : {
9819 : "SHADEOFF", // 1
9820 : "INTERIORSHADE", // 2
9821 : "SWITCHABLEGLAZING", // 3
9822 : "EXTERIORSHADE", // 4
9823 : "EXTERIORSCREEN", // 5
9824 : "INTERIORBLIND", // 6
9825 : "EXTERIORBLIND", // 7
9826 : "BETWEENGLASSSHADE", // 8
9827 : "BETWEENGLASSBLIND" // 9
9828 796 : });
9829 :
9830 796 : constexpr std::array<std::string_view, static_cast<int>(WindowShadingControlType::Num)> WindowShadingControlTypeNamesUC{
9831 : "ALWAYSON",
9832 : "ALWAYSOFF",
9833 : "ONIFSCHEDULEALLOWS",
9834 : "ONIFHIGHSOLARONWINDOW",
9835 : "ONIFHIGHHORIZONTALSOLAR",
9836 : "ONIFHIGHOUTDOORAIRTEMPERATURE",
9837 : "ONIFHIGHZONEAIRTEMPERATURE",
9838 : "ONIFHIGHZONECOOLING",
9839 : "ONIFHIGHGLARE",
9840 : "MEETDAYLIGHTILLUMINANCESETPOINT",
9841 : "ONNIGHTIFLOWOUTDOORTEMPANDOFFDAY",
9842 : "ONNIGHTIFLOWINSIDETEMPANDOFFDAY",
9843 : "ONNIGHTIFHEATINGANDOFFDAY",
9844 : "ONNIGHTIFLOWOUTDOORTEMPANDONDAYIFCOOLING",
9845 : "ONNIGHTIFHEATINGANDONDAYIFCOOLING",
9846 : "OFFNIGHTANDONDAYIFCOOLINGANDHIGHSOLARONWINDOW",
9847 : "ONNIGHTANDONDAYIFCOOLINGANDHIGHSOLARONWINDOW",
9848 : "ONIFHIGHOUTDOORAIRTEMPANDHIGHSOLARONWINDOW",
9849 : "ONIFHIGHOUTDOORAIRTEMPANDHIGHHORIZONTALSOLAR",
9850 : "ONIFHIGHZONEAIRTEMPANDHIGHSOLARONWINDOW",
9851 : "ONIFHIGHZONEAIRTEMPANDHIGHHORIZONTALSOLAR",
9852 : "ONIFHIGHSOLARORHIGHLUMINANCETILLMIDNIGHT",
9853 : "ONIFHIGHSOLARORHIGHLUMINANCETILLSUNSET",
9854 : "ONIFHIGHSOLARORHIGHLUMINANCETILLNEXTMORNING"};
9855 :
9856 796 : constexpr std::array<std::string_view, static_cast<int>(SlatAngleControl::Num)> SlatAngleNamesUC{
9857 : "FIXEDSLATANGLE", "SCHEDULEDSLATANGLE", "BLOCKBEAMSOLAR"};
9858 :
9859 796 : constexpr std::array<std::string_view, static_cast<int>(MultiSurfaceControl::Num)> MultiSurfaceControlNamesUC = {"SEQUENTIAL", "GROUP"};
9860 :
9861 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
9862 : int IOStat; // IO Status when calling get input subroutine
9863 : int ControlNumAlpha; // Number of control alpha names being passed
9864 : int ControlNumProp; // Number of control properties being passed
9865 : int ControlNum; // DO loop counter/index for window shading control number
9866 : int IShadedConst; // Construction number of shaded construction
9867 : int IShadingDevice; // Material number of shading device
9868 : int NLayers; // Layers in shaded construction
9869 : bool ErrorInName;
9870 : bool IsBlank;
9871 : int Loop;
9872 : bool BGShadeBlindError; // True if problem with construction that is supposed to have between-glass
9873 : // shade or blind
9874 : int Found;
9875 :
9876 796 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
9877 : // Get the total number of window shading control blocks
9878 796 : cCurrentModuleObject = "WindowShadingControl";
9879 796 : state.dataSurface->TotWinShadingControl = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
9880 796 : if (state.dataSurface->TotWinShadingControl == 0) return;
9881 :
9882 43 : state.dataSurface->WindowShadingControl.allocate(state.dataSurface->TotWinShadingControl);
9883 :
9884 43 : ControlNum = 0;
9885 116 : for (Loop = 1; Loop <= state.dataSurface->TotWinShadingControl; ++Loop) {
9886 :
9887 146 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
9888 : cCurrentModuleObject,
9889 : Loop,
9890 73 : state.dataIPShortCut->cAlphaArgs,
9891 : ControlNumAlpha,
9892 73 : state.dataIPShortCut->rNumericArgs,
9893 : ControlNumProp,
9894 : IOStat,
9895 73 : state.dataIPShortCut->lNumericFieldBlanks,
9896 73 : state.dataIPShortCut->lAlphaFieldBlanks,
9897 73 : state.dataIPShortCut->cAlphaFieldNames,
9898 73 : state.dataIPShortCut->cNumericFieldNames);
9899 :
9900 73 : ErrorInName = false;
9901 73 : IsBlank = false;
9902 73 : Util::VerifyName(state,
9903 73 : state.dataIPShortCut->cAlphaArgs(1),
9904 73 : state.dataSurface->WindowShadingControl,
9905 : ControlNum,
9906 : ErrorInName,
9907 : IsBlank,
9908 146 : cCurrentModuleObject + " Name");
9909 73 : if (ErrorInName) {
9910 0 : ErrorsFound = true;
9911 0 : continue;
9912 : }
9913 :
9914 73 : ++ControlNum;
9915 :
9916 73 : auto &windowShadingControl = state.dataSurface->WindowShadingControl(ControlNum);
9917 :
9918 73 : windowShadingControl.Name = state.dataIPShortCut->cAlphaArgs(1); // Set the Control Name in the Derived Type
9919 :
9920 73 : windowShadingControl.ZoneIndex = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(2), state.dataHeatBal->Zone);
9921 73 : if (windowShadingControl.ZoneIndex == 0) {
9922 0 : ShowSevereError(state,
9923 0 : format("{}=\"{}\" invalid {}=\"{}\" not found.",
9924 : cCurrentModuleObject,
9925 0 : state.dataIPShortCut->cAlphaArgs(1),
9926 0 : state.dataIPShortCut->cAlphaFieldNames(2),
9927 0 : state.dataIPShortCut->cAlphaArgs(2)));
9928 0 : ErrorsFound = true;
9929 : }
9930 :
9931 73 : windowShadingControl.SequenceNumber = int(state.dataIPShortCut->rNumericArgs(1));
9932 : // WindowShadingControl().getInputShadedConstruction is only used during GetInput process and is ultimately stored in
9933 : // Surface().shadedConstructionList
9934 73 : windowShadingControl.getInputShadedConstruction =
9935 73 : Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(4), state.dataConstruction->Construct, state.dataHeatBal->TotConstructs);
9936 73 : windowShadingControl.ShadingDevice =
9937 73 : Util::FindItemInPtrList(state.dataIPShortCut->cAlphaArgs(9), state.dataMaterial->Material, state.dataMaterial->TotMaterials);
9938 73 : windowShadingControl.Schedule = GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(6));
9939 73 : windowShadingControl.SetPoint = state.dataIPShortCut->rNumericArgs(2);
9940 73 : windowShadingControl.SetPoint2 = state.dataIPShortCut->rNumericArgs(3);
9941 73 : windowShadingControl.ShadingControlIsScheduled = getYesNoValue(state.dataIPShortCut->cAlphaArgs(7)) == BooleanSwitch::Yes;
9942 73 : windowShadingControl.GlareControlIsActive = getYesNoValue(state.dataIPShortCut->cAlphaArgs(8)) == BooleanSwitch::Yes;
9943 73 : windowShadingControl.SlatAngleSchedule = GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(11));
9944 :
9945 : // store the string for now and associate it after daylighting control objects are read
9946 73 : windowShadingControl.DaylightingControlName = state.dataIPShortCut->cAlphaArgs(12);
9947 :
9948 73 : windowShadingControl.multiSurfaceControl =
9949 73 : static_cast<MultiSurfaceControl>(getEnumValue(MultiSurfaceControlNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(13))));
9950 :
9951 73 : if (windowShadingControl.multiSurfaceControl == MultiSurfaceControl::Invalid) {
9952 0 : windowShadingControl.multiSurfaceControl = MultiSurfaceControl::Sequential;
9953 0 : ShowWarningError(state,
9954 0 : format("{}=\"{}\" should be either SEQUENTIAL or GROUP {}=\"{}\", defaulting to \"SEQUENTIAL\"",
9955 : cCurrentModuleObject,
9956 0 : windowShadingControl.Name,
9957 0 : state.dataIPShortCut->cAlphaFieldNames(13),
9958 0 : state.dataIPShortCut->cAlphaArgs(13)));
9959 : }
9960 :
9961 73 : if (ControlNumAlpha >= 14) {
9962 73 : windowShadingControl.FenestrationCount = ControlNumAlpha - 13;
9963 73 : windowShadingControl.FenestrationName.allocate(windowShadingControl.FenestrationCount);
9964 73 : windowShadingControl.FenestrationIndex.allocate(windowShadingControl.FenestrationCount);
9965 228 : for (int i = 1; i <= windowShadingControl.FenestrationCount; i++) {
9966 155 : windowShadingControl.FenestrationName(i) = state.dataIPShortCut->cAlphaArgs(i + 13);
9967 : }
9968 : } else {
9969 0 : ShowSevereError(state,
9970 0 : format("{}=\"{}\" invalid. Must reference at least one Fenestration Surface object name.",
9971 : cCurrentModuleObject,
9972 0 : state.dataIPShortCut->cAlphaArgs(1)));
9973 : }
9974 :
9975 73 : windowShadingControl.shadingControlType = static_cast<WindowShadingControlType>(
9976 73 : getEnumValue(WindowShadingControlTypeNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(5))));
9977 :
9978 73 : if (windowShadingControl.ShadingDevice > 0) {
9979 13 : if (state.dataMaterial->Material(windowShadingControl.ShadingDevice)->group == Material::Group::Screen &&
9980 0 : !(windowShadingControl.shadingControlType == WindowShadingControlType::AlwaysOn ||
9981 0 : windowShadingControl.shadingControlType == WindowShadingControlType::AlwaysOff ||
9982 0 : windowShadingControl.shadingControlType == WindowShadingControlType::OnIfScheduled)) {
9983 0 : ErrorsFound = true;
9984 0 : ShowSevereError(state,
9985 0 : format("{}=\"{}\" invalid {}=\"{}\" for exterior screens.",
9986 : cCurrentModuleObject,
9987 0 : windowShadingControl.Name,
9988 0 : state.dataIPShortCut->cAlphaFieldNames(5),
9989 0 : state.dataIPShortCut->cAlphaArgs(5)));
9990 0 : ShowContinueError(state,
9991 : "Valid shading control types for exterior window screens are ALWAYSON, ALWAYSOFF, or ONIFSCHEDULEALLOWS.");
9992 : }
9993 : } else {
9994 60 : if (windowShadingControl.getInputShadedConstruction > 0) {
9995 60 : state.dataConstruction->Construct(windowShadingControl.getInputShadedConstruction).IsUsed = true;
9996 60 : if (state.dataMaterial->Material(state.dataConstruction->Construct(windowShadingControl.getInputShadedConstruction).LayerPoint(1))
9997 62 : ->group == Material::Group::Screen &&
9998 2 : !(windowShadingControl.shadingControlType == WindowShadingControlType::AlwaysOn ||
9999 2 : windowShadingControl.shadingControlType == WindowShadingControlType::AlwaysOff ||
10000 2 : windowShadingControl.shadingControlType == WindowShadingControlType::OnIfScheduled)) {
10001 0 : ErrorsFound = true;
10002 0 : ShowSevereError(state,
10003 0 : format("{}=\"{}\" invalid {}=\"{}\" for exterior screens.",
10004 : cCurrentModuleObject,
10005 0 : windowShadingControl.Name,
10006 0 : state.dataIPShortCut->cAlphaFieldNames(5),
10007 0 : state.dataIPShortCut->cAlphaArgs(5)));
10008 0 : ShowContinueError(state,
10009 : "Valid shading control types for exterior window screens are ALWAYSON, ALWAYSOFF, or ONIFSCHEDULEALLOWS.");
10010 : }
10011 0 : } else if (state.dataIPShortCut->lAlphaFieldBlanks(4)) {
10012 0 : ShowSevereError(
10013 : state,
10014 0 : format(
10015 0 : "{}=\"{}\", {} is blank.", cCurrentModuleObject, windowShadingControl.Name, state.dataIPShortCut->cAlphaFieldNames(4)));
10016 0 : ShowContinueError(state, "A valid construction is required.");
10017 0 : ErrorsFound = true;
10018 : } else {
10019 0 : ShowSevereError(
10020 : state,
10021 0 : format(
10022 0 : "{}=\"{}\", {} is invalid.", cCurrentModuleObject, windowShadingControl.Name, state.dataIPShortCut->cAlphaFieldNames(4)));
10023 0 : ShowContinueError(state,
10024 0 : format("Construction=\"{}\" was used. A valid construction is required.", state.dataIPShortCut->cAlphaArgs(4)));
10025 0 : ErrorsFound = true;
10026 : }
10027 : }
10028 :
10029 : // Warning if setpoint is unintentionally zero
10030 73 : if (windowShadingControl.SetPoint == 0 && windowShadingControl.shadingControlType != WindowShadingControlType::AlwaysOn &&
10031 33 : windowShadingControl.shadingControlType != WindowShadingControlType::AlwaysOff &&
10032 33 : windowShadingControl.shadingControlType != WindowShadingControlType::OnIfScheduled &&
10033 22 : windowShadingControl.shadingControlType != WindowShadingControlType::HiGlare) {
10034 0 : ShowWarningError(state, format("{}=\"{}\", The first SetPoint is zero.", cCurrentModuleObject, windowShadingControl.Name));
10035 0 : ShowContinueError(state, "..You may have forgotten to specify that setpoint.");
10036 : }
10037 :
10038 : // Error checks
10039 73 : if (state.dataIPShortCut->cAlphaArgs(7) != "YES" && state.dataIPShortCut->cAlphaArgs(7) != "NO") { // Shading Control is Schedule field
10040 0 : ErrorsFound = true;
10041 0 : ShowSevereError(state,
10042 0 : format("{}=\"{}\" invalid {}=\"{}\".",
10043 : cCurrentModuleObject,
10044 0 : windowShadingControl.Name,
10045 0 : state.dataIPShortCut->cAlphaFieldNames(7),
10046 0 : state.dataIPShortCut->cAlphaArgs(7)));
10047 : }
10048 73 : if (state.dataIPShortCut->cAlphaArgs(8) != "YES" && state.dataIPShortCut->cAlphaArgs(8) != "NO") { // Glare Control is Active field
10049 0 : ErrorsFound = true;
10050 0 : ShowSevereError(state,
10051 0 : format("{}=\"{}\" invalid {}=\"{}\".",
10052 : cCurrentModuleObject,
10053 0 : windowShadingControl.Name,
10054 0 : state.dataIPShortCut->cAlphaFieldNames(8),
10055 0 : state.dataIPShortCut->cAlphaArgs(8)));
10056 : }
10057 :
10058 73 : if ((windowShadingControl.shadingControlType == WindowShadingControlType::OnIfScheduled) &&
10059 13 : (!windowShadingControl.ShadingControlIsScheduled)) { // CR 7709 BG
10060 0 : ErrorsFound = true;
10061 0 : ShowSevereError(state,
10062 0 : format("{} = \"{}\" invalid, {} must be set to \"Yes\" for {} = OnIfScheduleAllows",
10063 : cCurrentModuleObject,
10064 0 : windowShadingControl.Name,
10065 0 : state.dataIPShortCut->cAlphaFieldNames(7),
10066 0 : state.dataIPShortCut->cAlphaFieldNames(5)));
10067 : }
10068 73 : windowShadingControl.slatAngleControl =
10069 73 : static_cast<SlatAngleControl>(getEnumValue(SlatAngleNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(10))));
10070 :
10071 : // For upward compatibility change old "noninsulating" and "insulating" shade types to
10072 : // INTERIORSHADE or EXTERIORSHADE
10073 146 : if (state.dataIPShortCut->cAlphaArgs(3) == "INTERIORNONINSULATINGSHADE" ||
10074 73 : state.dataIPShortCut->cAlphaArgs(3) == "INTERIORINSULATINGSHADE") {
10075 0 : ShowWarningError(state,
10076 0 : format("{}=\"{}\" is using obsolete {}=\"{}\", changing to \"InteriorShade\"",
10077 : cCurrentModuleObject,
10078 0 : windowShadingControl.Name,
10079 0 : state.dataIPShortCut->cAlphaFieldNames(3),
10080 0 : state.dataIPShortCut->cAlphaArgs(3)));
10081 0 : windowShadingControl.ShadingType = WinShadingType::IntShade;
10082 0 : state.dataIPShortCut->cAlphaArgs(3) = "INTERIORSHADE";
10083 : }
10084 146 : if (state.dataIPShortCut->cAlphaArgs(3) == "EXTERIORNONINSULATINGSHADE" ||
10085 73 : state.dataIPShortCut->cAlphaArgs(3) == "EXTERIORINSULATINGSHADE") {
10086 0 : ShowWarningError(state,
10087 0 : format("{}=\"{}\" is using obsolete {}=\"{}\", changing to \"ExteriorShade\"",
10088 : cCurrentModuleObject,
10089 0 : windowShadingControl.Name,
10090 0 : state.dataIPShortCut->cAlphaFieldNames(3),
10091 0 : state.dataIPShortCut->cAlphaArgs(3)));
10092 0 : windowShadingControl.ShadingType = WinShadingType::ExtShade;
10093 0 : state.dataIPShortCut->cAlphaArgs(3) = "EXTERIORSHADE";
10094 : }
10095 :
10096 74 : if (windowShadingControl.shadingControlType == WindowShadingControlType::MeetDaylIlumSetp &&
10097 1 : state.dataIPShortCut->cAlphaArgs(3) != "SWITCHABLEGLAZING") {
10098 0 : ErrorsFound = true;
10099 0 : ShowSevereError(state,
10100 0 : format("{}=\"{}\" invalid {}=\"{}\".",
10101 : cCurrentModuleObject,
10102 0 : windowShadingControl.Name,
10103 0 : state.dataIPShortCut->cAlphaFieldNames(3),
10104 0 : state.dataIPShortCut->cAlphaArgs(3)));
10105 0 : ShowContinueError(state,
10106 0 : format("...{} must be SwitchableGlazing for this control, but entered type=\"{}\".",
10107 0 : state.dataIPShortCut->cAlphaFieldNames(3),
10108 0 : state.dataIPShortCut->cAlphaArgs(3)));
10109 : }
10110 :
10111 : // Check for illegal shading type name
10112 73 : Found = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(3), cValidShadingTypes, NumValidShadingTypes);
10113 73 : if (Found <= 1) {
10114 0 : ErrorsFound = true;
10115 0 : ShowSevereError(state,
10116 0 : format("{}=\"{}\" invalid {}=\"{}\".",
10117 : cCurrentModuleObject,
10118 0 : windowShadingControl.Name,
10119 0 : state.dataIPShortCut->cAlphaFieldNames(3),
10120 0 : state.dataIPShortCut->cAlphaArgs(3)));
10121 : } else {
10122 73 : windowShadingControl.ShadingType = WinShadingType(Found);
10123 : }
10124 :
10125 73 : WinShadingType ShTyp = windowShadingControl.ShadingType;
10126 73 : IShadedConst = windowShadingControl.getInputShadedConstruction;
10127 73 : IShadingDevice = windowShadingControl.ShadingDevice;
10128 :
10129 73 : if (IShadedConst == 0 && IShadingDevice == 0) {
10130 0 : ShowSevereError(
10131 : state,
10132 0 : format("{}=\"{}\" has no matching shaded construction or shading device.", cCurrentModuleObject, windowShadingControl.Name));
10133 0 : ErrorsFound = true;
10134 73 : } else if (IShadedConst == 0 && IShadingDevice > 0) {
10135 13 : if (ShTyp == WinShadingType::SwitchableGlazing) {
10136 0 : ShowSevereError(state,
10137 0 : format("{}=\"{}\" has {}= SwitchableGlazing but no matching shaded construction",
10138 : cCurrentModuleObject,
10139 0 : windowShadingControl.Name,
10140 0 : state.dataIPShortCut->cAlphaArgs(3)));
10141 0 : ErrorsFound = true;
10142 : }
10143 26 : if ((ShTyp == WinShadingType::IntShade || ShTyp == WinShadingType::ExtShade) &&
10144 13 : state.dataMaterial->Material(IShadingDevice)->group != Material::Group::Shade) {
10145 0 : ShowSevereError(state,
10146 0 : format("{}=\"{}\" has {}= InteriorShade or ExteriorShade but matching shading device is not a window shade",
10147 : cCurrentModuleObject,
10148 0 : windowShadingControl.Name,
10149 0 : state.dataIPShortCut->cAlphaArgs(3)));
10150 0 : ShowContinueError(
10151 : state,
10152 0 : format("{} in error=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(8), state.dataMaterial->Material(IShadingDevice)->Name));
10153 0 : ErrorsFound = true;
10154 : }
10155 13 : if ((ShTyp == WinShadingType::ExtScreen) && state.dataMaterial->Material(IShadingDevice)->group != Material::Group::Screen) {
10156 0 : ShowSevereError(state,
10157 0 : format("{}=\"{}\" has {}= ExteriorScreen but matching shading device is not a window screen",
10158 : cCurrentModuleObject,
10159 0 : windowShadingControl.Name,
10160 0 : state.dataIPShortCut->cAlphaArgs(3)));
10161 0 : ShowContinueError(
10162 : state,
10163 0 : format("{} in error=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(8), state.dataMaterial->Material(IShadingDevice)->Name));
10164 0 : ErrorsFound = true;
10165 : }
10166 13 : if ((ShTyp == WinShadingType::IntBlind || ShTyp == WinShadingType::ExtBlind) &&
10167 0 : state.dataMaterial->Material(IShadingDevice)->group != Material::Group::WindowBlind) {
10168 0 : ShowSevereError(state,
10169 0 : format("{}=\"{}\" has {}= InteriorBlind or ExteriorBlind but matching shading device is not a window blind",
10170 : cCurrentModuleObject,
10171 0 : windowShadingControl.Name,
10172 0 : state.dataIPShortCut->cAlphaArgs(3)));
10173 0 : ShowContinueError(
10174 : state,
10175 0 : format("{} in error=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(8), state.dataMaterial->Material(IShadingDevice)->Name));
10176 0 : ErrorsFound = true;
10177 : }
10178 13 : if (ShTyp == WinShadingType::BGShade || ShTyp == WinShadingType::BGBlind) {
10179 0 : ShowSevereError(state,
10180 0 : format("{}=\"{}\" has {}= BetweenGlassShade or BetweenGlassBlind and",
10181 : cCurrentModuleObject,
10182 0 : windowShadingControl.Name,
10183 0 : state.dataIPShortCut->cAlphaArgs(3)));
10184 0 : ShowContinueError(
10185 : state,
10186 0 : format("{} is specified. This is illegal. Specify shaded construction instead.", state.dataIPShortCut->cAlphaFieldNames(8)));
10187 0 : ErrorsFound = true;
10188 : }
10189 60 : } else if (IShadedConst > 0 && IShadingDevice > 0) {
10190 0 : IShadingDevice = 0;
10191 0 : ShowWarningError(state,
10192 0 : format("{}=\"{}\" Both {} and {} are specified.",
10193 : cCurrentModuleObject,
10194 0 : windowShadingControl.Name,
10195 0 : state.dataIPShortCut->cAlphaFieldNames(4),
10196 0 : state.dataIPShortCut->cAlphaFieldNames(9)));
10197 0 : ShowContinueError(state,
10198 0 : format("The {}=\"{}\" will be used.",
10199 0 : state.dataIPShortCut->cAlphaFieldNames(4),
10200 0 : state.dataConstruction->Construct(IShadedConst).Name));
10201 : }
10202 :
10203 : // If type = interior or exterior shade or blind require that the shaded construction
10204 : // have a shade layer in the correct position
10205 73 : if (IShadedConst != 0) {
10206 :
10207 60 : NLayers = state.dataConstruction->Construct(IShadedConst).TotLayers;
10208 60 : BGShadeBlindError = false;
10209 60 : IShadingDevice = 0;
10210 60 : if (state.dataConstruction->Construct(IShadedConst).LayerPoint(NLayers) != 0) {
10211 60 : if (windowShadingControl.ShadingType == WinShadingType::IntShade) {
10212 10 : IShadingDevice = state.dataConstruction->Construct(IShadedConst).LayerPoint(NLayers);
10213 10 : if (state.dataMaterial->Material(state.dataConstruction->Construct(IShadedConst).LayerPoint(NLayers))->group !=
10214 : Material::Group::Shade) {
10215 0 : ErrorsFound = true;
10216 0 : ShowSevereError(state,
10217 0 : format("{}=\"{}\" the {}=\"{}\"",
10218 : cCurrentModuleObject,
10219 0 : windowShadingControl.Name,
10220 0 : state.dataIPShortCut->cAlphaFieldNames(4),
10221 0 : state.dataIPShortCut->cAlphaArgs(4)));
10222 0 : ShowContinueError(state,
10223 0 : format("of {}=\"{}\" should have a shade layer on the inside of the window.",
10224 0 : state.dataIPShortCut->cAlphaFieldNames(3),
10225 0 : state.dataIPShortCut->cAlphaArgs(3)));
10226 : }
10227 50 : } else if (windowShadingControl.ShadingType == WinShadingType::ExtShade) {
10228 5 : IShadingDevice = state.dataConstruction->Construct(IShadedConst).LayerPoint(1);
10229 5 : if (state.dataMaterial->Material(state.dataConstruction->Construct(IShadedConst).LayerPoint(1))->group !=
10230 : Material::Group::Shade) {
10231 0 : ErrorsFound = true;
10232 0 : ShowSevereError(state,
10233 0 : format("{}=\"{}\" the {}=\"{}\"",
10234 : cCurrentModuleObject,
10235 0 : windowShadingControl.Name,
10236 0 : state.dataIPShortCut->cAlphaFieldNames(43),
10237 0 : state.dataIPShortCut->cAlphaArgs(4)));
10238 0 : ShowContinueError(state,
10239 0 : format("of {}=\"{}\" should have a shade layer on the outside of the window.",
10240 0 : state.dataIPShortCut->cAlphaFieldNames(3),
10241 0 : state.dataIPShortCut->cAlphaArgs(3)));
10242 : }
10243 45 : } else if (windowShadingControl.ShadingType == WinShadingType::ExtScreen) {
10244 2 : IShadingDevice = state.dataConstruction->Construct(IShadedConst).LayerPoint(1);
10245 2 : if (state.dataMaterial->Material(state.dataConstruction->Construct(IShadedConst).LayerPoint(1))->group !=
10246 : Material::Group::Screen) {
10247 0 : ErrorsFound = true;
10248 0 : ShowSevereError(state,
10249 0 : format("{}=\"{}\" the {}=\"{}\"",
10250 : cCurrentModuleObject,
10251 0 : windowShadingControl.Name,
10252 0 : state.dataIPShortCut->cAlphaFieldNames(4),
10253 0 : state.dataIPShortCut->cAlphaArgs(4)));
10254 0 : ShowContinueError(state,
10255 0 : format("of {}=\"{}\" should have a screen layer on the outside of the window.",
10256 0 : state.dataIPShortCut->cAlphaFieldNames(3),
10257 0 : state.dataIPShortCut->cAlphaArgs(3)));
10258 : }
10259 43 : } else if (windowShadingControl.ShadingType == WinShadingType::IntBlind) {
10260 13 : IShadingDevice = state.dataConstruction->Construct(IShadedConst).LayerPoint(NLayers);
10261 13 : if (state.dataMaterial->Material(state.dataConstruction->Construct(IShadedConst).LayerPoint(NLayers))->group !=
10262 : Material::Group::WindowBlind) {
10263 0 : ErrorsFound = true;
10264 0 : ShowSevereError(state,
10265 0 : format("{}=\"{}\" the {}=\"{}\"",
10266 : cCurrentModuleObject,
10267 0 : windowShadingControl.Name,
10268 0 : state.dataIPShortCut->cAlphaFieldNames(4),
10269 0 : state.dataIPShortCut->cAlphaArgs(4)));
10270 0 : ShowContinueError(state,
10271 0 : format("of {}=\"{}\" should have a blind layer on the inside of the window.",
10272 0 : state.dataIPShortCut->cAlphaFieldNames(3),
10273 0 : state.dataIPShortCut->cAlphaArgs(3)));
10274 : }
10275 30 : } else if (windowShadingControl.ShadingType == WinShadingType::ExtBlind) {
10276 2 : IShadingDevice = state.dataConstruction->Construct(IShadedConst).LayerPoint(1);
10277 2 : if (state.dataMaterial->Material(state.dataConstruction->Construct(IShadedConst).LayerPoint(1))->group !=
10278 : Material::Group::WindowBlind) {
10279 0 : ErrorsFound = true;
10280 0 : ShowSevereError(state,
10281 0 : format("{}=\"{}\" the {}=\"{}\"",
10282 : cCurrentModuleObject,
10283 0 : windowShadingControl.Name,
10284 0 : state.dataIPShortCut->cAlphaFieldNames(4),
10285 0 : state.dataIPShortCut->cAlphaArgs(4)));
10286 0 : ShowContinueError(state,
10287 0 : format("of {}=\"{}\" should have a blind layer on the outside of the window.",
10288 0 : state.dataIPShortCut->cAlphaFieldNames(3),
10289 0 : state.dataIPShortCut->cAlphaArgs(3)));
10290 : }
10291 28 : } else if (windowShadingControl.ShadingType == WinShadingType::BGShade) {
10292 2 : if (NLayers != 5 && NLayers != 7) BGShadeBlindError = true;
10293 2 : if (NLayers == 5) {
10294 1 : if (state.dataMaterial->Material(state.dataConstruction->Construct(IShadedConst).LayerPoint(3))->group !=
10295 : Material::Group::Shade)
10296 0 : BGShadeBlindError = true;
10297 : }
10298 2 : if (NLayers == 7) {
10299 1 : if (state.dataMaterial->Material(state.dataConstruction->Construct(IShadedConst).LayerPoint(5))->group !=
10300 : Material::Group::Shade)
10301 0 : BGShadeBlindError = true;
10302 : }
10303 2 : if (BGShadeBlindError) {
10304 0 : ErrorsFound = true;
10305 0 : ShowSevereError(state,
10306 0 : format("{}=\"{}\" the {}=\"{}\"",
10307 : cCurrentModuleObject,
10308 0 : windowShadingControl.Name,
10309 0 : state.dataIPShortCut->cAlphaFieldNames(4),
10310 0 : state.dataIPShortCut->cAlphaArgs(4)));
10311 0 : ShowContinueError(state,
10312 0 : format("of {}=\"{}\" should have two or three glass layers and a",
10313 0 : state.dataIPShortCut->cAlphaFieldNames(3),
10314 0 : state.dataIPShortCut->cAlphaArgs(32)));
10315 0 : ShowContinueError(state, "between-glass shade layer with a gas layer on each side.");
10316 : }
10317 26 : } else if (windowShadingControl.ShadingType == WinShadingType::BGBlind) {
10318 3 : if (NLayers != 5 && NLayers != 7) BGShadeBlindError = true;
10319 3 : if (NLayers == 5) {
10320 2 : if (state.dataMaterial->Material(state.dataConstruction->Construct(IShadedConst).LayerPoint(3))->group !=
10321 : Material::Group::WindowBlind)
10322 0 : BGShadeBlindError = true;
10323 : }
10324 3 : if (NLayers == 7) {
10325 1 : if (state.dataMaterial->Material(state.dataConstruction->Construct(IShadedConst).LayerPoint(5))->group !=
10326 : Material::Group::WindowBlind)
10327 0 : BGShadeBlindError = true;
10328 : }
10329 3 : if (BGShadeBlindError) {
10330 0 : ErrorsFound = true;
10331 0 : ShowSevereError(state,
10332 0 : format("{}=\"{}\" the {}=\"{}\"",
10333 : cCurrentModuleObject,
10334 0 : windowShadingControl.Name,
10335 0 : state.dataIPShortCut->cAlphaFieldNames(4),
10336 0 : state.dataIPShortCut->cAlphaArgs(4)));
10337 0 : ShowContinueError(state,
10338 0 : format("of {}=\"{}\" should have two or three glass layers and a",
10339 0 : state.dataIPShortCut->cAlphaFieldNames(3),
10340 0 : state.dataIPShortCut->cAlphaArgs(3)));
10341 0 : ShowContinueError(state, "between-glass blind layer with a gas layer on each side.");
10342 : }
10343 : }
10344 : }
10345 60 : if (IShadingDevice > 0) {
10346 47 : if ((ShTyp == WinShadingType::IntShade || ShTyp == WinShadingType::ExtShade) &&
10347 15 : state.dataMaterial->Material(IShadingDevice)->group != Material::Group::Shade) {
10348 0 : ShowSevereError(state,
10349 0 : format("{}=\"{}\" has {}= InteriorShade or ExteriorShade but matching shading device is not a window shade",
10350 : cCurrentModuleObject,
10351 0 : windowShadingControl.Name,
10352 0 : state.dataIPShortCut->cAlphaFieldNames(3)));
10353 0 : ShowContinueError(state, format("Shading Device in error=\"{}\".", state.dataMaterial->Material(IShadingDevice)->Name));
10354 0 : ErrorsFound = true;
10355 : }
10356 32 : if ((ShTyp == WinShadingType::ExtScreen) && state.dataMaterial->Material(IShadingDevice)->group != Material::Group::Screen) {
10357 0 : ShowSevereError(state,
10358 0 : format("{}=\"{}\" has {}= ExteriorScreen but matching shading device is not an exterior window screen.",
10359 : cCurrentModuleObject,
10360 0 : windowShadingControl.Name,
10361 0 : state.dataIPShortCut->cAlphaFieldNames(3)));
10362 0 : ShowContinueError(state, format("Shading Device in error=\"{}\".", state.dataMaterial->Material(IShadingDevice)->Name));
10363 0 : ErrorsFound = true;
10364 : }
10365 47 : if ((ShTyp == WinShadingType::IntBlind || ShTyp == WinShadingType::ExtBlind) &&
10366 15 : state.dataMaterial->Material(IShadingDevice)->group != Material::Group::WindowBlind) {
10367 0 : ShowSevereError(state,
10368 0 : format("{}=\"{}\" has {}= InteriorBlind or ExteriorBlind but matching shading device is not a window blind.",
10369 : cCurrentModuleObject,
10370 0 : windowShadingControl.Name,
10371 0 : state.dataIPShortCut->cAlphaFieldNames(3)));
10372 0 : ShowContinueError(state, format("Shading Device in error=\"{}\".", state.dataMaterial->Material(IShadingDevice)->Name));
10373 0 : ErrorsFound = true;
10374 : }
10375 : }
10376 : }
10377 : } // End of loop over window shading controls
10378 : }
10379 :
10380 6226 : void InitialAssociateWindowShadingControlFenestration(EnergyPlusData &state, bool &ErrorsFound, int &SurfNum)
10381 : {
10382 : // J.Glazer 2018 - operates on SurfaceTmp array before final indices are known for windows and sets the activeWindowShadingControl
10383 7916 : for (int iShadeCtrl = 1; iShadeCtrl <= state.dataSurface->TotWinShadingControl; ++iShadeCtrl) {
10384 1690 : int curShadedConstruction = state.dataSurface->WindowShadingControl(iShadeCtrl).getInputShadedConstruction;
10385 6672 : for (int jFeneRef = 1; jFeneRef <= state.dataSurface->WindowShadingControl(iShadeCtrl).FenestrationCount; ++jFeneRef) {
10386 4982 : if (Util::SameString(state.dataSurface->WindowShadingControl(iShadeCtrl).FenestrationName(jFeneRef),
10387 4982 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name)) {
10388 155 : state.dataGlobal->AndShadingControlInModel = true;
10389 155 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).HasShadeControl = true;
10390 155 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).windowShadingControlList.push_back(iShadeCtrl);
10391 155 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).activeWindowShadingControl = iShadeCtrl;
10392 155 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).shadedConstructionList.push_back(curShadedConstruction);
10393 155 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).activeShadedConstruction = curShadedConstruction;
10394 :
10395 : // check to make the window refenced is an exterior window
10396 155 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond != ExternalEnvironment) {
10397 0 : ErrorsFound = true;
10398 0 : ShowSevereError(
10399 : state,
10400 0 : format("InitialAssociateWindowShadingControlFenestration: \"{}\", invalid because it is not an exterior window.",
10401 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name));
10402 0 : ShowContinueError(
10403 : state,
10404 0 : format(".. It appears on WindowShadingControl object: \"{}", state.dataSurface->WindowShadingControl(iShadeCtrl).Name));
10405 : }
10406 : // check to make sure the window is not using equivalent layer window construction
10407 155 : if (state.dataConstruction->Construct(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction).WindowTypeEQL) {
10408 0 : ErrorsFound = true;
10409 0 : ShowSevereError(state,
10410 0 : format("InitialAssociateWindowShadingControlFenestration: =\"{}\", invalid \".",
10411 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name));
10412 0 : ShowContinueError(state, ".. equivalent layer window model does not use shading control object.");
10413 0 : ShowContinueError(state, ".. Shading control is set to none or zero, and simulation continues.");
10414 0 : ShowContinueError(
10415 : state,
10416 0 : format(".. It appears on WindowShadingControl object: \"{}", state.dataSurface->WindowShadingControl(iShadeCtrl).Name));
10417 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).activeWindowShadingControl = 0;
10418 : }
10419 : }
10420 : }
10421 : }
10422 6226 : }
10423 :
10424 46044 : void FinalAssociateWindowShadingControlFenestration(EnergyPlusData &state, bool &ErrorsFound)
10425 : {
10426 : // J.Glazer 2018 - operates on Surface array after final indices are known for windows and checks to make sure it is correct
10427 53724 : for (int iShadeCtrl = 1; iShadeCtrl <= state.dataSurface->TotWinShadingControl; ++iShadeCtrl) {
10428 25887 : for (int jFeneRef = 1; jFeneRef <= state.dataSurface->WindowShadingControl(iShadeCtrl).FenestrationCount; ++jFeneRef) {
10429 18207 : int fenestrationIndex = Util::FindItemInList(state.dataSurface->WindowShadingControl(iShadeCtrl).FenestrationName(jFeneRef),
10430 18207 : state.dataSurface->Surface,
10431 18207 : state.dataSurface->TotSurfaces);
10432 36414 : if (std::find(state.dataSurface->Surface(fenestrationIndex).windowShadingControlList.begin(),
10433 36414 : state.dataSurface->Surface(fenestrationIndex).windowShadingControlList.end(),
10434 54621 : iShadeCtrl) != state.dataSurface->Surface(fenestrationIndex).windowShadingControlList.end()) {
10435 18207 : state.dataSurface->WindowShadingControl(iShadeCtrl).FenestrationIndex(jFeneRef) = fenestrationIndex;
10436 : } else {
10437 : // this error condition should not occur since the rearrangement of Surface() from SurfureTmp() is reliable.
10438 0 : ErrorsFound = true;
10439 0 : ShowSevereError(state,
10440 0 : format("FinalAssociateWindowShadingControlFenestration: Fenestration surface named \"{}\" has "
10441 : "WindowShadingContol index that does not match the initial index assigned.",
10442 0 : state.dataSurface->Surface(fenestrationIndex).Name));
10443 0 : ShowContinueError(state,
10444 0 : format("This occurs while WindowShadingControl object: \"{}\" is being evaluated. ",
10445 0 : state.dataSurface->WindowShadingControl(iShadeCtrl).Name));
10446 : }
10447 : }
10448 : }
10449 46044 : }
10450 :
10451 46044 : void CheckWindowShadingControlSimilarForWindow(EnergyPlusData &state, bool &ErrorsFound)
10452 : {
10453 : // For each window check if all window shading controls on list are the same except for name, schedule name, construction, and
10454 : // material
10455 12259950 : for (auto &theSurf : state.dataSurface->Surface) {
10456 12213906 : if (theSurf.HasShadeControl) {
10457 18067 : if (theSurf.windowShadingControlList.size() > 1) {
10458 140 : int firstWindowShadingControl = theSurf.windowShadingControlList.front();
10459 420 : for (auto wsc = std::next(theSurf.windowShadingControlList.begin()); wsc != theSurf.windowShadingControlList.end(); ++wsc) {
10460 140 : if (!isWindowShadingControlSimilar(state, firstWindowShadingControl, *wsc)) {
10461 0 : ErrorsFound = true;
10462 0 : ShowSevereError(state,
10463 0 : format("CheckWindowShadingControlSimilarForWindow: Fenestration surface named \"{}\" has multiple "
10464 : "WindowShadingContols that are not similar.",
10465 0 : theSurf.Name));
10466 0 : ShowContinueError(state,
10467 0 : format("for: \"{} and: {}",
10468 0 : state.dataSurface->WindowShadingControl(firstWindowShadingControl).Name,
10469 0 : state.dataSurface->WindowShadingControl(*wsc).Name));
10470 : }
10471 140 : }
10472 : }
10473 : }
10474 46044 : }
10475 46044 : }
10476 :
10477 140 : bool isWindowShadingControlSimilar(EnergyPlusData &state, int a, int b)
10478 : {
10479 : // Compares two window shading controls are the same except for the name, schedule name, construction, and material
10480 140 : auto &WindowShadingControlA = state.dataSurface->WindowShadingControl(a);
10481 140 : auto &WindowShadingControlB = state.dataSurface->WindowShadingControl(b);
10482 280 : return (WindowShadingControlA.ZoneIndex == WindowShadingControlB.ZoneIndex &&
10483 140 : WindowShadingControlA.ShadingType == WindowShadingControlB.ShadingType &&
10484 140 : WindowShadingControlA.shadingControlType == WindowShadingControlB.shadingControlType &&
10485 140 : WindowShadingControlA.SetPoint == WindowShadingControlB.SetPoint &&
10486 140 : WindowShadingControlA.ShadingControlIsScheduled == WindowShadingControlB.ShadingControlIsScheduled &&
10487 140 : WindowShadingControlA.GlareControlIsActive == WindowShadingControlB.GlareControlIsActive &&
10488 140 : WindowShadingControlA.slatAngleControl == WindowShadingControlB.slatAngleControl &&
10489 280 : WindowShadingControlA.SetPoint2 == WindowShadingControlB.SetPoint2 &&
10490 140 : WindowShadingControlA.DaylightingControlName == WindowShadingControlB.DaylightingControlName &&
10491 420 : WindowShadingControlA.DaylightControlIndex == WindowShadingControlB.DaylightControlIndex &&
10492 280 : WindowShadingControlA.multiSurfaceControl == WindowShadingControlB.multiSurfaceControl);
10493 : }
10494 :
10495 796 : void GetStormWindowData(EnergyPlusData &state, bool &ErrorsFound) // If errors found in input
10496 : {
10497 :
10498 : // SUBROUTINE INFORMATION:
10499 : // AUTHOR Fred Winkelmann
10500 : // DATE WRITTEN December 2003
10501 : // MODIFIED na
10502 :
10503 : // RE-ENGINEERED na
10504 :
10505 : // PURPOSE OF THIS SUBROUTINE:
10506 : // Reads in the storm window data from the input file,
10507 : // interprets it and puts it in the derived type
10508 :
10509 : // Using/Aliasing
10510 :
10511 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
10512 :
10513 : int IOStat; // IO Status when calling get input subroutine
10514 : int StormWinNumAlpha; // Number of alpha names being passed
10515 : int StormWinNumProp; // Number of properties being passed
10516 : int StormWinNum; // Index for storm window number
10517 : int loop; // Do loop counter
10518 : int SurfNum; // Surface number
10519 : int MatNum; // Material number
10520 :
10521 796 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
10522 :
10523 : // Get the total number of storm window input objects
10524 796 : cCurrentModuleObject = "WindowProperty:StormWindow";
10525 796 : state.dataSurface->TotStormWin = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
10526 796 : if (state.dataSurface->TotStormWin == 0) return;
10527 :
10528 1 : state.dataSurface->StormWindow.allocate(state.dataSurface->TotStormWin);
10529 :
10530 1 : StormWinNum = 0;
10531 1 : for (loop = 1; loop <= state.dataSurface->TotStormWin; ++loop) {
10532 :
10533 2 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
10534 : cCurrentModuleObject,
10535 : loop,
10536 1 : state.dataIPShortCut->cAlphaArgs,
10537 : StormWinNumAlpha,
10538 1 : state.dataIPShortCut->rNumericArgs,
10539 : StormWinNumProp,
10540 : IOStat,
10541 1 : state.dataIPShortCut->lNumericFieldBlanks,
10542 1 : state.dataIPShortCut->lAlphaFieldBlanks,
10543 1 : state.dataIPShortCut->cAlphaFieldNames,
10544 1 : state.dataIPShortCut->cNumericFieldNames);
10545 1 : ++StormWinNum;
10546 1 : state.dataSurface->StormWindow(StormWinNum).BaseWindowNum =
10547 1 : Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(1), state.dataSurface->Surface, state.dataSurface->TotSurfaces);
10548 1 : state.dataSurface->StormWindow(StormWinNum).StormWinMaterialNum =
10549 1 : Util::FindItemInPtrList(state.dataIPShortCut->cAlphaArgs(2), state.dataMaterial->Material, state.dataMaterial->TotMaterials);
10550 1 : state.dataSurface->StormWindow(StormWinNum).StormWinDistance = state.dataIPShortCut->rNumericArgs(1);
10551 1 : state.dataSurface->StormWindow(StormWinNum).MonthOn = state.dataIPShortCut->rNumericArgs(2);
10552 1 : state.dataSurface->StormWindow(StormWinNum).DayOfMonthOn = state.dataIPShortCut->rNumericArgs(3);
10553 1 : state.dataSurface->StormWindow(StormWinNum).DateOn =
10554 1 : General::OrdinalDay(state.dataSurface->StormWindow(StormWinNum).MonthOn, state.dataSurface->StormWindow(StormWinNum).DayOfMonthOn, 1);
10555 1 : state.dataSurface->StormWindow(StormWinNum).MonthOff = state.dataIPShortCut->rNumericArgs(4);
10556 1 : state.dataSurface->StormWindow(StormWinNum).DayOfMonthOff = state.dataIPShortCut->rNumericArgs(5);
10557 1 : state.dataSurface->StormWindow(StormWinNum).DateOff = General::OrdinalDay(
10558 1 : state.dataSurface->StormWindow(StormWinNum).MonthOff, state.dataSurface->StormWindow(StormWinNum).DayOfMonthOff, 1);
10559 :
10560 1 : if (state.dataSurface->StormWindow(StormWinNum).DateOn == state.dataSurface->StormWindow(StormWinNum).DateOff) {
10561 0 : ShowSevereError(state,
10562 0 : format("{}: Date On = Date Off -- not allowed, occurred in WindowProperty:StormWindow Input #{}",
10563 : cCurrentModuleObject,
10564 : StormWinNum));
10565 0 : ErrorsFound = true;
10566 : }
10567 :
10568 : enum Month
10569 : {
10570 : January = 1,
10571 : February,
10572 : March,
10573 : April,
10574 : May,
10575 : June,
10576 : July,
10577 : August,
10578 : September,
10579 : October,
10580 : November,
10581 : December
10582 : };
10583 1 : constexpr std::array<int, 13> oneBasedDaysInMonth = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
10584 :
10585 1 : int const monthOn = state.dataSurface->StormWindow(StormWinNum).MonthOn;
10586 1 : if (monthOn >= January && monthOn <= December) {
10587 2 : if (state.dataSurface->StormWindow(StormWinNum).DayOfMonthOn >
10588 1 : oneBasedDaysInMonth[state.dataSurface->StormWindow(StormWinNum).MonthOn]) {
10589 0 : ShowSevereError(state,
10590 0 : format("{}: Date On (Day of Month) [{}], invalid for WindowProperty:StormWindow Input #{}",
10591 : cCurrentModuleObject,
10592 0 : state.dataSurface->StormWindow(StormWinNum).DayOfMonthOn,
10593 : StormWinNum));
10594 0 : ErrorsFound = true;
10595 : }
10596 1 : break;
10597 : } else {
10598 0 : ShowSevereError(state,
10599 0 : format("{}: Date On Month [{}], invalid for WindowProperty:StormWindow Input #{}",
10600 : cCurrentModuleObject,
10601 0 : state.dataSurface->StormWindow(StormWinNum).MonthOn,
10602 : StormWinNum));
10603 0 : ErrorsFound = true;
10604 : }
10605 :
10606 0 : int const monthOff = state.dataSurface->StormWindow(StormWinNum).MonthOff;
10607 0 : if (monthOff >= January && monthOff <= December) {
10608 0 : if (state.dataSurface->StormWindow(StormWinNum).DayOfMonthOff >
10609 0 : oneBasedDaysInMonth[state.dataSurface->StormWindow(StormWinNum).MonthOff]) {
10610 0 : ShowSevereError(state,
10611 0 : format("{}: Date Off (Day of Month) [{}], invalid for WindowProperty:StormWindow Input #{}",
10612 : cCurrentModuleObject,
10613 0 : state.dataSurface->StormWindow(StormWinNum).DayOfMonthOff,
10614 : StormWinNum));
10615 0 : ErrorsFound = true;
10616 : }
10617 0 : break;
10618 : } else {
10619 0 : ShowSevereError(state,
10620 0 : format("{}: Date Off Month [{}], invalid for WindowProperty:StormWindow Input #{}",
10621 : cCurrentModuleObject,
10622 0 : state.dataSurface->StormWindow(StormWinNum).MonthOff,
10623 : StormWinNum));
10624 0 : ErrorsFound = true;
10625 : }
10626 : }
10627 :
10628 : // Error checks
10629 :
10630 2 : for (StormWinNum = 1; StormWinNum <= state.dataSurface->TotStormWin; ++StormWinNum) {
10631 : // Require BaseWindowNum be that of an exterior window
10632 1 : SurfNum = state.dataSurface->StormWindow(StormWinNum).BaseWindowNum;
10633 1 : if (SurfNum == 0) {
10634 0 : ShowSevereError(state, format("{}=\"{}\" invalid.", cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
10635 0 : ErrorsFound = true;
10636 : } else {
10637 1 : auto const &surf = state.dataSurface->Surface(SurfNum);
10638 1 : if (surf.Class != SurfaceClass::Window || surf.ExtBoundCond != 0) {
10639 0 : ShowSevereError(state, format("{}=\"{}\"", cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
10640 0 : ShowContinueError(state, format("cannot be used with surface={}", surf.Name));
10641 0 : ShowContinueError(state, "because that surface is not an exterior window.");
10642 0 : ErrorsFound = true;
10643 : }
10644 : }
10645 :
10646 : // Require that storm window material be glass
10647 1 : MatNum = state.dataSurface->StormWindow(StormWinNum).StormWinMaterialNum;
10648 1 : if (SurfNum > 0) {
10649 1 : if (MatNum == 0) {
10650 0 : ShowSevereError(state, format("{}=\"{}\"", cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
10651 0 : ShowContinueError(state,
10652 0 : format("{}=\"{}\" not found as storm window layer.",
10653 0 : state.dataIPShortCut->cAlphaFieldNames(2),
10654 0 : state.dataIPShortCut->cAlphaArgs(2)));
10655 0 : ErrorsFound = true;
10656 : } else {
10657 1 : if (state.dataMaterial->Material(MatNum)->group != Material::Group::WindowGlass) {
10658 0 : ShowSevereError(state, format("{}=\"{}\"", cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
10659 0 : ShowContinueError(state,
10660 0 : format("{}=\"{}must be a WindowMaterial:Glazing or WindowMaterial:Glazing:RefractionExtinctionMethod",
10661 0 : state.dataIPShortCut->cAlphaFieldNames(2),
10662 0 : state.dataIPShortCut->cAlphaArgs(2)));
10663 0 : ErrorsFound = true;
10664 : }
10665 : }
10666 : }
10667 :
10668 : // Error if base window has airflow control
10669 1 : if (SurfNum > 0) {
10670 1 : if (state.dataSurface->SurfWinAirflowControlType(SurfNum) != DataSurfaces::WindowAirFlowControlType::Invalid) {
10671 0 : ShowSevereError(
10672 : state,
10673 0 : format("{}=\"{} cannot be used because it is an airflow window (i.e., has WindowProperty:AirflowControl specified)",
10674 : cCurrentModuleObject,
10675 0 : state.dataIPShortCut->cAlphaArgs(1)));
10676 0 : ErrorsFound = true;
10677 : }
10678 : }
10679 :
10680 : // Check for reversal of on and off times
10681 1 : if (SurfNum > 0) {
10682 1 : if ((state.dataEnvrn->Latitude > 0.0 &&
10683 2 : (state.dataSurface->StormWindow(StormWinNum).MonthOn < state.dataSurface->StormWindow(StormWinNum).MonthOff)) ||
10684 1 : (state.dataEnvrn->Latitude <= 0.0 &&
10685 0 : (state.dataSurface->StormWindow(StormWinNum).MonthOn > state.dataSurface->StormWindow(StormWinNum).MonthOff))) {
10686 0 : ShowWarningError(state,
10687 0 : format("{}=\"{}\" check times that storm window", cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
10688 0 : ShowContinueError(state,
10689 0 : format("is put on (month={}, day={}) and taken off (month={}, day={});",
10690 0 : state.dataSurface->StormWindow(StormWinNum).MonthOn,
10691 0 : state.dataSurface->StormWindow(StormWinNum).DayOfMonthOn,
10692 0 : state.dataSurface->StormWindow(StormWinNum).MonthOff,
10693 0 : state.dataSurface->StormWindow(StormWinNum).DayOfMonthOff));
10694 0 : ShowContinueError(state, format("these times may be reversed for your building latitude={:.2R} deg.", state.dataEnvrn->Latitude));
10695 : }
10696 : }
10697 : }
10698 : }
10699 :
10700 796 : void GetWindowGapAirflowControlData(EnergyPlusData &state, bool &ErrorsFound) // If errors found in input
10701 : {
10702 :
10703 : // SUBROUTINE INFORMATION:
10704 : // AUTHOR Fred Winkelmann
10705 : // DATE WRITTEN Feb 2003
10706 : // MODIFIED June 2003, FCW: add destination = return air;
10707 : // more error messages
10708 : // RE-ENGINEERED na
10709 :
10710 : // PURPOSE OF THIS SUBROUTINE:
10711 : // Reads in the window airflow control information from the input data file,
10712 : // interprets it and puts it in the SurfaceWindow derived type
10713 :
10714 : // Using/Aliasing
10715 : using ScheduleManager::GetScheduleIndex;
10716 :
10717 : static constexpr std::string_view RoutineName("GetWindowGapAirflowControlData");
10718 : int IOStat; // IO Status when calling get input subroutine
10719 : int ControlNumAlpha; // Number of control alpha names being passed
10720 : int ControlNumProp; // Number of control properties being passed
10721 : int TotWinAirflowControl; // Total window airflow control statements
10722 : bool WrongSurfaceType; // True if associated surface is not 2- or 3-pane exterior window
10723 : int Loop;
10724 : int SurfNum; // Surface number
10725 796 : int ConstrNum(0); // Construction number
10726 : int ConstrNumSh; // Shaded Construction number
10727 : int MatGapFlow; // Material number of gas in airflow gap of window's construction
10728 : int MatGapFlow1; // Material number of gas on either side of a between-glass shade/blind
10729 : int MatGapFlow2;
10730 :
10731 796 : constexpr std::array<std::string_view, static_cast<int>(WindowAirFlowSource::Num)> WindowAirFlowSourceNamesUC{"INDOORAIR", "OUTDOORAIR"};
10732 796 : constexpr std::array<std::string_view, static_cast<int>(WindowAirFlowDestination::Num)> WindowAirFlowDestinationNamesUC{
10733 : "INDOORAIR", "OUTDOORAIR", "RETURNAIR"};
10734 :
10735 : // of the shaded construction of airflow window
10736 796 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
10737 : // Get the total number of window airflow control statements
10738 796 : cCurrentModuleObject = "WindowProperty:AirflowControl";
10739 796 : TotWinAirflowControl = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
10740 796 : if (TotWinAirflowControl == 0) return;
10741 :
10742 10 : for (Loop = 1; Loop <= TotWinAirflowControl; ++Loop) { // Loop through all surfaces in the input...
10743 :
10744 16 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
10745 : cCurrentModuleObject,
10746 : Loop,
10747 8 : state.dataIPShortCut->cAlphaArgs,
10748 : ControlNumAlpha,
10749 8 : state.dataIPShortCut->rNumericArgs,
10750 : ControlNumProp,
10751 : IOStat,
10752 8 : state.dataIPShortCut->lNumericFieldBlanks,
10753 8 : state.dataIPShortCut->lAlphaFieldBlanks,
10754 8 : state.dataIPShortCut->cAlphaFieldNames,
10755 8 : state.dataIPShortCut->cNumericFieldNames);
10756 :
10757 8 : SurfNum = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(1), state.dataSurface->Surface, state.dataSurface->TotSurfaces);
10758 8 : if (SurfNum == 0) {
10759 0 : ShowSevereError(state, format("{}=\"{}\" not found.", cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
10760 0 : ErrorsFound = true;
10761 : }
10762 : // Check that associated surface is a 2- or 3-pane exterior window
10763 8 : WrongSurfaceType = false;
10764 8 : if (SurfNum != 0) {
10765 8 : auto const &surf = state.dataSurface->Surface(SurfNum);
10766 8 : if (surf.Class != SurfaceClass::Window) WrongSurfaceType = true;
10767 8 : if (surf.Class == SurfaceClass::Window) {
10768 8 : ConstrNum = surf.Construction;
10769 12 : if (state.dataConstruction->Construct(ConstrNum).TotGlassLayers != 2 &&
10770 4 : state.dataConstruction->Construct(ConstrNum).TotGlassLayers != 3)
10771 0 : WrongSurfaceType = true;
10772 8 : if (surf.ExtBoundCond != ExternalEnvironment) WrongSurfaceType = true;
10773 : }
10774 8 : if (WrongSurfaceType) {
10775 0 : ShowSevereError(state,
10776 0 : format("{}=\"{}\" is not an exterior window with 2 or 3 glass layers.",
10777 : cCurrentModuleObject,
10778 0 : state.dataIPShortCut->cAlphaArgs(1)));
10779 0 : ErrorsFound = true;
10780 : }
10781 : }
10782 :
10783 : // Error if illegal airflow source
10784 8 : if (state.dataIPShortCut->cAlphaArgs(2) != "INDOORAIR" && state.dataIPShortCut->cAlphaArgs(2) != "OUTDOORAIR") {
10785 0 : ErrorsFound = true;
10786 0 : ShowSevereError(state,
10787 0 : format("{}=\"{}\" invalid {}=\"{}\"",
10788 : cCurrentModuleObject,
10789 0 : state.dataIPShortCut->cAlphaArgs(1),
10790 0 : state.dataIPShortCut->cAlphaFieldNames(2),
10791 0 : state.dataIPShortCut->cAlphaArgs(2)));
10792 : }
10793 :
10794 : // Error if illegal airflow destination
10795 8 : if (state.dataIPShortCut->cAlphaArgs(3) != "INDOORAIR" && state.dataIPShortCut->cAlphaArgs(3) != "OUTDOORAIR" &&
10796 0 : state.dataIPShortCut->cAlphaArgs(3) != "RETURNAIR") {
10797 0 : ErrorsFound = true;
10798 0 : ShowSevereError(state,
10799 0 : format("{}=\"{}\" invalid {}=\"{}\"",
10800 : cCurrentModuleObject,
10801 0 : state.dataIPShortCut->cAlphaArgs(1),
10802 0 : state.dataIPShortCut->cAlphaFieldNames(3),
10803 0 : state.dataIPShortCut->cAlphaArgs(3)));
10804 : }
10805 :
10806 : // Error if source = OutsideAir and destination = ReturnAir
10807 8 : if (state.dataIPShortCut->cAlphaArgs(2) == "OUTDOORAIR" && state.dataIPShortCut->cAlphaArgs(3) == "RETURNAIR") {
10808 0 : ErrorsFound = true;
10809 0 : ShowSevereError(state,
10810 0 : format("{}=\"{}\" invalid {}=\"{}\"",
10811 : cCurrentModuleObject,
10812 0 : state.dataIPShortCut->cAlphaArgs(1),
10813 0 : state.dataIPShortCut->cAlphaFieldNames(2),
10814 0 : state.dataIPShortCut->cAlphaArgs(2)));
10815 0 : ShowContinueError(state, format("..when {}=\"{}\"", state.dataIPShortCut->cAlphaFieldNames(3), state.dataIPShortCut->cAlphaArgs(3)));
10816 : }
10817 :
10818 : // Error if illegal airflow control type
10819 8 : if (state.dataIPShortCut->cAlphaArgs(4) != "ALWAYSONATMAXIMUMFLOW" && state.dataIPShortCut->cAlphaArgs(4) != "ALWAYSOFF" &&
10820 0 : state.dataIPShortCut->cAlphaArgs(4) != "SCHEDULEDONLY") {
10821 0 : ErrorsFound = true;
10822 0 : ShowSevereError(state,
10823 0 : format("{}=\"{}\" invalid {}=\"{}\"",
10824 : cCurrentModuleObject,
10825 0 : state.dataIPShortCut->cAlphaArgs(1),
10826 0 : state.dataIPShortCut->cAlphaFieldNames(4),
10827 0 : state.dataIPShortCut->cAlphaArgs(4)));
10828 : }
10829 :
10830 : // Error if illegal value for Airflow Has Multiplier Schedule
10831 8 : if (state.dataIPShortCut->cAlphaArgs(5) != "YES" && state.dataIPShortCut->cAlphaArgs(5) != "NO") {
10832 0 : ErrorsFound = true;
10833 0 : ShowSevereError(state,
10834 0 : format("{}=\"{}\" invalid {}=\"{}\"",
10835 : cCurrentModuleObject,
10836 0 : state.dataIPShortCut->cAlphaArgs(1),
10837 0 : state.dataIPShortCut->cAlphaFieldNames(5),
10838 0 : state.dataIPShortCut->cAlphaArgs(5)));
10839 : }
10840 :
10841 : // Error if Airflow Control Type = ScheduledOnly and Airflow Has Multiplier Schedule = No
10842 8 : if (state.dataIPShortCut->cAlphaArgs(4) == "SCHEDULEDONLY" && state.dataIPShortCut->cAlphaArgs(5) == "NO") {
10843 0 : ErrorsFound = true;
10844 0 : ShowSevereError(state,
10845 0 : format("{}=\"{}\" invalid {}=\"{}\"",
10846 : cCurrentModuleObject,
10847 0 : state.dataIPShortCut->cAlphaArgs(1),
10848 0 : state.dataIPShortCut->cAlphaFieldNames(4),
10849 0 : state.dataIPShortCut->cAlphaArgs(4)));
10850 0 : ShowContinueError(state, format("..when {}=\"{}\"", state.dataIPShortCut->cAlphaFieldNames(5), state.dataIPShortCut->cAlphaArgs(5)));
10851 : }
10852 :
10853 : // Warning if Airflow Control Type = AlwaysOnAtMaxFlow and Airflow Has Multiplier Schedule = Yes
10854 8 : if (state.dataIPShortCut->cAlphaArgs(4) == "ALWAYSONATMAXIMUMFLOW" && state.dataIPShortCut->cAlphaArgs(5) == "YES") {
10855 0 : ShowWarningError(state,
10856 0 : format("{}=\"{}has {}=\"{}\"",
10857 : cCurrentModuleObject,
10858 0 : state.dataIPShortCut->cAlphaArgs(1),
10859 0 : state.dataIPShortCut->cAlphaFieldNames(4),
10860 0 : state.dataIPShortCut->cAlphaArgs(4)));
10861 0 : ShowContinueError(state,
10862 0 : format("..but {}=\"{}If specified, the {} will be ignored.",
10863 0 : state.dataIPShortCut->cAlphaFieldNames(5),
10864 0 : state.dataIPShortCut->cAlphaArgs(5),
10865 0 : state.dataIPShortCut->cAlphaFieldNames(5)));
10866 : }
10867 :
10868 : // Warning if Airflow Control Type = AlwaysOff and Airflow Has Multiplier Schedule = Yes
10869 8 : if (state.dataIPShortCut->cAlphaArgs(4) == "ALWAYSOFF" && state.dataIPShortCut->cAlphaArgs(5) == "YES") {
10870 0 : ShowWarningError(state,
10871 0 : format("{}=\"{}has {}=\"{}\"",
10872 : cCurrentModuleObject,
10873 0 : state.dataIPShortCut->cAlphaArgs(1),
10874 0 : state.dataIPShortCut->cAlphaFieldNames(4),
10875 0 : state.dataIPShortCut->cAlphaArgs(4)));
10876 0 : ShowContinueError(state,
10877 0 : format("..but {}=\"{}\". If specified, the {} will be ignored.",
10878 0 : state.dataIPShortCut->cAlphaFieldNames(5),
10879 0 : state.dataIPShortCut->cAlphaArgs(5),
10880 0 : state.dataIPShortCut->cAlphaFieldNames(5)));
10881 : }
10882 :
10883 8 : if (SurfNum > 0) {
10884 8 : auto const &surf = state.dataSurface->Surface(SurfNum);
10885 8 : state.dataSurface->AirflowWindows = true;
10886 8 : state.dataSurface->SurfWinAirflowSource(SurfNum) =
10887 8 : static_cast<WindowAirFlowSource>(getEnumValue(WindowAirFlowSourceNamesUC, state.dataIPShortCut->cAlphaArgs(2)));
10888 :
10889 8 : state.dataSurface->SurfWinAirflowDestination(SurfNum) =
10890 8 : static_cast<WindowAirFlowDestination>(getEnumValue(WindowAirFlowDestinationNamesUC, state.dataIPShortCut->cAlphaArgs(3)));
10891 :
10892 8 : if (state.dataSurface->SurfWinAirflowDestination(SurfNum) == WindowAirFlowDestination::Return) {
10893 0 : int controlledZoneNum = DataZoneEquipment::GetControlledZoneIndex(state, surf.ZoneName);
10894 0 : if (controlledZoneNum > 0) {
10895 0 : state.dataHeatBal->Zone(surf.Zone).HasAirFlowWindowReturn = true;
10896 : }
10897 :
10898 : // Set return air node number
10899 0 : state.dataSurface->SurfWinAirflowReturnNodePtr(SurfNum) = 0;
10900 0 : std::string retNodeName = "";
10901 0 : if (!state.dataIPShortCut->lAlphaFieldBlanks(7)) {
10902 0 : retNodeName = state.dataIPShortCut->cAlphaArgs(7);
10903 : }
10904 0 : std::string callDescription = cCurrentModuleObject + "=" + surf.Name;
10905 0 : state.dataSurface->SurfWinAirflowReturnNodePtr(SurfNum) =
10906 0 : DataZoneEquipment::GetReturnAirNodeForZone(state, surf.Zone, retNodeName, callDescription);
10907 0 : if (state.dataSurface->SurfWinAirflowReturnNodePtr(SurfNum) == 0) {
10908 0 : ShowSevereError(state,
10909 0 : format("{}{}=\"{}\", airflow window return air node not found for {} = {}",
10910 : RoutineName,
10911 : cCurrentModuleObject,
10912 0 : surf.Name,
10913 0 : state.dataIPShortCut->cAlphaFieldNames(3),
10914 0 : state.dataIPShortCut->cAlphaArgs(3)));
10915 0 : if (!state.dataIPShortCut->lAlphaFieldBlanks(7))
10916 0 : ShowContinueError(state,
10917 0 : format("{}=\"{}\" did not find a matching return air node.",
10918 0 : state.dataIPShortCut->cAlphaFieldNames(7),
10919 0 : state.dataIPShortCut->cAlphaArgs(7)));
10920 0 : ShowContinueError(state,
10921 : "..Airflow windows with Airflow Destination = ReturnAir must reference a controlled Zone (appear in a "
10922 : "ZoneHVAC:EquipmentConnections object) with at least one return air node.");
10923 0 : ErrorsFound = true;
10924 : }
10925 0 : }
10926 8 : if (Util::SameString(state.dataIPShortCut->cAlphaArgs(4), "AlwaysOnAtMaximumFlow")) {
10927 8 : state.dataSurface->SurfWinAirflowControlType(SurfNum) = WindowAirFlowControlType::MaxFlow;
10928 0 : } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(4), "AlwaysOff")) {
10929 0 : state.dataSurface->SurfWinAirflowControlType(SurfNum) = WindowAirFlowControlType::AlwaysOff;
10930 0 : } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(4), "ScheduledOnly")) {
10931 0 : state.dataSurface->SurfWinAirflowControlType(SurfNum) = WindowAirFlowControlType::Schedule;
10932 : }
10933 8 : state.dataSurface->SurfWinMaxAirflow(SurfNum) = state.dataIPShortCut->rNumericArgs(1);
10934 8 : if (state.dataIPShortCut->cAlphaArgs(4) == "SCHEDULEDONLY" && state.dataIPShortCut->cAlphaArgs(5) == "YES") {
10935 0 : if (state.dataIPShortCut->lAlphaFieldBlanks(6)) {
10936 0 : ErrorsFound = true;
10937 0 : ShowSevereError(state,
10938 0 : format("{}=\"{}\", has {}=\"{}\"",
10939 : cCurrentModuleObject,
10940 0 : state.dataIPShortCut->cAlphaArgs(1),
10941 0 : state.dataIPShortCut->cAlphaFieldNames(4),
10942 0 : state.dataIPShortCut->cAlphaArgs(4)));
10943 0 : ShowContinueError(state,
10944 0 : format("..and {}=\"{}\", but no {} specified.",
10945 0 : state.dataIPShortCut->cAlphaFieldNames(5),
10946 0 : state.dataIPShortCut->cAlphaArgs(5),
10947 0 : state.dataIPShortCut->cAlphaFieldNames(6)));
10948 : } else {
10949 0 : state.dataSurface->SurfWinAirflowHasSchedule(SurfNum) = true;
10950 0 : state.dataSurface->SurfWinAirflowSchedulePtr(SurfNum) = GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(6));
10951 0 : if (state.dataSurface->SurfWinAirflowSchedulePtr(SurfNum) == 0) {
10952 0 : ErrorsFound = true;
10953 0 : ShowSevereError(state,
10954 0 : format("{}=\"{}\", invalid {}=\"{}\"",
10955 : cCurrentModuleObject,
10956 0 : state.dataIPShortCut->cAlphaArgs(1),
10957 0 : state.dataIPShortCut->cAlphaFieldNames(6),
10958 0 : state.dataIPShortCut->cAlphaArgs(6)));
10959 : }
10960 : }
10961 : }
10962 : // Warning if associated window is an interior window
10963 8 : if (surf.ExtBoundCond != ExternalEnvironment && !ErrorsFound)
10964 0 : ShowWarningError(state,
10965 0 : format("{}=\"{}\", is an Interior window; cannot be an airflow window.",
10966 : cCurrentModuleObject,
10967 0 : state.dataIPShortCut->cAlphaArgs(1)));
10968 8 : if (!ErrorsFound) {
10969 : // Require that gas in airflow gap has type = air
10970 8 : MatGapFlow = state.dataConstruction->Construct(ConstrNum).LayerPoint(2);
10971 8 : if (state.dataConstruction->Construct(ConstrNum).TotGlassLayers == 3)
10972 4 : MatGapFlow = state.dataConstruction->Construct(ConstrNum).LayerPoint(4);
10973 8 : if (dynamic_cast<Material::MaterialGasMix const *>(state.dataMaterial->Material(MatGapFlow))->gases[0].type !=
10974 : Material::GasType::Air) {
10975 0 : ErrorsFound = true;
10976 0 : ShowSevereError(state,
10977 0 : format("{}=\"{}\", Gas type not air in airflow gap of construction {}",
10978 : cCurrentModuleObject,
10979 0 : state.dataIPShortCut->cAlphaArgs(1),
10980 0 : state.dataConstruction->Construct(ConstrNum).Name));
10981 : }
10982 : // Require that gas be air in airflow gaps on either side of a between glass shade/blind
10983 8 : if (surf.HasShadeControl) {
10984 4 : for (std::size_t listIndex = 0; listIndex < surf.windowShadingControlList.size(); ++listIndex) {
10985 4 : int WSCPtr = surf.windowShadingControlList[listIndex];
10986 4 : if (ANY_BETWEENGLASS_SHADE_BLIND(state.dataSurface->WindowShadingControl(WSCPtr).ShadingType)) {
10987 4 : ConstrNumSh = surf.shadedConstructionList[listIndex];
10988 4 : if (state.dataConstruction->Construct(ConstrNum).TotGlassLayers == 2) {
10989 2 : MatGapFlow1 = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(2);
10990 2 : MatGapFlow2 = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(4);
10991 : } else {
10992 2 : MatGapFlow1 = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(4);
10993 2 : MatGapFlow2 = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(6);
10994 : }
10995 4 : if (dynamic_cast<Material::MaterialGasMix const *>(state.dataMaterial->Material(MatGapFlow1))->gases[0].type !=
10996 8 : Material::GasType::Air ||
10997 4 : dynamic_cast<Material::MaterialGasMix const *>(state.dataMaterial->Material(MatGapFlow2))->gases[0].type !=
10998 : Material::GasType::Air) {
10999 0 : ErrorsFound = true;
11000 0 : ShowSevereError(state,
11001 0 : format("{}=\"{}\", gas type must be air on either side of the shade/blind",
11002 : cCurrentModuleObject,
11003 0 : state.dataIPShortCut->cAlphaArgs(1)));
11004 : }
11005 4 : break; // only need the first window shading control since they should be the same
11006 : }
11007 : }
11008 : }
11009 : }
11010 : }
11011 :
11012 : } // End of loop over window airflow controls
11013 : }
11014 :
11015 796 : void GetFoundationData(EnergyPlusData &state, bool &ErrorsFound)
11016 : {
11017 :
11018 : int NumAlphas;
11019 : int NumProps;
11020 : int IOStat;
11021 796 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
11022 :
11023 : // Read Kiva Settings
11024 796 : cCurrentModuleObject = "Foundation:Kiva:Settings";
11025 796 : int TotKivaStgs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
11026 :
11027 796 : if (TotKivaStgs > 1) {
11028 0 : ErrorsFound = true;
11029 0 : ShowSevereError(state, format("Multiple {} objects found. Only one is allowed.", cCurrentModuleObject));
11030 : }
11031 :
11032 796 : if (TotKivaStgs == 1) {
11033 10 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
11034 : cCurrentModuleObject,
11035 : 1,
11036 5 : state.dataIPShortCut->cAlphaArgs,
11037 : NumAlphas,
11038 5 : state.dataIPShortCut->rNumericArgs,
11039 : NumProps,
11040 : IOStat,
11041 5 : state.dataIPShortCut->lNumericFieldBlanks,
11042 5 : state.dataIPShortCut->lAlphaFieldBlanks,
11043 5 : state.dataIPShortCut->cAlphaFieldNames,
11044 5 : state.dataIPShortCut->cNumericFieldNames);
11045 :
11046 5 : int numF = 1;
11047 5 : int alpF = 1;
11048 :
11049 5 : if (!state.dataIPShortCut->lNumericFieldBlanks(numF)) {
11050 5 : state.dataSurfaceGeometry->kivaManager.settings.soilK = state.dataIPShortCut->rNumericArgs(numF);
11051 : }
11052 5 : numF++;
11053 5 : if (!state.dataIPShortCut->lNumericFieldBlanks(numF)) {
11054 5 : state.dataSurfaceGeometry->kivaManager.settings.soilRho = state.dataIPShortCut->rNumericArgs(numF);
11055 : }
11056 5 : numF++;
11057 5 : if (!state.dataIPShortCut->lNumericFieldBlanks(numF)) {
11058 5 : state.dataSurfaceGeometry->kivaManager.settings.soilCp = state.dataIPShortCut->rNumericArgs(numF);
11059 : }
11060 5 : numF++;
11061 5 : if (!state.dataIPShortCut->lNumericFieldBlanks(numF)) {
11062 5 : state.dataSurfaceGeometry->kivaManager.settings.groundSolarAbs = state.dataIPShortCut->rNumericArgs(numF);
11063 : }
11064 5 : numF++;
11065 5 : if (!state.dataIPShortCut->lNumericFieldBlanks(numF)) {
11066 5 : state.dataSurfaceGeometry->kivaManager.settings.groundThermalAbs = state.dataIPShortCut->rNumericArgs(numF);
11067 : }
11068 5 : numF++;
11069 5 : if (!state.dataIPShortCut->lNumericFieldBlanks(numF)) {
11070 5 : state.dataSurfaceGeometry->kivaManager.settings.groundRoughness = state.dataIPShortCut->rNumericArgs(numF);
11071 : }
11072 5 : numF++;
11073 5 : if (!state.dataIPShortCut->lNumericFieldBlanks(numF)) {
11074 5 : state.dataSurfaceGeometry->kivaManager.settings.farFieldWidth = state.dataIPShortCut->rNumericArgs(numF);
11075 : }
11076 5 : numF++;
11077 :
11078 5 : if (!state.dataIPShortCut->lAlphaFieldBlanks(alpF)) {
11079 5 : if (Util::SameString(state.dataIPShortCut->cAlphaArgs(alpF), "ZeroFlux")) {
11080 1 : state.dataSurfaceGeometry->kivaManager.settings.deepGroundBoundary = HeatBalanceKivaManager::KivaManager::Settings::ZERO_FLUX;
11081 4 : } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(alpF), "GroundWater")) {
11082 0 : state.dataSurfaceGeometry->kivaManager.settings.deepGroundBoundary = HeatBalanceKivaManager::KivaManager::Settings::GROUNDWATER;
11083 4 : } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(alpF), "Autoselect")) {
11084 4 : state.dataSurfaceGeometry->kivaManager.settings.deepGroundBoundary = HeatBalanceKivaManager::KivaManager::Settings::AUTO;
11085 : } else {
11086 0 : ErrorsFound = true;
11087 0 : ShowSevereError(state,
11088 0 : format("{}, {} is not a valid choice for {}",
11089 : cCurrentModuleObject,
11090 0 : state.dataIPShortCut->cAlphaArgs(alpF),
11091 0 : state.dataIPShortCut->cAlphaFieldNames(alpF)));
11092 : }
11093 : }
11094 5 : alpF++;
11095 :
11096 5 : if (state.dataIPShortCut->lNumericFieldBlanks(numF) || state.dataIPShortCut->rNumericArgs(numF) == Constant::AutoCalculate) {
11097 : // Autocalculate deep-ground depth (see KivaManager::defineDefaultFoundation() for actual calculation)
11098 4 : state.dataSurfaceGeometry->kivaManager.settings.deepGroundDepth = 40.0;
11099 4 : state.dataSurfaceGeometry->kivaManager.settings.autocalculateDeepGroundDepth = true;
11100 4 : if (state.dataSurfaceGeometry->kivaManager.settings.deepGroundBoundary != HeatBalanceKivaManager::KivaManager::Settings::AUTO) {
11101 0 : ErrorsFound = true;
11102 0 : ShowSevereError(state,
11103 0 : format("{}, {} should not be set to Autocalculate unless {} is set to Autoselect",
11104 : cCurrentModuleObject,
11105 0 : state.dataIPShortCut->cNumericFieldNames(numF),
11106 0 : state.dataIPShortCut->cAlphaFieldNames(alpF - 1)));
11107 : }
11108 : } else {
11109 1 : state.dataSurfaceGeometry->kivaManager.settings.deepGroundDepth = state.dataIPShortCut->rNumericArgs(numF);
11110 1 : state.dataSurfaceGeometry->kivaManager.settings.autocalculateDeepGroundDepth = false;
11111 : }
11112 5 : numF++;
11113 5 : if (!state.dataIPShortCut->lNumericFieldBlanks(numF)) {
11114 1 : state.dataSurfaceGeometry->kivaManager.settings.minCellDim = state.dataIPShortCut->rNumericArgs(numF);
11115 : }
11116 5 : numF++;
11117 5 : if (!state.dataIPShortCut->lNumericFieldBlanks(numF)) {
11118 1 : state.dataSurfaceGeometry->kivaManager.settings.maxGrowthCoeff = state.dataIPShortCut->rNumericArgs(numF);
11119 : }
11120 5 : numF++;
11121 :
11122 5 : if (!state.dataIPShortCut->lAlphaFieldBlanks(alpF)) {
11123 1 : if (Util::SameString(state.dataIPShortCut->cAlphaArgs(alpF), "Hourly")) {
11124 1 : state.dataSurfaceGeometry->kivaManager.settings.timestepType = HeatBalanceKivaManager::KivaManager::Settings::HOURLY;
11125 1 : state.dataSurfaceGeometry->kivaManager.timestep = 3600.; // seconds
11126 : } else { // if (Util::SameString(state.dataIPShortCut->cAlphaArgs( alpF ), "Timestep"))
11127 0 : state.dataSurfaceGeometry->kivaManager.settings.timestepType = HeatBalanceKivaManager::KivaManager::Settings::TIMESTEP;
11128 0 : state.dataSurfaceGeometry->kivaManager.timestep = state.dataGlobal->MinutesPerTimeStep * 60.;
11129 : }
11130 : }
11131 5 : alpF++;
11132 : }
11133 :
11134 : // Set default foundation (probably doesn't need to be called if there are no Kiva
11135 : // surfaces, but we don't know that yet). We call this here so that the default
11136 : // foundation is available for 1) the starting copy for user-defined Foundation:Kiva
11137 : // object default inputs, and 2) the actual default Foundation object if a
11138 : // user-defined Foundation:Kiva name is not referenced by a surface.
11139 796 : state.dataSurfaceGeometry->kivaManager.defineDefaultFoundation(state);
11140 :
11141 : // Read Foundation objects
11142 796 : cCurrentModuleObject = "Foundation:Kiva";
11143 796 : int TotKivaFnds = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
11144 :
11145 796 : if (TotKivaFnds > 0) {
11146 14 : for (int Loop = 1; Loop <= TotKivaFnds; ++Loop) {
11147 14 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
11148 : cCurrentModuleObject,
11149 : Loop,
11150 7 : state.dataIPShortCut->cAlphaArgs,
11151 : NumAlphas,
11152 7 : state.dataIPShortCut->rNumericArgs,
11153 : NumProps,
11154 : IOStat,
11155 7 : state.dataIPShortCut->lNumericFieldBlanks,
11156 7 : state.dataIPShortCut->lAlphaFieldBlanks,
11157 7 : state.dataIPShortCut->cAlphaFieldNames,
11158 7 : state.dataIPShortCut->cNumericFieldNames);
11159 :
11160 7 : int numF = 1;
11161 7 : int alpF = 1;
11162 :
11163 7 : bool ErrorInName = false;
11164 :
11165 7 : HeatBalanceKivaManager::FoundationKiva fndInput;
11166 :
11167 7 : fndInput.name = state.dataIPShortCut->cAlphaArgs(alpF);
11168 7 : alpF++;
11169 7 : Util::IsNameEmpty(state, fndInput.name, cCurrentModuleObject, ErrorInName);
11170 7 : if (ErrorInName) {
11171 0 : ErrorsFound = true;
11172 0 : continue;
11173 : }
11174 :
11175 : // Start with copy of default
11176 7 : auto &fnd = fndInput.foundation;
11177 7 : fnd = state.dataSurfaceGeometry->kivaManager.defaultFoundation.foundation;
11178 :
11179 : // Indoor temperature
11180 7 : if (!state.dataIPShortCut->lNumericFieldBlanks(numF)) {
11181 1 : fndInput.assumedIndoorTemperature = state.dataIPShortCut->rNumericArgs(numF);
11182 : } else {
11183 6 : fndInput.assumedIndoorTemperature = -9999;
11184 : }
11185 7 : numF++;
11186 :
11187 : // Interior horizontal insulation
11188 7 : if (!state.dataIPShortCut->lAlphaFieldBlanks(alpF)) {
11189 3 : int index = Util::FindItemInPtrList(state.dataIPShortCut->cAlphaArgs(alpF), state.dataMaterial->Material);
11190 3 : if (index == 0) {
11191 0 : ErrorsFound = true;
11192 0 : ShowSevereError(state,
11193 0 : format("Did not find matching material for {}=\"{}\", {}, missing material = {}",
11194 : cCurrentModuleObject,
11195 : fndInput.name,
11196 0 : state.dataIPShortCut->cAlphaFieldNames(alpF),
11197 0 : state.dataIPShortCut->cAlphaArgs(alpF)));
11198 0 : continue;
11199 : }
11200 3 : auto *m = state.dataMaterial->Material(index);
11201 3 : if (m->group != Material::Group::Regular || m->ROnly) {
11202 0 : ErrorsFound = true;
11203 0 : ShowSevereError(state,
11204 0 : format("{}=\"{}\", invalid {}=\"{}",
11205 : cCurrentModuleObject,
11206 : fndInput.name,
11207 0 : state.dataIPShortCut->cAlphaFieldNames(alpF),
11208 0 : state.dataIPShortCut->cAlphaArgs(alpF)));
11209 0 : ShowContinueError(state, "Must be of type \"Material\"");
11210 0 : continue;
11211 : }
11212 3 : fndInput.intHIns.x = 0.0;
11213 3 : fndInput.intHIns.material = Kiva::Material(m->Conductivity, m->Density, m->SpecHeat);
11214 3 : fndInput.intHIns.depth = m->Thickness;
11215 : }
11216 7 : alpF++;
11217 :
11218 7 : if (!state.dataIPShortCut->lAlphaFieldBlanks(alpF - 1)) {
11219 3 : if (state.dataIPShortCut->lNumericFieldBlanks(numF)) {
11220 3 : fndInput.intHIns.z = 0.0;
11221 : } else {
11222 0 : fndInput.intHIns.z = state.dataIPShortCut->rNumericArgs(numF);
11223 : }
11224 3 : numF++;
11225 3 : if (state.dataIPShortCut->lNumericFieldBlanks(numF)) {
11226 0 : ErrorsFound = true;
11227 0 : ShowSevereError(state,
11228 0 : format("{}=\"{}\", {} defined, but no {}provided",
11229 : cCurrentModuleObject,
11230 : fndInput.name,
11231 0 : state.dataIPShortCut->cAlphaFieldNames(alpF - 1),
11232 0 : state.dataIPShortCut->cNumericFieldNames(numF)));
11233 0 : continue;
11234 : } else {
11235 3 : fndInput.intHIns.width = -state.dataIPShortCut->rNumericArgs(numF);
11236 : }
11237 3 : numF++;
11238 : } else {
11239 4 : if (!state.dataIPShortCut->lNumericFieldBlanks(numF)) {
11240 0 : ShowWarningError(
11241 : state,
11242 0 : format(
11243 0 : "{}=\"{}\", no {} defined", cCurrentModuleObject, fndInput.name, state.dataIPShortCut->cAlphaFieldNames(alpF - 1)));
11244 0 : ShowContinueError(state, format("{} will not be used.", state.dataIPShortCut->cNumericFieldNames(numF)));
11245 : }
11246 4 : numF++;
11247 4 : if (!state.dataIPShortCut->lNumericFieldBlanks(numF)) {
11248 0 : ShowWarningError(
11249 : state,
11250 0 : format(
11251 0 : "{}=\"{}\", no {} defined", cCurrentModuleObject, fndInput.name, state.dataIPShortCut->cAlphaFieldNames(alpF - 1)));
11252 0 : ShowContinueError(state, format("{} will not be used.", state.dataIPShortCut->cNumericFieldNames(numF)));
11253 : }
11254 4 : numF++;
11255 : }
11256 :
11257 : // Interior vertical insulation
11258 7 : if (!state.dataIPShortCut->lAlphaFieldBlanks(alpF)) {
11259 0 : int index = Util::FindItemInPtrList(state.dataIPShortCut->cAlphaArgs(alpF), state.dataMaterial->Material);
11260 0 : if (index == 0) {
11261 0 : ErrorsFound = true;
11262 0 : ShowSevereError(state,
11263 0 : format("Did not find matching material for {}=\"{}\", {}, missing material = {}",
11264 : cCurrentModuleObject,
11265 : fndInput.name,
11266 0 : state.dataIPShortCut->cAlphaFieldNames(alpF),
11267 0 : state.dataIPShortCut->cAlphaArgs(alpF)));
11268 0 : continue;
11269 : }
11270 0 : auto *m = state.dataMaterial->Material(index);
11271 0 : if (m->group != Material::Group::Regular || m->ROnly) {
11272 0 : ErrorsFound = true;
11273 0 : ShowSevereError(state,
11274 0 : format("{}=\"{}\", invalid {}=\"{}",
11275 : cCurrentModuleObject,
11276 : fndInput.name,
11277 0 : state.dataIPShortCut->cAlphaFieldNames(alpF),
11278 0 : state.dataIPShortCut->cAlphaArgs(alpF)));
11279 0 : ShowContinueError(state, "Must be of type \"Material\"");
11280 0 : continue;
11281 : }
11282 0 : fndInput.intVIns.material = Kiva::Material(m->Conductivity, m->Density, m->SpecHeat);
11283 0 : fndInput.intVIns.width = -m->Thickness;
11284 0 : fndInput.intVIns.x = 0.0;
11285 0 : fndInput.intVIns.z = 0.0;
11286 : }
11287 7 : alpF++;
11288 :
11289 7 : if (!state.dataIPShortCut->lAlphaFieldBlanks(alpF - 1)) {
11290 0 : if (state.dataIPShortCut->lNumericFieldBlanks(numF)) {
11291 0 : ErrorsFound = true;
11292 0 : ShowSevereError(state,
11293 0 : format("{}=\"{}\", {} defined, but no {}provided",
11294 : cCurrentModuleObject,
11295 : fndInput.name,
11296 0 : state.dataIPShortCut->cAlphaFieldNames(alpF - 1),
11297 0 : state.dataIPShortCut->cNumericFieldNames(numF)));
11298 0 : continue;
11299 : } else {
11300 0 : fndInput.intVIns.depth = state.dataIPShortCut->rNumericArgs(numF);
11301 : }
11302 0 : numF++;
11303 : } else {
11304 7 : if (!state.dataIPShortCut->lNumericFieldBlanks(numF)) {
11305 0 : ShowWarningError(
11306 : state,
11307 0 : format(
11308 0 : "{}=\"{}\", no {} defined", cCurrentModuleObject, fndInput.name, state.dataIPShortCut->cAlphaFieldNames(alpF - 1)));
11309 0 : ShowContinueError(state, format("{} will not be used.", state.dataIPShortCut->cNumericFieldNames(numF)));
11310 : }
11311 7 : numF++;
11312 : }
11313 :
11314 : // Exterior horizontal insulation
11315 7 : if (!state.dataIPShortCut->lAlphaFieldBlanks(alpF)) {
11316 0 : int index = Util::FindItemInPtrList(state.dataIPShortCut->cAlphaArgs(alpF), state.dataMaterial->Material);
11317 0 : if (index == 0) {
11318 0 : ErrorsFound = true;
11319 0 : ShowSevereError(state,
11320 0 : format("Did not find matching material for {}=\"{}\", {}, missing material = {}",
11321 : cCurrentModuleObject,
11322 : fndInput.name,
11323 0 : state.dataIPShortCut->cAlphaFieldNames(alpF),
11324 0 : state.dataIPShortCut->cAlphaArgs(alpF)));
11325 0 : continue;
11326 : }
11327 0 : auto *m = state.dataMaterial->Material(index);
11328 0 : if (m->group != Material::Group::Regular || m->ROnly) {
11329 0 : ErrorsFound = true;
11330 0 : ShowSevereError(state,
11331 0 : format("{}=\"{}\", invalid {}=\"{}",
11332 : cCurrentModuleObject,
11333 : fndInput.name,
11334 0 : state.dataIPShortCut->cAlphaFieldNames(alpF),
11335 0 : state.dataIPShortCut->cAlphaArgs(alpF)));
11336 0 : ShowContinueError(state, "Must be of type \"Material\"");
11337 0 : continue;
11338 : }
11339 0 : fndInput.extHIns.x = 0.0;
11340 0 : fndInput.extHIns.material = Kiva::Material(m->Conductivity, m->Density, m->SpecHeat);
11341 0 : fndInput.extHIns.depth = m->Thickness;
11342 : }
11343 7 : alpF++;
11344 :
11345 7 : if (!state.dataIPShortCut->lAlphaFieldBlanks(alpF - 1)) {
11346 0 : if (state.dataIPShortCut->lNumericFieldBlanks(numF)) {
11347 0 : fndInput.extHIns.z = 0.0;
11348 : } else {
11349 0 : fndInput.extHIns.z = state.dataIPShortCut->rNumericArgs(numF);
11350 : }
11351 0 : numF++;
11352 0 : if (state.dataIPShortCut->lNumericFieldBlanks(numF)) {
11353 0 : ErrorsFound = true;
11354 0 : ShowSevereError(state,
11355 0 : format("{}=\"{}\", {} defined, but no {}provided",
11356 : cCurrentModuleObject,
11357 : fndInput.name,
11358 0 : state.dataIPShortCut->cAlphaFieldNames(alpF - 1),
11359 0 : state.dataIPShortCut->cNumericFieldNames(numF)));
11360 0 : continue;
11361 : } else {
11362 0 : fndInput.extHIns.width = state.dataIPShortCut->rNumericArgs(numF);
11363 : }
11364 0 : numF++;
11365 : } else {
11366 7 : if (!state.dataIPShortCut->lNumericFieldBlanks(numF)) {
11367 0 : ShowWarningError(
11368 : state,
11369 0 : format(
11370 0 : "{}=\"{}\", no {} defined", cCurrentModuleObject, fndInput.name, state.dataIPShortCut->cAlphaFieldNames(alpF - 1)));
11371 0 : ShowContinueError(state, format("{} will not be used.", state.dataIPShortCut->cNumericFieldNames(numF)));
11372 : }
11373 7 : numF++;
11374 7 : if (!state.dataIPShortCut->lNumericFieldBlanks(numF)) {
11375 0 : ShowWarningError(
11376 : state,
11377 0 : format(
11378 0 : "{}=\"{}\", no {} defined", cCurrentModuleObject, fndInput.name, state.dataIPShortCut->cAlphaFieldNames(alpF - 1)));
11379 0 : ShowContinueError(state, format("{} will not be used.", state.dataIPShortCut->cNumericFieldNames(numF)));
11380 : }
11381 7 : numF++;
11382 : }
11383 :
11384 : // Exterior vertical insulation
11385 7 : if (!state.dataIPShortCut->lAlphaFieldBlanks(alpF)) {
11386 4 : int index = Util::FindItemInPtrList(state.dataIPShortCut->cAlphaArgs(alpF), state.dataMaterial->Material);
11387 4 : if (index == 0) {
11388 0 : ErrorsFound = true;
11389 0 : ShowSevereError(state,
11390 0 : format("Did not find matching material for {}=\"{}\", {}, missing material = {}",
11391 : cCurrentModuleObject,
11392 : fndInput.name,
11393 0 : state.dataIPShortCut->cAlphaFieldNames(alpF),
11394 0 : state.dataIPShortCut->cAlphaArgs(alpF)));
11395 0 : continue;
11396 : }
11397 4 : auto *m = state.dataMaterial->Material(index);
11398 4 : if (m->group != Material::Group::Regular || m->ROnly) {
11399 0 : ErrorsFound = true;
11400 0 : ShowSevereError(state,
11401 0 : format("{}=\"{}\", invalid {}=\"{}",
11402 : cCurrentModuleObject,
11403 : fndInput.name,
11404 0 : state.dataIPShortCut->cAlphaFieldNames(alpF),
11405 0 : state.dataIPShortCut->cAlphaArgs(alpF)));
11406 0 : ShowContinueError(state, "Must be of type \"Material\"");
11407 0 : continue;
11408 : }
11409 4 : fndInput.extVIns.material = Kiva::Material(m->Conductivity, m->Density, m->SpecHeat);
11410 4 : fndInput.extVIns.width = m->Thickness;
11411 4 : fndInput.extVIns.x = 0.0;
11412 4 : fndInput.extVIns.z = 0.0;
11413 : }
11414 7 : alpF++;
11415 :
11416 7 : if (!state.dataIPShortCut->lAlphaFieldBlanks(alpF - 1)) {
11417 4 : if (state.dataIPShortCut->lNumericFieldBlanks(numF)) {
11418 0 : ErrorsFound = true;
11419 0 : ShowSevereError(state,
11420 0 : format("{}=\"{}\", {} defined, but no {}provided",
11421 : cCurrentModuleObject,
11422 : fndInput.name,
11423 0 : state.dataIPShortCut->cAlphaFieldNames(alpF - 1),
11424 0 : state.dataIPShortCut->cNumericFieldNames(numF)));
11425 0 : continue;
11426 : } else {
11427 4 : fndInput.extVIns.depth = state.dataIPShortCut->rNumericArgs(numF);
11428 : }
11429 4 : numF++;
11430 : } else {
11431 3 : if (!state.dataIPShortCut->lNumericFieldBlanks(numF)) {
11432 0 : ShowWarningError(
11433 : state,
11434 0 : format(
11435 0 : "{}=\"{}\", no {} defined", cCurrentModuleObject, fndInput.name, state.dataIPShortCut->cAlphaFieldNames(alpF - 1)));
11436 0 : ShowContinueError(state, format("{} will not be used.", state.dataIPShortCut->cNumericFieldNames(numF)));
11437 : }
11438 3 : numF++;
11439 : }
11440 :
11441 : // Foundation wall
11442 7 : if (!state.dataIPShortCut->lNumericFieldBlanks(numF)) {
11443 7 : fnd.wall.heightAboveGrade = state.dataIPShortCut->rNumericArgs(numF);
11444 : }
11445 7 : numF++;
11446 :
11447 7 : if (!state.dataIPShortCut->lNumericFieldBlanks(numF)) {
11448 7 : fnd.wall.depthBelowSlab = state.dataIPShortCut->rNumericArgs(numF);
11449 : }
11450 7 : numF++;
11451 :
11452 7 : if (!state.dataIPShortCut->lAlphaFieldBlanks(alpF)) {
11453 0 : fndInput.wallConstructionIndex = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(alpF), state.dataConstruction->Construct);
11454 0 : if (fndInput.wallConstructionIndex == 0) {
11455 0 : ErrorsFound = true;
11456 0 : ShowSevereError(state,
11457 0 : format("Did not find matching construction for {}=\"{}\", {}, missing construction = {}",
11458 : cCurrentModuleObject,
11459 : fndInput.name,
11460 0 : state.dataIPShortCut->cAlphaFieldNames(alpF),
11461 0 : state.dataIPShortCut->cAlphaArgs(alpF)));
11462 0 : continue;
11463 : }
11464 0 : auto &c = state.dataConstruction->Construct(fndInput.wallConstructionIndex);
11465 0 : c.IsUsed = true;
11466 0 : if (c.TypeIsWindow) {
11467 0 : ErrorsFound = true;
11468 0 : ShowSevereError(state,
11469 0 : format("{}=\"{}\", invalid {}=\"{}",
11470 : cCurrentModuleObject,
11471 : fndInput.name,
11472 0 : state.dataIPShortCut->cAlphaFieldNames(alpF),
11473 0 : state.dataIPShortCut->cAlphaArgs(alpF)));
11474 0 : ShowContinueError(state, "Cannot be a window construction");
11475 0 : continue;
11476 : }
11477 : } else {
11478 7 : fndInput.wallConstructionIndex = 0; // Use default wall construction
11479 : }
11480 7 : alpF++;
11481 :
11482 : // Footing
11483 7 : if (!state.dataIPShortCut->lAlphaFieldBlanks(alpF)) {
11484 0 : int index = Util::FindItemInPtrList(state.dataIPShortCut->cAlphaArgs(alpF), state.dataMaterial->Material);
11485 0 : if (index == 0) {
11486 0 : ErrorsFound = true;
11487 0 : ShowSevereError(state,
11488 0 : format("Did not find matching material for {}=\"{}\", {}, missing material = {}",
11489 : cCurrentModuleObject,
11490 : fndInput.name,
11491 0 : state.dataIPShortCut->cAlphaFieldNames(alpF),
11492 0 : state.dataIPShortCut->cAlphaArgs(alpF)));
11493 0 : continue;
11494 : }
11495 0 : auto *m = state.dataMaterial->Material(index);
11496 0 : if (m->group != Material::Group::Regular || m->ROnly) {
11497 0 : ErrorsFound = true;
11498 0 : ShowSevereError(state,
11499 0 : format("{}=\"{}\", invalid {}=\"{}",
11500 : cCurrentModuleObject,
11501 : fndInput.name,
11502 0 : state.dataIPShortCut->cAlphaFieldNames(alpF),
11503 0 : state.dataIPShortCut->cAlphaArgs(alpF)));
11504 0 : ShowContinueError(state, "Must be of type \"Material\"");
11505 0 : continue;
11506 : }
11507 0 : fndInput.footing.material = Kiva::Material(m->Conductivity, m->Density, m->SpecHeat);
11508 0 : fndInput.footing.width = m->Thickness;
11509 0 : fndInput.footing.x = 0.0;
11510 0 : fndInput.footing.z = 0.0;
11511 : }
11512 7 : alpF++;
11513 :
11514 7 : if (!state.dataIPShortCut->lAlphaFieldBlanks(alpF - 1)) {
11515 0 : if (state.dataIPShortCut->lNumericFieldBlanks(numF)) {
11516 0 : ErrorsFound = true;
11517 0 : ShowSevereError(state,
11518 0 : format("{}=\"{}\", {} defined, but no {}provided",
11519 : cCurrentModuleObject,
11520 : fndInput.name,
11521 0 : state.dataIPShortCut->cAlphaFieldNames(alpF - 1),
11522 0 : state.dataIPShortCut->cNumericFieldNames(numF)));
11523 0 : continue;
11524 : } else {
11525 0 : fndInput.footing.depth = state.dataIPShortCut->rNumericArgs(numF);
11526 : }
11527 0 : numF++;
11528 : } else {
11529 7 : if (!state.dataIPShortCut->lNumericFieldBlanks(numF)) {
11530 0 : ShowWarningError(
11531 : state,
11532 0 : format(
11533 0 : "{}=\"{}\", no {} defined", cCurrentModuleObject, fndInput.name, state.dataIPShortCut->cAlphaFieldNames(alpF - 1)));
11534 0 : ShowContinueError(state, format("{} will not be used.", state.dataIPShortCut->cNumericFieldNames(numF)));
11535 : }
11536 7 : numF++;
11537 : }
11538 :
11539 : // General Blocks
11540 7 : int numRemainingFields = NumAlphas - (alpF - 1) + NumProps - (numF - 1);
11541 7 : if (numRemainingFields > 0) {
11542 0 : int numBlocks = numRemainingFields / 4;
11543 0 : if (mod(numRemainingFields, 4) != 0) {
11544 0 : ShowWarningError(state,
11545 0 : format("{}=\"{}\", number of Block fields not even multiple of 4. Will read in {}",
11546 : cCurrentModuleObject,
11547 : fndInput.name,
11548 : numBlocks));
11549 : }
11550 0 : for (int blockNum = 0; blockNum < numBlocks; blockNum++) {
11551 0 : Kiva::InputBlock block;
11552 0 : if (!state.dataIPShortCut->lAlphaFieldBlanks(alpF)) {
11553 0 : int index = Util::FindItemInPtrList(state.dataIPShortCut->cAlphaArgs(alpF), state.dataMaterial->Material);
11554 0 : if (index == 0) {
11555 0 : ErrorsFound = true;
11556 0 : ShowSevereError(state,
11557 0 : format("Did not find matching material for {}=\"{}\", {}, missing material = {}",
11558 : cCurrentModuleObject,
11559 : fndInput.name,
11560 0 : state.dataIPShortCut->cAlphaFieldNames(alpF),
11561 0 : state.dataIPShortCut->cAlphaArgs(alpF)));
11562 0 : continue;
11563 : }
11564 0 : auto *m = state.dataMaterial->Material(index);
11565 0 : if (m->group != Material::Group::Regular || m->ROnly) {
11566 0 : ErrorsFound = true;
11567 0 : ShowSevereError(state,
11568 0 : format("{}=\"{}\", invalid {}=\"{}",
11569 : cCurrentModuleObject,
11570 : fndInput.name,
11571 0 : state.dataIPShortCut->cAlphaFieldNames(alpF),
11572 0 : state.dataIPShortCut->cAlphaArgs(alpF)));
11573 0 : ShowContinueError(state, "Must be of type \"Material\"");
11574 0 : continue;
11575 : }
11576 0 : block.material = Kiva::Material(m->Conductivity, m->Density, m->SpecHeat);
11577 0 : block.width = m->Thickness;
11578 : } else {
11579 0 : ErrorsFound = true;
11580 0 : ShowSevereError(state,
11581 0 : format("{}=\"{}\", {} is required and not given.",
11582 : cCurrentModuleObject,
11583 : fndInput.name,
11584 0 : state.dataIPShortCut->cAlphaFieldNames(alpF)));
11585 0 : continue;
11586 : }
11587 0 : alpF++;
11588 :
11589 0 : if (state.dataIPShortCut->lNumericFieldBlanks(numF)) {
11590 0 : block.depth = 0.0; // Temporary indicator to default to foundation depth
11591 : } else {
11592 0 : block.depth = state.dataIPShortCut->rNumericArgs(numF);
11593 : }
11594 0 : numF++;
11595 :
11596 0 : if (state.dataIPShortCut->lNumericFieldBlanks(numF)) {
11597 0 : ErrorsFound = true;
11598 0 : ShowSevereError(state,
11599 0 : format("{}=\"{}\", {} defined, but no {}provided",
11600 : cCurrentModuleObject,
11601 : fndInput.name,
11602 0 : state.dataIPShortCut->cAlphaFieldNames(alpF - 1),
11603 0 : state.dataIPShortCut->cNumericFieldNames(numF)));
11604 0 : continue;
11605 : } else {
11606 0 : block.x = state.dataIPShortCut->rNumericArgs(numF);
11607 : }
11608 0 : numF++;
11609 :
11610 0 : if (state.dataIPShortCut->lNumericFieldBlanks(numF)) {
11611 0 : block.z = 0.0;
11612 : } else {
11613 0 : block.z = state.dataIPShortCut->rNumericArgs(numF);
11614 : }
11615 0 : numF++;
11616 :
11617 0 : fnd.inputBlocks.push_back(block);
11618 : }
11619 : }
11620 :
11621 7 : state.dataSurfaceGeometry->kivaManager.foundationInputs.push_back(fndInput);
11622 7 : }
11623 : }
11624 796 : }
11625 :
11626 796 : void GetOSCData(EnergyPlusData &state, bool &ErrorsFound)
11627 : {
11628 :
11629 : // SUBROUTINE INFORMATION:
11630 : // AUTHOR Linda Lawrie
11631 : // DATE WRITTEN May 2000
11632 : // MODIFIED Jul 2011, M.J. Witte and C.O. Pedersen, add new fields to OSC for last T, max and min
11633 : // RE-ENGINEERED na
11634 :
11635 : // PURPOSE OF THIS SUBROUTINE:
11636 : // This subroutine gets the OtherSideCoefficient data.
11637 :
11638 : // METHODOLOGY EMPLOYED:
11639 : // na
11640 :
11641 : // REFERENCES:
11642 : // Other Side Coefficient Definition
11643 : // OtherSideCoefficients,
11644 : // \memo This object sets the other side conditions for a surface in a variety of ways.
11645 : // A1, \field OtherSideCoeff Name
11646 : // \required-field
11647 : // \reference OSCNames
11648 : // \reference OutFaceEnvNames
11649 : // N1, \field Combined convective/radiative film coefficient
11650 : // \required-field
11651 : // \type real
11652 : // \note if>0, N1 becomes exterior convective/radiative film coefficient and other fields
11653 : // \note are used to calc outside air temp then exterior surface temp based on outside air
11654 : // \note and specified coefficient
11655 : // \note if<=0, then remaining fields calculate the outside surface temperature(?)
11656 : // \note following fields are used in the equation:
11657 : // \note SurfTemp=N7*TempZone + N4*OutsideDryBulb + N2*N3 + GroundTemp*N5 + WindSpeed*N6*OutsideDryBulb
11658 : // N2, \field User selected Constant Temperature
11659 : // \units C
11660 : // \type real
11661 : // \note This parameter will be overwritten by the values from the schedule(A2 below) if one is present
11662 : // N3, \field Coefficient modifying the user selected constant temperature
11663 : // \note This coefficient is used even with a schedule. It should normally be 1.0 in that case
11664 : // N4, \field Coefficient modifying the external dry bulb temperature
11665 : // \type real
11666 : // N5, \field Coefficient modifying the ground temperature
11667 : // \type real
11668 : // N6, \field Coefficient modifying the wind speed term (s/m)
11669 : // \type real
11670 : // N7, \field Coefficient modifying the zone air temperature part of the equation
11671 : // \type real
11672 : // A2, \field ScheduleName for constant temperature
11673 : // \note Name of Schedule for values of "const" temperature.
11674 : // \note Schedule values replace N2 - User selected constant temperature.
11675 : // \type object-list
11676 : // \object-list ScheduleNames
11677 : // A3, \field Sinusoidal Variation of Constant Temperature Coefficient
11678 : // \note Optionally used to vary Constant Temperature Coefficient with unitary sine wave
11679 : // \type choice
11680 : // \key Yes
11681 : // \key No
11682 : // \default No
11683 : // N8; \field Period of Sinusoidal Variation
11684 : // \note Use with sinusoidal variation to define the time period
11685 : // \type real
11686 : // \units hr
11687 : // \default 24
11688 : // N9, \field Previous Other Side Temperature Coefficient
11689 : // \note This coeffient multiplies the other side temperature result from the
11690 : // \note previous zone timestep
11691 : // \type real
11692 : // \default 0
11693 : // N10, \field Minimum Other Side Temperature
11694 : // \type real
11695 : // \units C
11696 : // \default -100
11697 : // N11; \field Maximum Other Side Temperature
11698 : // \type real
11699 : // \units C
11700 : // \default 200
11701 :
11702 : // Using/Aliasing
11703 :
11704 : using ScheduleManager::GetScheduleIndex;
11705 :
11706 : // Locals
11707 : // SUBROUTINE ARGUMENT DEFINITIONS:
11708 :
11709 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
11710 : int NumAlphas;
11711 : int NumProps;
11712 : int Loop;
11713 : int IOStat;
11714 : int OSCNum;
11715 : bool ErrorInName;
11716 : bool IsBlank;
11717 796 : std::string cOSCLimitsString;
11718 796 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
11719 :
11720 796 : cCurrentModuleObject = "SurfaceProperty:OtherSideCoefficients";
11721 796 : state.dataSurface->TotOSC = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
11722 796 : state.dataSurface->OSC.allocate(state.dataSurface->TotOSC);
11723 :
11724 796 : OSCNum = 0;
11725 817 : for (Loop = 1; Loop <= state.dataSurface->TotOSC; ++Loop) {
11726 42 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
11727 : cCurrentModuleObject,
11728 : Loop,
11729 21 : state.dataIPShortCut->cAlphaArgs,
11730 : NumAlphas,
11731 21 : state.dataIPShortCut->rNumericArgs,
11732 : NumProps,
11733 : IOStat,
11734 21 : state.dataIPShortCut->lNumericFieldBlanks,
11735 21 : state.dataIPShortCut->lAlphaFieldBlanks,
11736 21 : state.dataIPShortCut->cAlphaFieldNames,
11737 21 : state.dataIPShortCut->cNumericFieldNames);
11738 21 : ErrorInName = false;
11739 21 : IsBlank = false;
11740 21 : Util::VerifyName(
11741 21 : state, state.dataIPShortCut->cAlphaArgs(1), state.dataSurface->OSC, OSCNum, ErrorInName, IsBlank, cCurrentModuleObject + " Name");
11742 21 : if (ErrorInName) {
11743 0 : ErrorsFound = true;
11744 0 : continue;
11745 : }
11746 :
11747 21 : ++OSCNum;
11748 21 : state.dataSurface->OSC(OSCNum).Name = state.dataIPShortCut->cAlphaArgs(1);
11749 21 : state.dataSurface->OSC(OSCNum).SurfFilmCoef = state.dataIPShortCut->rNumericArgs(1);
11750 21 : state.dataSurface->OSC(OSCNum).ConstTemp = state.dataIPShortCut->rNumericArgs(2); // This will be replaced if schedule is used
11751 21 : state.dataSurface->OSC(OSCNum).ConstTempCoef =
11752 21 : state.dataIPShortCut->rNumericArgs(3); // This multiplier is used (even with schedule). It should normally be 1.0
11753 21 : state.dataSurface->OSC(OSCNum).ExtDryBulbCoef = state.dataIPShortCut->rNumericArgs(4);
11754 21 : state.dataSurface->OSC(OSCNum).GroundTempCoef = state.dataIPShortCut->rNumericArgs(5);
11755 21 : state.dataSurface->OSC(OSCNum).WindSpeedCoef = state.dataIPShortCut->rNumericArgs(6);
11756 21 : state.dataSurface->OSC(OSCNum).ZoneAirTempCoef = state.dataIPShortCut->rNumericArgs(7);
11757 21 : state.dataSurface->OSC(OSCNum).SinusoidPeriod = state.dataIPShortCut->rNumericArgs(8);
11758 :
11759 21 : if ((!state.dataIPShortCut->lAlphaFieldBlanks(2)) && (NumAlphas != 1)) { // Const temp will come from schedule specified below.
11760 18 : state.dataSurface->OSC(OSCNum).ConstTempScheduleName = state.dataIPShortCut->cAlphaArgs(2);
11761 18 : if (!state.dataSurface->OSC(OSCNum).ConstTempScheduleName.empty()) {
11762 18 : state.dataSurface->OSC(OSCNum).ConstTempScheduleIndex =
11763 18 : GetScheduleIndex(state, state.dataSurface->OSC(OSCNum).ConstTempScheduleName);
11764 18 : if (state.dataSurface->OSC(OSCNum).ConstTempScheduleIndex == 0) {
11765 0 : ShowSevereError(state,
11766 0 : format("{}=\"{}\", invalid {}=\"{}",
11767 : cCurrentModuleObject,
11768 0 : state.dataIPShortCut->cAlphaArgs(1),
11769 0 : state.dataIPShortCut->cAlphaFieldNames(2),
11770 0 : state.dataIPShortCut->cAlphaArgs(2)));
11771 0 : ErrorsFound = true;
11772 : }
11773 : }
11774 : }
11775 :
11776 21 : if (!state.dataIPShortCut->lAlphaFieldBlanks(3)) {
11777 :
11778 18 : if (Util::SameString(state.dataIPShortCut->cAlphaArgs(3), "No")) {
11779 17 : state.dataSurface->OSC(OSCNum).SinusoidalConstTempCoef = false;
11780 1 : } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(3), "Yes")) {
11781 1 : state.dataSurface->OSC(OSCNum).SinusoidalConstTempCoef = true;
11782 : } else {
11783 0 : ShowSevereError(state,
11784 0 : format("{}=\"{}\", invalid {}=\"{}",
11785 : cCurrentModuleObject,
11786 0 : state.dataIPShortCut->cAlphaArgs(1),
11787 0 : state.dataIPShortCut->cAlphaFieldNames(3),
11788 0 : state.dataIPShortCut->cAlphaArgs(3)));
11789 0 : ErrorsFound = true;
11790 : }
11791 : }
11792 :
11793 21 : if (state.dataIPShortCut->rNumericArgs(1) > 0.0 && !any_ne(state.dataIPShortCut->rNumericArgs({3, 7}), 0.0) &&
11794 0 : (!state.dataSurface->OSC(OSCNum).SinusoidalConstTempCoef)) {
11795 0 : ShowSevereError(state,
11796 0 : format("{}=\"{}\" has zeros for all coefficients.", cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
11797 0 : ShowContinueError(state, "...The outdoor air temperature for surfaces using this OtherSideCoefficients object will always be 0C.");
11798 : }
11799 :
11800 22 : if (state.dataIPShortCut->rNumericArgs(1) <= 0.0 && !any_ne(state.dataIPShortCut->rNumericArgs({3, 7}), 0.0) &&
11801 1 : (!state.dataSurface->OSC(OSCNum).SinusoidalConstTempCoef)) {
11802 0 : ShowSevereError(state,
11803 0 : format("{}=\"{}\" has zeros for all coefficients.", cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
11804 0 : ShowContinueError(state,
11805 : "...The outside surface temperature for surfaces using this OtherSideCoefficients object will always be 0C.");
11806 : }
11807 :
11808 21 : state.dataSurface->OSC(OSCNum).TPreviousCoef = state.dataIPShortCut->rNumericArgs(9);
11809 :
11810 21 : if (!state.dataIPShortCut->lNumericFieldBlanks(10)) {
11811 1 : state.dataSurface->OSC(OSCNum).MinLimitPresent = true;
11812 1 : state.dataSurface->OSC(OSCNum).MinTempLimit = state.dataIPShortCut->rNumericArgs(10);
11813 1 : cOSCLimitsString = format("{:.3R}", state.dataIPShortCut->rNumericArgs(10));
11814 : } else {
11815 20 : cOSCLimitsString = "N/A";
11816 : }
11817 21 : if (!state.dataIPShortCut->lNumericFieldBlanks(11)) {
11818 1 : state.dataSurface->OSC(OSCNum).MaxLimitPresent = true;
11819 1 : state.dataSurface->OSC(OSCNum).MaxTempLimit = state.dataIPShortCut->rNumericArgs(11);
11820 1 : cOSCLimitsString += format(",{:.3R}", state.dataIPShortCut->rNumericArgs(10));
11821 : } else {
11822 20 : cOSCLimitsString += ",N/A";
11823 : }
11824 : }
11825 :
11826 817 : for (Loop = 1; Loop <= state.dataSurface->TotOSC; ++Loop) {
11827 21 : if (Loop == 1) {
11828 : static constexpr std::string_view OSCFormat1(
11829 : "! <Other Side Coefficients>,Name,Combined convective/radiative film coefficient {W/m2-K},User selected "
11830 : "Constant Temperature {C},Coefficient modifying the constant temperature term,Coefficient modifying the external "
11831 : "dry bulb temperature term,Coefficient modifying the ground temperature term,Coefficient modifying the wind speed "
11832 : "term {s/m},Coefficient modifying the zone air temperature term,Constant Temperature Schedule Name,Sinusoidal "
11833 : "Variation,Period of Sinusoidal Variation,Previous Other Side Temperature Coefficient,Minimum Other Side "
11834 : "Temperature {C},Maximum Other Side Temperature {C}");
11835 9 : print(state.files.eio, "{}\n", OSCFormat1);
11836 : }
11837 21 : if (state.dataSurface->OSC(Loop).SurfFilmCoef > 0.0) {
11838 1 : state.dataIPShortCut->cAlphaArgs(1) = format("{:.3R}", state.dataSurface->OSC(Loop).SurfFilmCoef);
11839 2 : SetupOutputVariable(state,
11840 : "Surface Other Side Coefficients Exterior Air Drybulb Temperature",
11841 : Constant::Units::C,
11842 1 : state.dataSurface->OSC(Loop).OSCTempCalc,
11843 : OutputProcessor::TimeStepType::System,
11844 : OutputProcessor::StoreType::Average,
11845 1 : state.dataSurface->OSC(Loop).Name);
11846 : } else {
11847 20 : state.dataIPShortCut->cAlphaArgs(1) = "N/A";
11848 : }
11849 21 : if (state.dataSurface->OSC(Loop).ConstTempScheduleIndex != 0) {
11850 18 : state.dataIPShortCut->cAlphaArgs(2) = state.dataSurface->OSC(Loop).ConstTempScheduleName;
11851 18 : constexpr std::string_view format = "Other Side Coefficients,{},{},{},{:.3R},{:.3R},{:.3R},{:.3R},{:.3R},{},{},{:.3R},{:.3R},{}\n";
11852 54 : print(state.files.eio,
11853 : format,
11854 18 : state.dataSurface->OSC(Loop).Name,
11855 18 : state.dataIPShortCut->cAlphaArgs(1),
11856 : "N/A",
11857 18 : state.dataSurface->OSC(Loop).ConstTempCoef,
11858 18 : state.dataSurface->OSC(Loop).ExtDryBulbCoef,
11859 18 : state.dataSurface->OSC(Loop).GroundTempCoef,
11860 18 : state.dataSurface->OSC(Loop).WindSpeedCoef,
11861 18 : state.dataSurface->OSC(Loop).ZoneAirTempCoef,
11862 18 : state.dataIPShortCut->cAlphaArgs(2),
11863 18 : state.dataIPShortCut->cAlphaArgs(3),
11864 18 : state.dataSurface->OSC(Loop).SinusoidPeriod,
11865 18 : state.dataSurface->OSC(Loop).TPreviousCoef,
11866 : cOSCLimitsString);
11867 : } else {
11868 3 : state.dataIPShortCut->cAlphaArgs(2) = "N/A";
11869 3 : constexpr std::string_view format =
11870 : "Other Side Coefficients,{},{},{:.2R},{:.3R},{:.3R},{:.3R},{:.3R},{:.3R},{},{},{:.3R},{:.3R},{}\n";
11871 9 : print(state.files.eio,
11872 : format,
11873 3 : state.dataSurface->OSC(Loop).Name,
11874 3 : state.dataIPShortCut->cAlphaArgs(1),
11875 3 : state.dataSurface->OSC(Loop).ConstTemp,
11876 3 : state.dataSurface->OSC(Loop).ConstTempCoef,
11877 3 : state.dataSurface->OSC(Loop).ExtDryBulbCoef,
11878 3 : state.dataSurface->OSC(Loop).GroundTempCoef,
11879 3 : state.dataSurface->OSC(Loop).WindSpeedCoef,
11880 3 : state.dataSurface->OSC(Loop).ZoneAirTempCoef,
11881 3 : state.dataIPShortCut->cAlphaArgs(2),
11882 3 : state.dataIPShortCut->cAlphaArgs(3),
11883 3 : state.dataSurface->OSC(Loop).SinusoidPeriod,
11884 3 : state.dataSurface->OSC(Loop).TPreviousCoef,
11885 : cOSCLimitsString);
11886 : }
11887 : }
11888 796 : }
11889 :
11890 796 : void GetOSCMData(EnergyPlusData &state, bool &ErrorsFound)
11891 : {
11892 :
11893 : // SUBROUTINE INFORMATION:
11894 : // AUTHOR Brent Griffith
11895 : // DATE WRITTEN November 2004
11896 : // MODIFIED na
11897 : // RE-ENGINEERED na
11898 :
11899 : // PURPOSE OF THIS SUBROUTINE:
11900 : // This subroutine gets the OtherSideConditionsModel data.
11901 :
11902 : // METHODOLOGY EMPLOYED:
11903 : // na
11904 :
11905 : // REFERENCES:
11906 : // derived from GetOSCData subroutine by Linda Lawrie
11907 :
11908 : // OtherSideConditionsModel,
11909 : // \memo This object sets up modifying the other side conditions for a surface from other model results.
11910 : // A1, \field OtherSideConditionsModel Name
11911 : // \required-field
11912 : // \reference OSCMNames
11913 : // \reference OutFaceEnvNames
11914 : // A2; \field Type of Model to determine Boundary Conditions
11915 : // \type choice
11916 : // \key Transpired Collector
11917 : // \key Vented PV Cavity
11918 : // \key Hybrid PV Transpired Collector
11919 :
11920 : // Using/Aliasing
11921 :
11922 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
11923 : int NumAlphas;
11924 : int NumProps;
11925 : int Loop;
11926 : int IOStat;
11927 : int OSCMNum;
11928 : bool ErrorInName;
11929 : bool IsBlank;
11930 796 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
11931 796 : cCurrentModuleObject = "SurfaceProperty:OtherSideConditionsModel";
11932 796 : state.dataSurface->TotOSCM = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
11933 796 : state.dataSurface->OSCM.allocate(state.dataSurface->TotOSCM);
11934 : // OSCM is already initialized in derived type defn.
11935 :
11936 796 : OSCMNum = 0;
11937 821 : for (Loop = 1; Loop <= state.dataSurface->TotOSCM; ++Loop) {
11938 50 : state.dataInputProcessing->inputProcessor->getObjectItem(
11939 25 : state, cCurrentModuleObject, Loop, state.dataIPShortCut->cAlphaArgs, NumAlphas, state.dataIPShortCut->rNumericArgs, NumProps, IOStat);
11940 25 : ErrorInName = false;
11941 25 : IsBlank = false;
11942 25 : Util::VerifyName(
11943 25 : state, state.dataIPShortCut->cAlphaArgs(1), state.dataSurface->OSCM, OSCMNum, ErrorInName, IsBlank, cCurrentModuleObject + " Name");
11944 25 : if (ErrorInName) {
11945 0 : ErrorsFound = true;
11946 0 : continue;
11947 : }
11948 :
11949 25 : ++OSCMNum;
11950 25 : state.dataSurface->OSCM(OSCMNum).Name = state.dataIPShortCut->cAlphaArgs(1);
11951 : // Note no validation of the below at this time:
11952 25 : state.dataSurface->OSCM(OSCMNum).Class = state.dataIPShortCut->cAlphaArgs(2);
11953 : // setup output vars for modeled coefficients
11954 50 : SetupOutputVariable(state,
11955 : "Surface Other Side Conditions Modeled Convection Air Temperature",
11956 : Constant::Units::C,
11957 25 : state.dataSurface->OSCM(OSCMNum).TConv,
11958 : OutputProcessor::TimeStepType::System,
11959 : OutputProcessor::StoreType::Average,
11960 25 : state.dataSurface->OSCM(OSCMNum).Name);
11961 50 : SetupOutputVariable(state,
11962 : "Surface Other Side Conditions Modeled Convection Heat Transfer Coefficient",
11963 : Constant::Units::W_m2K,
11964 25 : state.dataSurface->OSCM(OSCMNum).HConv,
11965 : OutputProcessor::TimeStepType::System,
11966 : OutputProcessor::StoreType::Average,
11967 25 : state.dataSurface->OSCM(OSCMNum).Name);
11968 50 : SetupOutputVariable(state,
11969 : "Surface Other Side Conditions Modeled Radiation Temperature",
11970 : Constant::Units::C,
11971 25 : state.dataSurface->OSCM(OSCMNum).TRad,
11972 : OutputProcessor::TimeStepType::System,
11973 : OutputProcessor::StoreType::Average,
11974 25 : state.dataSurface->OSCM(OSCMNum).Name);
11975 50 : SetupOutputVariable(state,
11976 : "Surface Other Side Conditions Modeled Radiation Heat Transfer Coefficient",
11977 : Constant::Units::W_m2K,
11978 25 : state.dataSurface->OSCM(OSCMNum).HRad,
11979 : OutputProcessor::TimeStepType::System,
11980 : OutputProcessor::StoreType::Average,
11981 25 : state.dataSurface->OSCM(OSCMNum).Name);
11982 :
11983 25 : if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
11984 0 : SetupEMSActuator(state,
11985 : "Other Side Boundary Conditions",
11986 0 : state.dataSurface->OSCM(OSCMNum).Name,
11987 : "Convection Bulk Air Temperature",
11988 : "[C]",
11989 0 : state.dataSurface->OSCM(OSCMNum).EMSOverrideOnTConv,
11990 0 : state.dataSurface->OSCM(OSCMNum).EMSOverrideTConvValue);
11991 0 : SetupEMSActuator(state,
11992 : "Other Side Boundary Conditions",
11993 0 : state.dataSurface->OSCM(OSCMNum).Name,
11994 : "Convection Heat Transfer Coefficient",
11995 : "[W/m2-K]",
11996 0 : state.dataSurface->OSCM(OSCMNum).EMSOverrideOnHConv,
11997 0 : state.dataSurface->OSCM(OSCMNum).EMSOverrideHConvValue);
11998 0 : SetupEMSActuator(state,
11999 : "Other Side Boundary Conditions",
12000 0 : state.dataSurface->OSCM(OSCMNum).Name,
12001 : "Radiation Effective Temperature",
12002 : "[C]",
12003 0 : state.dataSurface->OSCM(OSCMNum).EMSOverrideOnTRad,
12004 0 : state.dataSurface->OSCM(OSCMNum).EMSOverrideTRadValue);
12005 0 : SetupEMSActuator(state,
12006 : "Other Side Boundary Conditions",
12007 0 : state.dataSurface->OSCM(OSCMNum).Name,
12008 : "Radiation Linear Heat Transfer Coefficient",
12009 : "[W/m2-K]",
12010 0 : state.dataSurface->OSCM(OSCMNum).EMSOverrideOnHrad,
12011 0 : state.dataSurface->OSCM(OSCMNum).EMSOverrideHradValue);
12012 : }
12013 : }
12014 :
12015 821 : for (Loop = 1; Loop <= state.dataSurface->TotOSCM; ++Loop) {
12016 25 : if (Loop == 1) {
12017 : static constexpr std::string_view OSCMFormat1("! <Other Side Conditions Model>,Name,Class\n");
12018 12 : print(state.files.eio, OSCMFormat1);
12019 : }
12020 25 : print(state.files.eio, "Other Side Conditions Model,{},{}\n", state.dataSurface->OSCM(Loop).Name, state.dataSurface->OSCM(Loop).Class);
12021 : }
12022 796 : }
12023 :
12024 796 : void GetMovableInsulationData(EnergyPlusData &state, bool &ErrorsFound) // If errors found in input
12025 : {
12026 :
12027 : // SUBROUTINE INFORMATION:
12028 : // AUTHOR Linda Lawrie
12029 : // DATE WRITTEN May 2000
12030 : // MODIFIED na
12031 : // RE-ENGINEERED na
12032 :
12033 : // PURPOSE OF THIS SUBROUTINE:
12034 : // This subroutine gets the movable insulation data that can be associated with
12035 : // a surface.
12036 :
12037 : // METHODOLOGY EMPLOYED:
12038 : // na
12039 :
12040 : // REFERENCES:
12041 : // Movable Insulation Definition
12042 : // SurfaceControl:MovableInsulation,
12043 : // \memo Exterior or Interior Insulation on opaque surfaces
12044 : // A1, \field Insulation Type
12045 : // \required-field
12046 : // \type choice
12047 : // \key Outside
12048 : // \key Inside
12049 : // A2, \field Surface Name
12050 : // \required-field
12051 : // \type object-list
12052 : // \object-list SurfaceNames
12053 : // A3, \field Material Name
12054 : // \required-field
12055 : // \object-list MaterialName
12056 : // A4; \field Schedule Name
12057 : // \required-field
12058 : // \type object-list
12059 : // \object-list ScheduleNames
12060 :
12061 : // Using/Aliasing
12062 :
12063 : using ScheduleManager::GetScheduleIndex;
12064 :
12065 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
12066 : int NAlphas;
12067 : int NNums;
12068 : int IOStat;
12069 : int Loop;
12070 : int NMatInsul;
12071 : int SurfNum;
12072 : int MaterNum;
12073 : int SchNum;
12074 :
12075 : enum class InsulationType
12076 : {
12077 : Invalid = -1,
12078 : Outside,
12079 : Inside,
12080 : Num
12081 : };
12082 796 : constexpr std::array<std::string_view, static_cast<int>(InsulationType::Num)> insulationTypeNamesUC = {"OUTSIDE", "INSIDE"};
12083 :
12084 796 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
12085 796 : cCurrentModuleObject = "SurfaceControl:MovableInsulation";
12086 796 : NMatInsul = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
12087 801 : for (Loop = 1; Loop <= NMatInsul; ++Loop) {
12088 10 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
12089 : cCurrentModuleObject,
12090 : Loop,
12091 5 : state.dataIPShortCut->cAlphaArgs,
12092 : NAlphas,
12093 5 : state.dataIPShortCut->rNumericArgs,
12094 : NNums,
12095 : IOStat,
12096 5 : state.dataIPShortCut->lNumericFieldBlanks,
12097 5 : state.dataIPShortCut->lAlphaFieldBlanks,
12098 5 : state.dataIPShortCut->cAlphaFieldNames,
12099 5 : state.dataIPShortCut->cNumericFieldNames);
12100 5 : SurfNum = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(2), state.dataSurface->Surface, state.dataSurface->TotSurfaces);
12101 5 : MaterNum = Util::FindItemInPtrList(state.dataIPShortCut->cAlphaArgs(3), state.dataMaterial->Material, state.dataMaterial->TotMaterials);
12102 5 : auto *thisMaterial = state.dataMaterial->Material(MaterNum);
12103 5 : SchNum = GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(4));
12104 5 : InsulationType insulationType = static_cast<InsulationType>(getEnumValue(insulationTypeNamesUC, state.dataIPShortCut->cAlphaArgs(1)));
12105 5 : if (insulationType == InsulationType::Invalid) {
12106 0 : ShowSevereError(state,
12107 0 : format("{}, {}=\"{}\", invalid data.",
12108 : cCurrentModuleObject,
12109 0 : state.dataIPShortCut->cAlphaFieldNames(2),
12110 0 : state.dataIPShortCut->cAlphaArgs(2)));
12111 0 : ShowContinueError(state,
12112 0 : format(" invalid {}=\"{}\", [should be Inside or Outside]",
12113 0 : state.dataIPShortCut->cAlphaFieldNames(1),
12114 0 : state.dataIPShortCut->cAlphaArgs(1)));
12115 0 : ErrorsFound = true;
12116 : }
12117 5 : if (SurfNum == 0) {
12118 0 : ShowSevereError(state,
12119 0 : format("{}, {}=\"{}\", invalid data.",
12120 : cCurrentModuleObject,
12121 0 : state.dataIPShortCut->cAlphaFieldNames(2),
12122 0 : state.dataIPShortCut->cAlphaArgs(2)));
12123 0 : ShowContinueError(state, format(" invalid (not found) {}", state.dataIPShortCut->cAlphaFieldNames(2)));
12124 0 : ErrorsFound = true;
12125 : } else {
12126 5 : if (MaterNum == 0) {
12127 0 : ShowSevereError(state,
12128 0 : format("{}, {}=\"{}\", invalid data.",
12129 : cCurrentModuleObject,
12130 0 : state.dataIPShortCut->cAlphaFieldNames(2),
12131 0 : state.dataIPShortCut->cAlphaArgs(2)));
12132 0 : ShowContinueError(
12133 : state,
12134 0 : format(" invalid (not found) {}=\"{}\"", state.dataIPShortCut->cAlphaFieldNames(3), state.dataIPShortCut->cAlphaArgs(3)));
12135 0 : ErrorsFound = true;
12136 : } else {
12137 :
12138 : Array1D_string const cMaterialGroupType({-1, 18},
12139 : {"invalid",
12140 : "Material/Material:NoMass",
12141 : "Material:AirGap",
12142 : "WindowMaterial:Shade",
12143 : "WindowMaterial:Glazing*",
12144 : "WindowMaterial:Gas",
12145 : "WindowMaterial:Blind",
12146 : "WindowMaterial:GasMixture",
12147 : "WindowMaterial:Screen",
12148 : "Material:RoofVegetation",
12149 : "Material:InfraredTransparent",
12150 : "WindowMaterial:SimpleGlazingSystem",
12151 : "WindowMaterial:ComplexShade",
12152 : "WindowMaterial:Gap",
12153 : "WindowMaterial:Glazing:EquivalentLayer",
12154 : "WindowMaterial:Shade:EquivalentLayer",
12155 : "WindowMaterial:Drape:EquivalentLayer",
12156 : "WindowMaterial:Blind:EquivalentLayer",
12157 : "WindowMaterial:Screen:EquivalentLayer",
12158 5 : "WindowMaterial:Gap:EquivalentLayer"});
12159 :
12160 5 : Material::Group const MaterialLayerGroup = thisMaterial->group;
12161 5 : if ((MaterialLayerGroup == Material::Group::WindowSimpleGlazing) ||
12162 5 : (MaterialLayerGroup == Material::Group::ShadeEquivalentLayer) ||
12163 5 : (MaterialLayerGroup == Material::Group::DrapeEquivalentLayer) ||
12164 5 : (MaterialLayerGroup == Material::Group::BlindEquivalentLayer) ||
12165 5 : (MaterialLayerGroup == Material::Group::ScreenEquivalentLayer) ||
12166 : (MaterialLayerGroup == Material::Group::GapEquivalentLayer)) {
12167 0 : ShowSevereError(state, format("Invalid movable insulation material for {}:", cCurrentModuleObject));
12168 0 : ShowContinueError(
12169 : state,
12170 0 : format("...Movable insulation material type specified = {}", cMaterialGroupType(static_cast<int>(MaterialLayerGroup))));
12171 0 : ShowContinueError(state, format("...Movable insulation material name specified = {}", state.dataIPShortCut->cAlphaArgs(3)));
12172 0 : ErrorsFound = true;
12173 : }
12174 5 : if (SchNum == 0) {
12175 0 : ShowSevereError(state,
12176 0 : format("{}, {}=\"{}\", invalid data.",
12177 : cCurrentModuleObject,
12178 0 : state.dataIPShortCut->cAlphaFieldNames(2),
12179 0 : state.dataIPShortCut->cAlphaArgs(2)));
12180 0 : ShowContinueError(
12181 : state,
12182 0 : format(" invalid (not found) {}=\"{}\"", state.dataIPShortCut->cAlphaFieldNames(4), state.dataIPShortCut->cAlphaArgs(4)));
12183 0 : ErrorsFound = true;
12184 : } else {
12185 : {
12186 5 : switch (insulationType) {
12187 2 : case InsulationType::Outside:
12188 2 : if (state.dataSurface->SurfMaterialMovInsulExt(SurfNum) > 0) {
12189 0 : ShowSevereError(state,
12190 0 : format("{}, {}=\"{}\", already assigned.",
12191 : cCurrentModuleObject,
12192 0 : state.dataIPShortCut->cAlphaFieldNames(2),
12193 0 : state.dataIPShortCut->cAlphaArgs(2)));
12194 0 : ShowContinueError(
12195 : state,
12196 0 : format("\"Outside\", was already assigned Material=\"{}\".",
12197 0 : state.dataMaterial->Material(state.dataSurface->SurfMaterialMovInsulInt(SurfNum))->Name));
12198 0 : ShowContinueError(state, format("attempting to assign Material=\"{}\".", thisMaterial->Name));
12199 0 : ErrorsFound = true;
12200 : }
12201 2 : state.dataSurface->SurfMaterialMovInsulExt(SurfNum) = MaterNum;
12202 2 : state.dataSurface->SurfSchedMovInsulExt(SurfNum) = SchNum;
12203 2 : state.dataSurface->AnyMovableInsulation = true;
12204 2 : if (thisMaterial->Resistance <= 0.0) {
12205 0 : if (thisMaterial->Conductivity <= 0.0 || thisMaterial->Thickness <= 0.0) {
12206 0 : ShowSevereError(state,
12207 0 : format("{}, {}=\"{}\", invalid material.",
12208 : cCurrentModuleObject,
12209 0 : state.dataIPShortCut->cAlphaFieldNames(2),
12210 0 : state.dataIPShortCut->cAlphaArgs(2)));
12211 0 : ShowContinueError(state, "\"Outside\", invalid material for movable insulation.");
12212 0 : ShowContinueError(state,
12213 0 : format("Material=\"{}\",Resistance=[{:.3R}], must be > 0 for use in Movable Insulation.",
12214 0 : thisMaterial->Name,
12215 0 : thisMaterial->Resistance));
12216 0 : ErrorsFound = true;
12217 0 : } else if (thisMaterial->Conductivity > 0.0) {
12218 0 : thisMaterial->Resistance = thisMaterial->Thickness / thisMaterial->Conductivity;
12219 : }
12220 : }
12221 2 : if (thisMaterial->Conductivity <= 0.0) {
12222 1 : if (thisMaterial->Resistance <= 0.0) {
12223 0 : ShowSevereError(state,
12224 0 : format("{}, {}=\"{}\", invalid material.",
12225 : cCurrentModuleObject,
12226 0 : state.dataIPShortCut->cAlphaFieldNames(2),
12227 0 : state.dataIPShortCut->cAlphaArgs(2)));
12228 0 : ShowContinueError(state, "\"Outside\", invalid material for movable insulation.");
12229 0 : ShowContinueError(state,
12230 0 : format("Material=\"{}\",Conductivity=[{:.3R}], must be > 0 for use in Movable Insulation.",
12231 0 : thisMaterial->Name,
12232 0 : thisMaterial->Conductivity));
12233 0 : ErrorsFound = true;
12234 : }
12235 : }
12236 2 : break;
12237 3 : case InsulationType::Inside:
12238 3 : if (state.dataSurface->SurfMaterialMovInsulInt(SurfNum) > 0) {
12239 0 : ShowSevereError(state,
12240 0 : cCurrentModuleObject + ", " + state.dataIPShortCut->cAlphaFieldNames(2) + "=\"" +
12241 0 : state.dataIPShortCut->cAlphaArgs(2) + "\", already assigned.");
12242 0 : ShowContinueError(state,
12243 0 : "\"Inside\", was already assigned Material=\"" +
12244 0 : state.dataMaterial->Material(state.dataSurface->SurfMaterialMovInsulInt(SurfNum))->Name +
12245 : "\".");
12246 0 : ShowContinueError(state, "attempting to assign Material=\"" + thisMaterial->Name + "\".");
12247 0 : ErrorsFound = true;
12248 : }
12249 3 : state.dataSurface->SurfMaterialMovInsulInt(SurfNum) = MaterNum;
12250 3 : state.dataSurface->SurfSchedMovInsulInt(SurfNum) = SchNum;
12251 3 : state.dataSurface->AnyMovableInsulation = true;
12252 3 : if (thisMaterial->Resistance <= 0.0) {
12253 0 : if (thisMaterial->Conductivity <= 0.0 || thisMaterial->Thickness <= 0.0) {
12254 0 : ShowSevereError(state,
12255 0 : format("{}, {}=\"{}\", invalid material.",
12256 : cCurrentModuleObject,
12257 0 : state.dataIPShortCut->cAlphaFieldNames(2),
12258 0 : state.dataIPShortCut->cAlphaArgs(2)));
12259 0 : ShowContinueError(state, "\"Inside\", invalid material for movable insulation.");
12260 0 : ShowContinueError(state,
12261 0 : format("Material=\"{}\",Resistance=[{:.3R}], must be > 0 for use in Movable Insulation.",
12262 0 : thisMaterial->Name,
12263 0 : thisMaterial->Resistance));
12264 0 : ErrorsFound = true;
12265 0 : } else if (thisMaterial->Conductivity > 0.0) {
12266 0 : thisMaterial->Resistance = thisMaterial->Thickness / thisMaterial->Conductivity;
12267 : }
12268 : }
12269 3 : break;
12270 0 : default:
12271 0 : assert(false);
12272 : }
12273 : }
12274 5 : if (state.dataSurface->Surface(SurfNum).Class == SurfaceClass::Window) {
12275 0 : ShowSevereError(state,
12276 0 : format("{}, {}=\"{}\"",
12277 : cCurrentModuleObject,
12278 0 : state.dataIPShortCut->cAlphaFieldNames(2),
12279 0 : state.dataIPShortCut->cAlphaArgs(2)));
12280 0 : ShowContinueError(state, "invalid use on a Window. Use WindowShadingControl instead.");
12281 0 : ErrorsFound = true;
12282 : }
12283 : }
12284 5 : }
12285 : }
12286 : }
12287 796 : }
12288 :
12289 : // Calculates the volume (m3) of a zone using the surfaces as possible.
12290 796 : void CalculateZoneVolume(EnergyPlusData &state)
12291 : {
12292 : // SUBROUTINE INFORMATION:
12293 : // AUTHOR Legacy Code
12294 : // DATE WRITTEN 1992-1994
12295 : // MODIFIED Sep 2007, Mar 2017
12296 :
12297 : // METHODOLOGY EMPLOYED:
12298 : // Uses surface area information for calculations. Modified to use the
12299 : // user-entered ceiling height (x floor area, if applicable) instead of using
12300 : // the calculated volume when the user enters the ceiling height.
12301 :
12302 : // REFERENCES:
12303 : // Legacy Code (IBLAST)
12304 :
12305 796 : Vectors::Polyhedron ZoneStruct;
12306 796 : bool initmsg = true;
12307 796 : bool ShowZoneSurfaces = (state.dataInputProcessing->inputProcessor->getNumSectionsFound("SHOWZONESURFACES_DEBUG") > 0);
12308 796 : EPVector<int> surfacenotused;
12309 :
12310 : enum class ZoneVolumeCalcMethod
12311 : {
12312 : Invalid = -1,
12313 : Enclosed,
12314 : FloorAreaTimesHeight1,
12315 : FloorAreaTimesHeight2,
12316 : CeilingAreaTimesHeight,
12317 : OpWallAreaTimesDistance,
12318 : UserProvided,
12319 : Num
12320 : };
12321 :
12322 796 : int countNotFullyEnclosedZones = 0;
12323 5852 : for (auto &thisZone : state.dataHeatBal->Zone) {
12324 5056 : if (!thisZone.HasFloor) {
12325 4 : ShowWarningError(state,
12326 4 : format("No floor exists in Zone=\"{}\", zone floor area is zero. All values for this zone that are entered per "
12327 : "floor area will be zero.",
12328 2 : thisZone.Name));
12329 : }
12330 :
12331 5056 : Real64 SumAreas = 0.0;
12332 5056 : Real64 CalcVolume = 0.0;
12333 : // Use AllSurfaceFirst which includes air boundaries
12334 5056 : int NFaces = thisZone.AllSurfaceLast - thisZone.AllSurfaceFirst + 1;
12335 5056 : int notused = 0;
12336 5056 : ZoneStruct.NumSurfaceFaces = NFaces;
12337 5056 : ZoneStruct.SurfaceFace.allocate(NFaces);
12338 5056 : int NActFaces = 0;
12339 5056 : surfacenotused.dimension(NFaces, 0);
12340 :
12341 49464 : for (int SurfNum = thisZone.AllSurfaceFirst; SurfNum <= thisZone.AllSurfaceLast; ++SurfNum) {
12342 44408 : auto &thisSurface = state.dataSurface->Surface(SurfNum);
12343 : // Only include Base Surfaces in Calc.
12344 :
12345 44408 : if (thisSurface.Class != SurfaceClass::Wall && thisSurface.Class != SurfaceClass::Floor && thisSurface.Class != SurfaceClass::Roof) {
12346 9096 : ++notused;
12347 9096 : surfacenotused(notused) = SurfNum;
12348 9096 : continue;
12349 : }
12350 :
12351 35312 : ++NActFaces;
12352 35312 : auto &thisFace = ZoneStruct.SurfaceFace(NActFaces);
12353 35312 : thisFace.FacePoints.allocate(thisSurface.Sides);
12354 35312 : thisFace.NSides = thisSurface.Sides;
12355 35312 : thisFace.SurfNum = SurfNum;
12356 35312 : thisFace.FacePoints({1, thisSurface.Sides}) = thisSurface.Vertex({1, thisSurface.Sides});
12357 35312 : Vectors::CreateNewellAreaVector(thisFace.FacePoints, thisFace.NSides, thisFace.NewellAreaVector);
12358 35312 : SumAreas += Vectors::VecLength(thisFace.NewellAreaVector);
12359 : }
12360 5056 : ZoneStruct.NumSurfaceFaces = NActFaces;
12361 :
12362 5056 : bool isFloorHorizontal = false;
12363 5056 : bool isCeilingHorizontal = false;
12364 5056 : bool areWallsVertical = false;
12365 5056 : std::tie(isFloorHorizontal, isCeilingHorizontal, areWallsVertical) = areSurfaceHorizAndVert(state, ZoneStruct);
12366 5056 : Real64 oppositeWallArea = 0.0;
12367 5056 : Real64 distanceBetweenOppositeWalls = 0.0;
12368 :
12369 5056 : bool areWallsSameHeight = areWallHeightSame(state, ZoneStruct);
12370 :
12371 5056 : std::vector<EdgeOfSurf> listOfedgeNotUsedTwice;
12372 5056 : bool isZoneEnclosed = isEnclosedVolume(ZoneStruct, listOfedgeNotUsedTwice);
12373 : ZoneVolumeCalcMethod volCalcMethod;
12374 :
12375 5056 : Real64 floorAreaForVolume = (thisZone.FloorArea > 0.0) ? thisZone.FloorArea : thisZone.geometricFloorArea;
12376 5056 : Real64 ceilingAreaForVolume = (thisZone.CeilingArea > 0.0) ? thisZone.CeilingArea : thisZone.geometricCeilingArea;
12377 :
12378 5056 : if (isZoneEnclosed) {
12379 5032 : CalcVolume = Vectors::CalcPolyhedronVolume(state, ZoneStruct);
12380 5032 : volCalcMethod = ZoneVolumeCalcMethod::Enclosed;
12381 24 : } else if (floorAreaForVolume > 0.0 && thisZone.CeilingHeight > 0.0 && areFloorAndCeilingSame(state, ZoneStruct)) {
12382 16 : CalcVolume = floorAreaForVolume * thisZone.CeilingHeight;
12383 16 : volCalcMethod = ZoneVolumeCalcMethod::FloorAreaTimesHeight1;
12384 8 : } else if (isFloorHorizontal && areWallsVertical && areWallsSameHeight && floorAreaForVolume > 0.0 && thisZone.CeilingHeight > 0.0) {
12385 2 : CalcVolume = floorAreaForVolume * thisZone.CeilingHeight;
12386 2 : volCalcMethod = ZoneVolumeCalcMethod::FloorAreaTimesHeight2;
12387 6 : } else if (isCeilingHorizontal && areWallsVertical && areWallsSameHeight && ceilingAreaForVolume > 0.0 && thisZone.CeilingHeight > 0.0) {
12388 0 : CalcVolume = ceilingAreaForVolume * thisZone.CeilingHeight;
12389 0 : volCalcMethod = ZoneVolumeCalcMethod::CeilingAreaTimesHeight;
12390 6 : } else if (areOppositeWallsSame(state, ZoneStruct, oppositeWallArea, distanceBetweenOppositeWalls)) {
12391 4 : CalcVolume = oppositeWallArea * distanceBetweenOppositeWalls;
12392 4 : volCalcMethod = ZoneVolumeCalcMethod::OpWallAreaTimesDistance;
12393 2 : } else if (thisZone.Volume == Constant::AutoCalculate) { // no user entered zone volume
12394 0 : ShowSevereError(state,
12395 0 : format("For zone: {} it is not possible to calculate the volume from the surrounding surfaces so either provide the "
12396 : "volume value or define all the surfaces to fully enclose the zone.",
12397 0 : thisZone.Name));
12398 0 : CalcVolume = 0.;
12399 0 : volCalcMethod = ZoneVolumeCalcMethod::Invalid;
12400 : } else {
12401 2 : CalcVolume = 0.;
12402 2 : volCalcMethod = ZoneVolumeCalcMethod::UserProvided;
12403 : }
12404 5056 : if (!isZoneEnclosed) {
12405 24 : ++countNotFullyEnclosedZones;
12406 24 : if (state.dataGlobal->DisplayExtraWarnings) { // report missing
12407 0 : ShowWarningError(state,
12408 0 : format("CalculateZoneVolume: The Zone=\"{}\" is not fully enclosed. To be fully enclosed, each edge of a "
12409 : "surface must also be an edge on one other surface.",
12410 0 : thisZone.Name));
12411 0 : switch (volCalcMethod) {
12412 0 : case ZoneVolumeCalcMethod::FloorAreaTimesHeight1:
12413 0 : ShowContinueError(state,
12414 : " The zone volume was calculated using the floor area times ceiling height method where the floor and "
12415 : "ceiling are the same except for the z-coordinates.");
12416 0 : break;
12417 0 : case ZoneVolumeCalcMethod::FloorAreaTimesHeight2:
12418 0 : ShowContinueError(state,
12419 : " The zone volume was calculated using the floor area times ceiling height method where the floor is "
12420 : "horizontal, the walls are vertical, and the wall heights are all the same.");
12421 0 : break;
12422 0 : case ZoneVolumeCalcMethod::CeilingAreaTimesHeight:
12423 0 : ShowContinueError(state,
12424 : " The zone volume was calculated using the ceiling area times ceiling height method where the ceiling is "
12425 : "horizontal, the walls are vertical, and the wall heights are all the same.");
12426 0 : break;
12427 0 : case ZoneVolumeCalcMethod::OpWallAreaTimesDistance:
12428 0 : ShowContinueError(state,
12429 : " The zone volume was calculated using the opposite wall area times the distance between them method ");
12430 0 : break;
12431 0 : case ZoneVolumeCalcMethod::UserProvided:
12432 0 : ShowContinueError(state, " The zone volume was provided as an input to the ZONE object ");
12433 0 : break;
12434 0 : case ZoneVolumeCalcMethod::Invalid:
12435 0 : ShowContinueError(state, " The zone volume was not calculated and an error exists. ");
12436 0 : break;
12437 0 : case ZoneVolumeCalcMethod::Enclosed: // should not be called but completes enumeration
12438 0 : ShowContinueError(state, " The zone volume was calculated using multiple pyramids and was fully enclosed. ");
12439 0 : break;
12440 0 : default:
12441 0 : assert(false);
12442 : }
12443 0 : for (auto &edge : listOfedgeNotUsedTwice) {
12444 0 : if (edge.count < 2) {
12445 0 : ShowContinueError(
12446 : state,
12447 0 : fmt::format(" The surface \"{}\" has an edge that was used only once: it is not an edge on another surface",
12448 0 : state.dataSurface->Surface(edge.surfNum).Name));
12449 :
12450 : } else {
12451 0 : ShowContinueError(
12452 : state,
12453 0 : fmt::format(" The surface \"{}\" has an edge that was used {} times: it is an edge on three or more surfaces: ",
12454 0 : state.dataSurface->Surface(edge.surfNum).Name,
12455 0 : edge.count));
12456 0 : std::string surfaceNames = " It was found on the following Surfaces: ";
12457 0 : for (int surfNum : edge.otherSurfNums) {
12458 0 : surfaceNames += fmt::format("'{}' ", state.dataSurface->Surface(surfNum).Name);
12459 0 : }
12460 0 : ShowContinueError(state, surfaceNames);
12461 0 : }
12462 0 : ShowContinueError(state, format(" Vertex start {{ {:.4R}, {:.4R}, {:.4R}}}", edge.start.x, edge.start.y, edge.start.z));
12463 0 : ShowContinueError(state, format(" Vertex end {{ {:.4R}, {:.4R}, {:.4R}}}", edge.end.x, edge.end.y, edge.end.z));
12464 0 : }
12465 : }
12466 : }
12467 5056 : if (thisZone.Volume > 0.0) { // User entered zone volume, produce message if not near calculated
12468 2342 : if (CalcVolume > 0.0) {
12469 2340 : if (std::abs(CalcVolume - thisZone.Volume) / thisZone.Volume > 0.05) {
12470 2 : ++state.dataSurfaceGeometry->ErrCount5;
12471 2 : if (state.dataSurfaceGeometry->ErrCount5 == 1 && !state.dataGlobal->DisplayExtraWarnings) {
12472 1 : if (initmsg) {
12473 1 : ShowMessage(state,
12474 : "Note that the following warning(s) may/will occur if you have not enclosed your zone completely.");
12475 1 : initmsg = false;
12476 : }
12477 1 : ShowWarningError(state, "Entered Zone Volumes differ from calculated zone volume(s).");
12478 1 : ShowContinueError(state, "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on individual zones.");
12479 : }
12480 2 : if (state.dataGlobal->DisplayExtraWarnings) {
12481 0 : if (initmsg) {
12482 0 : ShowMessage(state,
12483 : "Note that the following warning(s) may/will occur if you have not enclosed your zone completely.");
12484 0 : initmsg = false;
12485 : }
12486 : // Warn user of using specified Zone Volume
12487 0 : ShowWarningError(
12488 : state,
12489 0 : format("Entered Volume entered for Zone=\"{}\" significantly different from calculated Volume", thisZone.Name));
12490 0 : ShowContinueError(state,
12491 0 : format("Entered Zone Volume value={:.2R}, Calculated Zone Volume value={:.2R}, entered volume will be "
12492 : "used in calculations.",
12493 0 : thisZone.Volume,
12494 : CalcVolume));
12495 : }
12496 : }
12497 : }
12498 2714 : } else if (thisZone.ceilingHeightEntered) { // User did not enter zone volume, but entered ceiling height
12499 129 : if (floorAreaForVolume > 0.0) {
12500 129 : thisZone.Volume = floorAreaForVolume * thisZone.CeilingHeight;
12501 : } else { // ceiling height entered but floor area zero
12502 0 : thisZone.Volume = CalcVolume;
12503 : }
12504 : } else { // Neither ceiling height nor volume entered
12505 2585 : thisZone.Volume = CalcVolume;
12506 : }
12507 :
12508 5056 : if (thisZone.Volume <= 0.0) {
12509 0 : ShowWarningError(state, format("Indicated Zone Volume <= 0.0 for Zone={}", thisZone.Name));
12510 0 : ShowContinueError(state, format("The calculated Zone Volume was={:.2R}", thisZone.Volume));
12511 0 : ShowContinueError(state, "The simulation will continue with the Zone Volume set to 10.0 m3. ");
12512 0 : ShowContinueError(state, "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on individual zones.");
12513 0 : thisZone.Volume = 10.;
12514 : }
12515 : // For now - pro-rate space volumes by floor area, if not entered
12516 10124 : for (int spaceNum : thisZone.spaceIndexes) {
12517 5068 : auto &thisSpace = state.dataHeatBal->space(spaceNum);
12518 : // don't touch if already user-specified
12519 5068 : if (thisSpace.Volume > 0.0) continue;
12520 5068 : if (thisZone.numSpaces == 1) {
12521 5050 : thisSpace.Volume = thisZone.Volume;
12522 18 : } else if (thisZone.geometricFloorArea > 0.0) {
12523 18 : thisSpace.Volume = thisZone.Volume * thisSpace.FloorArea / thisZone.geometricFloorArea;
12524 : }
12525 5056 : }
12526 5056 : Real64 totSpacesVolume = 0.0;
12527 10124 : for (int spaceNum : thisZone.spaceIndexes) {
12528 5068 : totSpacesVolume += state.dataHeatBal->space(spaceNum).Volume;
12529 5056 : }
12530 5056 : if (totSpacesVolume > 0.0) {
12531 10124 : for (int spaceNum : thisZone.spaceIndexes) {
12532 5068 : state.dataHeatBal->space(spaceNum).fracZoneVolume = state.dataHeatBal->space(spaceNum).Volume / totSpacesVolume;
12533 5056 : }
12534 : } // else leave fractions at zero
12535 :
12536 5056 : if (ShowZoneSurfaces) {
12537 0 : if (state.dataSurfaceGeometry->ShowZoneSurfaceHeaders) {
12538 0 : print(state.files.debug, "{}\n", "===================================");
12539 0 : print(state.files.debug, "{}\n", "showing zone surfaces used and not used in volume calculation");
12540 0 : print(state.files.debug, "{}\n", "for volume calculation, only floors, walls and roofs/ceilings are used");
12541 0 : print(state.files.debug, "{}\n", "surface class, 1=wall, 2=floor, 3=roof/ceiling");
12542 0 : print(state.files.debug, "{}\n", "unused surface class(es), 5=internal mass, 11=window, 12=glass door");
12543 0 : print(state.files.debug, "{}\n", " 13=door, 14=shading, 15=overhang, 16=fin");
12544 0 : print(state.files.debug, "{}\n", " 17=TDD Dome, 18=TDD Diffuser");
12545 0 : state.dataSurfaceGeometry->ShowZoneSurfaceHeaders = false;
12546 : }
12547 0 : print(state.files.debug, "{}\n", "===================================");
12548 0 : print(state.files.debug, "zone={} calc volume={}\n", thisZone.Name, CalcVolume);
12549 0 : print(state.files.debug, " nsurfaces={} nactual={}\n", NFaces, NActFaces);
12550 : }
12551 40368 : for (int faceNum = 1; faceNum <= ZoneStruct.NumSurfaceFaces; ++faceNum) {
12552 35312 : auto &thisFace = ZoneStruct.SurfaceFace(faceNum);
12553 35312 : if (ShowZoneSurfaces) {
12554 0 : if (faceNum <= NActFaces) {
12555 0 : auto &thisSurface = state.dataSurface->Surface(thisFace.SurfNum);
12556 0 : print(state.files.debug, "surface={} nsides={}\n", thisFace.SurfNum, thisFace.NSides);
12557 0 : print(state.files.debug, "surface name={} class={}\n", thisSurface.Name, thisSurface.Class);
12558 0 : print(state.files.debug, "area={}\n", thisSurface.GrossArea);
12559 0 : for (int iside = 1; iside <= thisFace.NSides; ++iside) {
12560 0 : auto const &FacePoint(thisFace.FacePoints(iside));
12561 0 : print(state.files.debug, "{} {} {}\n", FacePoint.x, FacePoint.y, FacePoint.z);
12562 : }
12563 : }
12564 : }
12565 35312 : thisFace.FacePoints.deallocate();
12566 : }
12567 5056 : if (ShowZoneSurfaces) {
12568 0 : for (int SurfNum = 1; SurfNum <= notused; ++SurfNum) {
12569 0 : print(state.files.debug,
12570 : "notused:surface={} name={} class={}\n",
12571 : surfacenotused(SurfNum),
12572 0 : state.dataSurface->Surface(surfacenotused(SurfNum)).Name,
12573 0 : state.dataSurface->Surface(surfacenotused(SurfNum)).Class);
12574 : }
12575 : }
12576 :
12577 5056 : ZoneStruct.SurfaceFace.deallocate();
12578 5056 : surfacenotused.deallocate();
12579 :
12580 5852 : } // zone loop
12581 796 : if (!state.dataGlobal->DisplayExtraWarnings) {
12582 745 : if (countNotFullyEnclosedZones == 1) {
12583 16 : ShowWarningError(
12584 : state, "CalculateZoneVolume: 1 zone is not fully enclosed. For more details use: Output:Diagnostics,DisplayExtrawarnings; ");
12585 729 : } else if (countNotFullyEnclosedZones > 1) {
12586 8 : ShowWarningError(state,
12587 8 : format("CalculateZoneVolume: {} zones are not fully enclosed. For more details use: "
12588 : "Output:Diagnostics,DisplayExtrawarnings; ",
12589 : countNotFullyEnclosedZones));
12590 : }
12591 : }
12592 796 : }
12593 :
12594 : // test if the volume described by the polyhedron if full enclosed (would not leak)
12595 5056 : bool isEnclosedVolume(DataVectorTypes::Polyhedron const &zonePoly, std::vector<EdgeOfSurf> &edgeNot2)
12596 : {
12597 : // J. Glazer - March 2017
12598 :
12599 5056 : std::vector<Vector> uniqueVertices = makeListOfUniqueVertices(zonePoly);
12600 :
12601 5056 : std::vector<EdgeOfSurf> edgeNot2orig = edgesNotTwoForEnclosedVolumeTest(zonePoly, uniqueVertices);
12602 : // if all edges had two counts then it is fully enclosed
12603 5056 : if (edgeNot2orig.empty()) {
12604 4058 : edgeNot2 = edgeNot2orig;
12605 4058 : return true;
12606 : } else { // if the count is three or greater it is likely that a vertex that is colinear was counted on the faces on one edge and not
12607 : // on the "other side" of the edge Go through all the points looking for the number that are colinear and see if that is
12608 : // consistent with the number of edges found that didn't have a count of two
12609 : DataVectorTypes::Polyhedron updatedZonePoly = updateZonePolygonsForMissingColinearPoints(
12610 998 : zonePoly, uniqueVertices); // this is done after initial test since it is computationally intensive.
12611 998 : std::vector<EdgeOfSurf> edgeNot2again = edgesNotTwoForEnclosedVolumeTest(updatedZonePoly, uniqueVertices);
12612 998 : if (edgeNot2again.empty()) {
12613 974 : return true;
12614 : } else {
12615 48 : edgeNot2 = edgesInBoth(edgeNot2orig,
12616 24 : edgeNot2again); // only return a list of those edges that appear in both the original edge and the
12617 : // revised edges this eliminates added edges that will confuse users and edges that
12618 : // were caught by the updateZonePoly routine
12619 24 : return false;
12620 : }
12621 998 : }
12622 5056 : }
12623 :
12624 : // returns a vector of edges that are in both vectors
12625 24 : std::vector<EdgeOfSurf> edgesInBoth(std::vector<EdgeOfSurf> edges1, std::vector<EdgeOfSurf> edges2)
12626 : {
12627 : // J. Glazer - June 2017
12628 : // this is not optimized but the number of edges for a typical polyhedron is 12 and is probably rarely bigger than 20.
12629 :
12630 24 : std::vector<EdgeOfSurf> inBoth;
12631 288 : for (const auto &e1 : edges1) {
12632 3229 : for (const auto &e2 : edges2) {
12633 3181 : if (edgesEqualOnSameSurface(e1, e2)) {
12634 216 : inBoth.push_back(e1);
12635 216 : break;
12636 : }
12637 264 : }
12638 24 : }
12639 24 : return inBoth;
12640 0 : }
12641 :
12642 : // returns true if the edges match - including the surface number
12643 3181 : bool edgesEqualOnSameSurface(EdgeOfSurf a, EdgeOfSurf b)
12644 : {
12645 3181 : if (a.surfNum != b.surfNum) {
12646 2681 : return false;
12647 : }
12648 :
12649 : // vertex comparison (we compare indices, so absolute equal)
12650 500 : return ((a.start == b.start && a.end == b.end) || (a.start == b.end && a.end == b.start));
12651 : }
12652 :
12653 : // returns the number of times the edges of the polyhedron of the zone are not used twice by the sides
12654 6054 : std::vector<EdgeOfSurf> edgesNotTwoForEnclosedVolumeTest(DataVectorTypes::Polyhedron const &zonePoly, std::vector<Vector> const &uniqueVertices)
12655 : {
12656 : // J. Glazer - March 2017
12657 :
12658 : using DataVectorTypes::Vector;
12659 :
12660 : struct EdgeByPts
12661 : {
12662 : int start;
12663 : int end;
12664 : int count;
12665 : int firstSurfNum;
12666 : std::vector<int> otherSurfNums;
12667 94930 : EdgeByPts() : start(0), end(0), count(0), firstSurfNum(0)
12668 : {
12669 94930 : }
12670 : };
12671 6054 : std::vector<EdgeByPts> uniqueEdges;
12672 6054 : uniqueEdges.reserve(zonePoly.NumSurfaceFaces * 6);
12673 :
12674 : // construct list of unique edges
12675 6054 : Vector curVertex;
12676 : int curVertexIndex;
12677 49958 : for (int iFace = 1; iFace <= zonePoly.NumSurfaceFaces; ++iFace) {
12678 43904 : Vector prevVertex;
12679 : int prevVertexIndex;
12680 224533 : for (int jVertex = 1; jVertex <= zonePoly.SurfaceFace(iFace).NSides; ++jVertex) {
12681 180629 : if (jVertex == 1) {
12682 43904 : prevVertex = zonePoly.SurfaceFace(iFace).FacePoints(zonePoly.SurfaceFace(iFace).NSides); // the last point
12683 43904 : prevVertexIndex = findIndexOfVertex(prevVertex, uniqueVertices);
12684 : } else {
12685 136725 : prevVertex = curVertex;
12686 136725 : prevVertexIndex = curVertexIndex;
12687 : }
12688 180629 : curVertex = zonePoly.SurfaceFace(iFace).FacePoints(jVertex);
12689 180629 : curVertexIndex = findIndexOfVertex(curVertex, uniqueVertices); // uses isAlmostEqual3dPt
12690 361258 : auto it = std::find_if(uniqueEdges.begin(), uniqueEdges.end(), [&curVertexIndex, &prevVertexIndex](const auto &edge) {
12691 3327787 : return ((edge.start == curVertexIndex && edge.end == prevVertexIndex) ||
12692 3327787 : (edge.start == prevVertexIndex && edge.end == curVertexIndex));
12693 361258 : });
12694 180629 : if (it == uniqueEdges.end()) {
12695 94930 : EdgeByPts curEdge;
12696 94930 : curEdge.start = prevVertexIndex;
12697 94930 : curEdge.end = curVertexIndex;
12698 94930 : curEdge.count = 1;
12699 94930 : curEdge.firstSurfNum = zonePoly.SurfaceFace(iFace).SurfNum;
12700 94930 : uniqueEdges.emplace_back(curEdge);
12701 94930 : } else {
12702 85699 : ++(it->count);
12703 85699 : it->otherSurfNums.push_back(zonePoly.SurfaceFace(iFace).SurfNum);
12704 : }
12705 180629 : }
12706 43904 : }
12707 : // All edges for an enclosed polyhedron should be shared by two (and only two) sides.
12708 : // So if the count is not two for all edges, the polyhedron is not enclosed
12709 6054 : std::vector<EdgeOfSurf> edgesNotTwoCount;
12710 100984 : for (const auto &anEdge : uniqueEdges) {
12711 94930 : if (anEdge.count != 2) {
12712 9479 : EdgeOfSurf curEdgeOne;
12713 9479 : curEdgeOne.surfNum = anEdge.firstSurfNum;
12714 9479 : curEdgeOne.start = uniqueVertices[anEdge.start];
12715 9479 : curEdgeOne.end = uniqueVertices[anEdge.end];
12716 9479 : curEdgeOne.count = anEdge.count;
12717 9479 : curEdgeOne.otherSurfNums = anEdge.otherSurfNums;
12718 9479 : edgesNotTwoCount.push_back(curEdgeOne);
12719 9479 : }
12720 6054 : }
12721 12108 : return edgesNotTwoCount;
12722 6054 : }
12723 :
12724 : // create a list of unique vertices given the polyhedron describing the zone
12725 5056 : std::vector<Vector> makeListOfUniqueVertices(DataVectorTypes::Polyhedron const &zonePoly)
12726 : {
12727 : // J. Glazer - March 2017
12728 :
12729 : using DataVectorTypes::Vector;
12730 5056 : std::vector<Vector> uniqVertices;
12731 5056 : uniqVertices.reserve(zonePoly.NumSurfaceFaces * 6);
12732 :
12733 40368 : for (int iFace = 1; iFace <= zonePoly.NumSurfaceFaces; ++iFace) {
12734 177447 : for (int jVertex = 1; jVertex <= zonePoly.SurfaceFace(iFace).NSides; ++jVertex) {
12735 142135 : Vector curVertex = zonePoly.SurfaceFace(iFace).FacePoints(jVertex);
12736 142135 : if (uniqVertices.size() == 0) {
12737 5056 : uniqVertices.emplace_back(curVertex);
12738 : } else {
12739 137079 : bool found = false;
12740 850302 : for (const auto &unqV : uniqVertices) {
12741 807496 : if (isAlmostEqual3dPt(curVertex, unqV)) {
12742 94273 : found = true;
12743 94273 : break;
12744 : }
12745 137079 : }
12746 137079 : if (!found) {
12747 42806 : uniqVertices.emplace_back(curVertex);
12748 : }
12749 : }
12750 142135 : }
12751 : }
12752 5056 : return uniqVertices;
12753 0 : }
12754 :
12755 : // updates the polyhedron used to describe a zone to include points on an edge that are between and collinear to points already describing
12756 : // the edge
12757 998 : DataVectorTypes::Polyhedron updateZonePolygonsForMissingColinearPoints(DataVectorTypes::Polyhedron const &zonePoly,
12758 : std::vector<Vector> const &uniqVertices)
12759 : {
12760 : // J. Glazer - March 2017
12761 :
12762 : using DataVectorTypes::Vector;
12763 :
12764 998 : DataVectorTypes::Polyhedron updZonePoly = zonePoly; // set the return value to the original polyhedron describing the zone
12765 :
12766 11125 : for (auto &updFace : updZonePoly.SurfaceFace) {
12767 10127 : bool insertedVertext = true;
12768 24057 : while (insertedVertext) {
12769 13930 : insertedVertext = false;
12770 13930 : auto &vertices = updFace.FacePoints;
12771 62615 : for (auto it = vertices.begin(); it != vertices.end(); ++it) {
12772 :
12773 52488 : auto itnext = std::next(it);
12774 52488 : if (itnext == std::end(vertices)) {
12775 9872 : itnext = std::begin(vertices);
12776 : }
12777 :
12778 52488 : auto curVertex = *it; // (AUTO_OK_OBJ) can't tell if a copy is the intended behavior here
12779 52488 : auto nextVertex = *itnext; // (AUTO_OK_OBJ)
12780 :
12781 : // now go through all the vertices and see if they are colinear with start and end vertices
12782 930754 : for (const auto &testVertex : uniqVertices) {
12783 882069 : if (!isAlmostEqual3dPt(curVertex, testVertex) && !isAlmostEqual3dPt(nextVertex, testVertex)) {
12784 779113 : if (isPointOnLineBetweenPoints(curVertex, nextVertex, testVertex)) {
12785 3803 : vertices.insert(itnext, testVertex);
12786 3803 : ++updFace.NSides;
12787 3803 : insertedVertext = true;
12788 3803 : break;
12789 : }
12790 : }
12791 52488 : }
12792 : // Break out of the loop on vertices of the surface too, and start again at the while
12793 52488 : if (insertedVertext) {
12794 3803 : break;
12795 : }
12796 56291 : }
12797 : }
12798 : }
12799 998 : return updZonePoly;
12800 0 : }
12801 :
12802 : // test if the ceiling and floor are the same except for their height difference by looking at the corners
12803 22 : bool areFloorAndCeilingSame(EnergyPlusData &state, DataVectorTypes::Polyhedron const &zonePoly)
12804 : {
12805 : // J. Glazer - March 2017
12806 :
12807 : // check if the floor and ceiling are the same
12808 : // this is almost equivalent to saying, if you ignore the z-coordinate, are the vertices the same
12809 : // so if you could all the unique vertices of the floor and ceiling, ignoring the z-coordinate, they
12810 : // should always be even (they would be two but you might define multiple surfaces that meet in a corner)
12811 :
12812 : using DataVectorTypes::Vector;
12813 : using DataVectorTypes::Vector2dCount;
12814 : using DataVectorTypes::Vector_2d;
12815 :
12816 22 : std::vector<Vector2dCount> floorCeilingXY;
12817 22 : floorCeilingXY.reserve(zonePoly.NumSurfaceFaces * 6);
12818 :
12819 : // make list of x and y coordinates for all faces that are on the floor or ceiling
12820 248 : for (int iFace = 1; iFace <= zonePoly.NumSurfaceFaces; ++iFace) {
12821 226 : int curSurfNum = zonePoly.SurfaceFace(iFace).SurfNum;
12822 414 : if (state.dataSurface->Surface(curSurfNum).Class == SurfaceClass::Floor ||
12823 188 : state.dataSurface->Surface(curSurfNum).Class == SurfaceClass::Roof) {
12824 390 : for (int jVertex = 1; jVertex <= zonePoly.SurfaceFace(iFace).NSides; ++jVertex) {
12825 312 : Vector curVertex = zonePoly.SurfaceFace(iFace).FacePoints(jVertex);
12826 312 : Vector2dCount curXYc;
12827 312 : curXYc.x = curVertex.x;
12828 312 : curXYc.y = curVertex.y;
12829 312 : curXYc.count = 1;
12830 312 : bool found = false;
12831 1153 : for (Vector2dCount &curFloorCeiling : floorCeilingXY) { // can't use just "auto" because updating floorCeilingXY
12832 1014 : if (isAlmostEqual2dPt(curXYc, curFloorCeiling)) { // count ignored in comparison
12833 173 : ++curFloorCeiling.count;
12834 173 : found = true;
12835 173 : break;
12836 : }
12837 312 : }
12838 312 : if (!found) {
12839 139 : floorCeilingXY.emplace_back(curXYc);
12840 : }
12841 312 : }
12842 : }
12843 : }
12844 : // now make sure every point has been counted and even number of times (usually twice)
12845 : // if they are then the ceiling and floor are (almost certainly) the same x and y coordinates.
12846 22 : bool areFlrAndClgSame = true;
12847 22 : if (floorCeilingXY.size() > 0) {
12848 115 : for (auto const &curFloorCeiling : floorCeilingXY) {
12849 99 : if (curFloorCeiling.count % 2 != 0) {
12850 6 : areFlrAndClgSame = false;
12851 6 : break;
12852 : }
12853 22 : }
12854 : } else {
12855 0 : areFlrAndClgSame = false;
12856 : }
12857 22 : return areFlrAndClgSame;
12858 22 : }
12859 :
12860 : // test if the walls of a zone are all the same height using the polyhedron describing the zone geometry
12861 5056 : bool areWallHeightSame(EnergyPlusData &state, DataVectorTypes::Polyhedron const &zonePoly)
12862 : {
12863 : // J. Glazer - March 2017
12864 :
12865 : // test if all the wall heights are the same (all walls have the same maximum z-coordinate
12866 :
12867 5056 : bool areWlHgtSame = true;
12868 5056 : Real64 wallHeightZ = -Constant::BigNumber;
12869 5056 : bool foundWallHeight = false;
12870 39395 : for (int iFace = 1; iFace <= zonePoly.NumSurfaceFaces; ++iFace) {
12871 34413 : int curSurfNum = zonePoly.SurfaceFace(iFace).SurfNum;
12872 34413 : if (state.dataSurface->Surface(curSurfNum).Class == SurfaceClass::Wall) {
12873 22102 : Real64 maxZ = -Constant::BigNumber;
12874 110439 : for (int jVertex = 1; jVertex <= zonePoly.SurfaceFace(iFace).NSides; ++jVertex) {
12875 88337 : Vector curVertex = zonePoly.SurfaceFace(iFace).FacePoints(jVertex);
12876 88337 : if (maxZ < curVertex.z) {
12877 22147 : maxZ = curVertex.z;
12878 : }
12879 88337 : }
12880 22102 : if (foundWallHeight) {
12881 17068 : if (std::abs(maxZ - wallHeightZ) > Constant::TwoCentimeters) {
12882 74 : areWlHgtSame = false;
12883 74 : break;
12884 : }
12885 : } else {
12886 5034 : wallHeightZ = maxZ;
12887 5034 : foundWallHeight = true;
12888 : }
12889 : }
12890 : }
12891 5056 : return areWlHgtSame;
12892 : }
12893 :
12894 : // tests if the floor is horizontal, ceiling is horizontal, and walls are vertical and returns all three as a tuple of booleans
12895 5056 : std::tuple<bool, bool, bool> areSurfaceHorizAndVert(EnergyPlusData &state, DataVectorTypes::Polyhedron const &zonePoly)
12896 : {
12897 : // J. Glazer - March 2017
12898 :
12899 : // check if floors and ceilings are horizontal and walls are vertical
12900 5056 : bool isFlrHoriz = true;
12901 5056 : bool isClgHoriz = true;
12902 5056 : bool areWlVert = true;
12903 40368 : for (int iFace = 1; iFace <= zonePoly.NumSurfaceFaces; ++iFace) {
12904 35312 : int curSurfNum = zonePoly.SurfaceFace(iFace).SurfNum;
12905 35312 : if (state.dataSurface->Surface(curSurfNum).Class == SurfaceClass::Floor) {
12906 6890 : if (std::abs(state.dataSurface->Surface(curSurfNum).Tilt - 180.) > 1.) { // with 1 degree angle
12907 0 : isFlrHoriz = false;
12908 : }
12909 28422 : } else if (state.dataSurface->Surface(curSurfNum).Class == SurfaceClass::Roof) { // includes ceilings
12910 5801 : if (std::abs(state.dataSurface->Surface(curSurfNum).Tilt) > 1.) { // with 1 degree angle of
12911 252 : isClgHoriz = false;
12912 : }
12913 22621 : } else if (state.dataSurface->Surface(curSurfNum).Class == SurfaceClass::Wall) {
12914 22621 : if (std::abs(state.dataSurface->Surface(curSurfNum).Tilt - 90) > 1.) { // with 1 degree angle
12915 2 : areWlVert = false;
12916 : }
12917 : }
12918 : }
12919 10112 : return std::make_tuple(isFlrHoriz, isClgHoriz, areWlVert);
12920 : }
12921 :
12922 : // tests whether a pair of walls in the zone are the same except offset from one another and facing the opposite direction and also
12923 : // returns the wall area and distance between
12924 6 : bool areOppositeWallsSame(EnergyPlusData &state,
12925 : DataVectorTypes::Polyhedron const &zonePoly,
12926 : Real64 &oppositeWallArea, // return the area of the wall that has an opposite wall
12927 : Real64 &distanceBetweenOppositeWalls // returns distance
12928 : )
12929 : {
12930 : // J. Glazer - March 2017
12931 :
12932 : // approach: if opposite surfaces have opposite azimuth and same area, then check the distance between the
12933 : // vertices( one counting backwards ) and if it is the same distance than assume that it is the same.
12934 : using DataVectorTypes::Vector;
12935 6 : bool foundOppEqual = false;
12936 19 : for (int iFace = 1; iFace <= zonePoly.NumSurfaceFaces; ++iFace) {
12937 17 : int curSurfNum = zonePoly.SurfaceFace(iFace).SurfNum;
12938 17 : if (state.dataSurface->Surface(curSurfNum).Class == SurfaceClass::Wall) {
12939 17 : std::vector<int> facesAtAz = listOfFacesFacingAzimuth(state, zonePoly, state.dataSurface->Surface(curSurfNum).Azimuth);
12940 17 : bool allFacesEquidistant = true;
12941 17 : oppositeWallArea = 0.;
12942 38 : for (int curFace : facesAtAz) {
12943 34 : int possOppFace = findPossibleOppositeFace(state, zonePoly, curFace);
12944 34 : if (possOppFace > 0) { // an opposite fact was found
12945 22 : oppositeWallArea += state.dataSurface->Surface(zonePoly.SurfaceFace(curFace).SurfNum).Area;
12946 22 : if (!areCornersEquidistant(zonePoly, curFace, possOppFace, distanceBetweenOppositeWalls)) {
12947 1 : allFacesEquidistant = false;
12948 1 : break;
12949 : }
12950 : } else {
12951 12 : allFacesEquidistant = false;
12952 12 : break;
12953 : }
12954 17 : }
12955 17 : if (allFacesEquidistant) {
12956 4 : foundOppEqual = true;
12957 4 : break; // only need to find the first case where opposite walls are the same
12958 : }
12959 17 : }
12960 : }
12961 6 : return foundOppEqual;
12962 : }
12963 :
12964 : // provides a list of indices of polyhedron faces that are facing a specific azimuth
12965 17 : std::vector<int> listOfFacesFacingAzimuth(EnergyPlusData &state, DataVectorTypes::Polyhedron const &zonePoly, Real64 const azimuth)
12966 : {
12967 : // J. Glazer - March 2017
12968 :
12969 17 : std::vector<int> facingAzimuth;
12970 17 : facingAzimuth.reserve(zonePoly.NumSurfaceFaces);
12971 :
12972 187 : for (int iFace = 1; iFace <= zonePoly.NumSurfaceFaces; ++iFace) {
12973 170 : int curSurfNum = zonePoly.SurfaceFace(iFace).SurfNum;
12974 170 : if (General::rotAzmDiffDeg(state.dataSurface->Surface(curSurfNum).Azimuth, azimuth) < 1.) {
12975 45 : facingAzimuth.emplace_back(iFace);
12976 : }
12977 : }
12978 17 : return facingAzimuth;
12979 0 : }
12980 :
12981 : // returns the index of the face of a polyhedron that is probably opposite of the face index provided
12982 34 : int findPossibleOppositeFace(EnergyPlusData &state, DataVectorTypes::Polyhedron const &zonePoly, int const faceIndex)
12983 : {
12984 : // J. Glazer - March 2017
12985 :
12986 34 : int selectedSurNum = zonePoly.SurfaceFace(faceIndex).SurfNum;
12987 34 : Real64 selectedAzimuth = state.dataSurface->Surface(selectedSurNum).Azimuth;
12988 34 : Real64 oppositeAzimuth = fmod(selectedAzimuth + 180., 360.);
12989 34 : Real64 selectedArea = state.dataSurface->Surface(selectedSurNum).Area;
12990 34 : int selectedNumCorners = zonePoly.SurfaceFace(faceIndex).NSides;
12991 34 : int found = -1;
12992 :
12993 222 : for (int iFace = 1; iFace <= zonePoly.NumSurfaceFaces; ++iFace) {
12994 210 : int curSurfNum = zonePoly.SurfaceFace(iFace).SurfNum;
12995 420 : if ((zonePoly.SurfaceFace(iFace).NSides == selectedNumCorners) &&
12996 420 : (std::abs(state.dataSurface->Surface(curSurfNum).Area - selectedArea) < 0.01) &&
12997 78 : (std::abs(state.dataSurface->Surface(curSurfNum).Azimuth - oppositeAzimuth) < 1.)) {
12998 22 : found = iFace;
12999 22 : break;
13000 : }
13001 : }
13002 34 : return found;
13003 : }
13004 :
13005 : // tests if the corners of one face of the polyhedron are the same distance from corners of another face
13006 22 : bool areCornersEquidistant(DataVectorTypes::Polyhedron const &zonePoly, int const faceIndex, int const opFaceIndex, Real64 &distanceBetween)
13007 : {
13008 : // J. Glazer - March 2017
13009 :
13010 22 : bool allAreEquidistant = true;
13011 22 : Real64 firstDistance = -99.;
13012 22 : if (zonePoly.SurfaceFace(faceIndex).NSides == zonePoly.SurfaceFace(opFaceIndex).NSides) { // double check that the number of sides match
13013 107 : for (int iVertex = 1; iVertex <= zonePoly.SurfaceFace(faceIndex).NSides; ++iVertex) {
13014 86 : int iVertexOpp = 1 + zonePoly.SurfaceFace(faceIndex).NSides - iVertex; // count backwards for opposite face
13015 : Real64 curDistBetwCorners =
13016 86 : distance(zonePoly.SurfaceFace(faceIndex).FacePoints(iVertex), zonePoly.SurfaceFace(opFaceIndex).FacePoints(iVertexOpp));
13017 86 : if (iVertex == 1) {
13018 22 : firstDistance = curDistBetwCorners;
13019 : } else {
13020 64 : if (std::abs(curDistBetwCorners - firstDistance) > Constant::OneCentimeter) {
13021 1 : allAreEquidistant = false;
13022 1 : break;
13023 : }
13024 : }
13025 : }
13026 : } else {
13027 0 : allAreEquidistant = false;
13028 : }
13029 22 : if (allAreEquidistant) distanceBetween = firstDistance;
13030 22 : return allAreEquidistant;
13031 : }
13032 :
13033 : // test if two points in space are in the same position based on a small tolerance
13034 19285734 : bool isAlmostEqual3dPt(DataVectorTypes::Vector v1, DataVectorTypes::Vector v2)
13035 : {
13036 : // J. Glazer - March 2017
13037 :
13038 20119852 : return ((std::abs(v1.x - v2.x) < Constant::OneCentimeter) && (std::abs(v1.y - v2.y) < Constant::OneCentimeter) &&
13039 20119852 : (std::abs(v1.z - v2.z) < Constant::OneCentimeter));
13040 : }
13041 :
13042 : // test if two points on a plane are in the same position based on a small tolerance
13043 1014 : bool isAlmostEqual2dPt(DataVectorTypes::Vector_2d v1, DataVectorTypes::Vector_2d v2)
13044 : {
13045 : // J. Glazer - March 2017
13046 :
13047 1014 : return ((std::abs(v1.x - v2.x) < Constant::OneCentimeter) && (std::abs(v1.y - v2.y) < Constant::OneCentimeter));
13048 : }
13049 :
13050 : // test if two points on a plane are in the same position based on a small tolerance (based on Vector2dCount comparison)
13051 0 : bool isAlmostEqual2dPt(DataVectorTypes::Vector2dCount v1, DataVectorTypes::Vector2dCount v2)
13052 : {
13053 : // J. Glazer - March 2017
13054 :
13055 0 : return ((std::abs(v1.x - v2.x) < Constant::OneCentimeter) && (std::abs(v1.y - v2.y) < Constant::OneCentimeter));
13056 : }
13057 :
13058 : // returns the index of vertex in a list that is in the same position in space as the given vertex
13059 224533 : int findIndexOfVertex(DataVectorTypes::Vector vertexToFind, std::vector<DataVectorTypes::Vector> listOfVertices)
13060 : {
13061 : // J. Glazer - March 2017
13062 :
13063 1454727 : for (std::size_t i = 0; i < listOfVertices.size(); i++) {
13064 1454727 : if (isAlmostEqual3dPt(listOfVertices[i], vertexToFind)) {
13065 224533 : return i;
13066 : }
13067 : }
13068 0 : return -1;
13069 : }
13070 :
13071 : // returns the distance between two points in space
13072 1026756 : Real64 distance(DataVectorTypes::Vector v1, DataVectorTypes::Vector v2)
13073 : {
13074 : // J. Glazer - March 2017
13075 :
13076 1026756 : return sqrt(pow(v1.x - v2.x, 2) + pow(v1.y - v2.y, 2) + pow(v1.z - v2.z, 2));
13077 : }
13078 :
13079 6817715 : Real64 distanceFromPointToLine(DataVectorTypes::Vector start, DataVectorTypes::Vector end, DataVectorTypes::Vector test)
13080 : {
13081 : // np.linalg.norm(np.cross(e-s,p-s)/np.linalg.norm(e-s))
13082 6817715 : DataVectorTypes::Vector t = end - start;
13083 6817715 : t.normalize(); // Unit vector of start to end
13084 :
13085 6817715 : DataVectorTypes::Vector other = test - start;
13086 :
13087 6817715 : DataVectorTypes::Vector projection = DataVectorTypes::cross(t, other); // normal unit vector, that's the distance component
13088 13635430 : return projection.length();
13089 6817715 : }
13090 :
13091 : // tests if a point in space lies on the line segment defined by two other points
13092 6817715 : bool isPointOnLineBetweenPoints(DataVectorTypes::Vector start, DataVectorTypes::Vector end, DataVectorTypes::Vector test)
13093 : {
13094 : // J. Glazer - March 2017
13095 : // The tolerance has to be low enough. Take for eg a plenum that has an edge that's 30meters long, you risk adding point from the
13096 : // floor to the roof, cf #7383 compute the shortest distance from the point to the line first to avoid false positive
13097 6817715 : if (distanceFromPointToLine(start, end, test) <
13098 : Constant::OneCentimeter) { // distanceFromPointToLine always positive, it's calculated as norml_L2
13099 282940 : return (std::abs((distance(start, end) - (distance(start, test) + distance(test, end)))) < Constant::OneCentimeter);
13100 : }
13101 6534775 : return false;
13102 : }
13103 :
13104 1355977 : bool EdgeOfSurf::operator==(const EdgeOfSurf &other) const
13105 : {
13106 4058640 : return ((isAlmostEqual3dPt(this->start, other.start) && isAlmostEqual3dPt(this->end, other.end)) ||
13107 4058640 : (isAlmostEqual3dPt(this->start, other.end) && isAlmostEqual3dPt(this->end, other.start)));
13108 : }
13109 :
13110 0 : bool EdgeOfSurf::operator!=(const EdgeOfSurf &other) const
13111 : {
13112 0 : return !(*this == other);
13113 : }
13114 :
13115 6117112 : bool EdgeOfSurf::containsPoints(const Vector &vertex) const
13116 : {
13117 18272826 : return (!isAlmostEqual3dPt(this->start, vertex) && !isAlmostEqual3dPt(this->end, vertex) &&
13118 18272826 : isPointOnLineBetweenPoints(this->start, this->end, vertex));
13119 : }
13120 :
13121 7155 : double EdgeOfSurf::length() const
13122 : {
13123 7155 : return distance(this->start, this->end);
13124 : }
13125 :
13126 43646 : void ProcessSurfaceVertices(EnergyPlusData &state, int const ThisSurf, bool &ErrorsFound)
13127 : {
13128 : // SUBROUTINE INFORMATION:
13129 : // AUTHOR Legacy Code (Walton)
13130 : // DATE WRITTEN 1976
13131 : // MODIFIED FW, Mar 2002: Add triangular windows
13132 : // FW, May 2002: modify test for 4-sided but non-rectangular subsurfaces
13133 : // FW, Sep 2002: add shape for base surfaces (walls and detached shading surfaces)
13134 :
13135 : // PURPOSE OF THIS SUBROUTINE:
13136 : // This subroutine processes each surface into the vertex representation used
13137 : // by the shading procedures.
13138 :
13139 : // METHODOLOGY EMPLOYED:
13140 : // Detached Shading, Base Surfaces, Attached Shading surfaces are represented in the
13141 : // same manner as original. Subsurfaces (windows, doors) are a "relative coordinate".
13142 :
13143 : using namespace Vectors;
13144 :
13145 : static constexpr std::string_view RoutineName("ProcessSurfaceVertices: ");
13146 :
13147 : Real64 X1; // Intermediate Result
13148 : Real64 Y1; // Intermediate Result
13149 : Real64 Z1; // Intermediate Result
13150 : Real64 XLLC; // X-coordinate of lower left corner
13151 : Real64 YLLC; // Y-coordinate of lower left corner
13152 : Real64 ZLLC; // Z-coordinate of lower left corner
13153 : int n; // Vertex Number in Loop
13154 : int ThisBaseSurface; // Current base surface
13155 : Real64 Xp;
13156 : Real64 Yp;
13157 : Real64 Zp;
13158 : Real64 SurfWorldAz; // Surface Azimuth (facing)
13159 : Real64 SurfTilt; // Surface Tilt
13160 43646 : SurfaceShape ThisShape(SurfaceShape::None);
13161 : bool BaseSurface; // True if a base surface or a detached shading surface
13162 : Real64 ThisSurfAz;
13163 : Real64 ThisSurfTilt;
13164 : Real64 ThisReveal;
13165 : Real64 ThisWidth;
13166 : Real64 ThisHeight;
13167 : int FrDivNum; // Frame/divider number
13168 : Real64 FrWidth; // Frame width for exterior windows (m)
13169 : Real64 FrArea; // Frame area for exterior windows(m2)
13170 : Real64 DivWidth; // Divider width for exterior windows (m)
13171 : Real64 DivArea; // Divider area for exterior windows (m2)
13172 : Real64 DivFrac; // Fraction of divider area without overlaps
13173 : bool ErrorInSurface; // false/true, depending on pass through routine
13174 : bool SError; // Bool used for return value of calls to PlaneEquation
13175 : bool HeatTransSurf;
13176 : bool IsCoPlanar;
13177 : Real64 OutOfLine;
13178 : int LastVertexInError;
13179 :
13180 : // Object Data
13181 43646 : PlaneEq BasePlane;
13182 43646 : Vector TVect;
13183 43646 : Vector CoordinateTransVector;
13184 :
13185 43646 : if (state.dataSurface->Surface(ThisSurf).VerticesProcessed) {
13186 0 : return;
13187 : }
13188 :
13189 43646 : ErrorInSurface = false;
13190 :
13191 43646 : if (state.dataSurfaceGeometry->ProcessSurfaceVerticesOneTimeFlag) {
13192 765 : state.dataSurfaceGeometry->Xpsv.allocate(state.dataSurface->MaxVerticesPerSurface);
13193 765 : state.dataSurfaceGeometry->Ypsv.allocate(state.dataSurface->MaxVerticesPerSurface);
13194 765 : state.dataSurfaceGeometry->Zpsv.allocate(state.dataSurface->MaxVerticesPerSurface);
13195 765 : state.dataSurfaceGeometry->Xpsv = 0.0;
13196 765 : state.dataSurfaceGeometry->Ypsv = 0.0;
13197 765 : state.dataSurfaceGeometry->Zpsv = 0.0;
13198 765 : state.dataSurfaceGeometry->ProcessSurfaceVerticesOneTimeFlag = false;
13199 : }
13200 :
13201 : // Categorize this surface
13202 43646 : auto &surf = state.dataSurface->Surface(ThisSurf);
13203 43646 : BaseSurface = (surf.BaseSurf == 0 || surf.BaseSurf == ThisSurf);
13204 :
13205 43646 : ThisBaseSurface = surf.BaseSurf; // Dont know if this is still needed or not
13206 43646 : HeatTransSurf = surf.HeatTransSurf;
13207 :
13208 : // Kludge for daylighting shelves
13209 43646 : if (surf.IsShadowing) {
13210 1636 : ThisBaseSurface = ThisSurf;
13211 1636 : HeatTransSurf = true;
13212 : }
13213 :
13214 : // IF (Surface(ThisSurf)%Name(1:3) /= 'Mir') THEN
13215 43646 : if (!surf.MirroredSurf) {
13216 42828 : CalcCoPlanarNess(surf.Vertex, surf.Sides, IsCoPlanar, OutOfLine, LastVertexInError);
13217 42828 : if (!IsCoPlanar) {
13218 0 : if (OutOfLine > 0.01) {
13219 0 : ShowSevereError(state,
13220 0 : format("{}Suspected non-planar surface:\"{}\", Max \"out of line\"={:.5T} at Vertex # {}",
13221 : RoutineName,
13222 0 : surf.Name,
13223 : OutOfLine,
13224 : LastVertexInError));
13225 : } else {
13226 0 : ShowWarningError(state,
13227 0 : format("{}Possible non-planar surface:\"{}\", Max \"out of line\"={:.5T} at Vertex # {}",
13228 : RoutineName,
13229 0 : surf.Name,
13230 : OutOfLine,
13231 : LastVertexInError));
13232 : }
13233 : // ErrorInSurface=.TRUE.
13234 : }
13235 : }
13236 :
13237 43646 : if (BaseSurface) {
13238 36950 : SurfWorldAz = surf.Azimuth;
13239 36950 : SurfTilt = surf.Tilt;
13240 185593 : for (n = 1; n <= surf.Sides; ++n) {
13241 148643 : state.dataSurfaceGeometry->Xpsv(n) = surf.Vertex(n).x;
13242 148643 : state.dataSurfaceGeometry->Ypsv(n) = surf.Vertex(n).y;
13243 148643 : state.dataSurfaceGeometry->Zpsv(n) = surf.Vertex(n).z;
13244 : }
13245 36950 : TVect = surf.Vertex(3) - surf.Vertex(2);
13246 36950 : ThisWidth = VecLength(TVect);
13247 36950 : TVect = surf.Vertex(2) - surf.Vertex(1);
13248 36950 : ThisHeight = VecLength(TVect);
13249 36950 : surf.Width = ThisWidth;
13250 36950 : surf.Height = ThisHeight; // For a horizontal surface this is actually length!
13251 36950 : if (surf.Sides == 3) {
13252 197 : surf.Shape = SurfaceShape::Triangle;
13253 36753 : } else if (surf.Sides == 4) {
13254 : // Test for rectangularity
13255 36556 : if (isRectangle(state, ThisSurf)) {
13256 31314 : surf.Shape = SurfaceShape::Rectangle;
13257 : } else {
13258 5242 : surf.Shape = SurfaceShape::Quadrilateral;
13259 : }
13260 : } else { // Surface( ThisSurf ).Sides > 4
13261 197 : surf.Shape = SurfaceShape::Polygonal;
13262 197 : if (std::abs(ThisHeight * ThisWidth - surf.GrossArea) > 0.001) {
13263 197 : surf.Width = std::sqrt(surf.GrossArea);
13264 197 : surf.Height = surf.Width;
13265 197 : ThisWidth = surf.Width;
13266 197 : ThisHeight = surf.Height;
13267 : }
13268 : }
13269 :
13270 : } else { // It's a subsurface to previous basesurface in this set of calls
13271 :
13272 6696 : ThisSurfAz = surf.Azimuth;
13273 6696 : ThisSurfTilt = surf.Tilt;
13274 :
13275 : // Retrieve base surface info
13276 6696 : Real64 const baseSurfWorldAz = state.dataSurface->Surface(ThisBaseSurface).Azimuth;
13277 6696 : Real64 const baseSurfTilt = state.dataSurface->Surface(ThisBaseSurface).Tilt;
13278 6696 : Real64 const BaseCosAzimuth = std::cos(baseSurfWorldAz * Constant::DegToRadians);
13279 6696 : Real64 const BaseSinAzimuth = std::sin(baseSurfWorldAz * Constant::DegToRadians);
13280 6696 : Real64 const BaseCosTilt = std::cos(baseSurfTilt * Constant::DegToRadians);
13281 6696 : Real64 const BaseSinTilt = std::sin(baseSurfTilt * Constant::DegToRadians);
13282 6696 : Real64 const BaseXLLC = state.dataSurface->Surface(ThisBaseSurface).Vertex(2).x;
13283 6696 : Real64 const BaseYLLC = state.dataSurface->Surface(ThisBaseSurface).Vertex(2).y;
13284 6696 : Real64 const BaseZLLC = state.dataSurface->Surface(ThisBaseSurface).Vertex(2).z;
13285 :
13286 6696 : if (HeatTransSurf) {
13287 :
13288 6696 : if (surf.Sides == 4) {
13289 6694 : ThisShape = SurfaceShape::RectangularDoorWindow;
13290 2 : } else if (surf.Sides == 3 && surf.Class == SurfaceClass::Window) {
13291 2 : ThisShape = SurfaceShape::TriangularWindow;
13292 0 : } else if (surf.Sides == 3 && surf.Class == SurfaceClass::Door) {
13293 0 : ThisShape = SurfaceShape::TriangularDoor;
13294 : } else {
13295 0 : assert(false);
13296 : }
13297 :
13298 : } else { // this is a shadowing subsurface
13299 :
13300 0 : if (std::abs(state.dataSurface->Surface(surf.BaseSurf).Tilt - ThisSurfTilt) <= 0.01) {
13301 : // left or right fin
13302 0 : if (ThisSurfAz < 0.0) ThisSurfAz += 360.0;
13303 0 : if (ThisSurfAz > state.dataSurface->Surface(surf.BaseSurf).Azimuth) {
13304 0 : ThisShape = SurfaceShape::RectangularLeftFin;
13305 : } else {
13306 0 : ThisShape = SurfaceShape::RectangularRightFin;
13307 : }
13308 : } else {
13309 0 : ThisShape = SurfaceShape::RectangularOverhang;
13310 : }
13311 : }
13312 :
13313 : // Setting relative coordinates for shadowing calculations for subsurfaces
13314 6696 : switch (ThisShape) {
13315 6694 : case SurfaceShape::RectangularDoorWindow: { // Rectangular heat transfer subsurface
13316 6694 : PlaneEquation(state.dataSurface->Surface(surf.BaseSurf).Vertex, state.dataSurface->Surface(surf.BaseSurf).Sides, BasePlane, SError);
13317 6694 : if (SError) {
13318 0 : ShowSevereError(state, format("{}Degenerate surface (likely two vertices equal):\"{}\".", RoutineName, surf.Name));
13319 0 : ErrorInSurface = true;
13320 : }
13321 6694 : ThisReveal = -Pt2Plane(surf.Vertex(2), BasePlane);
13322 6694 : if (std::abs(ThisReveal) < 0.0002) ThisReveal = 0.0;
13323 6694 : surf.Reveal = ThisReveal;
13324 6694 : Xp = surf.Vertex(2).x - BaseXLLC;
13325 6694 : Yp = surf.Vertex(2).y - BaseYLLC;
13326 6694 : Zp = surf.Vertex(2).z - BaseZLLC;
13327 6694 : XLLC = -Xp * BaseCosAzimuth + Yp * BaseSinAzimuth;
13328 6694 : YLLC = -Xp * BaseSinAzimuth * BaseCosTilt - Yp * BaseCosAzimuth * BaseCosTilt + Zp * BaseSinTilt;
13329 6694 : ZLLC = Xp * BaseSinAzimuth * BaseSinTilt + Yp * BaseCosAzimuth * BaseSinTilt + Zp * BaseCosTilt;
13330 6694 : TVect = surf.Vertex(3) - surf.Vertex(2);
13331 6694 : ThisWidth = VecLength(TVect);
13332 6694 : TVect = surf.Vertex(2) - surf.Vertex(1);
13333 6694 : ThisHeight = VecLength(TVect);
13334 6694 : surf.Width = ThisWidth;
13335 6694 : surf.Height = ThisHeight;
13336 :
13337 : // Processing of 4-sided but non-rectangular Window, Door or GlassDoor, for use in calc of convective air flow.
13338 6694 : if (!isRectangle(state, ThisSurf)) {
13339 :
13340 : // Transform the surface into an equivalent rectangular surface with the same area and aspect ratio.
13341 1 : MakeEquivalentRectangle(state, ThisSurf, ErrorsFound);
13342 :
13343 1 : if (state.dataGlobal->DisplayExtraWarnings) {
13344 0 : ShowWarningError(state, format("{}Suspected 4-sided but non-rectangular Window, Door or GlassDoor:", RoutineName));
13345 0 : ShowContinueError(
13346 : state,
13347 0 : format("Surface={} is transformed into an equivalent rectangular surface with the same area and aspect ratio. ",
13348 0 : surf.Name));
13349 : }
13350 : }
13351 :
13352 6694 : state.dataSurfaceGeometry->Xpsv(1) = XLLC;
13353 6694 : state.dataSurfaceGeometry->Xpsv(2) = XLLC;
13354 6694 : state.dataSurfaceGeometry->Xpsv(3) = XLLC + surf.Width;
13355 6694 : state.dataSurfaceGeometry->Xpsv(4) = XLLC + surf.Width;
13356 6694 : state.dataSurfaceGeometry->Ypsv(1) = YLLC + surf.Height;
13357 6694 : state.dataSurfaceGeometry->Ypsv(4) = YLLC + surf.Height;
13358 6694 : state.dataSurfaceGeometry->Ypsv(2) = YLLC;
13359 6694 : state.dataSurfaceGeometry->Ypsv(3) = YLLC;
13360 6694 : state.dataSurfaceGeometry->Zpsv(1) = ZLLC;
13361 6694 : state.dataSurfaceGeometry->Zpsv(2) = ZLLC;
13362 6694 : state.dataSurfaceGeometry->Zpsv(3) = ZLLC;
13363 6694 : state.dataSurfaceGeometry->Zpsv(4) = ZLLC;
13364 :
13365 6694 : if (surf.Class == SurfaceClass::Window && surf.ExtBoundCond == ExternalEnvironment && surf.FrameDivider > 0) {
13366 381 : FrDivNum = surf.FrameDivider;
13367 : // Set flag for calculating beam solar reflection from outside and/or inside window reveal
13368 0 : if ((surf.Reveal > 0.0 && state.dataSurface->FrameDivider(FrDivNum).OutsideRevealSolAbs > 0.0) ||
13369 381 : (state.dataSurface->FrameDivider(FrDivNum).InsideSillDepth > 0.0 &&
13370 762 : state.dataSurface->FrameDivider(FrDivNum).InsideSillSolAbs > 0.0) ||
13371 378 : (state.dataSurface->FrameDivider(FrDivNum).InsideReveal > 0.0 &&
13372 0 : state.dataSurface->FrameDivider(FrDivNum).InsideRevealSolAbs > 0.0))
13373 3 : state.dataHeatBal->CalcWindowRevealReflection = true;
13374 :
13375 : // For exterior window with frame, subtract frame area from base surface
13376 : // (only rectangular windows are allowed to have a frame and/or divider;
13377 : // Surface(ThisSurf)%FrameDivider will be 0 for triangular windows)
13378 381 : FrWidth = state.dataSurface->FrameDivider(FrDivNum).FrameWidth;
13379 381 : if (FrWidth > 0.0) {
13380 130 : FrArea = (surf.Height + 2.0 * FrWidth) * (surf.Width + 2.0 * FrWidth) - surf.Area / surf.Multiplier;
13381 130 : state.dataSurface->SurfWinFrameArea(ThisSurf) = FrArea * surf.Multiplier;
13382 130 : if ((state.dataSurface->Surface(surf.BaseSurf).Area - state.dataSurface->SurfWinFrameArea(ThisSurf)) <= 0.0) {
13383 0 : ShowSevereError(state, format("{}Base Surface=\"{}\", ", RoutineName, state.dataSurface->Surface(surf.BaseSurf).Name));
13384 0 : ShowContinueError(state,
13385 0 : format("Window Surface=\"{}\" area (with frame) is too large to fit on the surface.", surf.Name));
13386 0 : ShowContinueError(state,
13387 0 : format("Base surface area (-windows and doors)=[{:.2T}] m2, frame area=[{:.2T}] m2.",
13388 0 : state.dataSurface->Surface(surf.BaseSurf).Area,
13389 0 : state.dataSurface->SurfWinFrameArea(ThisSurf)));
13390 0 : ErrorInSurface = true;
13391 : }
13392 130 : state.dataSurface->Surface(surf.BaseSurf).Area -= state.dataSurface->SurfWinFrameArea(ThisSurf);
13393 : }
13394 : // If exterior window has divider, subtract divider area to get glazed area
13395 381 : DivWidth = state.dataSurface->FrameDivider(surf.FrameDivider).DividerWidth;
13396 381 : if (DivWidth > 0.0 && !ErrorInSurface) {
13397 64 : DivArea = DivWidth * (state.dataSurface->FrameDivider(FrDivNum).HorDividers * surf.Width +
13398 64 : state.dataSurface->FrameDivider(FrDivNum).VertDividers * surf.Height -
13399 64 : state.dataSurface->FrameDivider(FrDivNum).HorDividers *
13400 64 : state.dataSurface->FrameDivider(FrDivNum).VertDividers * DivWidth);
13401 64 : state.dataSurface->SurfWinDividerArea(ThisSurf) = DivArea * surf.Multiplier;
13402 64 : if ((surf.Area - state.dataSurface->SurfWinDividerArea(ThisSurf)) <= 0.0) {
13403 0 : ShowSevereError(state, format("{}Divider area exceeds glazed opening for window {}", RoutineName, surf.Name));
13404 0 : ShowContinueError(state,
13405 0 : format("Window surface area=[{:.2T}] m2, divider area=[{:.2T}] m2.",
13406 0 : surf.Area,
13407 0 : state.dataSurface->SurfWinDividerArea(ThisSurf)));
13408 0 : ErrorInSurface = true;
13409 : }
13410 64 : surf.Area -= state.dataSurface->SurfWinDividerArea(ThisSurf); // Glazed area
13411 64 : if (DivArea <= 0.0) {
13412 0 : ShowWarningError(state, format("{}Calculated Divider Area <= 0.0 for Window={}", RoutineName, surf.Name));
13413 0 : if (state.dataSurface->FrameDivider(FrDivNum).HorDividers == 0) {
13414 0 : ShowContinueError(state, "..Number of Horizontal Dividers = 0.");
13415 : }
13416 0 : if (state.dataSurface->FrameDivider(FrDivNum).VertDividers == 0) {
13417 0 : ShowContinueError(state, "..Number of Vertical Dividers = 0.");
13418 : }
13419 : } else {
13420 64 : auto &surfWin = state.dataSurface->SurfaceWindow(ThisSurf);
13421 64 : surfWin.glazedFrac = surf.Area / (surf.Area + state.dataSurface->SurfWinDividerArea(ThisSurf));
13422 : // Correction factor for portion of divider subject to divider projection correction
13423 64 : DivFrac = (1.0 - state.dataSurface->FrameDivider(FrDivNum).HorDividers *
13424 64 : state.dataSurface->FrameDivider(FrDivNum).VertDividers * pow_2(DivWidth) / DivArea);
13425 64 : state.dataSurface->SurfWinProjCorrDivOut(ThisSurf) =
13426 64 : DivFrac * state.dataSurface->FrameDivider(FrDivNum).DividerProjectionOut / DivWidth;
13427 64 : state.dataSurface->SurfWinProjCorrDivIn(ThisSurf) =
13428 64 : DivFrac * state.dataSurface->FrameDivider(FrDivNum).DividerProjectionIn / DivWidth;
13429 : // Correction factor for portion of frame subject to frame projection correction
13430 64 : if (FrWidth > 0.0) {
13431 64 : state.dataSurface->SurfWinProjCorrFrOut(ThisSurf) =
13432 64 : (state.dataSurface->FrameDivider(FrDivNum).FrameProjectionOut / FrWidth) *
13433 128 : (ThisHeight + ThisWidth -
13434 64 : (state.dataSurface->FrameDivider(FrDivNum).HorDividers +
13435 64 : state.dataSurface->FrameDivider(FrDivNum).VertDividers) *
13436 64 : DivWidth) /
13437 64 : (ThisHeight + ThisWidth + 2 * FrWidth);
13438 64 : state.dataSurface->SurfWinProjCorrFrIn(ThisSurf) =
13439 64 : (state.dataSurface->FrameDivider(FrDivNum).FrameProjectionIn / FrWidth) *
13440 128 : (ThisHeight + ThisWidth -
13441 64 : (state.dataSurface->FrameDivider(FrDivNum).HorDividers +
13442 64 : state.dataSurface->FrameDivider(FrDivNum).VertDividers) *
13443 64 : DivWidth) /
13444 64 : (ThisHeight + ThisWidth + 2 * FrWidth);
13445 : }
13446 : }
13447 : }
13448 : }
13449 6694 : } break;
13450 2 : case SurfaceShape::TriangularWindow:
13451 : case SurfaceShape::TriangularDoor: {
13452 2 : PlaneEquation(state.dataSurface->Surface(surf.BaseSurf).Vertex, state.dataSurface->Surface(surf.BaseSurf).Sides, BasePlane, SError);
13453 2 : if (SError) {
13454 0 : ShowSevereError(state, format("{}Degenerate surface (likely two vertices equal):\"{}\".", RoutineName, surf.Name));
13455 0 : ErrorInSurface = true;
13456 : }
13457 2 : ThisReveal = -Pt2Plane(surf.Vertex(2), BasePlane);
13458 2 : if (std::abs(ThisReveal) < 0.0002) ThisReveal = 0.0;
13459 2 : surf.Reveal = ThisReveal;
13460 2 : Xp = surf.Vertex(2).x - BaseXLLC;
13461 2 : Yp = surf.Vertex(2).y - BaseYLLC;
13462 2 : Zp = surf.Vertex(2).z - BaseZLLC;
13463 2 : state.dataSurfaceGeometry->Xpsv(2) = -Xp * BaseCosAzimuth + Yp * BaseSinAzimuth;
13464 2 : state.dataSurfaceGeometry->Ypsv(2) = -Xp * BaseSinAzimuth * BaseCosTilt - Yp * BaseCosAzimuth * BaseCosTilt + Zp * BaseSinTilt;
13465 2 : state.dataSurfaceGeometry->Zpsv(2) = Xp * BaseSinAzimuth * BaseSinTilt + Yp * BaseCosAzimuth * BaseSinTilt + Zp * BaseCosTilt;
13466 2 : TVect = surf.Vertex(3) - surf.Vertex(2);
13467 2 : ThisWidth = VecLength(TVect);
13468 2 : TVect = surf.Vertex(2) - surf.Vertex(1);
13469 2 : ThisHeight = VecLength(TVect);
13470 2 : surf.Width = ThisWidth;
13471 2 : surf.Height = ThisHeight;
13472 : // Effective height and width of a triangular window for use in calc of convective air flow
13473 : // in gap between glass and shading device when shading device is present
13474 2 : surf.Height = 4.0 * surf.Area / (3.0 * surf.Width);
13475 2 : surf.Width *= 0.75;
13476 :
13477 2 : Xp = surf.Vertex(1).x - BaseXLLC;
13478 2 : Yp = surf.Vertex(1).y - BaseYLLC;
13479 2 : Zp = surf.Vertex(1).z - BaseZLLC;
13480 2 : state.dataSurfaceGeometry->Xpsv(1) = -Xp * BaseCosAzimuth + Yp * BaseSinAzimuth;
13481 2 : state.dataSurfaceGeometry->Ypsv(1) = -Xp * BaseSinAzimuth * BaseCosTilt - Yp * BaseCosAzimuth * BaseCosTilt + Zp * BaseSinTilt;
13482 2 : state.dataSurfaceGeometry->Zpsv(1) = Xp * BaseSinAzimuth * BaseSinTilt + Yp * BaseCosAzimuth * BaseSinTilt + Zp * BaseCosTilt;
13483 :
13484 2 : Xp = surf.Vertex(3).x - BaseXLLC;
13485 2 : Yp = surf.Vertex(3).y - BaseYLLC;
13486 2 : Zp = surf.Vertex(3).z - BaseZLLC;
13487 2 : state.dataSurfaceGeometry->Xpsv(3) = -Xp * BaseCosAzimuth + Yp * BaseSinAzimuth;
13488 2 : state.dataSurfaceGeometry->Ypsv(3) = -Xp * BaseSinAzimuth * BaseCosTilt - Yp * BaseCosAzimuth * BaseCosTilt + Zp * BaseSinTilt;
13489 2 : state.dataSurfaceGeometry->Zpsv(3) = Xp * BaseSinAzimuth * BaseSinTilt + Yp * BaseCosAzimuth * BaseSinTilt + Zp * BaseCosTilt;
13490 2 : } break;
13491 0 : case SurfaceShape::RectangularOverhang: {
13492 0 : Xp = surf.Vertex(2).x - BaseXLLC;
13493 0 : Yp = surf.Vertex(2).y - BaseYLLC;
13494 0 : Zp = surf.Vertex(2).z - BaseZLLC;
13495 0 : XLLC = -Xp * BaseCosAzimuth + Yp * BaseSinAzimuth;
13496 0 : YLLC = -Xp * BaseSinAzimuth * BaseCosTilt - Yp * BaseCosAzimuth * BaseCosTilt + Zp * BaseSinTilt;
13497 0 : ZLLC = Xp * BaseSinAzimuth * BaseSinTilt + Yp * BaseCosAzimuth * BaseSinTilt + Zp * BaseCosTilt;
13498 0 : TVect = surf.Vertex(3) - surf.Vertex(2);
13499 0 : ThisWidth = VecLength(TVect);
13500 0 : TVect = surf.Vertex(2) - surf.Vertex(1);
13501 0 : ThisHeight = VecLength(TVect);
13502 0 : surf.Width = ThisWidth;
13503 0 : surf.Height = ThisHeight;
13504 0 : state.dataSurfaceGeometry->Xpsv(1) = XLLC;
13505 0 : state.dataSurfaceGeometry->Xpsv(2) = XLLC;
13506 0 : state.dataSurfaceGeometry->Xpsv(3) = XLLC + surf.Width;
13507 0 : state.dataSurfaceGeometry->Xpsv(4) = XLLC + surf.Width;
13508 0 : state.dataSurfaceGeometry->Ypsv(1) = YLLC;
13509 0 : state.dataSurfaceGeometry->Ypsv(2) = YLLC;
13510 0 : state.dataSurfaceGeometry->Ypsv(3) = YLLC;
13511 0 : state.dataSurfaceGeometry->Ypsv(4) = YLLC;
13512 0 : state.dataSurfaceGeometry->Zpsv(1) = surf.Height;
13513 0 : state.dataSurfaceGeometry->Zpsv(4) = surf.Height;
13514 0 : state.dataSurfaceGeometry->Zpsv(2) = 0.0;
13515 0 : state.dataSurfaceGeometry->Zpsv(3) = 0.0;
13516 0 : } break;
13517 0 : case SurfaceShape::RectangularLeftFin: {
13518 0 : Xp = surf.Vertex(2).x - BaseXLLC;
13519 0 : Yp = surf.Vertex(2).y - BaseYLLC;
13520 0 : Zp = surf.Vertex(2).z - BaseZLLC;
13521 0 : XLLC = -Xp * BaseCosAzimuth + Yp * BaseSinAzimuth;
13522 0 : YLLC = -Xp * BaseSinAzimuth * BaseCosTilt - Yp * BaseCosAzimuth * BaseCosTilt + Zp * BaseSinTilt;
13523 0 : ZLLC = Xp * BaseSinAzimuth * BaseSinTilt + Yp * BaseCosAzimuth * BaseSinTilt + Zp * BaseCosTilt;
13524 0 : TVect = surf.Vertex(3) - surf.Vertex(2);
13525 0 : ThisWidth = VecLength(TVect);
13526 0 : TVect = surf.Vertex(2) - surf.Vertex(1);
13527 0 : ThisHeight = VecLength(TVect);
13528 0 : surf.Width = ThisWidth;
13529 0 : surf.Height = ThisHeight;
13530 0 : state.dataSurfaceGeometry->Xpsv(1) = XLLC;
13531 0 : state.dataSurfaceGeometry->Xpsv(2) = XLLC;
13532 0 : state.dataSurfaceGeometry->Xpsv(3) = XLLC;
13533 0 : state.dataSurfaceGeometry->Xpsv(4) = XLLC;
13534 0 : state.dataSurfaceGeometry->Ypsv(1) = YLLC;
13535 0 : state.dataSurfaceGeometry->Ypsv(2) = YLLC;
13536 0 : state.dataSurfaceGeometry->Ypsv(3) = YLLC + surf.Width;
13537 0 : state.dataSurfaceGeometry->Ypsv(4) = YLLC + surf.Width;
13538 0 : state.dataSurfaceGeometry->Zpsv(1) = surf.Height;
13539 0 : state.dataSurfaceGeometry->Zpsv(4) = surf.Height;
13540 0 : state.dataSurfaceGeometry->Zpsv(2) = 0.0;
13541 0 : state.dataSurfaceGeometry->Zpsv(3) = 0.0;
13542 0 : } break;
13543 0 : case SurfaceShape::RectangularRightFin: {
13544 0 : Xp = surf.Vertex(2).x - BaseXLLC;
13545 0 : Yp = surf.Vertex(2).y - BaseYLLC;
13546 0 : Zp = surf.Vertex(2).z - BaseZLLC;
13547 0 : XLLC = -Xp * BaseCosAzimuth + Yp * BaseSinAzimuth;
13548 0 : YLLC = -Xp * BaseSinAzimuth * BaseCosTilt - Yp * BaseCosAzimuth * BaseCosTilt + Zp * BaseSinTilt;
13549 0 : ZLLC = Xp * BaseSinAzimuth * BaseSinTilt + Yp * BaseCosAzimuth * BaseSinTilt + Zp * BaseCosTilt;
13550 0 : TVect = surf.Vertex(3) - surf.Vertex(2);
13551 0 : ThisWidth = VecLength(TVect);
13552 0 : TVect = surf.Vertex(2) - surf.Vertex(1);
13553 0 : ThisHeight = VecLength(TVect);
13554 0 : surf.Width = ThisWidth;
13555 0 : surf.Height = ThisHeight;
13556 0 : state.dataSurfaceGeometry->Xpsv(1) = XLLC;
13557 0 : state.dataSurfaceGeometry->Xpsv(2) = XLLC;
13558 0 : state.dataSurfaceGeometry->Xpsv(3) = XLLC;
13559 0 : state.dataSurfaceGeometry->Xpsv(4) = XLLC;
13560 0 : state.dataSurfaceGeometry->Ypsv(1) = YLLC + surf.Width;
13561 0 : state.dataSurfaceGeometry->Ypsv(2) = YLLC + surf.Width;
13562 0 : state.dataSurfaceGeometry->Ypsv(3) = YLLC;
13563 0 : state.dataSurfaceGeometry->Ypsv(4) = YLLC;
13564 0 : state.dataSurfaceGeometry->Zpsv(1) = surf.Height;
13565 0 : state.dataSurfaceGeometry->Zpsv(4) = surf.Height;
13566 0 : state.dataSurfaceGeometry->Zpsv(2) = 0.0;
13567 0 : state.dataSurfaceGeometry->Zpsv(3) = 0.0;
13568 0 : } break;
13569 0 : default: {
13570 : // Error Condition
13571 0 : ShowSevereError(state, format("{}Incorrect surface shape number.", RoutineName), OptionalOutputFileRef{state.files.eso});
13572 0 : ShowContinueError(state, "Please notify EnergyPlus support of this error and send input file.");
13573 0 : ErrorInSurface = true;
13574 0 : } break;
13575 : }
13576 :
13577 33478 : for (n = 1; n <= surf.Sides; ++n) {
13578 : // if less than 1/10 inch
13579 26782 : state.dataSurfaceGeometry->Xpsv(n) = nint64(10000.0 * state.dataSurfaceGeometry->Xpsv(n)) / 10000.0;
13580 26782 : if (std::abs(state.dataSurfaceGeometry->Xpsv(n)) < 0.0025) state.dataSurfaceGeometry->Xpsv(n) = 0.0;
13581 26782 : state.dataSurfaceGeometry->Ypsv(n) = nint64(10000.0 * state.dataSurfaceGeometry->Ypsv(n)) / 10000.0;
13582 26782 : if (std::abs(state.dataSurfaceGeometry->Ypsv(n)) < 0.0025) state.dataSurfaceGeometry->Ypsv(n) = 0.0;
13583 26782 : state.dataSurfaceGeometry->Zpsv(n) = nint64(10000.0 * state.dataSurfaceGeometry->Zpsv(n)) / 10000.0;
13584 26782 : if (std::abs(state.dataSurfaceGeometry->Zpsv(n)) < 0.0025) state.dataSurfaceGeometry->Zpsv(n) = 0.0;
13585 : }
13586 :
13587 6696 : surf.Shape = ThisShape;
13588 :
13589 : } // End of check if ThisSurf is a base surface
13590 :
13591 43646 : if (ErrorInSurface) {
13592 0 : ErrorsFound = true;
13593 0 : return;
13594 : }
13595 :
13596 : // Transfer to XV,YV,ZV arrays
13597 :
13598 43646 : state.dataSurface->ShadeV(ThisSurf).NVert = surf.Sides;
13599 43646 : state.dataSurface->ShadeV(ThisSurf).XV.allocate(surf.Sides);
13600 43646 : state.dataSurface->ShadeV(ThisSurf).YV.allocate(surf.Sides);
13601 43646 : state.dataSurface->ShadeV(ThisSurf).ZV.allocate(surf.Sides);
13602 :
13603 219071 : for (n = 1; n <= surf.Sides; ++n) {
13604 : // if less than 1/10 inch
13605 175425 : state.dataSurface->ShadeV(ThisSurf).XV(n) = state.dataSurfaceGeometry->Xpsv(n);
13606 175425 : state.dataSurface->ShadeV(ThisSurf).YV(n) = state.dataSurfaceGeometry->Ypsv(n);
13607 175425 : state.dataSurface->ShadeV(ThisSurf).ZV(n) = state.dataSurfaceGeometry->Zpsv(n);
13608 : }
13609 :
13610 : // Process Surfaces According to Type of Coordinate Origin.
13611 43646 : if (BaseSurface) {
13612 :
13613 : // General Surfaces:
13614 36950 : CalcCoordinateTransformation(state, ThisSurf, CoordinateTransVector); // X00,Y00,Z00,X,Y,Z,A) ! Compute Coordinate Transformation
13615 :
13616 : // RECORD DIRECTION COSINES.
13617 36950 : if (HeatTransSurf) { // This is a general surface but not detached shading surface
13618 :
13619 : // RECORD COORDINATE TRANSFORMATION FOR BASE SURFACES.
13620 36932 : state.dataSurface->X0(ThisBaseSurface) = CoordinateTransVector.x;
13621 36932 : state.dataSurface->Y0(ThisBaseSurface) = CoordinateTransVector.y;
13622 36932 : state.dataSurface->Z0(ThisBaseSurface) = CoordinateTransVector.z;
13623 :
13624 : // COMPUTE INVERSE TRANSFORMATION.
13625 36932 : X1 = state.dataSurfaceGeometry->Xpsv(2) - CoordinateTransVector.x;
13626 36932 : Y1 = state.dataSurfaceGeometry->Ypsv(2) - CoordinateTransVector.y;
13627 36932 : Z1 = state.dataSurfaceGeometry->Zpsv(2) - CoordinateTransVector.z;
13628 : // Store the relative coordinate shift values for later use by any subsurfaces
13629 73864 : state.dataSurface->Surface(ThisBaseSurface).XShift = state.dataSurface->Surface(ThisBaseSurface).lcsx.x * X1 +
13630 36932 : state.dataSurface->Surface(ThisBaseSurface).lcsx.y * Y1 +
13631 36932 : state.dataSurface->Surface(ThisBaseSurface).lcsx.z * Z1;
13632 73864 : state.dataSurface->Surface(ThisBaseSurface).YShift = state.dataSurface->Surface(ThisBaseSurface).lcsy.x * X1 +
13633 36932 : state.dataSurface->Surface(ThisBaseSurface).lcsy.y * Y1 +
13634 36932 : state.dataSurface->Surface(ThisBaseSurface).lcsy.z * Z1;
13635 36932 : state.dataSurface->Surface(ThisBaseSurface).VerticesProcessed = true;
13636 : }
13637 :
13638 : // SUBSURFACES: (Surface(ThisSurf)%BaseSurf /= ThisSurf)
13639 : } else {
13640 : // WINDOWS OR DOORS:
13641 :
13642 : // SHIFT RELATIVE COORDINATES FROM LOWER LEFT CORNER TO ORIGIN DEFINED
13643 : // BY CTRAN AND SET DIRECTION COSINES SAME AS BASE SURFACE.
13644 6696 : if (!state.dataSurface->Surface(ThisBaseSurface).VerticesProcessed) {
13645 :
13646 0 : if (surf.IsAirBoundarySurf) {
13647 0 : ProcessSurfaceVertices(state, ThisBaseSurface, ErrorsFound);
13648 : } else {
13649 :
13650 0 : ShowSevereError(state, format("{}Developer error for Subsurface={}", RoutineName, surf.Name));
13651 0 : ShowContinueError(state,
13652 0 : format("Base surface={} vertices must be processed before any subsurfaces.",
13653 0 : state.dataSurface->Surface(ThisBaseSurface).Name));
13654 0 : ShowFatalError(state, std::string{RoutineName});
13655 : }
13656 : }
13657 :
13658 33478 : for (n = 1; n <= surf.Sides; ++n) {
13659 26782 : state.dataSurface->ShadeV(ThisSurf).XV(n) += state.dataSurface->Surface(ThisBaseSurface).XShift;
13660 26782 : state.dataSurface->ShadeV(ThisSurf).YV(n) += state.dataSurface->Surface(ThisBaseSurface).YShift;
13661 : }
13662 : }
13663 :
13664 43646 : if (ErrorInSurface) {
13665 0 : ErrorsFound = true;
13666 : }
13667 43646 : }
13668 :
13669 36950 : void CalcCoordinateTransformation(EnergyPlusData &state,
13670 : int const SurfNum, // Surface Number
13671 : Vector &CompCoordTranslVector // Coordinate Translation Vector
13672 : )
13673 : {
13674 : // SUBROUTINE INFORMATION:
13675 : // AUTHOR George Walton, BLAST
13676 : // DATE WRITTEN August 1976
13677 : // MODIFIED LKL, May 2004 -- >4 sided polygons
13678 : // RE-ENGINEERED Yes
13679 :
13680 : // PURPOSE OF THIS SUBROUTINE:
13681 : // This subroutine develops a coordinate transformation such that the X-axis goes
13682 : // through points 2 and 3 and the Y-axis goes through point 1
13683 : // of a plane figure in 3-d space.
13684 :
13685 : // METHODOLOGY EMPLOYED:
13686 : // na
13687 :
13688 : // REFERENCES:
13689 : // 'NECAP' - NASA'S Energy-Cost Analysis Program
13690 :
13691 : // Using/Aliasing
13692 : using namespace Vectors;
13693 :
13694 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
13695 : int I; // Loop Control
13696 : Real64 Gamma; // Intermediate Result
13697 : Real64 DotSelfX23;
13698 :
13699 : // Object Data
13700 36950 : Vector x21;
13701 36950 : Vector x23;
13702 :
13703 : // Determine Components of the Coordinate Translation Vector.
13704 36950 : auto const &surf = state.dataSurface->Surface(SurfNum);
13705 :
13706 36950 : x21 = surf.Vertex(2) - surf.Vertex(1);
13707 36950 : x23 = surf.Vertex(2) - surf.Vertex(3);
13708 :
13709 36950 : DotSelfX23 = magnitude_squared(x23);
13710 :
13711 36950 : if (DotSelfX23 <= Constant::OneMillionth) {
13712 0 : ShowSevereError(state, format("CalcCoordinateTransformation: Invalid dot product, surface=\"{}\":", surf.Name));
13713 0 : for (I = 1; I <= surf.Sides; ++I) {
13714 0 : auto const &point = surf.Vertex(I);
13715 0 : ShowContinueError(state, format(" ({:8.3F},{:8.3F},{:8.3F})", point.x, point.y, point.z));
13716 : }
13717 0 : ShowFatalError(
13718 0 : state, "CalcCoordinateTransformation: Program terminates due to preceding condition.", OptionalOutputFileRef{state.files.eso});
13719 0 : return;
13720 : }
13721 :
13722 36950 : Gamma = dot(x21, x23) / magnitude_squared(x23);
13723 :
13724 36950 : CompCoordTranslVector = surf.Vertex(2) + Gamma * (surf.Vertex(3) - surf.Vertex(2));
13725 36950 : }
13726 :
13727 18 : void CreateShadedWindowConstruction(EnergyPlusData &state,
13728 : int const SurfNum, // Surface number
13729 : int const WSCPtr, // Pointer to WindowShadingControl for SurfNum
13730 : int const ShDevNum, // Shading device material number for WSCptr
13731 : int const shadeControlIndex // index to the Surface().windowShadingControlList,
13732 : // Surface().shadedConstructionList, and Surface().shadedStormWinConstructionList
13733 : )
13734 : {
13735 : // SUBROUTINE INFORMATION:
13736 : // AUTHOR Fred Winkelmann
13737 : // DATE WRITTEN Nov 2001
13738 : // MODIFIED na
13739 : // RE-ENGINEERED na
13740 :
13741 : // PURPOSE OF THIS SUBROUTINE:
13742 : // Creates a shaded window construction for windows whose WindowShadingControl
13743 : // has a shading device specified instead of a shaded construction
13744 :
13745 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
13746 : int ConstrNum; // Number of unshaded construction
13747 : int ConstrNewSh; // Number of shaded construction that is created
13748 18 : std::string ShDevName; // Shading device material name
13749 18 : std::string ConstrName; // Unshaded construction name
13750 18 : std::string ConstrNameSh; // Shaded construction name
13751 : int TotLayersOld; // Total layers in old (unshaded) construction
13752 : int TotLayersNew; // Total layers in new (shaded) construction
13753 : // INTEGER :: loop ! DO loop index
13754 :
13755 18 : ShDevName = state.dataMaterial->Material(ShDevNum)->Name;
13756 18 : ConstrNum = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction;
13757 18 : ConstrName = state.dataConstruction->Construct(ConstrNum).Name;
13758 18 : if (ANY_INTERIOR_SHADE_BLIND(state.dataSurface->WindowShadingControl(WSCPtr).ShadingType)) {
13759 18 : ConstrNameSh = ConstrName + ':' + ShDevName + ":INT";
13760 : } else {
13761 0 : ConstrNameSh = ConstrName + ':' + ShDevName + ":EXT";
13762 : }
13763 :
13764 : // If this construction name already exists, set the surface's shaded construction number to it
13765 :
13766 18 : ConstrNewSh = Util::FindItemInList(ConstrNameSh, state.dataConstruction->Construct);
13767 :
13768 18 : if (ConstrNewSh > 0) {
13769 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).shadedConstructionList[shadeControlIndex] = ConstrNewSh;
13770 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).activeShadedConstruction = ConstrNewSh; // set the active to the current for now
13771 : } else {
13772 :
13773 : // Create new construction
13774 :
13775 18 : ConstrNewSh = state.dataHeatBal->TotConstructs + 1;
13776 18 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).shadedConstructionList[shadeControlIndex] = ConstrNewSh;
13777 18 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).activeShadedConstruction = ConstrNewSh; // set the active to the current for now
13778 18 : state.dataHeatBal->TotConstructs = ConstrNewSh;
13779 18 : state.dataConstruction->Construct.redimension(state.dataHeatBal->TotConstructs);
13780 18 : state.dataHeatBal->NominalRforNominalUCalculation.redimension(state.dataHeatBal->TotConstructs);
13781 18 : state.dataHeatBal->NominalRforNominalUCalculation(state.dataHeatBal->TotConstructs) = 0.0;
13782 18 : state.dataHeatBal->NominalU.redimension(state.dataHeatBal->TotConstructs);
13783 18 : state.dataHeatBal->NominalU(state.dataHeatBal->TotConstructs) = 0.0;
13784 18 : state.dataHeatBal->NominalUBeforeAdjusted.redimension(state.dataHeatBal->TotConstructs);
13785 18 : state.dataHeatBal->CoeffAdjRatio.redimension(state.dataHeatBal->TotConstructs) = 1.0;
13786 :
13787 18 : state.dataConstruction->Construct(state.dataHeatBal->TotConstructs).setArraysBasedOnMaxSolidWinLayers(state);
13788 :
13789 18 : TotLayersOld = state.dataConstruction->Construct(ConstrNum).TotLayers;
13790 18 : TotLayersNew = TotLayersOld + 1;
13791 :
13792 18 : state.dataConstruction->Construct(ConstrNewSh).LayerPoint = 0;
13793 :
13794 18 : auto const *thisMaterialSh = dynamic_cast<const Material::MaterialChild *>(state.dataMaterial->Material(ShDevNum));
13795 18 : auto &thisConstructNewSh = state.dataConstruction->Construct(ConstrNewSh);
13796 18 : if (state.dataSurface->WindowShadingControl(WSCPtr).ShadingType == WinShadingType::IntShade ||
13797 0 : state.dataSurface->WindowShadingControl(WSCPtr).ShadingType == WinShadingType::IntBlind) {
13798 : // Interior shading device
13799 18 : thisConstructNewSh.LayerPoint({1, TotLayersOld}) = state.dataConstruction->Construct(ConstrNum).LayerPoint({1, TotLayersOld});
13800 18 : thisConstructNewSh.LayerPoint(TotLayersNew) = ShDevNum;
13801 18 : thisConstructNewSh.InsideAbsorpSolar = thisMaterialSh->AbsorpSolar;
13802 18 : auto const *thisMaterialShLayer1 = dynamic_cast<const Material::MaterialChild *>(
13803 18 : state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNewSh).LayerPoint(1)));
13804 18 : thisConstructNewSh.OutsideAbsorpSolar = thisMaterialShLayer1->AbsorpSolar;
13805 18 : thisConstructNewSh.OutsideAbsorpThermal = thisMaterialShLayer1->AbsorpThermalFront;
13806 : } else {
13807 : // Exterior shading device
13808 0 : thisConstructNewSh.LayerPoint(1) = ShDevNum;
13809 0 : thisConstructNewSh.LayerPoint({2, TotLayersNew}) = state.dataConstruction->Construct(ConstrNum).LayerPoint({1, TotLayersOld});
13810 0 : auto const *thisMaterialShInside = dynamic_cast<const Material::MaterialChild *>(
13811 0 : state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNewSh).LayerPoint(TotLayersNew)));
13812 0 : thisConstructNewSh.InsideAbsorpSolar = thisMaterialShInside->AbsorpSolar;
13813 0 : thisConstructNewSh.OutsideAbsorpSolar = thisMaterialSh->AbsorpSolar;
13814 0 : thisConstructNewSh.OutsideAbsorpThermal = thisMaterialSh->AbsorpThermalFront;
13815 : }
13816 : // The following InsideAbsorpThermal applies only to inside glass; it is corrected
13817 : // later in InitGlassOpticalCalculations if construction has inside shade or blind.
13818 18 : thisConstructNewSh.InsideAbsorpThermal =
13819 18 : dynamic_cast<Material::MaterialChild *>(
13820 18 : state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(TotLayersOld)))
13821 18 : ->AbsorpThermalBack;
13822 18 : thisConstructNewSh.OutsideRoughness = Material::SurfaceRoughness::VerySmooth;
13823 18 : thisConstructNewSh.DayltPropPtr = 0;
13824 18 : thisConstructNewSh.CTFCross.fill(0.0);
13825 18 : thisConstructNewSh.CTFFlux.fill(0.0);
13826 18 : thisConstructNewSh.CTFInside.fill(0.0);
13827 18 : thisConstructNewSh.CTFOutside.fill(0.0);
13828 18 : thisConstructNewSh.CTFSourceIn.fill(0.0);
13829 18 : thisConstructNewSh.CTFSourceOut.fill(0.0);
13830 18 : thisConstructNewSh.CTFTimeStep = 0.0;
13831 18 : thisConstructNewSh.CTFTSourceOut.fill(0.0);
13832 18 : thisConstructNewSh.CTFTSourceIn.fill(0.0);
13833 18 : thisConstructNewSh.CTFTSourceQ.fill(0.0);
13834 18 : thisConstructNewSh.CTFTUserOut.fill(0.0);
13835 18 : thisConstructNewSh.CTFTUserIn.fill(0.0);
13836 18 : thisConstructNewSh.CTFTUserSource.fill(0.0);
13837 18 : thisConstructNewSh.NumHistories = 0;
13838 18 : thisConstructNewSh.NumCTFTerms = 0;
13839 18 : thisConstructNewSh.UValue = 0.0;
13840 18 : thisConstructNewSh.SourceSinkPresent = false;
13841 18 : thisConstructNewSh.SolutionDimensions = 0;
13842 18 : thisConstructNewSh.SourceAfterLayer = 0;
13843 18 : thisConstructNewSh.TempAfterLayer = 0;
13844 18 : thisConstructNewSh.ThicknessPerpend = 0.0;
13845 18 : thisConstructNewSh.AbsDiff = 0.0;
13846 18 : thisConstructNewSh.AbsDiffBack = 0.0;
13847 18 : thisConstructNewSh.AbsDiffShade = 0.0;
13848 18 : thisConstructNewSh.AbsDiffBackShade = 0.0;
13849 18 : thisConstructNewSh.ShadeAbsorpThermal = 0.0;
13850 18 : thisConstructNewSh.AbsBeamShadeCoef = 0.0;
13851 18 : thisConstructNewSh.TransDiff = 0.0;
13852 18 : thisConstructNewSh.TransDiffVis = 0.0;
13853 18 : thisConstructNewSh.ReflectSolDiffBack = 0.0;
13854 18 : thisConstructNewSh.ReflectSolDiffFront = 0.0;
13855 18 : thisConstructNewSh.ReflectVisDiffBack = 0.0;
13856 18 : thisConstructNewSh.ReflectVisDiffFront = 0.0;
13857 18 : thisConstructNewSh.TransSolBeamCoef = 0.0;
13858 18 : thisConstructNewSh.TransVisBeamCoef = 0.0;
13859 18 : thisConstructNewSh.ReflSolBeamFrontCoef = 0.0;
13860 18 : thisConstructNewSh.ReflSolBeamBackCoef = 0.0;
13861 18 : thisConstructNewSh.W5FrameDivider = 0;
13862 18 : thisConstructNewSh.FromWindow5DataFile = false;
13863 :
13864 18 : thisConstructNewSh.Name = ConstrNameSh;
13865 18 : thisConstructNewSh.TotLayers = TotLayersNew;
13866 18 : thisConstructNewSh.TotSolidLayers = state.dataConstruction->Construct(ConstrNum).TotSolidLayers + 1;
13867 18 : thisConstructNewSh.TotGlassLayers = state.dataConstruction->Construct(ConstrNum).TotGlassLayers;
13868 18 : thisConstructNewSh.TypeIsWindow = true;
13869 18 : thisConstructNewSh.IsUsed = true;
13870 :
13871 144 : for (int Layer = 1; Layer <= state.dataHeatBal->MaxSolidWinLayers; ++Layer) {
13872 882 : for (int index = 1; index <= DataSurfaces::MaxPolyCoeff; ++index) {
13873 756 : thisConstructNewSh.AbsBeamCoef(Layer)(index) = 0.0;
13874 756 : thisConstructNewSh.AbsBeamBackCoef(Layer)(index) = 0.0;
13875 : }
13876 : }
13877 : }
13878 18 : }
13879 :
13880 1 : void CreateStormWindowConstructions(EnergyPlusData &state)
13881 : {
13882 : // For windows with an associated StormWindow object, creates a construction
13883 : // consisting of the base construction plus a storm window and air gap on the outside.
13884 : // If the window has an interior or between-glass shade/blind, also creates a
13885 : // construction consisting of the storm window added to the shaded construction.
13886 1 : DisplayString(state, "Creating Storm Window Constructions");
13887 :
13888 2 : for (int StormWinNum = 1; StormWinNum <= state.dataSurface->TotStormWin; ++StormWinNum) {
13889 1 : int SurfNum = state.dataSurface->StormWindow(StormWinNum).BaseWindowNum; // Surface number
13890 1 : auto &surf = state.dataSurface->Surface(SurfNum);
13891 1 : int ConstrNum = surf.Construction; // Number of unshaded construction
13892 : // Fatal error if base construction has more than three glass layers
13893 1 : if (state.dataConstruction->Construct(ConstrNum).TotGlassLayers > 3) {
13894 0 : ShowFatalError(state, format("Window={} has more than 3 glass layers; a storm window cannot be applied.", surf.Name));
13895 : }
13896 :
13897 : // create unshaded construction with storm window
13898 1 : const std::string ChrNum = fmt::to_string(StormWinNum);
13899 1 : std::string ConstrNameSt = "BARECONSTRUCTIONWITHSTORMWIN:" + ChrNum; // Name of unshaded construction with storm window
13900 : // If this construction name already exists, set the surface's storm window construction number to it
13901 1 : int ConstrNewSt = Util::FindItemInList(ConstrNameSt,
13902 1 : state.dataConstruction->Construct,
13903 1 : state.dataHeatBal->TotConstructs); // Number of unshaded storm window construction that is created
13904 : // If necessary, create new material corresponding to the air layer between the storm winddow and the rest of the window
13905 1 : int MatNewStAir = createAirMaterialFromDistance(state, state.dataSurface->StormWindow(StormWinNum).StormWinDistance, "AIR:STORMWIN:");
13906 1 : if (ConstrNewSt == 0) {
13907 1 : ConstrNewSt = createConstructionWithStorm(
13908 1 : state, ConstrNum, ConstrNameSt, state.dataSurface->StormWindow(StormWinNum).StormWinMaterialNum, MatNewStAir);
13909 : }
13910 1 : state.dataSurface->SurfWinStormWinConstr(SurfNum) = ConstrNewSt;
13911 :
13912 : // create shaded constructions with storm window
13913 1 : surf.shadedStormWinConstructionList.resize(surf.shadedConstructionList.size(),
13914 1 : 0); // make the shaded storm window size the same size as the number of shaded constructions
13915 1 : for (std::size_t iConstruction = 0; iConstruction < surf.shadedConstructionList.size(); ++iConstruction) {
13916 0 : int curConstruction = surf.shadedConstructionList[iConstruction];
13917 : // Set ShAndSt, which is true if the window has a shaded construction to which a storm window
13918 : // can be added. (A storm window can be added if there is an interior shade or blind and up to three
13919 : // glass layers, or there is a between-glass shade or blind and two glass layers.)
13920 0 : bool ShAndSt = false; // True if unshaded and shaded window can have a storm window
13921 0 : std::string ConstrNameSh = state.dataConstruction->Construct(curConstruction).Name; // Name of original shaded window construction
13922 0 : int TotLayers = state.dataConstruction->Construct(curConstruction).TotLayers; // Total layers in a construction
13923 0 : int MatIntSh = state.dataConstruction->Construct(curConstruction).LayerPoint(TotLayers); // Material number of interior shade or blind
13924 0 : int MatBetweenGlassSh = 0; // Material number of between-glass shade or blind
13925 0 : if (TotLayers == 5) MatBetweenGlassSh = state.dataConstruction->Construct(curConstruction).LayerPoint(3);
13926 0 : if (state.dataConstruction->Construct(curConstruction).TotGlassLayers <= 3 &&
13927 0 : (state.dataMaterial->Material(MatIntSh)->group == Material::Group::Shade ||
13928 0 : state.dataMaterial->Material(MatIntSh)->group == Material::Group::WindowBlind))
13929 0 : ShAndSt = true;
13930 0 : if (MatBetweenGlassSh > 0) {
13931 0 : if (state.dataMaterial->Material(MatBetweenGlassSh)->group == Material::Group::Shade ||
13932 0 : state.dataMaterial->Material(MatBetweenGlassSh)->group == Material::Group::WindowBlind) {
13933 0 : ShAndSt = true;
13934 : } else {
13935 0 : ShowContinueError(state, format("Window={} has a shaded construction to which a storm window cannot be applied.", surf.Name));
13936 0 : ShowContinueError(state, "Storm windows can only be applied to shaded constructions that:");
13937 0 : ShowContinueError(state, "have an interior shade or blind and up to three glass layers, or");
13938 0 : ShowContinueError(state, "have a between-glass shade or blind and two glass layers.");
13939 0 : ShowFatalError(state, "EnergyPlus is exiting due to reason stated above.");
13940 : }
13941 : }
13942 0 : if (ShAndSt) {
13943 0 : auto &surf = state.dataSurface->Surface(SurfNum);
13944 0 : std::string ConstrNameStSh = "SHADEDCONSTRUCTIONWITHSTORMWIN:" + state.dataConstruction->Construct(iConstruction).Name + ":" +
13945 0 : ChrNum; // Name of shaded construction with storm window
13946 0 : int ConstrNewStSh = createConstructionWithStorm(
13947 0 : state, ConstrNum, ConstrNameStSh, state.dataSurface->StormWindow(StormWinNum).StormWinMaterialNum, MatNewStAir);
13948 0 : surf.shadedStormWinConstructionList[iConstruction] = ConstrNewStSh; // put in same index as the shaded constuction
13949 0 : }
13950 0 : } // end of loop for shaded constructions
13951 1 : } // end of loop over storm window objects
13952 1 : }
13953 :
13954 1 : int createAirMaterialFromDistance(EnergyPlusData &state, Real64 distance, std::string_view namePrefix)
13955 : {
13956 1 : int mmDistance = int(1000 * distance); // Thickness of air gap in mm (usually between storm window and rest of window)
13957 1 : std::string MatNameStAir = format("{}{}MM", namePrefix, mmDistance); // Name of created air layer material
13958 1 : int newAirMaterial = Util::FindItemInPtrList(MatNameStAir, state.dataMaterial->Material, state.dataMaterial->TotMaterials);
13959 1 : if (newAirMaterial == 0) {
13960 : // Create new material
13961 1 : state.dataMaterial->TotMaterials = state.dataMaterial->TotMaterials + 1;
13962 1 : newAirMaterial = state.dataMaterial->TotMaterials;
13963 1 : auto *thisMaterial = new Material::MaterialGasMix;
13964 1 : state.dataMaterial->Material.push_back(thisMaterial);
13965 1 : state.dataHeatBal->NominalR.redimension(state.dataMaterial->TotMaterials);
13966 1 : thisMaterial->Name = MatNameStAir;
13967 1 : thisMaterial->group = Material::Group::WindowGas;
13968 1 : thisMaterial->Roughness = Material::SurfaceRoughness::MediumRough;
13969 1 : thisMaterial->Conductivity = 0.0;
13970 1 : thisMaterial->Density = 0.0;
13971 : // thisMaterial->IsoMoistCap = 0.0;
13972 : // thisMaterial->Porosity = 0.0;
13973 1 : thisMaterial->Resistance = 0.0;
13974 1 : thisMaterial->SpecHeat = 0.0;
13975 : // thisMaterial->ThermGradCoef = 0.0;
13976 1 : thisMaterial->Thickness = distance;
13977 : // thisMaterial->VaporDiffus = 0.0;
13978 : // thisMaterial->GlassSpectralDataPtr = 0;
13979 1 : thisMaterial->numGases = 1;
13980 1 : thisMaterial->gases[0] = Material::gases[(int)Material::GasType::Air];
13981 1 : thisMaterial->gasFracts[0] = 1.0;
13982 1 : thisMaterial->AbsorpSolar = 0.0;
13983 1 : thisMaterial->AbsorpThermal = 0.0;
13984 1 : thisMaterial->AbsorpVisible = 0.0;
13985 1 : thisMaterial->Trans = 0.0;
13986 1 : thisMaterial->TransVis = 0.0;
13987 : // thisMaterial->GlassTransDirtFactor = 0.0;
13988 : // thisMaterial->ReflectShade = 0.0;
13989 : // thisMaterial->ReflectShadeVis = 0.0;
13990 : // thisMaterial->AbsorpThermalBack = 0.0;
13991 : // thisMaterial->AbsorpThermalFront = 0.0;
13992 : // thisMaterial->ReflectSolBeamBack = 0.0;
13993 : // thisMaterial->ReflectSolBeamFront = 0.0;
13994 : // thisMaterial->ReflectSolDiffBack = 0.0;
13995 : // thisMaterial->ReflectSolDiffFront = 0.0;
13996 : // thisMaterial->ReflectVisBeamBack = 0.0;
13997 : // thisMaterial->ReflectVisBeamFront = 0.0;
13998 : // thisMaterial->ReflectVisDiffBack = 0.0;
13999 : // thisMaterial->ReflectVisDiffFront = 0.0;
14000 : // thisMaterial->TransSolBeam = 0.0;
14001 : // thisMaterial->TransThermal = 0.0;
14002 : // thisMaterial->TransVisBeam = 0.0;
14003 : // thisMaterial->BlindDataPtr = 0;
14004 : // thisMaterial->WinShadeToGlassDist = 0.0;
14005 : // thisMaterial->WinShadeTopOpeningMult = 0.0;
14006 : // thisMaterial->WinShadeBottomOpeningMult = 0.0;
14007 : // thisMaterial->WinShadeLeftOpeningMult = 0.0;
14008 : // thisMaterial->WinShadeRightOpeningMult = 0.0;
14009 : // thisMaterial->WinShadeAirFlowPermeability = 0.0;
14010 : }
14011 1 : return (newAirMaterial);
14012 1 : }
14013 :
14014 : // create a new construction with storm based on an old construction and storm and gap materials
14015 1 : int createConstructionWithStorm(EnergyPlusData &state, int oldConstruction, std::string name, int stormMaterial, int gapMaterial)
14016 : {
14017 1 : int newConstruct = Util::FindItemInList(name,
14018 1 : state.dataConstruction->Construct,
14019 1 : state.dataHeatBal->TotConstructs); // Number of shaded storm window construction that is created
14020 1 : if (newConstruct == 0) {
14021 1 : state.dataHeatBal->TotConstructs = state.dataHeatBal->TotConstructs + 1;
14022 1 : newConstruct = state.dataHeatBal->TotConstructs;
14023 1 : state.dataConstruction->Construct.redimension(state.dataHeatBal->TotConstructs);
14024 1 : state.dataHeatBal->NominalRforNominalUCalculation.redimension(state.dataHeatBal->TotConstructs);
14025 1 : state.dataHeatBal->NominalU.redimension(state.dataHeatBal->TotConstructs);
14026 1 : state.dataHeatBal->NominalUBeforeAdjusted.redimension(state.dataHeatBal->TotConstructs);
14027 1 : state.dataHeatBal->CoeffAdjRatio.redimension(state.dataHeatBal->TotConstructs) = 1.0;
14028 :
14029 1 : auto &thisConstruct = state.dataConstruction->Construct(state.dataHeatBal->TotConstructs);
14030 : // these Construct arrays dimensioned based on MaxSolidWinLayers
14031 1 : thisConstruct.setArraysBasedOnMaxSolidWinLayers(state);
14032 :
14033 1 : int TotLayersOld = state.dataConstruction->Construct(oldConstruction).TotLayers;
14034 1 : thisConstruct.LayerPoint({1, Construction::MaxLayersInConstruct}) = 0;
14035 1 : thisConstruct.LayerPoint(1) = stormMaterial;
14036 1 : thisConstruct.LayerPoint(2) = gapMaterial;
14037 1 : thisConstruct.LayerPoint({3, TotLayersOld + 2}) = state.dataConstruction->Construct(oldConstruction).LayerPoint({1, TotLayersOld});
14038 1 : thisConstruct.Name = name;
14039 1 : thisConstruct.TotLayers = TotLayersOld + 2;
14040 1 : thisConstruct.TotSolidLayers = state.dataConstruction->Construct(oldConstruction).TotSolidLayers + 1;
14041 1 : thisConstruct.TotGlassLayers = state.dataConstruction->Construct(oldConstruction).TotGlassLayers + 1;
14042 1 : thisConstruct.TypeIsWindow = true;
14043 1 : thisConstruct.InsideAbsorpVis = 0.0;
14044 1 : thisConstruct.OutsideAbsorpVis = 0.0;
14045 1 : thisConstruct.InsideAbsorpSolar = 0.0;
14046 1 : thisConstruct.OutsideAbsorpSolar = 0.0;
14047 1 : thisConstruct.InsideAbsorpThermal = state.dataConstruction->Construct(oldConstruction).InsideAbsorpThermal;
14048 1 : thisConstruct.OutsideAbsorpThermal =
14049 1 : dynamic_cast<Material::MaterialChild *>(state.dataMaterial->Material(stormMaterial))->AbsorpThermalFront;
14050 1 : thisConstruct.OutsideRoughness = Material::SurfaceRoughness::VerySmooth;
14051 1 : thisConstruct.DayltPropPtr = 0;
14052 1 : thisConstruct.CTFCross.fill(0.0);
14053 1 : thisConstruct.CTFFlux.fill(0.0);
14054 1 : thisConstruct.CTFInside.fill(0.0);
14055 1 : thisConstruct.CTFOutside.fill(0.0);
14056 1 : thisConstruct.CTFSourceIn.fill(0.0);
14057 1 : thisConstruct.CTFSourceOut.fill(0.0);
14058 1 : thisConstruct.CTFTimeStep = 0.0;
14059 1 : thisConstruct.CTFTSourceOut.fill(0.0);
14060 1 : thisConstruct.CTFTSourceIn.fill(0.0);
14061 1 : thisConstruct.CTFTSourceQ.fill(0.0);
14062 1 : thisConstruct.CTFTUserOut.fill(0.0);
14063 1 : thisConstruct.CTFTUserIn.fill(0.0);
14064 1 : thisConstruct.CTFTUserSource.fill(0.0);
14065 1 : thisConstruct.NumHistories = 0;
14066 1 : thisConstruct.NumCTFTerms = 0;
14067 1 : thisConstruct.UValue = 0.0;
14068 1 : thisConstruct.SourceSinkPresent = false;
14069 1 : thisConstruct.SolutionDimensions = 0;
14070 1 : thisConstruct.SourceAfterLayer = 0;
14071 1 : thisConstruct.TempAfterLayer = 0;
14072 1 : thisConstruct.ThicknessPerpend = 0.0;
14073 1 : thisConstruct.AbsDiffIn = 0.0;
14074 1 : thisConstruct.AbsDiffOut = 0.0;
14075 1 : thisConstruct.AbsDiff = 0.0;
14076 1 : thisConstruct.AbsDiffBack = 0.0;
14077 1 : thisConstruct.AbsDiffShade = 0.0;
14078 1 : thisConstruct.AbsDiffBackShade = 0.0;
14079 1 : thisConstruct.ShadeAbsorpThermal = 0.0;
14080 1 : thisConstruct.AbsBeamShadeCoef = 0.0;
14081 1 : thisConstruct.TransDiff = 0.0;
14082 1 : thisConstruct.TransDiffVis = 0.0;
14083 1 : thisConstruct.ReflectSolDiffBack = 0.0;
14084 1 : thisConstruct.ReflectSolDiffFront = 0.0;
14085 1 : thisConstruct.ReflectVisDiffBack = 0.0;
14086 1 : thisConstruct.ReflectVisDiffFront = 0.0;
14087 1 : thisConstruct.TransSolBeamCoef = 0.0;
14088 1 : thisConstruct.TransVisBeamCoef = 0.0;
14089 1 : thisConstruct.ReflSolBeamFrontCoef = 0.0;
14090 1 : thisConstruct.ReflSolBeamBackCoef = 0.0;
14091 1 : thisConstruct.W5FrameDivider = 0;
14092 1 : thisConstruct.FromWindow5DataFile = false;
14093 1 : thisConstruct.W5FileMullionWidth = 0.0;
14094 1 : thisConstruct.W5FileMullionOrientation = DataWindowEquivalentLayer::Orientation::Invalid;
14095 1 : thisConstruct.W5FileGlazingSysWidth = 0.0;
14096 1 : thisConstruct.W5FileGlazingSysHeight = 0.0;
14097 8 : for (int Layer = 1; Layer <= state.dataHeatBal->MaxSolidWinLayers; ++Layer) {
14098 49 : for (int index = 1; index <= DataSurfaces::MaxPolyCoeff; ++index) {
14099 42 : thisConstruct.AbsBeamCoef(Layer)(index) = 0.0;
14100 42 : thisConstruct.AbsBeamBackCoef(Layer)(index) = 0.0;
14101 : }
14102 : }
14103 : }
14104 1 : return (newConstruct);
14105 : }
14106 :
14107 8 : void ModifyWindow(EnergyPlusData &state,
14108 : int const SurfNum, // SurfNum has construction of glazing system from Window5 Data File;
14109 : bool &ErrorsFound, // Set to true if errors found
14110 : int &AddedSubSurfaces // Subsurfaces added when window references a
14111 : )
14112 : {
14113 : // SUBROUTINE INFORMATION:
14114 : // AUTHOR Fred Winkelmann
14115 : // DATE WRITTEN Feb 2002
14116 : // MODIFIED June 2004, FCW: SinAzim, CosAzim, SinTilt, CosTilt, OutNormVec, GrossArea
14117 : // and Perimeter weren't being set for created window for case when
14118 : // window from Window5DataFile had two different glazing systems. Also,
14119 : // GrossArea and Perimeter of original window were not being recalculated.
14120 : // October 2007, LKL: Net area for shading calculations was not being
14121 : // recalculated.
14122 : // RE-ENGINEERED na
14123 :
14124 : // PURPOSE OF THIS SUBROUTINE:
14125 : // If a window from the Window5DataFile has one glazing system, modify the
14126 : // vertex coordinates of the original window to correspond to the dimensions
14127 : // of the glazing system on the Data File.
14128 : // If a window from the Window5DataFile has two different glazing systems, split
14129 : // the window into two separate windows with different properties and adjust the
14130 : // vertices of these windows taking into account the dimensions of the glazing systems
14131 : // on the Data File and the width and orientation of the mullion that separates
14132 : // the glazing systems.
14133 :
14134 : // Using/Aliasing
14135 :
14136 : using namespace Vectors;
14137 :
14138 : // Locals
14139 : // SUBROUTINE ARGUMENT DEFINITIONS:
14140 : // If there is a second glazing systme on the Data File, SurfNum+1
14141 : // has the construction of the second glazing system.
14142 :
14143 : // 2-glazing system Window5 data file entry
14144 :
14145 : // DERIVED TYPE DEFINITIONS:
14146 :
14147 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
14148 : Real64 H; // Height and width of original window (m)
14149 : Real64 W;
14150 : // unused1208 REAL(r64) :: MulWidth ! Mullion width (m)
14151 : Real64 h1; // height and width of first glazing system (m)
14152 : Real64 w1;
14153 : // unused1208 REAL(r64) :: h2,w2 ! height and width of second glazing system (m)
14154 : // unused1208 type (rectangularwindow) :: NewCoord
14155 : int IConst; // Construction number of first glazing system
14156 : int IConst2; // Construction number of second glazing system
14157 8 : std::string Const2Name; // Name of construction of second glazing system
14158 : // unused1208 REAL(r64) :: AreaNew ! Sum of areas of the two glazing systems (m2)
14159 :
14160 : struct rectangularwindow
14161 : {
14162 : // Members
14163 : Array1D<Vector> Vertex;
14164 :
14165 : // Default Constructor
14166 8 : rectangularwindow() : Vertex(4)
14167 : {
14168 8 : }
14169 : };
14170 :
14171 : // Object Data
14172 8 : Vector TVect;
14173 8 : rectangularwindow OriginalCoord;
14174 :
14175 8 : IConst = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction;
14176 :
14177 : // Height and width of original window
14178 8 : TVect = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(3) - state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(2);
14179 8 : W = VecLength(TVect); // SQRT((X(3)-X(2))**2 + (Y(3)-Y(2))**2 + (Z(3)-Z(2))**2)
14180 8 : TVect = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(2) - state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(1);
14181 8 : H = VecLength(TVect); // SQRT((X(1)-X(2))**2 + (Y(1)-Y(2))**2 + (Z(1)-Z(2))**2)
14182 :
14183 : // Save coordinates of original window in case Window 5 data overwrites.
14184 16 : OriginalCoord.Vertex({1, state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides}) =
14185 24 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex({1, state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides});
14186 :
14187 : // Height and width of first glazing system
14188 8 : h1 = state.dataConstruction->Construct(IConst).W5FileGlazingSysHeight;
14189 8 : w1 = state.dataConstruction->Construct(IConst).W5FileGlazingSysWidth;
14190 :
14191 8 : Const2Name = state.dataConstruction->Construct(IConst).Name + ":2";
14192 8 : IConst2 = Util::FindItemInList(Const2Name, state.dataConstruction->Construct);
14193 :
14194 8 : if (IConst2 == 0) { // Only one glazing system on Window5 Data File for this window.
14195 :
14196 : // So... original dimensions and area of window are used (entered in IDF)
14197 : // Warning if dimensions of original window differ from those on Data File by more than 10%
14198 :
14199 8 : if (std::abs((H - h1) / H) > 0.10 || std::abs((W - w1) / W) > 0.10) {
14200 :
14201 8 : if (state.dataGlobal->DisplayExtraWarnings) {
14202 0 : ShowWarningError(state,
14203 0 : format("SurfaceGeometry: ModifyWindow: Window {} uses the Window5 Data File Construction {}",
14204 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
14205 0 : state.dataConstruction->Construct(IConst).Name));
14206 0 : ShowContinueError(state, format("The height {:.3R}(m) or width (m) of this window differs by more than 10%{:.3R}", H, W));
14207 0 : ShowContinueError(state,
14208 0 : format("from the corresponding height {:.3R} (m) or width (m) on the Window5 Data file.{:.3R}", h1, w1));
14209 0 : ShowContinueError(state, "This will affect the frame heat transfer calculation if the frame in the Data File entry");
14210 0 : ShowContinueError(state, "is not uniform, i.e., has sections with different geometry and/or thermal properties.");
14211 : } else {
14212 8 : ++state.dataSurfaceGeometry->Warning1Count;
14213 : }
14214 : }
14215 :
14216 : // Calculate net area for base surface
14217 8 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).BaseSurf).Area -=
14218 8 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Area;
14219 8 : if (state.dataSurfaceGeometry->SurfaceTmp(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).BaseSurf).Area <= 0.0) {
14220 0 : ShowSevereError(state,
14221 0 : format("Subsurfaces have too much area for base surface={}",
14222 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).BaseSurf).Name));
14223 0 : ShowContinueError(state, format("Subsurface creating error={}", state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name));
14224 0 : ErrorsFound = true;
14225 : }
14226 :
14227 : // Net area of base surface with unity window multipliers (used in shadowing checks)
14228 8 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).BaseSurf).NetAreaShadowCalc -=
14229 8 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Area / state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Multiplier;
14230 :
14231 : } else { // Two glazing systems on Window5 data file for this window
14232 :
14233 : // if exterior window, okay.
14234 :
14235 0 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond == ExternalEnvironment) {
14236 : // There are two glazing systems (separated by a vertical or horizontal mullion) on the Window5 Data File.
14237 : // Fill in geometry data for the second window (corresponding to the second glazing system on the data file.
14238 : // The first glazing system is assumed to be at left for vertical mullion, at bottom for horizontal mullion.
14239 : // The second glazing system is assumed to be at right for vertical mullion, at top for horizontal mullion.
14240 : // The lower left-hand corner of the original window (its vertex #2) is assumed to coincide with
14241 : // vertex #2 of the first glazing system.
14242 :
14243 0 : if (state.dataGlobal->DisplayExtraWarnings) {
14244 0 : ShowMessage(state,
14245 0 : format("SurfaceGeometry: ModifyWindow: Window {} has been replaced with the Window 5/6 two glazing system=\"{}\".",
14246 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
14247 0 : state.dataConstruction->Construct(IConst).Name));
14248 0 : ShowContinueError(state, "Note that originally entered dimensions are overridden.");
14249 : } else {
14250 0 : ++state.dataSurfaceGeometry->Warning2Count;
14251 : }
14252 :
14253 : // Allocate another window
14254 0 : AddWindow(state, SurfNum, ErrorsFound, AddedSubSurfaces);
14255 :
14256 0 : } else if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond > 0) { // Interior window, specified ! not external environment
14257 :
14258 0 : if (state.dataGlobal->DisplayExtraWarnings) {
14259 0 : ShowWarningError(
14260 : state,
14261 0 : format("SurfaceGeometry: ModifyWindow: Interior Window {} has been replaced with the Window 5/6 two glazing system=\"{}\".",
14262 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
14263 0 : state.dataConstruction->Construct(IConst).Name));
14264 0 : ShowContinueError(
14265 : state, "Please check to make sure interior window is correct. Note that originally entered dimensions are overridden.");
14266 : } else {
14267 0 : ++state.dataSurfaceGeometry->Warning3Count;
14268 : }
14269 :
14270 0 : AddWindow(state, SurfNum, ErrorsFound, AddedSubSurfaces);
14271 :
14272 : } else { // Interior window, specified not entered
14273 :
14274 0 : ShowSevereError(state,
14275 0 : format("SurfaceGeometry: ModifyWindow: Interior Window {} is a window in an adjacent zone.",
14276 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name));
14277 0 : ShowContinueError(
14278 : state,
14279 0 : format("Attempted to add/reverse Window 5/6 multiple glazing system=\"{}\".", state.dataConstruction->Construct(IConst).Name));
14280 0 : ShowContinueError(state, "Cannot use these Window 5/6 constructs for these Interior Windows. Program will terminate.");
14281 0 : ErrorsFound = true;
14282 : }
14283 :
14284 : } // End of check if one or two glazing systems are on the Window5 Data File
14285 8 : }
14286 :
14287 0 : void AddWindow(EnergyPlusData &state,
14288 : int const SurfNum, // SurfNum has construction of glazing system from Window5 Data File;
14289 : bool &ErrorsFound, // Set to true if errors found
14290 : int &AddedSubSurfaces // Subsurfaces added when window references a
14291 : )
14292 : {
14293 : // SUBROUTINE INFORMATION:
14294 : // AUTHOR Linda Lawrie
14295 : // DATE WRITTEN Nov 2008
14296 : // MODIFIED na
14297 : // RE-ENGINEERED na
14298 :
14299 : // PURPOSE OF THIS SUBROUTINE:
14300 : // This routine is called from ModifyWindow to add a window. Allows it to be
14301 : // called in more than one place in the calling routine so as to be able to have
14302 : // specific warnings or errors issued.
14303 :
14304 : // Using/Aliasing
14305 :
14306 : using namespace Vectors;
14307 :
14308 : // Locals
14309 : // SUBROUTINE ARGUMENT DEFINITIONS:
14310 : // If there is a second glazing systme on the Data File, SurfNum+1
14311 : // has the construction of the second glazing system.
14312 :
14313 : // 2-glazing system Window5 data file entry
14314 :
14315 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
14316 : int loop; // DO loop index
14317 : Real64 H; // Height and width of original window (m)
14318 : Real64 W;
14319 : Real64 MulWidth; // Mullion width (m)
14320 : Real64 h1; // height and width of first glazing system (m)
14321 : Real64 w1;
14322 : Real64 h2; // height and width of second glazing system (m)
14323 : Real64 w2;
14324 : Real64 xa; // Vertex intermediate variables (m)
14325 : Real64 ya;
14326 : Real64 za;
14327 : Real64 xb;
14328 : Real64 yb;
14329 : Real64 zb;
14330 : Real64 dx; // Vertex displacements from original window (m)
14331 : Real64 dy;
14332 : int IConst; // Construction number of first glazing system
14333 : int IConst2; // Construction number of second glazing system
14334 0 : std::string Const2Name; // Name of construction of second glazing system
14335 : Real64 AreaNew; // Sum of areas of the two glazing systems (m2)
14336 :
14337 : struct rectangularwindow
14338 : {
14339 : // Members
14340 : Array1D<Vector> Vertex;
14341 :
14342 : // Default Constructor
14343 0 : rectangularwindow() : Vertex(4)
14344 : {
14345 0 : }
14346 : };
14347 :
14348 : // Object Data
14349 0 : Vector TVect;
14350 0 : rectangularwindow NewCoord;
14351 0 : rectangularwindow OriginalCoord;
14352 :
14353 0 : IConst = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction;
14354 :
14355 : // Height and width of original window
14356 0 : TVect = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(3) - state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(2);
14357 0 : W = VecLength(TVect); // SQRT((X(3)-X(2))**2 + (Y(3)-Y(2))**2 + (Z(3)-Z(2))**2)
14358 0 : TVect = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(2) - state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(1);
14359 0 : H = VecLength(TVect); // SQRT((X(1)-X(2))**2 + (Y(1)-Y(2))**2 + (Z(1)-Z(2))**2)
14360 :
14361 : // Save coordinates of original window in case Window 5 data overwrites.
14362 0 : OriginalCoord.Vertex({1, state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides}) =
14363 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex({1, state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides});
14364 :
14365 : // Height and width of first glazing system
14366 0 : h1 = state.dataConstruction->Construct(IConst).W5FileGlazingSysHeight;
14367 0 : w1 = state.dataConstruction->Construct(IConst).W5FileGlazingSysWidth;
14368 :
14369 0 : Const2Name = state.dataConstruction->Construct(IConst).Name + ":2";
14370 0 : IConst2 = Util::FindItemInList(Const2Name, state.dataConstruction->Construct);
14371 :
14372 0 : ++AddedSubSurfaces;
14373 0 : state.dataSurfaceGeometry->SurfaceTmp.redimension(++state.dataSurface->TotSurfaces);
14374 :
14375 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Vertex.allocate(4);
14376 :
14377 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Name = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name + ":2";
14378 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Construction = IConst2;
14379 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).ConstructionStoredInputValue = IConst2;
14380 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Class = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class;
14381 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Azimuth = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Azimuth;
14382 : // Sine and cosine of azimuth and tilt
14383 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).SinAzim = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).SinAzim;
14384 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).CosAzim = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).CosAzim;
14385 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).SinTilt = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).SinTilt;
14386 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).CosTilt = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).CosTilt;
14387 : // Outward normal unit vector (pointing away from room)
14388 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Centroid = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Centroid;
14389 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).lcsx = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).lcsx;
14390 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).lcsy = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).lcsy;
14391 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).lcsz = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).lcsz;
14392 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).NewellAreaVector =
14393 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).NewellAreaVector;
14394 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).OutNormVec = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).OutNormVec;
14395 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Reveal = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Reveal;
14396 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Shape = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Shape;
14397 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Sides = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides;
14398 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Tilt = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Tilt;
14399 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).convOrientation =
14400 0 : Convect::GetSurfConvOrientation(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Tilt);
14401 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).HeatTransSurf =
14402 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).HeatTransSurf;
14403 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).BaseSurfName =
14404 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).BaseSurfName;
14405 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).BaseSurf = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).BaseSurf;
14406 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).ZoneName = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ZoneName;
14407 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Zone = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Zone;
14408 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).ExtBoundCondName =
14409 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCondName;
14410 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).ExtBoundCond =
14411 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond;
14412 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).ExtSolar = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtSolar;
14413 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).ExtWind = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtWind;
14414 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).ViewFactorGround =
14415 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ViewFactorGround;
14416 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).ViewFactorSky =
14417 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ViewFactorSky;
14418 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).ViewFactorGroundIR =
14419 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ViewFactorGroundIR;
14420 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).ViewFactorSkyIR =
14421 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ViewFactorSkyIR;
14422 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).OSCPtr = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).OSCPtr;
14423 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).SchedShadowSurfIndex =
14424 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).SchedShadowSurfIndex;
14425 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).activeWindowShadingControl =
14426 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).activeWindowShadingControl;
14427 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).windowShadingControlList =
14428 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).windowShadingControlList;
14429 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).HasShadeControl =
14430 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).HasShadeControl;
14431 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).activeShadedConstruction =
14432 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).activeShadedConstruction;
14433 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).windowShadingControlList =
14434 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).windowShadingControlList;
14435 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).shadedStormWinConstructionList =
14436 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).shadedStormWinConstructionList;
14437 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).FrameDivider =
14438 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).FrameDivider;
14439 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Multiplier = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Multiplier;
14440 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).NetAreaShadowCalc =
14441 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).NetAreaShadowCalc;
14442 :
14443 0 : MulWidth = state.dataConstruction->Construct(IConst).W5FileMullionWidth;
14444 0 : w2 = state.dataConstruction->Construct(IConst2).W5FileGlazingSysWidth;
14445 0 : h2 = state.dataConstruction->Construct(IConst2).W5FileGlazingSysHeight;
14446 :
14447 : // Correction to net area of base surface. Add back in the original glazing area and subtract the
14448 : // area of the two glazing systems. Note that for Surface(SurfNum)%Class = 'Window' the effect
14449 : // of a window multiplier is included in the glazing area. Note that frame areas are subtracted later.
14450 :
14451 0 : AreaNew = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Multiplier * (h1 * w1 + h2 * w2); // both glazing systems
14452 : // Adjust net area for base surface
14453 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).BaseSurf).Area -= AreaNew;
14454 :
14455 : // Net area of base surface with unity window multipliers (used in shadowing checks)
14456 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).BaseSurf).NetAreaShadowCalc -=
14457 0 : AreaNew / state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Multiplier;
14458 :
14459 : // Reset area, etc. of original window
14460 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Area = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Multiplier * (h1 * w1);
14461 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).GrossArea = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Area;
14462 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).NetAreaShadowCalc = h1 * w1;
14463 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Perimeter = 2 * (h1 + w1);
14464 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Height = h1;
14465 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Width = w1;
14466 : // Set area, etc. of new window
14467 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Area =
14468 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Multiplier * (h2 * w2);
14469 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).GrossArea =
14470 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Area;
14471 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).NetAreaShadowCalc = h2 * w2;
14472 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Perimeter = 2 * (h2 + w2);
14473 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Height = h2;
14474 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Width = w2;
14475 :
14476 0 : if (state.dataSurfaceGeometry->SurfaceTmp(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).BaseSurf).Area <= 0.0) {
14477 0 : ShowSevereError(state,
14478 0 : format("SurfaceGeometry: ModifyWindow: Subsurfaces have too much area for base surface={}",
14479 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurfaceGeometry->SurfaceTmp(SurfNum).BaseSurf).Name));
14480 0 : ShowContinueError(state, format("Subsurface (window) creating error={}", state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name));
14481 0 : ShowContinueError(state,
14482 0 : format("This window has been replaced by two windows from the Window5 Data File of total area {:.2R} m2", AreaNew));
14483 0 : ErrorsFound = true;
14484 : }
14485 :
14486 : // Assign vertices to the new window; modify vertices of original window.
14487 : // In the following, vertices are numbered counter-clockwise with vertex #1 at the upper left.
14488 :
14489 0 : if (state.dataConstruction->Construct(IConst).W5FileMullionOrientation == DataWindowEquivalentLayer::Orientation::Vertical) {
14490 :
14491 : // VERTICAL MULLION: original window is modified to become left-hand glazing (system #1);
14492 : // new window is created to become right-hand glazing (system #2)
14493 :
14494 : // Left-hand glazing
14495 :
14496 : // Vertex 1
14497 0 : dx = 0.0;
14498 0 : dy = H - h1;
14499 0 : xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
14500 0 : ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
14501 0 : za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
14502 0 : xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
14503 0 : yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
14504 0 : zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
14505 0 : NewCoord.Vertex(1).x = xa + (dx / W) * (xb - xa);
14506 0 : NewCoord.Vertex(1).y = ya + (dx / W) * (yb - ya);
14507 0 : NewCoord.Vertex(1).z = za + (dx / W) * (zb - za);
14508 :
14509 : // Vertex 2
14510 0 : dx = 0.0;
14511 0 : dy = H;
14512 0 : xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
14513 0 : ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
14514 0 : za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
14515 0 : xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
14516 0 : yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
14517 0 : zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
14518 0 : NewCoord.Vertex(2).x = xa + (dx / W) * (xb - xa);
14519 0 : NewCoord.Vertex(2).y = ya + (dx / W) * (yb - ya);
14520 0 : NewCoord.Vertex(2).z = za + (dx / W) * (zb - za);
14521 :
14522 : // Vertex 3
14523 0 : dx = w1;
14524 0 : dy = H;
14525 0 : xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
14526 0 : ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
14527 0 : za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
14528 0 : xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
14529 0 : yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
14530 0 : zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
14531 0 : NewCoord.Vertex(3).x = xa + (dx / W) * (xb - xa);
14532 0 : NewCoord.Vertex(3).y = ya + (dx / W) * (yb - ya);
14533 0 : NewCoord.Vertex(3).z = za + (dx / W) * (zb - za);
14534 :
14535 : // Vertex 4
14536 0 : dx = w1;
14537 0 : dy = H - h1;
14538 0 : xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
14539 0 : ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
14540 0 : za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
14541 0 : xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
14542 0 : yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
14543 0 : zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
14544 0 : NewCoord.Vertex(4).x = xa + (dx / W) * (xb - xa);
14545 0 : NewCoord.Vertex(4).y = ya + (dx / W) * (yb - ya);
14546 0 : NewCoord.Vertex(4).z = za + (dx / W) * (zb - za);
14547 :
14548 0 : for (loop = 1; loop <= state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides; ++loop) {
14549 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(loop) = NewCoord.Vertex(loop);
14550 : }
14551 :
14552 : // Right-hand glazing
14553 :
14554 : // Vertex 1
14555 0 : dx = w1 + MulWidth;
14556 0 : dy = H - (h1 + h2) / 2.0;
14557 0 : xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
14558 0 : ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
14559 0 : za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
14560 0 : xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
14561 0 : yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
14562 0 : zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
14563 0 : NewCoord.Vertex(1).x = xa + (dx / W) * (xb - xa);
14564 0 : NewCoord.Vertex(1).y = ya + (dx / W) * (yb - ya);
14565 0 : NewCoord.Vertex(1).z = za + (dx / W) * (zb - za);
14566 :
14567 : // Vertex 2
14568 0 : dx = w1 + MulWidth;
14569 0 : dy = H + (h2 - h1) / 2.0;
14570 0 : xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
14571 0 : ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
14572 0 : za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
14573 0 : xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
14574 0 : yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
14575 0 : zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
14576 0 : NewCoord.Vertex(2).x = xa + (dx / W) * (xb - xa);
14577 0 : NewCoord.Vertex(2).y = ya + (dx / W) * (yb - ya);
14578 0 : NewCoord.Vertex(2).z = za + (dx / W) * (zb - za);
14579 :
14580 : // Vertex 3
14581 0 : dx = w1 + MulWidth + w2;
14582 0 : dy = H + (h2 - h1) / 2.0;
14583 0 : xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
14584 0 : ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
14585 0 : za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
14586 0 : xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
14587 0 : yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
14588 0 : zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
14589 0 : NewCoord.Vertex(3).x = xa + (dx / W) * (xb - xa);
14590 0 : NewCoord.Vertex(3).y = ya + (dx / W) * (yb - ya);
14591 0 : NewCoord.Vertex(3).z = za + (dx / W) * (zb - za);
14592 :
14593 : // Vertex 4
14594 0 : dx = w1 + MulWidth + w2;
14595 0 : dy = H - (h1 + h2) / 2.0;
14596 0 : xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
14597 0 : ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
14598 0 : za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
14599 0 : xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
14600 0 : yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
14601 0 : zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
14602 0 : NewCoord.Vertex(4).x = xa + (dx / W) * (xb - xa);
14603 0 : NewCoord.Vertex(4).y = ya + (dx / W) * (yb - ya);
14604 0 : NewCoord.Vertex(4).z = za + (dx / W) * (zb - za);
14605 :
14606 0 : for (loop = 1; loop <= state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Sides; ++loop) {
14607 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Vertex(loop) = NewCoord.Vertex(loop);
14608 : }
14609 :
14610 : } else { // Horizontal mullion
14611 :
14612 : // HORIZONTAL MULLION: original window is modified to become bottom glazing (system #1);
14613 : // new window is created to become top glazing (system #2)
14614 :
14615 : // Bottom glazing
14616 :
14617 : // Vertex 1
14618 0 : dx = 0.0;
14619 0 : dy = H - h1;
14620 0 : xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
14621 0 : ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
14622 0 : za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
14623 0 : xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
14624 0 : yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
14625 0 : zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
14626 0 : NewCoord.Vertex(1).x = xa + (dx / W) * (xb - xa);
14627 0 : NewCoord.Vertex(1).y = ya + (dx / W) * (yb - ya);
14628 0 : NewCoord.Vertex(1).z = za + (dx / W) * (zb - za);
14629 :
14630 : // Vertex 2
14631 0 : dx = 0.0;
14632 0 : dy = H;
14633 0 : xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
14634 0 : ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
14635 0 : za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
14636 0 : xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
14637 0 : yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
14638 0 : zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
14639 0 : NewCoord.Vertex(2).x = xa + (dx / W) * (xb - xa);
14640 0 : NewCoord.Vertex(2).y = ya + (dx / W) * (yb - ya);
14641 0 : NewCoord.Vertex(2).z = za + (dx / W) * (zb - za);
14642 :
14643 : // Vertex 3
14644 0 : dx = w1;
14645 0 : dy = H;
14646 0 : xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
14647 0 : ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
14648 0 : za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
14649 0 : xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
14650 0 : yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
14651 0 : zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
14652 0 : NewCoord.Vertex(3).x = xa + (dx / W) * (xb - xa);
14653 0 : NewCoord.Vertex(3).y = ya + (dx / W) * (yb - ya);
14654 0 : NewCoord.Vertex(3).z = za + (dx / W) * (zb - za);
14655 :
14656 : // Vertex 4
14657 0 : dx = w1;
14658 0 : dy = H - h1;
14659 0 : xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
14660 0 : ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
14661 0 : za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
14662 0 : xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
14663 0 : yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
14664 0 : zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
14665 0 : NewCoord.Vertex(4).x = xa + (dx / W) * (xb - xa);
14666 0 : NewCoord.Vertex(4).y = ya + (dx / W) * (yb - ya);
14667 0 : NewCoord.Vertex(4).z = za + (dx / W) * (zb - za);
14668 :
14669 0 : for (loop = 1; loop <= state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Sides; ++loop) {
14670 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(loop) = NewCoord.Vertex(loop);
14671 : }
14672 :
14673 : // Top glazing
14674 :
14675 : // Vertex 1
14676 0 : dx = (w1 - w2) / 2.0;
14677 0 : dy = H - (h1 + h2 + MulWidth);
14678 0 : xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
14679 0 : ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
14680 0 : za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
14681 0 : xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
14682 0 : yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
14683 0 : zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
14684 0 : NewCoord.Vertex(1).x = xa + (dx / W) * (xb - xa);
14685 0 : NewCoord.Vertex(1).y = ya + (dx / W) * (yb - ya);
14686 0 : NewCoord.Vertex(1).z = za + (dx / W) * (zb - za);
14687 :
14688 : // Vertex 2
14689 0 : dx = (w1 - w2) / 2.0;
14690 0 : dy = H - (h1 + MulWidth);
14691 0 : xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
14692 0 : ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
14693 0 : za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
14694 0 : xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
14695 0 : yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
14696 0 : zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
14697 0 : NewCoord.Vertex(2).x = xa + (dx / W) * (xb - xa);
14698 0 : NewCoord.Vertex(2).y = ya + (dx / W) * (yb - ya);
14699 0 : NewCoord.Vertex(2).z = za + (dx / W) * (zb - za);
14700 :
14701 : // Vertex 3
14702 0 : dx = (w1 + w2) / 2.0;
14703 0 : dy = H - (h1 + MulWidth);
14704 0 : xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
14705 0 : ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
14706 0 : za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
14707 0 : xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
14708 0 : yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
14709 0 : zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
14710 0 : NewCoord.Vertex(3).x = xa + (dx / W) * (xb - xa);
14711 0 : NewCoord.Vertex(3).y = ya + (dx / W) * (yb - ya);
14712 0 : NewCoord.Vertex(3).z = za + (dx / W) * (zb - za);
14713 :
14714 : // Vertex 4
14715 0 : dx = (w1 + w2) / 2.0;
14716 0 : dy = H - (h1 + h2 + MulWidth);
14717 0 : xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
14718 0 : ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
14719 0 : za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
14720 0 : xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
14721 0 : yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
14722 0 : zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
14723 0 : NewCoord.Vertex(4).x = xa + (dx / W) * (xb - xa);
14724 0 : NewCoord.Vertex(4).y = ya + (dx / W) * (yb - ya);
14725 0 : NewCoord.Vertex(4).z = za + (dx / W) * (zb - za);
14726 :
14727 0 : for (loop = 1; loop <= state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Sides; ++loop) {
14728 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Vertex(loop) = NewCoord.Vertex(loop);
14729 : }
14730 :
14731 : } // End of check if vertical or horizontal mullion
14732 0 : }
14733 :
14734 42458 : void TransformVertsByAspect(EnergyPlusData &state,
14735 : int const SurfNum, // Current surface number
14736 : int const NSides // Number of sides to figure
14737 : )
14738 : {
14739 : // SUBROUTINE INFORMATION:
14740 : // AUTHOR Brent T Griffith
14741 : // DATE WRITTEN April 2003
14742 : // MODIFIED na
14743 : // RE-ENGINEERED na
14744 :
14745 : // PURPOSE OF THIS SUBROUTINE:
14746 : // Alter input for surface geometry
14747 : // Optimizing building design for energy can involve
14748 : // altering building geometry. Rather than assemble routines to transform
14749 : // geometry through pre-processing on input, it may be simpler to change
14750 : // vertices within EnergyPlus since it already reads the data from the input
14751 : // file and there would no longer be a need to rewrite the text data.
14752 : // This is essentially a crude hack to allow adjusting geometry with
14753 : // a single parameter...
14754 :
14755 : // METHODOLOGY EMPLOYED:
14756 : // once vertices have been converted to WCS, change them to reflect a different aspect
14757 : // ratio for the entire building based on user input.
14758 : // This routine is called once for each surface by subroutine GetVertices
14759 :
14760 42458 : static std::string const CurrentModuleObject("GeometryTransform");
14761 :
14762 42458 : Array1D_string cAlphas(1);
14763 42458 : Array1D<Real64> rNumerics(2);
14764 : int NAlphas;
14765 : int NNum;
14766 : int IOStat;
14767 42458 : auto &OldAspectRatio = state.dataSurfaceGeometry->OldAspectRatio;
14768 42458 : auto &NewAspectRatio = state.dataSurfaceGeometry->NewAspectRatio;
14769 42458 : auto &transformPlane = state.dataSurfaceGeometry->transformPlane;
14770 : int n;
14771 : Real64 Xo;
14772 : Real64 XnoRot;
14773 : Real64 Xtrans;
14774 : Real64 Yo;
14775 : Real64 YnoRot;
14776 : Real64 Ytrans;
14777 : // begin execution
14778 : // get user input...
14779 :
14780 42458 : if (state.dataSurfaceGeometry->firstTime) {
14781 765 : if (state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject) == 1) {
14782 2 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
14783 : CurrentModuleObject,
14784 : 1,
14785 : cAlphas,
14786 : NAlphas,
14787 : rNumerics,
14788 : NNum,
14789 : IOStat,
14790 1 : state.dataIPShortCut->lNumericFieldBlanks,
14791 1 : state.dataIPShortCut->lAlphaFieldBlanks,
14792 1 : state.dataIPShortCut->cAlphaFieldNames,
14793 1 : state.dataIPShortCut->cNumericFieldNames);
14794 1 : OldAspectRatio = rNumerics(1);
14795 1 : NewAspectRatio = rNumerics(2);
14796 1 : transformPlane = cAlphas(1);
14797 1 : if (transformPlane != "XY") {
14798 0 : ShowWarningError(
14799 0 : state, format("{}: invalid {}=\"{}...ignored.", CurrentModuleObject, state.dataIPShortCut->cAlphaFieldNames(1), cAlphas(1)));
14800 : }
14801 1 : state.dataSurfaceGeometry->firstTime = false;
14802 1 : state.dataSurfaceGeometry->noTransform = false;
14803 1 : state.dataSurface->AspectTransform = true;
14804 1 : if (state.dataSurface->WorldCoordSystem) {
14805 0 : ShowWarningError(state, format("{}: must use Relative Coordinate System. Transform request ignored.", CurrentModuleObject));
14806 0 : state.dataSurfaceGeometry->noTransform = true;
14807 0 : state.dataSurface->AspectTransform = false;
14808 : }
14809 : } else {
14810 764 : state.dataSurfaceGeometry->firstTime = false;
14811 : }
14812 : }
14813 42458 : if (state.dataSurfaceGeometry->noTransform) return;
14814 :
14815 : // check surface type.
14816 48 : if (!state.dataSurfaceGeometry->SurfaceTmp(SurfNum).HeatTransSurf) {
14817 : // Site Shading do not get transformed.
14818 2 : if (state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class == SurfaceClass::Detached_F) return;
14819 : }
14820 :
14821 : // testing method of transforming x and y coordinates as follows
14822 :
14823 : // this works if not rotated wrt north axis ... but if it is, then trouble
14824 : // try to first derotate it , transform by aspect and then rotate back.
14825 :
14826 240 : for (n = 1; n <= NSides; ++n) {
14827 192 : Xo = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(n).x; // world coordinates.... shifted by relative north angle...
14828 192 : Yo = state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(n).y;
14829 : // next derotate the building
14830 192 : XnoRot = Xo * state.dataSurfaceGeometry->CosBldgRelNorth + Yo * state.dataSurfaceGeometry->SinBldgRelNorth;
14831 192 : YnoRot = Yo * state.dataSurfaceGeometry->CosBldgRelNorth - Xo * state.dataSurfaceGeometry->SinBldgRelNorth;
14832 : // translate
14833 192 : Xtrans = XnoRot * std::sqrt(NewAspectRatio / OldAspectRatio);
14834 192 : Ytrans = YnoRot * std::sqrt(OldAspectRatio / NewAspectRatio);
14835 : // rerotate
14836 192 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(n).x =
14837 192 : Xtrans * state.dataSurfaceGeometry->CosBldgRelNorth - Ytrans * state.dataSurfaceGeometry->SinBldgRelNorth;
14838 :
14839 192 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Vertex(n).y =
14840 192 : Xtrans * state.dataSurfaceGeometry->SinBldgRelNorth + Ytrans * state.dataSurfaceGeometry->CosBldgRelNorth;
14841 : }
14842 84868 : }
14843 :
14844 796 : void CalcSurfaceCentroid(EnergyPlusData &state)
14845 : {
14846 : // SUBROUTINE INFORMATION:
14847 : // AUTHOR B. Griffith
14848 : // DATE WRITTEN Feb. 2004
14849 : // MODIFIED na
14850 : // RE-ENGINEERED na
14851 :
14852 : // PURPOSE OF THIS SUBROUTINE:
14853 : // compute centroid of all the surfaces in the main
14854 : // surface structure. Store the vertex coordinates of
14855 : // the centroid in the 'SURFACE' derived type.
14856 :
14857 : // METHODOLOGY EMPLOYED:
14858 : // The centroid of triangle is easily computed by averaging the vertices
14859 : // The centroid of a quadrilateral is computed by area weighting the centroids
14860 : // of two triangles.
14861 : // (Algorithm would need to be changed for higher order
14862 : // polygons with more than four sides).
14863 :
14864 : using namespace Vectors;
14865 :
14866 796 : auto &Triangle1 = state.dataSurfaceGeometry->Triangle1;
14867 796 : auto &Triangle2 = state.dataSurfaceGeometry->Triangle2;
14868 796 : static Vector const zero_vector(0.0);
14869 796 : Vector centroid;
14870 :
14871 796 : int negZcount(0); // for warning error in surface centroids
14872 :
14873 : // loop through all the surfaces
14874 46840 : for (int ThisSurf = 1; ThisSurf <= state.dataSurface->TotSurfaces; ++ThisSurf) {
14875 46044 : auto &surface = state.dataSurface->Surface(ThisSurf);
14876 :
14877 46044 : if (surface.Class == SurfaceClass::IntMass) continue;
14878 :
14879 43646 : auto const &vertex = surface.Vertex;
14880 :
14881 43646 : if (surface.Sides == 3) { // 3-sided polygon
14882 :
14883 199 : centroid = cen(vertex(1), vertex(2), vertex(3));
14884 :
14885 43447 : } else if (surface.Sides == 4) { // 4-sided polygon
14886 :
14887 : // split into 2 3-sided polygons (Triangle 1 and Triangle 2)
14888 43250 : Triangle1(1) = vertex(1);
14889 43250 : Triangle1(2) = vertex(2);
14890 43250 : Triangle1(3) = vertex(3);
14891 43250 : Triangle2(1) = vertex(1);
14892 43250 : Triangle2(2) = vertex(3);
14893 43250 : Triangle2(3) = vertex(4);
14894 :
14895 : // get total Area of quad.
14896 43250 : Real64 TotalArea(surface.GrossArea);
14897 43250 : if (TotalArea <= 0.0) {
14898 : // catch a problem....
14899 0 : ShowWarningError(state, format("CalcSurfaceCentroid: zero area surface, for surface={}", surface.Name));
14900 0 : continue;
14901 : }
14902 :
14903 : // get area fraction of triangles.
14904 43250 : Real64 Tri1Area(AreaPolygon(3, Triangle1) / TotalArea);
14905 43250 : Real64 Tri2Area(AreaPolygon(3, Triangle2) / TotalArea);
14906 :
14907 : // check if sum of fractions are slightly greater than 1.0 which is a symptom of the triangles for a non-convex
14908 : // quadralateral using the wrong two triangles
14909 43250 : if ((Tri1Area + Tri2Area) > 1.05) {
14910 :
14911 : // if so repeat the process with the other two possible triangles (notice the vertices are in a different order this
14912 : // time) split into 2 3-sided polygons (Triangle 1 and Triangle 2)
14913 20 : Triangle1(1) = vertex(1);
14914 20 : Triangle1(2) = vertex(2);
14915 20 : Triangle1(3) = vertex(4);
14916 20 : Triangle2(1) = vertex(2);
14917 20 : Triangle2(2) = vertex(3);
14918 20 : Triangle2(3) = vertex(4);
14919 :
14920 : // get area fraction of triangles.
14921 20 : Real64 AreaTriangle1 = AreaPolygon(3, Triangle1);
14922 20 : Real64 AreaTriangle2 = AreaPolygon(3, Triangle2);
14923 20 : TotalArea = AreaTriangle1 + AreaTriangle2;
14924 20 : Tri1Area = AreaTriangle1 / TotalArea;
14925 20 : Tri2Area = AreaTriangle2 / TotalArea;
14926 : }
14927 :
14928 : // get centroid of Triangle 1
14929 43250 : Vector cen1(cen(Triangle1(1), Triangle1(2), Triangle1(3)));
14930 :
14931 : // get centroid of Triangle 2
14932 43250 : Vector cen2(cen(Triangle2(1), Triangle2(2), Triangle2(3)));
14933 :
14934 : // find area weighted combination of the two centroids (coded to avoid temporary Vectors)
14935 43250 : cen1 *= Tri1Area;
14936 43250 : cen2 *= Tri2Area;
14937 43250 : centroid = cen1;
14938 43250 : centroid += cen2;
14939 :
14940 43447 : } else if (surface.Sides >= 5) { // multi-sided polygon
14941 : // (Maybe triangulate? For now, use old "z" average method")
14942 : // and X and Y -- straight average
14943 :
14944 : // X1=MINVAL(Surface(ThisSurf)%Vertex(1:Surface(ThisSurf)%Sides)%x)
14945 : // X2=MAXVAL(Surface(ThisSurf)%Vertex(1:Surface(ThisSurf)%Sides)%x)
14946 : // Y1=MINVAL(Surface(ThisSurf)%Vertex(1:Surface(ThisSurf)%Sides)%y)
14947 : // Y2=MAXVAL(Surface(ThisSurf)%Vertex(1:Surface(ThisSurf)%Sides)%y)
14948 : // Z1=MINVAL(Surface(ThisSurf)%Vertex(1:Surface(ThisSurf)%Sides)%z)
14949 : // Z2=MAXVAL(Surface(ThisSurf)%Vertex(1:Surface(ThisSurf)%Sides)%z)
14950 : // Xcm=(X1+X2)/2.0d0
14951 : // Ycm=(Y1+Y2)/2.0d0
14952 : // Zcm=(Z1+Z2)/2.0d0
14953 :
14954 : // Calc centroid as average of surfaces
14955 197 : centroid = 0.0;
14956 2025 : for (int vert = 1; vert <= surface.Sides; ++vert) {
14957 1828 : centroid += vertex(vert);
14958 : }
14959 197 : centroid /= double(surface.Sides);
14960 :
14961 : } else {
14962 :
14963 0 : if (!surface.Name.empty()) {
14964 0 : ShowWarningError(state, format("CalcSurfaceCentroid: caught problem with # of sides, for surface={}", surface.Name));
14965 0 : ShowContinueError(state, format("... number of sides must be >= 3, this surface # sides={}", surface.Sides));
14966 : } else {
14967 0 : ShowWarningError(state, format("CalcSurfaceCentroid: caught problem with # of sides, for surface=#{}", ThisSurf));
14968 0 : ShowContinueError(state,
14969 : "...surface name is blank. Examine surfaces -- this may be a problem with ill-formed interzone surfaces.");
14970 0 : ShowContinueError(state, format("... number of sides must be >= 3, this surface # sides={}", surface.Sides));
14971 : }
14972 0 : centroid = 0.0;
14973 : }
14974 :
14975 : // store result in the surface structure in DataSurfaces
14976 43646 : surface.Centroid = centroid;
14977 :
14978 43646 : if (centroid.z < 0.0) {
14979 303 : if (surface.ExtWind || surface.ExtBoundCond == ExternalEnvironment) ++negZcount;
14980 : }
14981 :
14982 : } // loop through surfaces
14983 :
14984 796 : if (negZcount > 0) {
14985 4 : ShowWarningError(state, format("CalcSurfaceCentroid: {} Surfaces have the Z coordinate < 0.", negZcount));
14986 4 : ShowContinueError(state, "...in any calculations, Wind Speed will be 0.0 for these surfaces.");
14987 8 : ShowContinueError(state,
14988 8 : format("...in any calculations, Outside temperatures will be the outside temperature + {:.3R} for these surfaces.",
14989 4 : state.dataEnvrn->WeatherFileTempModCoeff));
14990 4 : ShowContinueError(state, "...that is, these surfaces will have conditions as though at ground level.");
14991 : }
14992 796 : }
14993 :
14994 796 : void SetupShadeSurfacesForSolarCalcs(EnergyPlusData &state)
14995 : {
14996 : // SUBROUTINE INFORMATION:
14997 : // AUTHOR B. Griffith
14998 : // DATE WRITTEN Dec. 2008
14999 : // MODIFIED na
15000 : // RE-ENGINEERED na
15001 :
15002 : // PURPOSE OF THIS SUBROUTINE:
15003 : // determine if Shading surfaces need full solar calcs because they
15004 : // are also used to define geometry of an active solar component.
15005 : // Normally, a shading surface is not included in calculations of incident solar, only shading
15006 :
15007 : // METHODOLOGY EMPLOYED:
15008 : // Mine solar renewables input and collect surface names.
15009 : // find shading surfaces with names that match those in solar objects.
15010 : // setup flags for shading surfaces so that the solar renewables can resuse incident solar calcs
15011 : // new solar component models that use shading surfaces will have to extend the code here.
15012 :
15013 : // Using/Aliasing
15014 :
15015 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
15016 796 : Array1D_string TmpCandidateSurfaceNames;
15017 796 : Array1D_string TmpCandidateICSSurfaceNames;
15018 796 : Array1D_string TmpCandidateICSBCTypeNames;
15019 : int NumCandidateNames;
15020 : int NumOfCollectors;
15021 : int NumOfICSUnits;
15022 : int NumOfFlatPlateUnits;
15023 : int NumPVTs;
15024 : int NumPVs;
15025 : int SurfNum;
15026 : int Found;
15027 : int CollectorNum;
15028 : int PVTnum;
15029 : int PVnum;
15030 : int NumAlphas; // Number of alpha names being passed
15031 : int NumNumbers; // Number of numeric parameters being passed
15032 : int IOStatus;
15033 796 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
15034 : // First collect names of surfaces referenced by active solar components
15035 796 : cCurrentModuleObject = "SolarCollector:FlatPlate:Water";
15036 796 : NumOfFlatPlateUnits = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
15037 796 : cCurrentModuleObject = "SolarCollector:FlatPlate:PhotovoltaicThermal";
15038 796 : NumPVTs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
15039 796 : cCurrentModuleObject = "Generator:Photovoltaic";
15040 796 : NumPVs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
15041 796 : cCurrentModuleObject = "SolarCollector:IntegralCollectorStorage";
15042 796 : NumOfICSUnits = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
15043 :
15044 796 : NumCandidateNames = NumOfFlatPlateUnits + NumPVTs + NumPVs + NumOfICSUnits;
15045 796 : NumOfCollectors = NumOfFlatPlateUnits + NumOfICSUnits;
15046 :
15047 796 : TmpCandidateSurfaceNames.allocate(NumCandidateNames);
15048 796 : TmpCandidateICSSurfaceNames.allocate(NumOfCollectors);
15049 796 : TmpCandidateICSBCTypeNames.allocate(NumOfCollectors);
15050 :
15051 796 : if (NumOfCollectors > 0) {
15052 3 : cCurrentModuleObject = "SolarCollector:FlatPlate:Water";
15053 11 : for (CollectorNum = 1; CollectorNum <= NumOfFlatPlateUnits; ++CollectorNum) {
15054 :
15055 16 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
15056 : cCurrentModuleObject,
15057 : CollectorNum,
15058 8 : state.dataIPShortCut->cAlphaArgs,
15059 : NumAlphas,
15060 8 : state.dataIPShortCut->rNumericArgs,
15061 : NumNumbers,
15062 : IOStatus);
15063 :
15064 8 : TmpCandidateSurfaceNames(CollectorNum) = state.dataIPShortCut->cAlphaArgs(3);
15065 8 : TmpCandidateICSBCTypeNames(CollectorNum) = "";
15066 : }
15067 : }
15068 :
15069 796 : if (NumPVTs > 0) {
15070 2 : cCurrentModuleObject = "SolarCollector:FlatPlate:PhotovoltaicThermal";
15071 22 : for (PVTnum = 1; PVTnum <= NumPVTs; ++PVTnum) {
15072 :
15073 40 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
15074 : cCurrentModuleObject,
15075 : PVTnum,
15076 20 : state.dataIPShortCut->cAlphaArgs,
15077 : NumAlphas,
15078 20 : state.dataIPShortCut->rNumericArgs,
15079 : NumNumbers,
15080 : IOStatus);
15081 :
15082 20 : TmpCandidateSurfaceNames(NumOfFlatPlateUnits + PVTnum) = state.dataIPShortCut->cAlphaArgs(2);
15083 : }
15084 : }
15085 :
15086 796 : if (NumPVs > 0) {
15087 6 : cCurrentModuleObject = "Generator:Photovoltaic";
15088 59 : for (PVnum = 1; PVnum <= NumPVs; ++PVnum) {
15089 106 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
15090 : cCurrentModuleObject,
15091 : PVnum,
15092 53 : state.dataIPShortCut->cAlphaArgs,
15093 : NumAlphas,
15094 53 : state.dataIPShortCut->rNumericArgs,
15095 : NumNumbers,
15096 : IOStatus);
15097 53 : TmpCandidateSurfaceNames(NumOfFlatPlateUnits + NumPVTs + PVnum) = state.dataIPShortCut->cAlphaArgs(2);
15098 : }
15099 : }
15100 :
15101 796 : if (NumOfICSUnits > 0) {
15102 1 : cCurrentModuleObject = "SolarCollector:IntegralCollectorStorage";
15103 3 : for (CollectorNum = 1; CollectorNum <= NumOfICSUnits; ++CollectorNum) {
15104 4 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
15105 : cCurrentModuleObject,
15106 : CollectorNum,
15107 2 : state.dataIPShortCut->cAlphaArgs,
15108 : NumAlphas,
15109 2 : state.dataIPShortCut->rNumericArgs,
15110 : NumNumbers,
15111 : IOStatus);
15112 2 : TmpCandidateSurfaceNames(NumOfFlatPlateUnits + NumPVTs + NumPVs + CollectorNum) = state.dataIPShortCut->cAlphaArgs(3);
15113 2 : TmpCandidateICSSurfaceNames(NumOfFlatPlateUnits + CollectorNum) = state.dataIPShortCut->cAlphaArgs(3);
15114 2 : TmpCandidateICSBCTypeNames(NumOfFlatPlateUnits + CollectorNum) = state.dataIPShortCut->cAlphaArgs(4);
15115 : }
15116 : }
15117 :
15118 : // loop through all the surfaces
15119 46840 : for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
15120 46044 : auto &surf = state.dataSurface->Surface(SurfNum);
15121 46044 : Found = Util::FindItemInList(surf.Name, TmpCandidateSurfaceNames, NumCandidateNames);
15122 46044 : if (Found > 0) {
15123 53 : if (!surf.HeatTransSurf) { // not BIPV, must be a shading surf with solar device
15124 : // Setup missing values to allow shading surfaces to model incident solar and wind
15125 21 : surf.ExtSolar = true;
15126 21 : surf.ExtWind = true;
15127 21 : surf.ViewFactorGround = 0.5 * (1.0 - surf.CosTilt);
15128 : }
15129 : // check if this surface is used for ICS collector mounting and has OthersideCondictionsModel as its
15130 : // boundary condition
15131 53 : if (NumOfICSUnits > 0) {
15132 6 : for (CollectorNum = 1; CollectorNum <= NumOfCollectors; ++CollectorNum) {
15133 6 : if (Util::SameString(surf.Name, TmpCandidateICSSurfaceNames(CollectorNum)) &&
15134 6 : Util::SameString(TmpCandidateICSBCTypeNames(CollectorNum), "OTHERSIDECONDITIONSMODEL")) {
15135 2 : state.dataSurface->SurfIsICS(SurfNum) = true;
15136 2 : state.dataSurface->SurfICSPtr(SurfNum) = CollectorNum;
15137 : }
15138 : }
15139 : }
15140 :
15141 : } // end of IF (Found > 0) Then
15142 : }
15143 796 : }
15144 :
15145 : void
15146 1592 : SetupEnclosuresAndAirBoundaries(EnergyPlusData &state,
15147 : EPVector<DataViewFactorInformation::EnclosureViewFactorInformation> &Enclosures, // Radiant or Solar Enclosures
15148 : SurfaceGeometry::enclosureType const EnclosureType, // Radiant or Solar
15149 : bool &ErrorsFound) // Set to true if errors found
15150 : {
15151 : static constexpr std::string_view RoutineName = "SetupEnclosuresAndAirBoundaries";
15152 1592 : bool anyGroupedSpaces = false;
15153 1592 : bool radiantSetup = false;
15154 1592 : bool solarSetup = false;
15155 1592 : std::string RadiantOrSolar = "";
15156 1592 : int enclosureNum = 0;
15157 1592 : if (EnclosureType == RadiantEnclosures) {
15158 796 : radiantSetup = true;
15159 796 : RadiantOrSolar = "Radiant";
15160 796 : state.dataViewFactor->EnclRadInfo.allocate(state.dataGlobal->numSpaces);
15161 796 : } else if (EnclosureType == SolarEnclosures) {
15162 796 : solarSetup = true;
15163 796 : RadiantOrSolar = "Solar";
15164 796 : state.dataViewFactor->EnclSolInfo.allocate(state.dataGlobal->numSpaces);
15165 : } else {
15166 0 : ShowFatalError(
15167 0 : state, format("{}: Illegal call to this function. Second argument must be 'RadiantEnclosures' or 'SolarEnclosures'", RoutineName));
15168 : }
15169 1592 : if (std::any_of(state.dataConstruction->Construct.begin(),
15170 1592 : state.dataConstruction->Construct.end(),
15171 12055 : [](Construction::ConstructionProps const &e) { return e.TypeIsAirBoundary; })) {
15172 10 : int errorCount = 0;
15173 632 : for (int surfNum = 1; surfNum <= state.dataSurface->TotSurfaces; ++surfNum) {
15174 622 : auto &surf = state.dataSurface->Surface(surfNum);
15175 622 : if (surf.Construction == 0) continue;
15176 582 : auto &constr = state.dataConstruction->Construct(surf.Construction);
15177 582 : if (!constr.TypeIsAirBoundary) continue;
15178 36 : surf.IsAirBoundarySurf = true;
15179 :
15180 : // Check for invalid air boundary surfaces - valid only on non-adiabatic interzone surfaces
15181 : // Only check this once during radiant setup, skip for solar setup
15182 36 : if (radiantSetup && (surf.ExtBoundCond <= 0 || surf.ExtBoundCond == surfNum)) {
15183 0 : ErrorsFound = true;
15184 0 : if (!state.dataGlobal->DisplayExtraWarnings) {
15185 0 : ++errorCount;
15186 : } else {
15187 0 : ShowSevereError(
15188 0 : state, format("{}: Surface=\"{}\" uses Construction:AirBoundary in a non-interzone surface.", RoutineName, surf.Name));
15189 : }
15190 : } else {
15191 : // Process air boundary - set surface properties and set up enclosures
15192 : // Radiant exchange
15193 36 : if (surf.IsAirBoundarySurf) {
15194 : // Boundary is grouped - assign enclosure
15195 36 : state.dataHeatBal->AnyAirBoundary = true;
15196 36 : int thisSideEnclosureNum = 0;
15197 36 : int otherSideEnclosureNum = 0;
15198 36 : if (radiantSetup) {
15199 : // Radiant enclosure setup
15200 18 : constr.IsUsedCTF = false;
15201 18 : surf.HeatTransSurf = false;
15202 18 : surf.HeatTransferAlgorithm = DataSurfaces::HeatTransferModel::AirBoundaryNoHT;
15203 18 : thisSideEnclosureNum = state.dataHeatBal->space(surf.spaceNum).radiantEnclosureNum;
15204 18 : otherSideEnclosureNum =
15205 18 : state.dataHeatBal->space(state.dataSurface->Surface(surf.ExtBoundCond).spaceNum).radiantEnclosureNum;
15206 : } else {
15207 : // Solar enclosure setup
15208 18 : thisSideEnclosureNum = state.dataHeatBal->space(surf.spaceNum).solarEnclosureNum;
15209 18 : otherSideEnclosureNum =
15210 18 : state.dataHeatBal->space(state.dataSurface->Surface(surf.ExtBoundCond).spaceNum).solarEnclosureNum;
15211 : }
15212 36 : anyGroupedSpaces = true;
15213 36 : if ((thisSideEnclosureNum == 0) && (otherSideEnclosureNum == 0)) {
15214 : // Neither zone is assigned to an enclosure, so increment the counter and assign to both
15215 10 : ++enclosureNum;
15216 10 : auto &thisEnclosure = Enclosures(enclosureNum);
15217 10 : thisSideEnclosureNum = enclosureNum;
15218 10 : thisEnclosure.Name = format("{} Enclosure {}", RadiantOrSolar, enclosureNum);
15219 10 : thisEnclosure.spaceNames.push_back(state.dataHeatBal->space(surf.spaceNum).Name);
15220 10 : thisEnclosure.spaceNums.push_back(surf.spaceNum);
15221 10 : thisEnclosure.FloorArea += state.dataHeatBal->space(surf.spaceNum).FloorArea;
15222 10 : otherSideEnclosureNum = enclosureNum;
15223 10 : int otherSideSpaceNum = state.dataSurface->Surface(surf.ExtBoundCond).spaceNum;
15224 10 : if (otherSideSpaceNum != surf.spaceNum) {
15225 10 : thisEnclosure.spaceNames.push_back(state.dataHeatBal->space(otherSideSpaceNum).Name);
15226 10 : thisEnclosure.spaceNums.push_back(otherSideSpaceNum);
15227 10 : thisEnclosure.FloorArea += state.dataHeatBal->space(otherSideSpaceNum).FloorArea;
15228 : }
15229 10 : if (radiantSetup) {
15230 5 : state.dataHeatBal->space(surf.spaceNum).radiantEnclosureNum = thisSideEnclosureNum;
15231 5 : state.dataHeatBal->space(state.dataSurface->Surface(surf.ExtBoundCond).spaceNum).radiantEnclosureNum =
15232 : otherSideEnclosureNum;
15233 : } else {
15234 5 : thisEnclosure.ExtWindowArea += state.dataHeatBal->space(surf.spaceNum).extWindowArea;
15235 5 : thisEnclosure.TotalSurfArea += state.dataHeatBal->space(surf.spaceNum).totalSurfArea;
15236 5 : if (otherSideSpaceNum != surf.spaceNum) {
15237 5 : thisEnclosure.ExtWindowArea += state.dataHeatBal->space(otherSideSpaceNum).extWindowArea;
15238 5 : thisEnclosure.TotalSurfArea += state.dataHeatBal->space(otherSideSpaceNum).totalSurfArea;
15239 : }
15240 5 : state.dataHeatBal->space(surf.spaceNum).solarEnclosureNum = thisSideEnclosureNum;
15241 5 : state.dataHeatBal->space(state.dataSurface->Surface(surf.ExtBoundCond).spaceNum).solarEnclosureNum =
15242 : otherSideEnclosureNum;
15243 : }
15244 36 : } else if (thisSideEnclosureNum == 0) {
15245 : // Other side is assigned, so use that one for both
15246 0 : thisSideEnclosureNum = otherSideEnclosureNum;
15247 0 : auto &thisEnclosure = Enclosures(thisSideEnclosureNum);
15248 0 : thisEnclosure.spaceNames.push_back(state.dataHeatBal->space(surf.spaceNum).Name);
15249 0 : thisEnclosure.spaceNums.push_back(surf.spaceNum);
15250 0 : thisEnclosure.FloorArea += state.dataHeatBal->space(surf.spaceNum).FloorArea;
15251 0 : if (radiantSetup) {
15252 0 : state.dataHeatBal->space(surf.spaceNum).radiantEnclosureNum = thisSideEnclosureNum;
15253 : } else {
15254 0 : thisEnclosure.ExtWindowArea += state.dataHeatBal->space(surf.spaceNum).extWindowArea;
15255 0 : thisEnclosure.TotalSurfArea += state.dataHeatBal->space(surf.spaceNum).totalSurfArea;
15256 0 : state.dataHeatBal->space(surf.spaceNum).solarEnclosureNum = thisSideEnclosureNum;
15257 : }
15258 26 : } else if (otherSideEnclosureNum == 0) {
15259 : // This side is assigned, so use that one for both
15260 4 : otherSideEnclosureNum = thisSideEnclosureNum;
15261 4 : auto &thisEnclosure = Enclosures(thisSideEnclosureNum);
15262 4 : thisEnclosure.spaceNames.push_back(state.dataHeatBal->space(state.dataSurface->Surface(surf.ExtBoundCond).spaceNum).Name);
15263 4 : thisEnclosure.spaceNums.push_back(state.dataSurface->Surface(surf.ExtBoundCond).spaceNum);
15264 4 : thisEnclosure.FloorArea += state.dataHeatBal->space(state.dataSurface->Surface(surf.ExtBoundCond).spaceNum).FloorArea;
15265 4 : if (radiantSetup) {
15266 2 : state.dataHeatBal->space(state.dataSurface->Surface(surf.ExtBoundCond).spaceNum).radiantEnclosureNum =
15267 : otherSideEnclosureNum;
15268 : } else {
15269 2 : thisEnclosure.ExtWindowArea +=
15270 2 : state.dataHeatBal->space(state.dataSurface->Surface(surf.ExtBoundCond).spaceNum).extWindowArea;
15271 2 : thisEnclosure.TotalSurfArea +=
15272 2 : state.dataHeatBal->space(state.dataSurface->Surface(surf.ExtBoundCond).spaceNum).totalSurfArea;
15273 2 : state.dataHeatBal->space(state.dataSurface->Surface(surf.ExtBoundCond).spaceNum).solarEnclosureNum =
15274 : otherSideEnclosureNum;
15275 : }
15276 22 : } else if (thisSideEnclosureNum != otherSideEnclosureNum) {
15277 : // If both sides are already assigned to an enclosure, then merge the two enclosures
15278 0 : auto &thisEnclosure = Enclosures(thisSideEnclosureNum);
15279 0 : auto &otherEnclosure = Enclosures(otherSideEnclosureNum);
15280 0 : for (const auto &zName : thisEnclosure.spaceNames) {
15281 0 : otherEnclosure.spaceNames.push_back(zName);
15282 0 : }
15283 0 : for (int zNum : thisEnclosure.spaceNums) {
15284 0 : otherEnclosure.spaceNums.push_back(zNum);
15285 0 : if (radiantSetup) {
15286 0 : state.dataHeatBal->space(zNum).radiantEnclosureNum = otherSideEnclosureNum;
15287 : } else {
15288 0 : state.dataHeatBal->space(zNum).solarEnclosureNum = otherSideEnclosureNum;
15289 : }
15290 0 : }
15291 0 : otherEnclosure.FloorArea += thisEnclosure.FloorArea;
15292 0 : otherEnclosure.ExtWindowArea += thisEnclosure.ExtWindowArea;
15293 0 : otherEnclosure.TotalSurfArea += thisEnclosure.TotalSurfArea;
15294 : // Move any enclosures beyond thisEnclosure down one slot - at this point all enclosures are named "Radiant
15295 : // Enclosure N"
15296 0 : for (int enclNum = thisSideEnclosureNum; enclNum < enclosureNum; ++enclNum) {
15297 0 : std::string saveName = Enclosures(enclNum).Name;
15298 0 : Enclosures(enclNum) = Enclosures(enclNum + 1);
15299 0 : Enclosures(enclNum).Name = saveName;
15300 0 : for (int sNum : Enclosures(enclNum).spaceNums) {
15301 0 : if (radiantSetup) {
15302 0 : state.dataHeatBal->space(sNum).radiantEnclosureNum = enclNum;
15303 : } else {
15304 0 : state.dataHeatBal->space(sNum).solarEnclosureNum = enclNum;
15305 : }
15306 0 : }
15307 0 : }
15308 : // Clear the last rad enclosure and reduce the total number of enclosures by 1
15309 0 : Enclosures(enclosureNum).Name.clear();
15310 0 : Enclosures(enclosureNum).spaceNames.clear();
15311 0 : Enclosures(enclosureNum).spaceNums.clear();
15312 0 : Enclosures(enclosureNum).FloorArea = 0;
15313 0 : Enclosures(enclosureNum).ExtWindowArea = 0;
15314 0 : Enclosures(enclosureNum).TotalSurfArea = 0;
15315 0 : enclosureNum -= 1;
15316 : }
15317 : } else {
15318 0 : ErrorsFound = true;
15319 0 : ShowSevereError(state, format("{}: Surface={} uses Construction:AirBoundary with illegal option:", RoutineName, surf.Name));
15320 0 : if (radiantSetup) {
15321 0 : ShowContinueError(state, "Radiant Exchange Method must be either GroupedSpaces or IRTSurface.");
15322 : } else {
15323 0 : ShowContinueError(state, "Solar and Daylighting Method must be either GroupedSpaces or InteriorWindow");
15324 : }
15325 : }
15326 36 : if (solarSetup && constr.TypeIsAirBoundaryMixing) {
15327 : // Set up mixing air boundaries only once, during solar setup
15328 12 : int spaceNum1 = min(surf.spaceNum, state.dataSurface->Surface(surf.ExtBoundCond).spaceNum);
15329 12 : int spaceNum2 = max(surf.spaceNum, state.dataSurface->Surface(surf.ExtBoundCond).spaceNum);
15330 : // This pair already saved?
15331 12 : bool found = false;
15332 24 : for (auto const &thisAirBoundaryMixing : state.dataHeatBal->airBoundaryMixing) {
15333 18 : if ((spaceNum1 == thisAirBoundaryMixing.space1) && (spaceNum2 == thisAirBoundaryMixing.space2)) {
15334 6 : found = true;
15335 6 : break;
15336 : }
15337 12 : }
15338 12 : if (!found) {
15339 : // Store the space pairs, schedule, and flow rate to use later to create cross mixing objects
15340 : DataHeatBalance::AirBoundaryMixingSpecs newAirBoundaryMixing;
15341 6 : newAirBoundaryMixing.space1 = spaceNum1;
15342 6 : newAirBoundaryMixing.space2 = spaceNum2;
15343 6 : newAirBoundaryMixing.scheduleIndex = state.dataConstruction->Construct(surf.Construction).AirBoundaryMixingSched;
15344 6 : Real64 mixingVolume = state.dataConstruction->Construct(surf.Construction).AirBoundaryACH *
15345 6 : min(state.dataHeatBal->space(spaceNum1).Volume, state.dataHeatBal->space(spaceNum2).Volume) /
15346 6 : Constant::SecInHour;
15347 6 : newAirBoundaryMixing.mixingVolumeFlowRate = mixingVolume;
15348 6 : state.dataHeatBal->airBoundaryMixing.push_back(newAirBoundaryMixing);
15349 : }
15350 : }
15351 : }
15352 : }
15353 10 : if (errorCount > 0) {
15354 0 : ShowSevereError(state, format("{}: {} surfaces use Construction:AirBoundary in non-interzone surfaces.", RoutineName, errorCount));
15355 0 : ShowContinueError(state, "For explicit details on each use, use Output:Diagnostics,DisplayExtraWarnings;");
15356 : }
15357 : }
15358 : // Check for any spaces defined only by floor surface(s) and group them
15359 11704 : for (auto const &zone : state.dataHeatBal->Zone) {
15360 10112 : int newEnclosureNum = 0;
15361 20248 : for (int const spaceNum : zone.spaceIndexes) {
15362 10136 : int spaceEnclosureNum = 0;
15363 10136 : bool spaceHasOnlyFloors = false;
15364 10136 : if (radiantSetup) {
15365 5068 : spaceEnclosureNum = state.dataHeatBal->space(spaceNum).radiantEnclosureNum;
15366 : } else {
15367 5068 : spaceEnclosureNum = state.dataHeatBal->space(spaceNum).solarEnclosureNum;
15368 : }
15369 10136 : if (spaceEnclosureNum == 0) {
15370 10112 : spaceHasOnlyFloors = true;
15371 10458 : for (int const surfNum : state.dataHeatBal->space(spaceNum).surfaces) {
15372 10446 : if (state.dataSurface->Surface(surfNum).Class == SurfaceClass::IntMass) continue;
15373 10438 : if (state.dataSurface->Surface(surfNum).Class != SurfaceClass::Floor) {
15374 10100 : spaceHasOnlyFloors = false;
15375 10100 : break;
15376 : }
15377 10112 : }
15378 : }
15379 10136 : if (spaceEnclosureNum == 0 && spaceHasOnlyFloors) {
15380 12 : anyGroupedSpaces = true;
15381 12 : if (newEnclosureNum == 0) {
15382 : // Assign one new enclosure for all loose floors in this zone
15383 6 : ++enclosureNum;
15384 6 : newEnclosureNum = enclosureNum;
15385 : }
15386 12 : if (radiantSetup) {
15387 6 : state.dataHeatBal->space(spaceNum).radiantEnclosureNum = enclosureNum;
15388 : } else {
15389 6 : state.dataHeatBal->space(spaceNum).solarEnclosureNum = enclosureNum;
15390 : }
15391 12 : auto &thisEnclosure = Enclosures(enclosureNum);
15392 : // Give this enclosure the zone name and assign this to the zone-remainder space if it exists
15393 12 : thisEnclosure.Name = zone.Name;
15394 12 : thisEnclosure.spaceNames.push_back(state.dataHeatBal->space(spaceNum).Name);
15395 12 : thisEnclosure.spaceNums.push_back(spaceNum);
15396 12 : thisEnclosure.FloorArea = state.dataHeatBal->space(spaceNum).FloorArea;
15397 12 : thisEnclosure.ExtWindowArea = state.dataHeatBal->space(spaceNum).extWindowArea;
15398 12 : thisEnclosure.TotalSurfArea = state.dataHeatBal->space(spaceNum).totalSurfArea;
15399 : }
15400 10112 : }
15401 1592 : }
15402 :
15403 1592 : if (anyGroupedSpaces) {
15404 : // All grouped spaces have been assigned to an enclosure, now assign remaining spaces
15405 94 : for (int spaceNum = 1; spaceNum <= state.dataGlobal->numSpaces; ++spaceNum) {
15406 84 : auto &curSpace = state.dataHeatBal->space(spaceNum);
15407 84 : int spaceEnclosureNum = 0;
15408 84 : if (radiantSetup) {
15409 42 : spaceEnclosureNum = curSpace.radiantEnclosureNum;
15410 : } else {
15411 42 : spaceEnclosureNum = curSpace.solarEnclosureNum;
15412 : }
15413 84 : if (spaceEnclosureNum == 0) {
15414 48 : if (Util::SameString(curSpace.Name, state.dataHeatBal->Zone(curSpace.zoneNum).Name + "-REMAINDER")) {
15415 : // Search for existing enclosure with same name as the zone
15416 6 : spaceEnclosureNum = Util::FindItemInList(state.dataHeatBal->Zone(curSpace.zoneNum).Name, Enclosures);
15417 : }
15418 48 : if (spaceEnclosureNum == 0) {
15419 : // Otherwise add a new one named for the space
15420 42 : ++enclosureNum;
15421 42 : spaceEnclosureNum = enclosureNum;
15422 42 : Enclosures(spaceEnclosureNum).Name = curSpace.Name;
15423 : }
15424 48 : if (radiantSetup) {
15425 24 : curSpace.radiantEnclosureNum = spaceEnclosureNum;
15426 : } else {
15427 24 : curSpace.solarEnclosureNum = spaceEnclosureNum;
15428 : }
15429 48 : auto &thisEnclosure = Enclosures(spaceEnclosureNum);
15430 48 : thisEnclosure.spaceNames.push_back(curSpace.Name);
15431 48 : thisEnclosure.spaceNums.push_back(spaceNum);
15432 48 : thisEnclosure.FloorArea += curSpace.FloorArea;
15433 48 : thisEnclosure.ExtWindowArea += curSpace.extWindowArea;
15434 48 : thisEnclosure.TotalSurfArea += curSpace.totalSurfArea;
15435 : }
15436 : }
15437 10 : if (radiantSetup) {
15438 5 : state.dataViewFactor->NumOfRadiantEnclosures = enclosureNum;
15439 : } else {
15440 5 : state.dataViewFactor->NumOfSolarEnclosures = enclosureNum;
15441 : }
15442 : } else {
15443 : // There are no grouped radiant air boundaries, assign each space to it's own radiant enclosure
15444 11634 : for (int spaceNum = 1; spaceNum <= state.dataGlobal->numSpaces; ++spaceNum) {
15445 10052 : auto &thisEnclosure = Enclosures(spaceNum);
15446 10052 : thisEnclosure.Name = state.dataHeatBal->space(spaceNum).Name;
15447 10052 : thisEnclosure.spaceNames.push_back(state.dataHeatBal->space(spaceNum).Name);
15448 10052 : thisEnclosure.spaceNums.push_back(spaceNum);
15449 10052 : thisEnclosure.FloorArea = state.dataHeatBal->space(spaceNum).FloorArea;
15450 10052 : if (radiantSetup) {
15451 5026 : state.dataHeatBal->space(spaceNum).radiantEnclosureNum = spaceNum;
15452 : } else {
15453 5026 : state.dataHeatBal->space(spaceNum).solarEnclosureNum = spaceNum;
15454 5026 : thisEnclosure.ExtWindowArea = state.dataHeatBal->space(spaceNum).extWindowArea;
15455 5026 : thisEnclosure.TotalSurfArea = state.dataHeatBal->space(spaceNum).totalSurfArea;
15456 : }
15457 : }
15458 1582 : if (radiantSetup) {
15459 791 : state.dataViewFactor->NumOfRadiantEnclosures = state.dataGlobal->numSpaces;
15460 : } else {
15461 791 : state.dataViewFactor->NumOfSolarEnclosures = state.dataGlobal->numSpaces;
15462 : }
15463 : }
15464 1592 : if (radiantSetup) {
15465 796 : assert(state.dataViewFactor->NumOfRadiantEnclosures <= int(Enclosures.size()));
15466 796 : Enclosures.resize(state.dataViewFactor->NumOfRadiantEnclosures);
15467 : } else {
15468 796 : assert(state.dataViewFactor->NumOfSolarEnclosures <= int(Enclosures.size()));
15469 796 : Enclosures.resize(state.dataViewFactor->NumOfSolarEnclosures);
15470 : }
15471 :
15472 11702 : for (auto &thisEnclosure : state.dataViewFactor->EnclRadInfo) {
15473 20220 : SetupOutputVariable(state,
15474 : "Enclosure Mean Radiant Temperature",
15475 : Constant::Units::C,
15476 10110 : thisEnclosure.MRT,
15477 : OutputProcessor::TimeStepType::Zone,
15478 : OutputProcessor::StoreType::Average,
15479 10110 : thisEnclosure.Name);
15480 1592 : }
15481 :
15482 : // TODO MJW: For now, set the max and min enclosure numbers for each zone to be used in CalcInteriorRadExchange with ZoneToResimulate
15483 11704 : for (int zoneNum = 1; zoneNum <= state.dataGlobal->NumOfZones; ++zoneNum) {
15484 20248 : for (int spaceNum : state.dataHeatBal->Zone(zoneNum).spaceIndexes) {
15485 10136 : if (state.dataHeatBal->Zone(zoneNum).zoneRadEnclosureFirst == -1) { // initial value
15486 5056 : state.dataHeatBal->Zone(zoneNum).zoneRadEnclosureFirst = state.dataHeatBal->space(spaceNum).radiantEnclosureNum;
15487 : } else {
15488 5080 : state.dataHeatBal->Zone(zoneNum).zoneRadEnclosureFirst =
15489 5080 : min(state.dataHeatBal->Zone(zoneNum).zoneRadEnclosureFirst, state.dataHeatBal->space(spaceNum).radiantEnclosureNum);
15490 : }
15491 10136 : state.dataHeatBal->Zone(zoneNum).zoneRadEnclosureLast =
15492 10136 : max(state.dataHeatBal->Zone(zoneNum).zoneRadEnclosureLast, state.dataHeatBal->space(spaceNum).radiantEnclosureNum);
15493 10112 : }
15494 10112 : assert(state.dataHeatBal->Zone(zoneNum).zoneRadEnclosureFirst != -1);
15495 10112 : assert(state.dataHeatBal->Zone(zoneNum).zoneRadEnclosureLast != -1);
15496 10112 : assert(state.dataHeatBal->Zone(zoneNum).zoneRadEnclosureFirst <= state.dataHeatBal->Zone(zoneNum).zoneRadEnclosureLast);
15497 : }
15498 1592 : }
15499 :
15500 42201 : void CheckConvexity(EnergyPlusData &state,
15501 : int const SurfNum, // Current surface number
15502 : int const NSides // Number of sides to figure
15503 : )
15504 : {
15505 : // SUBROUTINE INFORMATION:
15506 : // AUTHOR Tyler Hoyt
15507 : // DATE WRITTEN December 2010
15508 : // MODIFIED CR8752 - incorrect note of non-convex polygons
15509 : // RE-ENGINEERED na
15510 :
15511 : // PURPOSE OF THIS SUBROUTINE: This subroutine verifies the convexity of a
15512 : // surface that is exposed to the sun in the case that full shading calculations
15513 : // are required. The calculation conveniently detects collinear points as well,
15514 : // and returns a list of indices that are collinear within the plane of the surface.
15515 :
15516 : // METHODOLOGY EMPLOYED: First the surface is determined to have dimension 2 in
15517 : // either the xy, yz, or xz plane. That plane is selected to do the testing.
15518 : // Vectors representing the edges of the polygon and the perpendicular dot product
15519 : // between adjacent edges are computed. This allows the turning angle to be determined.
15520 : // If the turning angle is greater than pi/2, it turns to the right, and if it is
15521 : // less than pi/2, it turns left. The direction of the turn is stored, and if it
15522 : // changes as the edges are iterated the surface is not convex. Meanwhile it stores
15523 : // the indices of vertices that are collinear and are later removed.
15524 :
15525 : // REFERENCES:
15526 : // http://mathworld.wolfram.com/ConvexPolygon.html
15527 :
15528 : // Using/Aliasing
15529 :
15530 : using namespace DataErrorTracking;
15531 :
15532 42201 : constexpr Real64 TurnThreshold(0.000001); // Sensitivity of convexity test, in radians
15533 :
15534 42201 : Real64 LastTheta = 0.0; // Angle between edge vectors
15535 : bool SignFlag; // Direction of edge turn : true is right, false is left
15536 42201 : bool PrevSignFlag(false); // Container for the sign of the previous iteration's edge turn
15537 42201 : bool PrevSignFlagInitialized(false); // Whether we picked a PrevSignFlag already or not
15538 42201 : auto &X = state.dataSurfaceGeometry->X; // containers for x,y,z vertices of the surface
15539 42201 : auto &Y = state.dataSurfaceGeometry->Y;
15540 42201 : auto &Z = state.dataSurfaceGeometry->Z;
15541 42201 : auto &A = state.dataSurfaceGeometry->A; // containers for convexity test
15542 42201 : auto &B = state.dataSurfaceGeometry->B;
15543 42201 : auto &VertSize = state.dataSurfaceGeometry->VertSize; // size of X,Y,Z,A,B arrays
15544 :
15545 42201 : std::vector<int> surfCollinearVerts; // index of vertices to remove, 1-indexed
15546 42201 : surfCollinearVerts.reserve(NSides + 2);
15547 :
15548 42201 : if (state.dataSurfaceGeometry->CheckConvexityFirstTime) {
15549 760 : X.allocate(state.dataSurface->MaxVerticesPerSurface + 2);
15550 760 : Y.allocate(state.dataSurface->MaxVerticesPerSurface + 2);
15551 760 : Z.allocate(state.dataSurface->MaxVerticesPerSurface + 2);
15552 760 : A.allocate(state.dataSurface->MaxVerticesPerSurface + 2);
15553 760 : B.allocate(state.dataSurface->MaxVerticesPerSurface + 2);
15554 760 : VertSize = state.dataSurface->MaxVerticesPerSurface;
15555 760 : state.dataSurfaceGeometry->CheckConvexityFirstTime = false;
15556 : }
15557 :
15558 42201 : if (NSides > VertSize) {
15559 33 : X.deallocate();
15560 33 : Y.deallocate();
15561 33 : Z.deallocate();
15562 33 : A.deallocate();
15563 33 : B.deallocate();
15564 33 : X.allocate(state.dataSurface->MaxVerticesPerSurface + 2);
15565 33 : Y.allocate(state.dataSurface->MaxVerticesPerSurface + 2);
15566 33 : Z.allocate(state.dataSurface->MaxVerticesPerSurface + 2);
15567 33 : A.allocate(state.dataSurface->MaxVerticesPerSurface + 2);
15568 33 : B.allocate(state.dataSurface->MaxVerticesPerSurface + 2);
15569 33 : VertSize = state.dataSurface->MaxVerticesPerSurface;
15570 : }
15571 :
15572 42201 : auto &surfaceTmp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
15573 42201 : auto &vertices = surfaceTmp.Vertex;
15574 :
15575 211868 : for (int n = 1; n <= NSides; ++n) {
15576 169667 : X(n) = vertices(n).x;
15577 169667 : Y(n) = vertices(n).y;
15578 169667 : Z(n) = vertices(n).z;
15579 : }
15580 42201 : X(NSides + 1) = vertices(1).x;
15581 42201 : Y(NSides + 1) = vertices(1).y;
15582 42201 : Z(NSides + 1) = vertices(1).z;
15583 42201 : X(NSides + 2) = vertices(2).x;
15584 42201 : Y(NSides + 2) = vertices(2).y;
15585 42201 : Z(NSides + 2) = vertices(2).z;
15586 :
15587 : // Determine a suitable plane in which to do the tests
15588 42201 : Real64 Det = 0.0;
15589 211868 : for (int n = 1; n <= NSides; ++n) {
15590 169667 : Det += X(n) * Y(n + 1) - X(n + 1) * Y(n);
15591 : }
15592 42201 : if (std::abs(Det) > Constant::SmallDistance) {
15593 13648 : A = X;
15594 13648 : B = Y;
15595 : } else {
15596 28553 : Det = 0.0;
15597 142669 : for (int n = 1; n <= NSides; ++n) {
15598 114116 : Det += X(n) * Z(n + 1) - X(n + 1) * Z(n);
15599 : }
15600 28553 : if (std::abs(Det) > Constant::SmallDistance) {
15601 19242 : A = X;
15602 19242 : B = Z;
15603 : } else {
15604 9311 : Det = 0.0;
15605 46487 : for (int n = 1; n <= NSides; ++n) {
15606 37176 : Det += Y(n) * Z(n + 1) - Y(n + 1) * Z(n);
15607 : }
15608 9311 : if (std::abs(Det) > Constant::SmallDistance) {
15609 9311 : A = Y;
15610 9311 : B = Z;
15611 : } else {
15612 : // This condition should not be reached if the surfaces are guaranteed to be planar already
15613 0 : ShowSevereError(state, format("CheckConvexity: Surface=\"{}\" is non-planar.", surfaceTmp.Name));
15614 0 : ShowContinueError(state, "Coincident Vertices will be removed as possible.");
15615 0 : for (int n = 1; n <= surfaceTmp.Sides; ++n) {
15616 0 : auto const &point = vertices(n);
15617 : static constexpr std::string_view ErrFmt = " ({:8.3F},{:8.3F},{:8.3F})";
15618 0 : ShowContinueError(state, format(ErrFmt, point.x, point.y, point.z));
15619 : }
15620 : }
15621 : }
15622 : }
15623 :
15624 211868 : for (int n = 1; n <= NSides; ++n) { // perform convexity test in the plane determined above.
15625 :
15626 169667 : DataVectorTypes::Vector_2d pt0(A(n), B(n));
15627 169667 : DataVectorTypes::Vector_2d pt1(A(n + 1), B(n + 1));
15628 169667 : DataVectorTypes::Vector_2d pt2(A(n + 2), B(n + 2));
15629 :
15630 169667 : DataVectorTypes::Vector_2d V1 = pt1 - pt0;
15631 169667 : DataVectorTypes::Vector_2d V2 = pt2 - pt1;
15632 :
15633 169667 : Real64 V1len = V1.length(); // = norm_L2()
15634 169667 : Real64 V2len = V2.length();
15635 169667 : if (V1len <= 1.e-8 || V2len <= 1.e-8) {
15636 : // At least two points are coincident. Should this happen? GetVertices is supposed to pop these vertices
15637 0 : continue;
15638 : }
15639 169667 : Real64 CrossProd = V1.cross(V2);
15640 169667 : Real64 sinarg = CrossProd / (V1len * V2len);
15641 169667 : if (sinarg < -1.0) {
15642 884 : sinarg = -1.0;
15643 168783 : } else if (sinarg > 1.0) {
15644 660 : sinarg = 1.0;
15645 : }
15646 169667 : Real64 Theta = std::asin(sinarg);
15647 169667 : if (Theta > TurnThreshold) {
15648 83886 : SignFlag = true;
15649 85781 : } else if (Theta < -TurnThreshold) {
15650 85781 : SignFlag = false;
15651 : } else { // std::abs(Theta) < TurnThreshold
15652 : // Store the index of the collinear vertex for removal
15653 0 : int colinearIndex = n + 1;
15654 0 : if (colinearIndex > NSides) {
15655 0 : colinearIndex -= NSides;
15656 : }
15657 0 : if (state.dataGlobal->DisplayExtraWarnings) {
15658 0 : ShowWarningError(
15659 : state,
15660 0 : format("CheckConvexity: Surface=\"{}\", vertex {} is colinear with previous and next.", surfaceTmp.Name, colinearIndex));
15661 : }
15662 0 : ++state.dataErrTracking->TotalCoincidentVertices;
15663 0 : surfCollinearVerts.push_back(colinearIndex);
15664 0 : continue;
15665 0 : }
15666 :
15667 169667 : if (!PrevSignFlagInitialized) {
15668 42201 : PrevSignFlag = SignFlag;
15669 42201 : LastTheta = Theta;
15670 42201 : PrevSignFlagInitialized = true;
15671 42201 : continue;
15672 : }
15673 :
15674 127466 : if (SignFlag != PrevSignFlag) {
15675 801 : if (state.dataGlobal->DisplayExtraWarnings && surfaceTmp.ExtSolar &&
15676 0 : (state.dataHeatBal->SolarDistribution != DataHeatBalance::Shadowing::Minimal) && surfaceTmp.IsConvex &&
15677 801 : !state.dataSysVars->SutherlandHodgman &&
15678 0 : (state.dataSysVars->shadingMethod == DataSystemVariables::ShadingMethod::PolygonClipping)) {
15679 0 : ShowWarningError(state,
15680 0 : format("CheckConvexity: Zone=\"{}\", Surface=\"{}\" is non-convex.",
15681 0 : state.dataHeatBal->Zone(surfaceTmp.Zone).Name,
15682 0 : surfaceTmp.Name));
15683 0 : int Np1 = n + 1;
15684 0 : if (Np1 > NSides) {
15685 0 : Np1 -= NSides;
15686 : }
15687 0 : int Np2 = n + 2;
15688 0 : if (Np2 > NSides) {
15689 0 : Np2 -= NSides;
15690 : }
15691 0 : ShowContinueError(state, format("...vertex {} to vertex {} to vertex {}", n, Np1, Np2));
15692 0 : ShowContinueError(state, format("...vertex {}=[{:.2R},{:.2R},{:.2R}]", n, X(n), Y(n), Z(n)));
15693 0 : ShowContinueError(state, format("...vertex {}=[{:.2R},{:.2R},{:.2R}]", Np1, X(n + 1), Y(n + 1), Z(n + 1)));
15694 0 : ShowContinueError(state, format("...vertex {}=[{:.2R},{:.2R},{:.2R}]", Np2, X(n + 2), Y(n + 2), Z(n + 2)));
15695 : // ShowContinueError(state, format("...theta angle=[{:.6R}]", Theta));
15696 : // ShowContinueError(state, format("...last theta angle=[{:.6R}]", LastTheta));
15697 : }
15698 801 : surfaceTmp.IsConvex = false;
15699 : // #10103 - We do not want to break early, because we do want to consistently remove colinear vertices
15700 : // to avoid potential vertex size mismatch fatal errors
15701 : // break;
15702 : }
15703 127466 : PrevSignFlag = SignFlag;
15704 127466 : LastTheta = Theta;
15705 338471 : }
15706 :
15707 : // must check to make sure don't remove NSides below 3
15708 42201 : int M = surfCollinearVerts.size();
15709 42201 : if (M > 0) { // Remove the collinear points determined above
15710 0 : if (NSides - M >= 3) {
15711 0 : surfaceTmp.Sides = NSides - M;
15712 0 : if (state.dataGlobal->DisplayExtraWarnings) {
15713 0 : ShowWarningError(state,
15714 0 : format("CheckConvexity: Surface=\"{}\" has [{}] collinear points that have been removed.", surfaceTmp.Name, M));
15715 : }
15716 : } else { // too many
15717 0 : if (state.dataGlobal->DisplayExtraWarnings) {
15718 0 : ShowWarningError(state, format("CheckConvexity: Surface=\"{}\" has [{}] collinear points.", surfaceTmp.Name, M));
15719 0 : ShowContinueError(state, "...too many to remove all. Will leave the surface with 3 sides. But this is now a degenerate surface");
15720 : }
15721 0 : ++state.dataErrTracking->TotalDegenerateSurfaces;
15722 0 : surfaceTmp.Sides = 3; // max(NSides - M, 3) = 3 since NSide - M is < 3;
15723 0 : surfCollinearVerts.resize(NSides - 3);
15724 : }
15725 :
15726 : // remove duplicated points: For that we construct a new array of vertices, only copying indices that aren't in SurfCollinearVerts
15727 : // Then we move that array into the original one
15728 0 : Array1D<Vector> newVertices;
15729 0 : newVertices.allocate(surfaceTmp.Sides);
15730 :
15731 0 : int n = 0;
15732 0 : for (int i = 1; i <= NSides; ++i) {
15733 0 : if (std::find(surfCollinearVerts.cbegin(), surfCollinearVerts.cend(), i) == surfCollinearVerts.cend()) {
15734 0 : newVertices(++n) = vertices(i);
15735 : }
15736 : }
15737 0 : vertices = std::move(newVertices);
15738 :
15739 0 : if (state.dataGlobal->DisplayExtraWarnings) {
15740 0 : ShowWarningError(state,
15741 0 : format("CheckConvexity: Surface=\"{}\": The vertex points has been reprocessed as Sides = {}",
15742 0 : surfaceTmp.Name,
15743 0 : surfaceTmp.Sides));
15744 : }
15745 0 : }
15746 42201 : }
15747 :
15748 43251 : bool isRectangle(EnergyPlusData &state, int const ThisSurf // Surface number
15749 : )
15750 : {
15751 : // SUBROUTINE INFORMATION:
15752 : // AUTHOR M.J. Witte
15753 : // DATE WRITTEN October 2015
15754 :
15755 : // PURPOSE: Check if a 4-sided surface is a rectangle
15756 :
15757 : using namespace Vectors;
15758 :
15759 : Real64 Diagonal1; // Length of diagonal of 4-sided figure from vertex 1 to vertex 3 (m)
15760 : Real64 Diagonal2; // Length of diagonal of 4-sided figure from vertex 2 to vertex 4 (m)
15761 : Real64 DotProd; // Dot product of two adjacent sides - to test for right angle
15762 43251 : Real64 const cos89deg = std::cos(89.0 * Constant::DegToRadians); // tolerance for right angle
15763 43251 : Vector Vect32; // normalized vector from vertex 3 to vertex 2
15764 43251 : Vector Vect21; // normalized vector from vertex 2 to vertex 1
15765 :
15766 43251 : auto &surf = state.dataSurface->Surface(ThisSurf);
15767 43251 : Diagonal1 = VecLength(surf.Vertex(1) - surf.Vertex(3));
15768 43251 : Diagonal2 = VecLength(surf.Vertex(2) - surf.Vertex(4));
15769 : // Test for rectangularity
15770 43251 : if (std::abs(Diagonal1 - Diagonal2) < 0.020) { // This tolerance based on coincident vertex tolerance of 0.01
15771 41806 : Vect32 = VecNormalize(surf.Vertex(3) - surf.Vertex(2));
15772 41806 : Vect21 = VecNormalize(surf.Vertex(2) - surf.Vertex(1));
15773 41806 : DotProd = dot(Vect32, Vect21);
15774 41806 : if (std::abs(DotProd) <= cos89deg) {
15775 38007 : return true;
15776 : } else {
15777 3799 : return false;
15778 : }
15779 : } else {
15780 1445 : return false;
15781 : }
15782 43251 : }
15783 :
15784 1 : void MakeEquivalentRectangle(EnergyPlusData &state,
15785 : int const SurfNum, // Surface number
15786 : bool &ErrorsFound // Error flag indicator (true if errors found)
15787 : )
15788 : {
15789 : // SUBROUTINE INFORMATION:
15790 : // AUTHOR R. Zhang, LBNL
15791 : // DATE WRITTEN September 2016
15792 : // MODIFIED na
15793 : // RE-ENGINEERED na
15794 :
15795 : // PURPOSE OF THIS SUBROUTINE:
15796 : // Processing of 4-sided but non-rectangular Window, Door or GlassDoor.
15797 : // Calculate the effective height and width of the surface.
15798 : //
15799 : // METHODOLOGY EMPLOYED:
15800 : // Transform the surface into an equivalent rectangular surface with the same area and aspect ratio.
15801 :
15802 : Real64 BaseCosAzimuth;
15803 : Real64 BaseCosTilt;
15804 : Real64 BaseSinAzimuth;
15805 : Real64 BaseSinTilt;
15806 : Real64 SurfWorldAz;
15807 : Real64 SurfTilt;
15808 : Real64 AspectRatio; // Aspect ratio
15809 : Real64 NumSurfSides; // Number of surface sides
15810 : Real64 WidthEff; // Effective width of the surface
15811 : Real64 WidthMax; // X difference between the vertex on the most left and the one on the most right
15812 : Real64 HeightEff; // Effective height of the surface
15813 : Real64 HeightMax; // Y difference between the lowest and toppest vertices
15814 : Real64 Xp;
15815 : Real64 Yp;
15816 : Real64 Zp;
15817 : Real64 XLLC;
15818 : Real64 YLLC;
15819 : Real64 ZLLC;
15820 :
15821 1 : if (SurfNum == 0) {
15822 : // invalid surface
15823 0 : ErrorsFound = true;
15824 0 : return;
15825 : }
15826 :
15827 1 : auto &surf = state.dataSurface->Surface(SurfNum);
15828 1 : if (surf.Sides != 4) {
15829 : // the method is designed for 4-sided surface
15830 0 : return;
15831 1 : } else if (isRectangle(state, SurfNum)) {
15832 : // no need to transform
15833 0 : return;
15834 : }
15835 :
15836 1 : SurfWorldAz = surf.Azimuth;
15837 1 : SurfTilt = surf.Tilt;
15838 1 : BaseCosAzimuth = std::cos(SurfWorldAz * Constant::DegToRadians);
15839 1 : BaseSinAzimuth = std::sin(SurfWorldAz * Constant::DegToRadians);
15840 1 : BaseCosTilt = std::cos(SurfTilt * Constant::DegToRadians);
15841 1 : BaseSinTilt = std::sin(SurfTilt * Constant::DegToRadians);
15842 1 : NumSurfSides = surf.Sides;
15843 :
15844 : // Calculate WidthMax and HeightMax
15845 1 : WidthMax = 0.0;
15846 1 : HeightMax = 0.0;
15847 4 : for (int i = 1; i < NumSurfSides; ++i) {
15848 9 : for (int j = i + 1; j <= NumSurfSides; ++j) {
15849 :
15850 6 : Xp = surf.Vertex(j).x - surf.Vertex(i).x;
15851 6 : Yp = surf.Vertex(j).y - surf.Vertex(i).y;
15852 6 : Zp = surf.Vertex(j).z - surf.Vertex(i).z;
15853 :
15854 6 : XLLC = -Xp * BaseCosAzimuth + Yp * BaseSinAzimuth;
15855 6 : YLLC = -Xp * BaseSinAzimuth * BaseCosTilt - Yp * BaseCosAzimuth * BaseCosTilt + Zp * BaseSinTilt;
15856 6 : ZLLC = Xp * BaseSinAzimuth * BaseSinTilt + Yp * BaseCosAzimuth * BaseSinTilt + Zp * BaseCosTilt;
15857 :
15858 6 : if (std::abs(XLLC) > WidthMax) WidthMax = std::abs(XLLC);
15859 6 : if (std::abs(YLLC) > WidthMax) HeightMax = std::abs(YLLC);
15860 : }
15861 : }
15862 :
15863 : // Perform transformation by calculating WidthEff and HeightEff
15864 1 : if ((WidthMax > 0) && (HeightMax > 0)) {
15865 1 : AspectRatio = WidthMax / HeightMax;
15866 : } else {
15867 0 : AspectRatio = 1;
15868 : }
15869 1 : WidthEff = std::sqrt(surf.Area * AspectRatio);
15870 1 : HeightEff = std::sqrt(surf.Area / AspectRatio);
15871 :
15872 : // Assign the effective width and length to the surface
15873 1 : surf.Width = WidthEff;
15874 1 : surf.Height = HeightEff;
15875 : }
15876 :
15877 8915 : void CheckForReversedLayers(EnergyPlusData &state,
15878 : bool &RevLayerDiffs, // true when differences are discovered in interzone constructions
15879 : int const ConstrNum, // construction index
15880 : int const ConstrNumRev, // construction index for reversed construction
15881 : int const TotalLayers // total layers for construction definition
15882 : )
15883 : {
15884 8915 : RevLayerDiffs = false;
15885 :
15886 27825 : for (int LayerNo = 1; LayerNo <= TotalLayers; ++LayerNo) {
15887 :
15888 18912 : int thisConstLayer = state.dataConstruction->Construct(ConstrNum).LayerPoint(LayerNo);
15889 18912 : int revConstLayer = state.dataConstruction->Construct(ConstrNumRev).LayerPoint(TotalLayers - LayerNo + 1);
15890 :
15891 18912 : auto *thisMatLay = dynamic_cast<Material::MaterialChild *>(state.dataMaterial->Material(thisConstLayer));
15892 18912 : assert(thisMatLay != nullptr);
15893 18912 : auto *revMatLay = dynamic_cast<Material::MaterialChild *>(state.dataMaterial->Material(revConstLayer));
15894 18912 : assert(revMatLay != nullptr);
15895 18912 : if ((thisConstLayer != revConstLayer) || // Not pointing to the same layer
15896 18910 : (thisMatLay->group == Material::Group::WindowGlass) || // Not window glass or glass equivalent layer which have
15897 18903 : (revMatLay->group == Material::Group::WindowGlass) || // to have certain properties flipped from front to back
15898 18903 : (thisMatLay->group == Material::Group::GlassEquivalentLayer) || (revMatLay->group == Material::Group::GlassEquivalentLayer)) {
15899 : // If not point to the same layer, check to see if this is window glass which might need to have
15900 : // front and back material properties reversed.
15901 9 : Real64 constexpr SmallDiff = 0.0001;
15902 9 : if ((thisMatLay->group == Material::Group::WindowGlass) && (revMatLay->group == Material::Group::WindowGlass)) {
15903 : // Both layers are window glass, so need to check to see if the properties are reversed
15904 14 : if ((abs(thisMatLay->Thickness - revMatLay->Thickness) > SmallDiff) ||
15905 14 : (abs(thisMatLay->ReflectSolBeamBack - revMatLay->ReflectSolBeamFront) > SmallDiff) ||
15906 14 : (abs(thisMatLay->ReflectSolBeamFront - revMatLay->ReflectSolBeamBack) > SmallDiff) ||
15907 14 : (abs(thisMatLay->TransVis - revMatLay->TransVis) > SmallDiff) ||
15908 14 : (abs(thisMatLay->ReflectVisBeamBack - revMatLay->ReflectVisBeamFront) > SmallDiff) ||
15909 14 : (abs(thisMatLay->ReflectVisBeamFront - revMatLay->ReflectVisBeamBack) > SmallDiff) ||
15910 14 : (abs(thisMatLay->TransThermal - revMatLay->TransThermal) > SmallDiff) ||
15911 14 : (abs(thisMatLay->AbsorpThermalBack - revMatLay->AbsorpThermalFront) > SmallDiff) ||
15912 14 : (abs(thisMatLay->AbsorpThermalFront - revMatLay->AbsorpThermalBack) > SmallDiff) ||
15913 14 : (abs(thisMatLay->Conductivity - revMatLay->Conductivity) > SmallDiff) ||
15914 7 : (abs(thisMatLay->GlassTransDirtFactor - revMatLay->GlassTransDirtFactor) > SmallDiff) ||
15915 14 : (thisMatLay->SolarDiffusing != revMatLay->SolarDiffusing) ||
15916 21 : (abs(thisMatLay->YoungModulus - revMatLay->YoungModulus) > SmallDiff) ||
15917 7 : (abs(thisMatLay->PoissonsRatio - revMatLay->PoissonsRatio) > SmallDiff)) {
15918 0 : RevLayerDiffs = true;
15919 0 : break; // exit when diff
15920 : } // If none of the above conditions is met, then these should be the same layers in reverse (RevLayersDiffs = false)
15921 2 : } else if ((thisMatLay->group == Material::Group::GlassEquivalentLayer) &&
15922 0 : (revMatLay->group == Material::Group::GlassEquivalentLayer)) {
15923 0 : if ((abs(thisMatLay->TausBackBeamBeam - revMatLay->TausFrontBeamBeam) > SmallDiff) ||
15924 0 : (abs(thisMatLay->TausFrontBeamBeam - revMatLay->TausBackBeamBeam) > SmallDiff) ||
15925 0 : (abs(thisMatLay->ReflBackBeamBeam - revMatLay->ReflFrontBeamBeam) > SmallDiff) ||
15926 0 : (abs(thisMatLay->ReflFrontBeamBeam - revMatLay->ReflBackBeamBeam) > SmallDiff) ||
15927 0 : (abs(thisMatLay->TausBackBeamBeamVis - revMatLay->TausFrontBeamBeamVis) > SmallDiff) ||
15928 0 : (abs(thisMatLay->TausFrontBeamBeamVis - revMatLay->TausBackBeamBeamVis) > SmallDiff) ||
15929 0 : (abs(thisMatLay->ReflBackBeamBeamVis - revMatLay->ReflFrontBeamBeamVis) > SmallDiff) ||
15930 0 : (abs(thisMatLay->ReflFrontBeamBeamVis - revMatLay->ReflBackBeamBeamVis) > SmallDiff) ||
15931 0 : (abs(thisMatLay->TausBackBeamDiff - revMatLay->TausFrontBeamDiff) > SmallDiff) ||
15932 0 : (abs(thisMatLay->TausFrontBeamDiff - revMatLay->TausBackBeamDiff) > SmallDiff) ||
15933 0 : (abs(thisMatLay->ReflBackBeamDiff - revMatLay->ReflFrontBeamDiff) > SmallDiff) ||
15934 0 : (abs(thisMatLay->ReflFrontBeamDiff - revMatLay->ReflBackBeamDiff) > SmallDiff) ||
15935 0 : (abs(thisMatLay->TausBackBeamDiffVis - revMatLay->TausFrontBeamDiffVis) > SmallDiff) ||
15936 0 : (abs(thisMatLay->TausFrontBeamDiffVis - revMatLay->TausBackBeamDiffVis) > SmallDiff) ||
15937 0 : (abs(thisMatLay->ReflBackBeamDiffVis - revMatLay->ReflFrontBeamDiffVis) > SmallDiff) ||
15938 0 : (abs(thisMatLay->ReflFrontBeamDiffVis - revMatLay->ReflBackBeamDiffVis) > SmallDiff) ||
15939 0 : (abs(thisMatLay->TausDiffDiff - revMatLay->TausDiffDiff) > SmallDiff) ||
15940 0 : (abs(thisMatLay->ReflBackDiffDiff - revMatLay->ReflFrontDiffDiff) > SmallDiff) ||
15941 0 : (abs(thisMatLay->ReflFrontDiffDiff - revMatLay->ReflBackDiffDiff) > SmallDiff) ||
15942 0 : (abs(thisMatLay->TausDiffDiffVis - revMatLay->TausDiffDiffVis) > SmallDiff) ||
15943 0 : (abs(thisMatLay->ReflBackDiffDiffVis - revMatLay->ReflFrontDiffDiffVis) > SmallDiff) ||
15944 0 : (abs(thisMatLay->ReflFrontDiffDiffVis - revMatLay->ReflBackDiffDiffVis) > SmallDiff) ||
15945 0 : (abs(thisMatLay->TausThermal - revMatLay->TausThermal) > SmallDiff) ||
15946 0 : (abs(thisMatLay->EmissThermalBack - revMatLay->EmissThermalFront) > SmallDiff) ||
15947 0 : (abs(thisMatLay->EmissThermalFront - revMatLay->EmissThermalBack) > SmallDiff) ||
15948 0 : (abs(thisMatLay->Resistance - revMatLay->Resistance) > SmallDiff)) {
15949 0 : RevLayerDiffs = true;
15950 0 : break; // exit when diff
15951 : } // If none of the above conditions is met, then these should be the same layers in reverse (RevLayersDiffs = false)
15952 : } else {
15953 : // Other material types do not have reversed constructions so if they are not the same layer there is a problem
15954 : // (RevLayersDiffs = true)
15955 2 : RevLayerDiffs = true;
15956 2 : break; // exit when diff
15957 : } // End check of whether or not these are WindowGlass
15958 : } // else: thisConstLayer is the same as revConstLayer--so there is no problem (RevLayersDiffs = false)
15959 : }
15960 8915 : }
15961 :
15962 796 : void GetGeoSummaryRoof(EnergyPlusData &state, GeoSummary &geoSummaryRoof)
15963 : {
15964 796 : std::vector<Vector> uniqueRoofVertices;
15965 796 : std::vector<SurfaceGeometry::EdgeOfSurf> uniqEdgeOfSurfs; // I'm only partially using this
15966 46840 : for (const auto &surface : state.dataSurface->Surface) {
15967 :
15968 46044 : if (surface.ExtBoundCond != ExternalEnvironment) {
15969 26609 : continue;
15970 : }
15971 19435 : if (!surface.HeatTransSurf) {
15972 1635 : continue;
15973 : }
15974 :
15975 17800 : if (surface.Tilt > 45.0) { // TODO Double check tilt wrt outside vs inside?
15976 15212 : continue;
15977 : }
15978 :
15979 2588 : Real64 const z_min(minval(surface.Vertex, &Vector::z));
15980 2588 : Real64 const z_max(maxval(surface.Vertex, &Vector::z));
15981 2588 : Real64 const verticalHeight = z_max - z_min;
15982 2588 : geoSummaryRoof.Height += verticalHeight * surface.Area;
15983 2588 : geoSummaryRoof.Tilt += surface.Tilt * surface.Area;
15984 2588 : geoSummaryRoof.Azimuth += surface.Azimuth * surface.Area;
15985 2588 : geoSummaryRoof.Area += surface.Area;
15986 :
15987 13128 : for (auto it = surface.Vertex.begin(); it != surface.Vertex.end(); ++it) {
15988 :
15989 10540 : auto itnext = std::next(it);
15990 10540 : if (itnext == std::end(surface.Vertex)) {
15991 2588 : itnext = std::begin(surface.Vertex);
15992 : }
15993 :
15994 10540 : auto &curVertex = *it;
15995 10540 : auto &nextVertex = *itnext;
15996 21080 : auto it2 = std::find_if(uniqueRoofVertices.begin(), uniqueRoofVertices.end(), [&curVertex](const auto &unqV) {
15997 381270 : return SurfaceGeometry::isAlmostEqual3dPt(curVertex, unqV);
15998 21080 : });
15999 10540 : if (it2 == std::end(uniqueRoofVertices)) {
16000 7960 : uniqueRoofVertices.emplace_back(curVertex);
16001 : }
16002 :
16003 10540 : SurfaceGeometry::EdgeOfSurf thisEdge;
16004 10540 : thisEdge.start = std::move(curVertex);
16005 10540 : thisEdge.end = std::move(nextVertex);
16006 10540 : thisEdge.count = 1;
16007 :
16008 : // Uses the custom operator== that uses isAlmostEqual3dPt internally and doesn't care about order of the start/end
16009 21080 : auto itEdge = std::find(uniqEdgeOfSurfs.begin(), uniqEdgeOfSurfs.end(), thisEdge);
16010 10540 : if (itEdge == uniqEdgeOfSurfs.end()) {
16011 9458 : uniqEdgeOfSurfs.emplace_back(std::move(thisEdge));
16012 : } else {
16013 1082 : ++(itEdge->count);
16014 : }
16015 10540 : }
16016 796 : }
16017 :
16018 796 : if (geoSummaryRoof.Area > 0) {
16019 744 : geoSummaryRoof.Height /= geoSummaryRoof.Area;
16020 744 : geoSummaryRoof.Tilt /= geoSummaryRoof.Area;
16021 744 : geoSummaryRoof.Azimuth /= geoSummaryRoof.Area;
16022 : } else {
16023 52 : geoSummaryRoof.Height = 0.0;
16024 52 : geoSummaryRoof.Tilt = 0.0;
16025 52 : geoSummaryRoof.Azimuth = 0.0;
16026 : }
16027 :
16028 : // Remove the ones that are already used twice
16029 1592 : uniqEdgeOfSurfs.erase(
16030 11050 : std::remove_if(uniqEdgeOfSurfs.begin(), uniqEdgeOfSurfs.end(), [](const auto &edge) -> bool { return edge.count == 2; }),
16031 1592 : uniqEdgeOfSurfs.end());
16032 :
16033 : // Intersect with unique vertices as much as needed
16034 796 : bool insertedVertext = true;
16035 2507 : while (insertedVertext) {
16036 1711 : insertedVertext = false;
16037 :
16038 40367 : for (auto &edge : uniqEdgeOfSurfs) {
16039 :
16040 : // now go through all the vertices and see if they are colinear with start and end vertices
16041 6155768 : for (const auto &testVertex : uniqueRoofVertices) {
16042 6117112 : if (edge.containsPoints(testVertex)) {
16043 915 : SurfaceGeometry::EdgeOfSurf newEdgeOfSurface;
16044 915 : newEdgeOfSurface.start = testVertex;
16045 915 : newEdgeOfSurface.end = edge.end;
16046 915 : edge.end = testVertex;
16047 915 : uniqEdgeOfSurfs.emplace_back(std::move(newEdgeOfSurface));
16048 915 : insertedVertext = true;
16049 915 : break;
16050 915 : }
16051 39571 : }
16052 : // Break out of the loop on edges, and start again at the while
16053 39571 : if (insertedVertext) {
16054 915 : break;
16055 : }
16056 1711 : }
16057 : }
16058 :
16059 : // recount
16060 10087 : for (auto &edge : uniqEdgeOfSurfs) {
16061 9291 : edge.count = std::count(uniqEdgeOfSurfs.begin(), uniqEdgeOfSurfs.end(), edge);
16062 796 : }
16063 :
16064 1592 : uniqEdgeOfSurfs.erase(
16065 10883 : std::remove_if(uniqEdgeOfSurfs.begin(), uniqEdgeOfSurfs.end(), [](const auto &edge) -> bool { return edge.count == 2; }),
16066 1592 : uniqEdgeOfSurfs.end());
16067 :
16068 796 : geoSummaryRoof.Perimeter =
16069 796 : std::accumulate(uniqEdgeOfSurfs.cbegin(), uniqEdgeOfSurfs.cend(), 0.0, [](const double &sum, const SurfaceGeometry::EdgeOfSurf &edge) {
16070 7155 : return sum + edge.length();
16071 : });
16072 796 : }
16073 :
16074 : } // namespace SurfaceGeometry
16075 :
16076 : } // namespace EnergyPlus
|