Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2025, The Board of Trustees of the University of Illinois,
2 : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
3 : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
4 : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
5 : // contributors. All rights reserved.
6 : //
7 : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
8 : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
9 : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
10 : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
11 : // derivative works, and perform publicly and display publicly, and to permit others to do so.
12 : //
13 : // Redistribution and use in source and binary forms, with or without modification, are permitted
14 : // provided that the following conditions are met:
15 : //
16 : // (1) Redistributions of source code must retain the above copyright notice, this list of
17 : // conditions and the following disclaimer.
18 : //
19 : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
20 : // conditions and the following disclaimer in the documentation and/or other materials
21 : // provided with the distribution.
22 : //
23 : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
24 : // the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
25 : // used to endorse or promote products derived from this software without specific prior
26 : // written permission.
27 : //
28 : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
29 : // without changes from the version obtained under this License, or (ii) Licensee makes a
30 : // reference solely to the software portion of its product, Licensee must refer to the
31 : // software as "EnergyPlus version X" software, where "X" is the version number Licensee
32 : // obtained under this License and may not use a different name for the software. Except as
33 : // specifically required in this Section (4), Licensee shall not use in a company name, a
34 : // product name, in advertising, publicity, or other promotional activities any name, trade
35 : // name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
36 : // similar designation, without the U.S. Department of Energy's prior written consent.
37 : //
38 : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
39 : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
40 : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
41 : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
42 : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
43 : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
44 : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
45 : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
46 : // POSSIBILITY OF SUCH DAMAGE.
47 :
48 : // C++ Headers
49 : #include <algorithm>
50 : #include <cassert>
51 : #include <cmath>
52 : #include <string>
53 :
54 : // ObjexxFCL Headers
55 : #include <ObjexxFCL/member.functions.hh>
56 : #include <ObjexxFCL/string.functions.hh>
57 :
58 : // EnergyPlus Headers
59 : #include <EnergyPlus/Construction.hh>
60 : #include <EnergyPlus/ConvectionCoefficients.hh>
61 : #include <EnergyPlus/ConvectionConstants.hh>
62 : #include <EnergyPlus/Data/EnergyPlusData.hh>
63 : #include <EnergyPlus/DataEnvironment.hh>
64 : #include <EnergyPlus/DataErrorTracking.hh>
65 : #include <EnergyPlus/DataHeatBalSurface.hh>
66 : #include <EnergyPlus/DataHeatBalance.hh>
67 : #include <EnergyPlus/DataIPShortCuts.hh>
68 : #include <EnergyPlus/DataLoopNode.hh>
69 : #include <EnergyPlus/DataReportingFlags.hh>
70 : #include <EnergyPlus/DataSystemVariables.hh>
71 : #include <EnergyPlus/DataViewFactorInformation.hh>
72 : #include <EnergyPlus/DataWindowEquivalentLayer.hh>
73 : #include <EnergyPlus/DataZoneEquipment.hh>
74 : #include <EnergyPlus/DaylightingManager.hh>
75 : #include <EnergyPlus/DisplayRoutines.hh>
76 : #include <EnergyPlus/EMSManager.hh>
77 : #include <EnergyPlus/General.hh>
78 : #include <EnergyPlus/GlobalNames.hh>
79 : #include <EnergyPlus/HeatBalanceManager.hh>
80 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
81 : #include <EnergyPlus/Material.hh>
82 : #include <EnergyPlus/NodeInputManager.hh>
83 : #include <EnergyPlus/OutAirNodeManager.hh>
84 : #include <EnergyPlus/OutputProcessor.hh>
85 : #include <EnergyPlus/OutputReportPredefined.hh>
86 : #include <EnergyPlus/ScheduleManager.hh>
87 : #include <EnergyPlus/SolarShading.hh>
88 : #include <EnergyPlus/SurfaceGeometry.hh>
89 : #include <EnergyPlus/UtilityRoutines.hh>
90 : #include <EnergyPlus/Vectors.hh>
91 : #include <EnergyPlus/WeatherManager.hh>
92 : #include <EnergyPlus/WindowManager.hh>
93 : #include <EnergyPlus/ZoneEquipmentManager.hh>
94 :
95 : namespace EnergyPlus {
96 :
97 : namespace SurfaceGeometry {
98 :
99 : // Module containing the routines dealing with the Surface Geometry
100 :
101 : // MODULE INFORMATION:
102 : // AUTHOR Linda Lawrie
103 : // DATE WRITTEN June 2000
104 : // MODIFIED DJS (PSU Dec 2006) to add ecoroof
105 :
106 : // PURPOSE OF THIS MODULE:
107 : // This module performs the functions required of the surface geometry.
108 :
109 : static std::string const BlankString;
110 :
111 : int constexpr unenteredAdjacentSpaceSurface = -997; // allows users to enter one zone surface ("Space")
112 : // referencing another in adjacent space
113 : int constexpr unenteredAdjacentZoneSurface = -998; // allows users to enter one zone surface ("Zone")
114 : // referencing another in adjacent zone
115 : int constexpr unreconciledZoneSurface = -999; // interim value between entering surfaces ("Surface") and reconciling
116 :
117 801 : void AllocateSurfaceWindows(EnergyPlusData &state, int NumSurfaces)
118 : {
119 801 : state.dataSurface->SurfWinA.dimension(state.dataSurface->TotSurfaces, DataWindowEquivalentLayer::CFSMAXNL + 1, 0.0);
120 801 : state.dataSurface->SurfWinADiffFront.dimension(state.dataSurface->TotSurfaces, DataWindowEquivalentLayer::CFSMAXNL + 1, 0.0);
121 801 : state.dataSurface->SurfWinACFOverlap.dimension(state.dataSurface->TotSurfaces, state.dataHeatBal->MaxSolidWinLayers, 0.0);
122 :
123 801 : state.dataSurface->SurfWinFrameQRadOutAbs.dimension(NumSurfaces, 0);
124 801 : state.dataSurface->SurfWinFrameQRadInAbs.dimension(NumSurfaces, 0);
125 801 : state.dataSurface->SurfWinDividerQRadOutAbs.dimension(NumSurfaces, 0);
126 801 : state.dataSurface->SurfWinDividerQRadInAbs.dimension(NumSurfaces, 0);
127 801 : state.dataSurface->SurfWinExtBeamAbsByShade.dimension(NumSurfaces, 0);
128 801 : state.dataSurface->SurfWinExtDiffAbsByShade.dimension(NumSurfaces, 0);
129 801 : state.dataSurface->SurfWinIntBeamAbsByShade.dimension(NumSurfaces, 0);
130 801 : state.dataSurface->SurfWinIntSWAbsByShade.dimension(NumSurfaces, 0);
131 801 : state.dataSurface->SurfWinInitialDifSolAbsByShade.dimension(NumSurfaces, 0);
132 801 : state.dataSurface->SurfWinIntLWAbsByShade.dimension(NumSurfaces, 0);
133 801 : state.dataSurface->SurfWinConvHeatFlowNatural.dimension(NumSurfaces, 0);
134 801 : state.dataSurface->SurfWinConvHeatGainToZoneAir.dimension(NumSurfaces, 0);
135 801 : state.dataSurface->SurfWinRetHeatGainToZoneAir.dimension(NumSurfaces, 0);
136 801 : state.dataSurface->SurfWinDividerHeatGain.dimension(NumSurfaces, 0);
137 801 : state.dataSurface->SurfWinBlTsolBmBm.dimension(NumSurfaces, 0);
138 801 : state.dataSurface->SurfWinBlTsolBmDif.dimension(NumSurfaces, 0);
139 801 : state.dataSurface->SurfWinBlTsolDifDif.dimension(NumSurfaces, 0);
140 801 : state.dataSurface->SurfWinBlGlSysTsolBmBm.dimension(NumSurfaces, 0);
141 801 : state.dataSurface->SurfWinBlGlSysTsolDifDif.dimension(NumSurfaces, 0);
142 801 : state.dataSurface->SurfWinScTsolBmBm.dimension(NumSurfaces, 0);
143 801 : state.dataSurface->SurfWinScTsolBmDif.dimension(NumSurfaces, 0);
144 801 : state.dataSurface->SurfWinScTsolDifDif.dimension(NumSurfaces, 0);
145 801 : state.dataSurface->SurfWinScGlSysTsolBmBm.dimension(NumSurfaces, 0);
146 801 : state.dataSurface->SurfWinScGlSysTsolDifDif.dimension(NumSurfaces, 0);
147 801 : state.dataSurface->SurfWinGlTsolBmBm.dimension(NumSurfaces, 0);
148 801 : state.dataSurface->SurfWinGlTsolBmDif.dimension(NumSurfaces, 0);
149 801 : state.dataSurface->SurfWinGlTsolDifDif.dimension(NumSurfaces, 0);
150 801 : state.dataSurface->SurfWinBmSolTransThruIntWinRep.dimension(NumSurfaces, 0);
151 801 : state.dataSurface->SurfWinBmSolAbsdOutsReveal.dimension(NumSurfaces, 0);
152 801 : state.dataSurface->SurfWinBmSolRefldOutsRevealReport.dimension(NumSurfaces, 0);
153 801 : state.dataSurface->SurfWinBmSolAbsdInsReveal.dimension(NumSurfaces, 0);
154 801 : state.dataSurface->SurfWinBmSolRefldInsReveal.dimension(NumSurfaces, 0);
155 801 : state.dataSurface->SurfWinBmSolRefldInsRevealReport.dimension(NumSurfaces, 0);
156 801 : state.dataSurface->SurfWinOutsRevealDiffOntoGlazing.dimension(NumSurfaces, 0);
157 801 : state.dataSurface->SurfWinInsRevealDiffOntoGlazing.dimension(NumSurfaces, 0);
158 801 : state.dataSurface->SurfWinInsRevealDiffIntoZone.dimension(NumSurfaces, 0);
159 801 : state.dataSurface->SurfWinOutsRevealDiffOntoFrame.dimension(NumSurfaces, 0);
160 801 : state.dataSurface->SurfWinInsRevealDiffOntoFrame.dimension(NumSurfaces, 0);
161 801 : state.dataSurface->SurfWinInsRevealDiffOntoGlazingReport.dimension(NumSurfaces, 0);
162 801 : state.dataSurface->SurfWinInsRevealDiffIntoZoneReport.dimension(NumSurfaces, 0);
163 801 : state.dataSurface->SurfWinInsRevealDiffOntoFrameReport.dimension(NumSurfaces, 0);
164 801 : state.dataSurface->SurfWinBmSolAbsdInsRevealReport.dimension(NumSurfaces, 0);
165 801 : state.dataSurface->SurfWinBmSolTransThruIntWinRepEnergy.dimension(NumSurfaces, 0);
166 801 : state.dataSurface->SurfWinBmSolRefldOutsRevealRepEnergy.dimension(NumSurfaces, 0);
167 801 : state.dataSurface->SurfWinBmSolRefldInsRevealRepEnergy.dimension(NumSurfaces, 0);
168 801 : state.dataSurface->SurfWinProfileAngHor.dimension(NumSurfaces, 0);
169 801 : state.dataSurface->SurfWinProfileAngVert.dimension(NumSurfaces, 0);
170 :
171 801 : state.dataSurface->SurfWinShadingFlag.dimension(NumSurfaces, DataSurfaces::WinShadingType::ShadeOff);
172 801 : state.dataSurface->SurfWinShadingFlagEMSOn.dimension(NumSurfaces, 0);
173 801 : state.dataSurface->SurfWinShadingFlagEMSValue.dimension(NumSurfaces, 0.0);
174 801 : state.dataSurface->SurfWinStormWinFlag.dimension(NumSurfaces, 0);
175 801 : state.dataSurface->SurfWinStormWinFlagPrevDay.dimension(NumSurfaces, 0);
176 801 : state.dataSurface->SurfWinFracTimeShadingDeviceOn.dimension(NumSurfaces, 0);
177 801 : state.dataSurface->SurfWinExtIntShadePrevTS.dimension(NumSurfaces, DataSurfaces::WinShadingType::ShadeOff);
178 801 : state.dataSurface->SurfWinHasShadeOrBlindLayer.dimension(NumSurfaces, 0);
179 801 : state.dataSurface->SurfWinSurfDayLightInit.dimension(NumSurfaces, 0);
180 801 : state.dataSurface->SurfWinDaylFacPoint.dimension(NumSurfaces, 0);
181 801 : state.dataSurface->SurfWinVisTransSelected.dimension(NumSurfaces, 0);
182 801 : state.dataSurface->SurfWinSwitchingFactor.dimension(NumSurfaces, 0);
183 801 : state.dataSurface->SurfWinVisTransRatio.dimension(NumSurfaces, 0);
184 801 : state.dataSurface->SurfWinIRfromParentZone.dimension(NumSurfaces, 0);
185 801 : state.dataSurface->SurfWinFrameArea.dimension(NumSurfaces, 0);
186 801 : state.dataSurface->SurfWinFrameConductance.dimension(NumSurfaces, 0);
187 801 : state.dataSurface->SurfWinFrameSolAbsorp.dimension(NumSurfaces, 0);
188 801 : state.dataSurface->SurfWinFrameVisAbsorp.dimension(NumSurfaces, 0);
189 801 : state.dataSurface->SurfWinFrameEmis.dimension(NumSurfaces, 0);
190 801 : state.dataSurface->SurfWinFrEdgeToCenterGlCondRatio.dimension(NumSurfaces, 1.0);
191 801 : state.dataSurface->SurfWinFrameEdgeArea.dimension(NumSurfaces, 0);
192 801 : state.dataSurface->SurfWinFrameTempIn.dimension(NumSurfaces, 23.0);
193 801 : state.dataSurface->SurfWinFrameTempInOld.dimension(NumSurfaces, 23.0);
194 801 : state.dataSurface->SurfWinFrameTempSurfOut.dimension(NumSurfaces, 23.0);
195 801 : state.dataSurface->SurfWinProjCorrFrOut.dimension(NumSurfaces, 0);
196 801 : state.dataSurface->SurfWinProjCorrFrIn.dimension(NumSurfaces, 0);
197 801 : state.dataSurface->SurfWinDividerType.dimension(NumSurfaces, DataSurfaces::FrameDividerType::DividedLite);
198 801 : state.dataSurface->SurfWinDividerArea.dimension(NumSurfaces, 0);
199 801 : state.dataSurface->SurfWinDividerConductance.dimension(NumSurfaces, 0);
200 801 : state.dataSurface->SurfWinDividerSolAbsorp.dimension(NumSurfaces, 0);
201 801 : state.dataSurface->SurfWinDividerVisAbsorp.dimension(NumSurfaces, 0);
202 801 : state.dataSurface->SurfWinDividerEmis.dimension(NumSurfaces, 0);
203 801 : state.dataSurface->SurfWinDivEdgeToCenterGlCondRatio.dimension(NumSurfaces, 1);
204 801 : state.dataSurface->SurfWinDividerEdgeArea.dimension(NumSurfaces, 0);
205 801 : state.dataSurface->SurfWinDividerTempIn.dimension(NumSurfaces, 23.0);
206 801 : state.dataSurface->SurfWinDividerTempInOld.dimension(NumSurfaces, 23.0);
207 801 : state.dataSurface->SurfWinDividerTempSurfOut.dimension(NumSurfaces, 23.0);
208 801 : state.dataSurface->SurfWinProjCorrDivOut.dimension(NumSurfaces, 0);
209 801 : state.dataSurface->SurfWinProjCorrDivIn.dimension(NumSurfaces, 0);
210 801 : state.dataSurface->SurfWinShadeAbsFacFace1.dimension(NumSurfaces, 0.5);
211 801 : state.dataSurface->SurfWinShadeAbsFacFace2.dimension(NumSurfaces, 0.5);
212 801 : state.dataSurface->SurfWinConvCoeffWithShade.dimension(NumSurfaces, 0);
213 801 : state.dataSurface->SurfWinOtherConvHeatGain.dimension(NumSurfaces, 0);
214 801 : state.dataSurface->SurfWinEffInsSurfTemp.dimension(NumSurfaces, 23.0);
215 801 : state.dataSurface->SurfWinTotGlazingThickness.dimension(NumSurfaces, 0);
216 801 : state.dataSurface->SurfWinTanProfileAngHor.dimension(NumSurfaces, 0);
217 801 : state.dataSurface->SurfWinTanProfileAngVert.dimension(NumSurfaces, 0);
218 801 : state.dataSurface->SurfWinInsideSillDepth.dimension(NumSurfaces, 0);
219 801 : state.dataSurface->SurfWinInsideReveal.dimension(NumSurfaces, 0);
220 801 : state.dataSurface->SurfWinInsideSillSolAbs.dimension(NumSurfaces, 0);
221 801 : state.dataSurface->SurfWinInsideRevealSolAbs.dimension(NumSurfaces, 0);
222 801 : state.dataSurface->SurfWinOutsideRevealSolAbs.dimension(NumSurfaces, 0);
223 801 : state.dataSurface->SurfWinAirflowSource.dimension(NumSurfaces, DataSurfaces::WindowAirFlowSource::Invalid);
224 801 : state.dataSurface->SurfWinAirflowDestination.dimension(NumSurfaces, DataSurfaces::WindowAirFlowDestination::Invalid);
225 801 : state.dataSurface->SurfWinAirflowReturnNodePtr.dimension(NumSurfaces, 0);
226 801 : state.dataSurface->SurfWinMaxAirflow.dimension(NumSurfaces, 0);
227 801 : state.dataSurface->SurfWinAirflowControlType.dimension(NumSurfaces, DataSurfaces::WindowAirFlowControlType::Invalid);
228 801 : state.dataSurface->SurfWinAirflowHasSchedule.dimension(NumSurfaces, 0);
229 801 : state.dataSurface->SurfWinAirflowScheds.dimension(NumSurfaces, nullptr);
230 801 : state.dataSurface->SurfWinAirflowThisTS.dimension(NumSurfaces, 0);
231 801 : state.dataSurface->SurfWinTAirflowGapOutlet.dimension(NumSurfaces, 0);
232 801 : state.dataSurface->SurfWinWindowCalcIterationsRep.dimension(NumSurfaces, 0);
233 801 : state.dataSurface->SurfWinVentingOpenFactorMultRep.dimension(NumSurfaces, 0);
234 801 : state.dataSurface->SurfWinInsideTempForVentingRep.dimension(NumSurfaces, 0);
235 801 : state.dataSurface->SurfWinVentingAvailabilityRep.dimension(NumSurfaces, 0);
236 801 : state.dataSurface->SurfWinSkyGndSolarInc.dimension(NumSurfaces, 0);
237 801 : state.dataSurface->SurfWinBmGndSolarInc.dimension(NumSurfaces, 0);
238 801 : state.dataSurface->SurfWinSolarDiffusing.dimension(NumSurfaces, 0);
239 801 : state.dataSurface->SurfWinFrameHeatGain.dimension(NumSurfaces, 0);
240 801 : state.dataSurface->SurfWinFrameHeatLoss.dimension(NumSurfaces, 0);
241 801 : state.dataSurface->SurfWinDividerHeatLoss.dimension(NumSurfaces, 0);
242 801 : state.dataSurface->SurfWinTCLayerTemp.dimension(NumSurfaces, 0);
243 801 : state.dataSurface->SurfWinSpecTemp.dimension(NumSurfaces, 0);
244 801 : state.dataSurface->SurfWinWindowModelType.dimension(NumSurfaces, DataSurfaces::WindowModel::Detailed);
245 801 : state.dataSurface->SurfWinTDDPipeNum.dimension(NumSurfaces, 0);
246 801 : state.dataSurface->SurfWinStormWinConstr.dimension(NumSurfaces, 0);
247 801 : state.dataSurface->SurfActiveConstruction.dimension(NumSurfaces, 0);
248 801 : state.dataSurface->SurfWinActiveShadedConstruction.dimension(NumSurfaces, 0);
249 801 : }
250 :
251 801 : void SetupZoneGeometry(EnergyPlusData &state, bool &ErrorsFound)
252 : {
253 :
254 : // SUBROUTINE INFORMATION:
255 : // AUTHOR George Walton
256 : // DATE WRITTEN September 1977
257 : // MODIFIED April 2002 (FCW): add warning for Solar Distribution
258 : // = FullInteriorExterior when window has reveal
259 : // Add fatal error when triangular window has reveal
260 : // May 2002(FCW): Allow triangular windows to have reveal (subr SHDRVL
261 : // in SolarShading). Remove above warning and fatal error.
262 : // RE-ENGINEERED November 1997 (RKS,LKL)
263 :
264 : // PURPOSE OF THIS SUBROUTINE:
265 : // This subroutine controls the processing of detached shadowing and zone surfaces for computing their vertices.
266 :
267 : static constexpr std::string_view RoutineName("SetUpZoneGeometry: ");
268 :
269 : // Zones must have been "gotten" before this call
270 : // The RelNorth variables are used if "relative" coordinates are input as well as setting up DaylightingCoords
271 :
272 : // these include building north axis and Building Rotation for Appendix G
273 1602 : state.dataSurfaceGeometry->CosBldgRelNorth =
274 801 : std::cos(-(state.dataHeatBal->BuildingAzimuth + state.dataHeatBal->BuildingRotationAppendixG) * Constant::DegToRad);
275 1602 : state.dataSurfaceGeometry->SinBldgRelNorth =
276 801 : std::sin(-(state.dataHeatBal->BuildingAzimuth + state.dataHeatBal->BuildingRotationAppendixG) * Constant::DegToRad);
277 :
278 : // these are only for Building Rotation for Appendix G when using world coordinate system
279 801 : state.dataSurfaceGeometry->CosBldgRotAppGonly = std::cos(-state.dataHeatBal->BuildingRotationAppendixG * Constant::DegToRad);
280 801 : state.dataSurfaceGeometry->SinBldgRotAppGonly = std::sin(-state.dataHeatBal->BuildingRotationAppendixG * Constant::DegToRad);
281 :
282 801 : state.dataSurfaceGeometry->CosZoneRelNorth.allocate(state.dataGlobal->NumOfZones);
283 801 : state.dataSurfaceGeometry->SinZoneRelNorth.allocate(state.dataGlobal->NumOfZones);
284 :
285 6002 : for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
286 :
287 5201 : state.dataSurfaceGeometry->CosZoneRelNorth(ZoneNum) = std::cos(-state.dataHeatBal->Zone(ZoneNum).RelNorth * Constant::DegToRad);
288 5201 : state.dataSurfaceGeometry->SinZoneRelNorth(ZoneNum) = std::sin(-state.dataHeatBal->Zone(ZoneNum).RelNorth * Constant::DegToRad);
289 : }
290 801 : GetSurfaceData(state, ErrorsFound);
291 :
292 801 : if (ErrorsFound) {
293 0 : state.dataSurfaceGeometry->CosZoneRelNorth.deallocate();
294 0 : state.dataSurfaceGeometry->SinZoneRelNorth.deallocate();
295 0 : return;
296 : }
297 :
298 801 : ZoneEquipmentManager::GetZoneEquipment(state); // Necessary to get this before window air gap code
299 :
300 801 : GetWindowGapAirflowControlData(state, ErrorsFound);
301 :
302 801 : GetStormWindowData(state, ErrorsFound);
303 :
304 801 : if (!ErrorsFound && state.dataSurface->TotStormWin > 0) {
305 1 : CreateStormWindowConstructions(state);
306 : }
307 :
308 801 : DataHeatBalance::SetFlagForWindowConstructionWithShadeOrBlindLayer(state);
309 :
310 801 : state.dataSurfaceGeometry->CosZoneRelNorth.deallocate();
311 801 : state.dataSurfaceGeometry->SinZoneRelNorth.deallocate();
312 :
313 801 : state.dataHeatBal->CalcWindowRevealReflection = false; // Set to True in ProcessSurfaceVertices if beam solar reflection from window reveals
314 : // is requested for one or more exterior windows.
315 801 : state.dataSurface->BuildingShadingCount = 0;
316 801 : state.dataSurface->FixedShadingCount = 0;
317 801 : state.dataSurface->AttachedShadingCount = 0;
318 801 : state.dataSurface->ShadingSurfaceFirst = 0;
319 801 : state.dataSurface->ShadingSurfaceLast = -1;
320 :
321 : // Reserve space to avoid excess allocations
322 801 : state.dataSurface->AllExtSolAndShadingSurfaceList.reserve(state.dataSurface->TotSurfaces);
323 :
324 48091 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) { // Loop through all surfaces...
325 47290 : auto &thisSurface = state.dataSurface->Surface(SurfNum);
326 :
327 47290 : state.dataSurface->SurfAirSkyRadSplit(SurfNum) = std::sqrt(0.5 * (1.0 + thisSurface.CosTilt));
328 :
329 : // Set flag that determines whether a surface is a shadowing surface
330 47290 : thisSurface.IsShadowing = false;
331 47290 : if (thisSurface.Class == SurfaceClass::Shading || thisSurface.Class == SurfaceClass::Detached_F ||
332 45642 : thisSurface.Class == SurfaceClass::Detached_B) {
333 1690 : thisSurface.IsShadowing = true;
334 1690 : if (state.dataSurface->ShadingSurfaceFirst == 0) {
335 269 : state.dataSurface->ShadingSurfaceFirst = SurfNum;
336 : }
337 1690 : state.dataSurface->ShadingSurfaceLast = SurfNum;
338 : }
339 47290 : if ((thisSurface.HeatTransSurf && thisSurface.ExtSolar) || thisSurface.IsShadowing) {
340 : // Some attached shading surfaces may be true for both
341 19758 : state.dataSurface->AllExtSolAndShadingSurfaceList.push_back(SurfNum);
342 : }
343 47290 : if (thisSurface.Class == SurfaceClass::Shading) {
344 1538 : ++state.dataSurface->AttachedShadingCount;
345 : }
346 47290 : if (thisSurface.Class == SurfaceClass::Detached_F) {
347 110 : ++state.dataSurface->FixedShadingCount;
348 : }
349 47290 : if (thisSurface.Class == SurfaceClass::Detached_B) {
350 42 : ++state.dataSurface->BuildingShadingCount;
351 : }
352 :
353 47290 : if (thisSurface.Class != SurfaceClass::IntMass) {
354 44753 : ProcessSurfaceVertices(state, SurfNum, ErrorsFound);
355 : }
356 : }
357 :
358 6002 : for (auto &e : state.dataHeatBal->Zone) {
359 5201 : e.ExtWindowArea = 0.0;
360 5201 : e.HasWindow = false;
361 5201 : e.ExtGrossWallArea = 0.0;
362 5201 : e.ExtNetWallArea = 0.0;
363 5201 : e.TotalSurfArea = 0.0;
364 801 : }
365 :
366 6014 : for (auto &s : state.dataHeatBal->space) {
367 5213 : s.extWindowArea = 0.0;
368 5213 : s.totalSurfArea = 0.0;
369 801 : }
370 1602 : bool DetailedWWR = (state.dataInputProcessing->inputProcessor->getNumSectionsFound("DETAILEDWWR_DEBUG") > 0);
371 801 : if (DetailedWWR) {
372 0 : print(state.files.debug, "{}", "=======User Entered Classification =================");
373 0 : print(state.files.debug, "{}", "Surface,Class,Area,Tilt");
374 : }
375 :
376 48091 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) { // Loop through all surfaces to find windows...
377 47290 : auto &thisSurface = state.dataSurface->Surface(SurfNum);
378 :
379 47290 : if (!thisSurface.HeatTransSurf && !thisSurface.IsAirBoundarySurf) {
380 1690 : continue; // Skip shadowing (sub)surfaces
381 : }
382 45600 : auto &thisZone = state.dataHeatBal->Zone(thisSurface.Zone);
383 45600 : auto &thisSpace = state.dataHeatBal->space(thisSurface.spaceNum);
384 :
385 45600 : thisZone.TotalSurfArea += thisSurface.Area;
386 45600 : thisSpace.totalSurfArea += thisSurface.Area;
387 45600 : if (thisSurface.Class == SurfaceClass::Roof) {
388 5958 : thisZone.geometricCeilingArea += thisSurface.GrossArea;
389 39642 : } else if (thisSurface.Class == SurfaceClass::Floor) {
390 7040 : thisZone.geometricFloorArea += thisSurface.GrossArea;
391 : }
392 45600 : if (state.dataConstruction->Construct(thisSurface.Construction).TypeIsWindow) {
393 6361 : thisZone.TotalSurfArea += state.dataSurface->SurfWinFrameArea(SurfNum);
394 6361 : thisZone.HasWindow = true;
395 6361 : thisSpace.totalSurfArea += state.dataSurface->SurfWinFrameArea(SurfNum);
396 6361 : if (((thisSurface.ExtBoundCond == DataSurfaces::ExternalEnvironment) ||
397 14 : (thisSurface.ExtBoundCond == DataSurfaces::OtherSideCondModeledExt)) &&
398 6347 : (thisSurface.Class != SurfaceClass::TDD_Dome)) {
399 6345 : thisZone.ExtWindowArea += thisSurface.GrossArea;
400 6345 : thisSpace.extWindowArea += thisSurface.GrossArea;
401 6345 : thisZone.ExtWindowArea_Multiplied =
402 6345 : thisZone.ExtWindowArea + thisSurface.GrossArea * thisSurface.Multiplier * thisZone.Multiplier * thisZone.ListMultiplier;
403 6345 : if (DetailedWWR) {
404 0 : print(state.files.debug,
405 : "{},Window,{:.2R},{:.1R}\n",
406 0 : thisSurface.Name,
407 0 : thisSurface.GrossArea * thisSurface.Multiplier * thisZone.Multiplier * thisZone.ListMultiplier,
408 0 : thisSurface.Tilt);
409 : }
410 : }
411 : } else {
412 39239 : if (thisSurface.ExtBoundCond == DataSurfaces::ExternalEnvironment ||
413 27415 : thisSurface.ExtBoundCond == DataSurfaces::OtherSideCondModeledExt) {
414 11879 : thisZone.ExteriorTotalSurfArea += thisSurface.GrossArea;
415 11879 : thisSpace.ExteriorTotalSurfArea += thisSurface.GrossArea;
416 11879 : if (thisSurface.Class == SurfaceClass::Wall) {
417 9068 : thisZone.ExtNetWallArea += thisSurface.Area;
418 9068 : thisZone.ExtGrossWallArea += thisSurface.GrossArea;
419 9068 : thisSpace.ExtGrossWallArea += thisSurface.GrossArea;
420 9068 : thisZone.ExtGrossWallArea_Multiplied += thisSurface.GrossArea * thisZone.Multiplier * thisZone.ListMultiplier;
421 9068 : thisZone.extPerimeter += thisSurface.Width;
422 9068 : thisSpace.extPerimeter += thisSurface.Width;
423 9068 : if (DetailedWWR) {
424 0 : print(state.files.debug,
425 : "{},Wall,{:.2R},{:.1R}\n",
426 0 : thisSurface.Name,
427 0 : thisSurface.GrossArea * thisZone.Multiplier * thisZone.ListMultiplier,
428 0 : thisSurface.Tilt);
429 : }
430 : }
431 27360 : } else if (thisSurface.ExtBoundCond == DataSurfaces::Ground || thisSurface.ExtBoundCond == DataSurfaces::GroundFCfactorMethod ||
432 24930 : thisSurface.ExtBoundCond == DataSurfaces::KivaFoundation) {
433 2470 : thisZone.ExteriorTotalGroundSurfArea += thisSurface.GrossArea;
434 2470 : if (thisSurface.Class == SurfaceClass::Wall) {
435 212 : thisZone.ExtGrossGroundWallArea += thisSurface.GrossArea;
436 212 : thisZone.ExtGrossGroundWallArea_Multiplied += thisSurface.GrossArea * thisZone.Multiplier * thisZone.ListMultiplier;
437 212 : if (DetailedWWR) {
438 0 : print(state.files.debug,
439 : "{},Wall-GroundContact,{:.2R},{:.1R}\n",
440 0 : thisSurface.Name,
441 0 : thisSurface.GrossArea * thisZone.Multiplier * thisZone.ListMultiplier,
442 0 : thisSurface.Tilt);
443 : }
444 : }
445 : }
446 : }
447 :
448 : } // ...end of surfaces windows DO loop
449 :
450 801 : if (DetailedWWR) {
451 0 : print(state.files.debug, "{}\n", "========================");
452 0 : print(state.files.debug, "{}\n", "Zone,ExtWallArea,ExtWindowArea");
453 : }
454 :
455 6002 : for (auto &thisZone : state.dataHeatBal->Zone) {
456 5201 : int CeilCount = 0;
457 5201 : int FloorCount = 0;
458 5201 : int WallCount = 0;
459 5201 : Real64 AverageHeight = 0.0; // Used to keep track of average height of a surface/zone
460 5201 : Real64 ZMax = -99999.0; // Maximum Z of a surface (detailed outside coefficient calculation)
461 5201 : Real64 ZMin = 99999.0; // Minimum Z of a surface (detailed outside coefficient calculation)
462 5201 : Real64 ZCeilAvg = 0.0;
463 5201 : Real64 ZFlrAvg = 0.0;
464 5201 : if (DetailedWWR) {
465 0 : print(state.files.debug, "{},{:.2R},{:.2R}\n", thisZone.Name, thisZone.ExtGrossWallArea, thisZone.ExtWindowArea);
466 : }
467 10414 : for (int spaceNum : thisZone.spaceIndexes) {
468 5213 : auto const &thisSpace = state.dataHeatBal->space(spaceNum);
469 : // Use AllSurfaceFirst which includes air boundaries
470 50813 : for (int SurfNum = thisSpace.AllSurfaceFirst; SurfNum <= thisSpace.AllSurfaceLast; ++SurfNum) {
471 45600 : auto &thisSurface = state.dataSurface->Surface(SurfNum);
472 :
473 45600 : if (thisSurface.Class == SurfaceClass::Roof) {
474 : // Use Average Z for surface, more important for roofs than floors...
475 5958 : ++CeilCount;
476 5958 : Real64 Z1 = minval(thisSurface.Vertex, &Vector::z);
477 5958 : Real64 Z2 = maxval(thisSurface.Vertex, &Vector::z);
478 : // ZCeilAvg=ZCeilAvg+(Z1+Z2)/2.d0
479 5958 : ZCeilAvg += ((Z1 + Z2) / 2.0) * (thisSurface.GrossArea / thisZone.geometricCeilingArea);
480 : }
481 45600 : if (thisSurface.Class == SurfaceClass::Floor) {
482 : // Use Average Z for surface, more important for roofs than floors...
483 7040 : ++FloorCount;
484 7040 : Real64 Z1 = minval(thisSurface.Vertex, &Vector::z);
485 7040 : Real64 Z2 = maxval(thisSurface.Vertex, &Vector::z);
486 : // ZFlrAvg=ZFlrAvg+(Z1+Z2)/2.d0
487 7040 : ZFlrAvg += ((Z1 + Z2) / 2.0) * (thisSurface.GrossArea / thisZone.geometricFloorArea);
488 : }
489 45600 : if (thisSurface.Class == SurfaceClass::Wall) {
490 : // Use Wall calculation in case no roof & floor in zone
491 23223 : ++WallCount;
492 23223 : if (WallCount == 1) {
493 5179 : ZMax = thisSurface.Vertex(1).z;
494 5179 : ZMin = ZMax;
495 : }
496 23223 : ZMax = max(ZMax, maxval(thisSurface.Vertex, &Vector::z));
497 23223 : ZMin = min(ZMin, minval(thisSurface.Vertex, &Vector::z));
498 : }
499 : }
500 5201 : }
501 5201 : if (CeilCount > 0 && FloorCount > 0) {
502 5198 : AverageHeight = ZCeilAvg - ZFlrAvg;
503 : } else {
504 3 : AverageHeight = (ZMax - ZMin);
505 : }
506 5201 : if (AverageHeight <= 0.0) {
507 1 : AverageHeight = (ZMax - ZMin);
508 : }
509 :
510 5201 : if (thisZone.CeilingHeight > 0.0) {
511 1821 : thisZone.ceilingHeightEntered = true;
512 1821 : if (AverageHeight > 0.0) {
513 1821 : if (std::abs(AverageHeight - thisZone.CeilingHeight) / thisZone.CeilingHeight > 0.05) {
514 8 : if (state.dataSurfaceGeometry->ErrCount == 1 && !state.dataGlobal->DisplayExtraWarnings) {
515 0 : ShowWarningError(
516 : state,
517 0 : format("{}Entered Ceiling Height for some zone(s) significantly different from calculated Ceiling Height",
518 : RoutineName));
519 0 : ShowContinueError(state,
520 : "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on each max iteration exceeded.");
521 : }
522 8 : if (state.dataGlobal->DisplayExtraWarnings) {
523 0 : ShowWarningError(state,
524 0 : format("{}Entered Ceiling Height for Zone=\"{}\" significantly different from calculated Ceiling Height",
525 : RoutineName,
526 0 : thisZone.Name));
527 : static constexpr std::string_view ValFmt("{:.2F}");
528 0 : std::string String1 = format(ValFmt, thisZone.CeilingHeight);
529 0 : std::string String2 = format(ValFmt, AverageHeight);
530 0 : ShowContinueError(
531 : state,
532 0 : format("{}Entered Ceiling Height={}, Calculated Ceiling Height={}, entered height will be used in calculations.",
533 : RoutineName,
534 : String1,
535 : String2));
536 0 : }
537 : }
538 : }
539 : }
540 5201 : if ((thisZone.CeilingHeight <= 0.0) && (AverageHeight > 0.0)) {
541 3380 : thisZone.CeilingHeight = AverageHeight;
542 : }
543 : // Need to add check here - don't touch if already user-specified
544 801 : }
545 :
546 801 : CalculateZoneVolume(state); // Calculate Zone Volumes
547 :
548 : // Calculate zone centroid (and min/max x,y,z for zone)
549 : // Use AllSurfaceFirst which includes air boundaries
550 6002 : for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
551 5201 : auto &thisZone = state.dataHeatBal->Zone(ZoneNum);
552 5201 : bool nonInternalMassSurfacesPresent = false;
553 5201 : bool internalMassSurfacesPresent = false;
554 5201 : Real64 TotSurfArea = 0.0;
555 5201 : thisZone.Centroid = Vector(0.0, 0.0, 0.0);
556 5201 : if ((thisZone.AllSurfaceFirst > 0) && (state.dataSurface->Surface(thisZone.AllSurfaceFirst).Sides > 0)) {
557 5201 : thisZone.MinimumX = state.dataSurface->Surface(thisZone.AllSurfaceFirst).Vertex(1).x;
558 5201 : thisZone.MaximumX = state.dataSurface->Surface(thisZone.AllSurfaceFirst).Vertex(1).x;
559 5201 : thisZone.MinimumY = state.dataSurface->Surface(thisZone.AllSurfaceFirst).Vertex(1).y;
560 5201 : thisZone.MaximumY = state.dataSurface->Surface(thisZone.AllSurfaceFirst).Vertex(1).y;
561 5201 : thisZone.MinimumZ = state.dataSurface->Surface(thisZone.AllSurfaceFirst).Vertex(1).z;
562 5201 : thisZone.MaximumZ = state.dataSurface->Surface(thisZone.AllSurfaceFirst).Vertex(1).z;
563 : }
564 10414 : for (int spaceNum : thisZone.spaceIndexes) {
565 5213 : auto const &thisSpace = state.dataHeatBal->space(spaceNum);
566 :
567 50813 : for (int SurfNum = thisSpace.AllSurfaceFirst; SurfNum <= thisSpace.AllSurfaceLast; ++SurfNum) {
568 45600 : auto &thisSurface = state.dataSurface->Surface(SurfNum);
569 45600 : if (thisSurface.Class == SurfaceClass::IntMass) {
570 2537 : internalMassSurfacesPresent = true;
571 2537 : continue;
572 : }
573 43063 : if (!thisSurface.IsAirBoundarySurf) {
574 43045 : nonInternalMassSurfacesPresent = true;
575 : }
576 43063 : if (thisSurface.Class == SurfaceClass::Wall || (thisSurface.Class == SurfaceClass::Roof) ||
577 13882 : (thisSurface.Class == SurfaceClass::Floor)) {
578 :
579 36221 : thisZone.Centroid.x += thisSurface.Centroid.x * thisSurface.GrossArea;
580 36221 : thisZone.Centroid.y += thisSurface.Centroid.y * thisSurface.GrossArea;
581 36221 : thisZone.Centroid.z += thisSurface.Centroid.z * thisSurface.GrossArea;
582 36221 : TotSurfArea += thisSurface.GrossArea;
583 : }
584 43063 : thisZone.MinimumX = min(thisZone.MinimumX, minval(thisSurface.Vertex, &Vector::x));
585 43063 : thisZone.MaximumX = max(thisZone.MaximumX, maxval(thisSurface.Vertex, &Vector::x));
586 43063 : thisZone.MinimumY = min(thisZone.MinimumY, minval(thisSurface.Vertex, &Vector::y));
587 43063 : thisZone.MaximumY = max(thisZone.MaximumY, maxval(thisSurface.Vertex, &Vector::y));
588 43063 : thisZone.MinimumZ = min(thisZone.MinimumZ, minval(thisSurface.Vertex, &Vector::z));
589 43063 : thisZone.MaximumZ = max(thisZone.MaximumZ, maxval(thisSurface.Vertex, &Vector::z));
590 : }
591 5201 : }
592 5201 : if (TotSurfArea > 0.0) {
593 5201 : thisZone.Centroid.x /= TotSurfArea;
594 5201 : thisZone.Centroid.y /= TotSurfArea;
595 5201 : thisZone.Centroid.z /= TotSurfArea;
596 : }
597 5201 : if (internalMassSurfacesPresent && !nonInternalMassSurfacesPresent) {
598 0 : ShowSevereError(
599 0 : state, format("{}Zone=\"{}\" has only internal mass surfaces. Need at least one other surface.", RoutineName, thisZone.Name));
600 0 : ErrorsFound = true;
601 : }
602 : }
603 :
604 801 : state.dataSurface->SurfAdjacentZone.dimension(state.dataSurface->TotSurfaces, 0);
605 : // note -- adiabatic surfaces will show same zone as surface
606 48091 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
607 47290 : if (state.dataSurface->Surface(SurfNum).ExtBoundCond <= 0) {
608 22419 : continue;
609 : }
610 24871 : state.dataSurface->SurfAdjacentZone(SurfNum) = state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).ExtBoundCond).Zone;
611 : }
612 :
613 6002 : for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
614 1419443 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
615 1414242 : auto const &thisSurface = state.dataSurface->Surface(SurfNum);
616 1414242 : if (!thisSurface.HeatTransSurf && thisSurface.ZoneName == state.dataHeatBal->Zone(ZoneNum).Name) {
617 1556 : ++state.dataHeatBal->Zone(ZoneNum).NumShadingSurfaces;
618 : }
619 :
620 1414242 : if (thisSurface.Zone != ZoneNum) {
621 1368642 : continue;
622 : }
623 :
624 45600 : if (thisSurface.HeatTransSurf && (thisSurface.Class == SurfaceClass::Wall || thisSurface.Class == SurfaceClass::Roof ||
625 16419 : thisSurface.Class == SurfaceClass::Floor)) {
626 36203 : ++state.dataHeatBal->Zone(ZoneNum).NumSurfaces;
627 : }
628 :
629 45600 : if (thisSurface.HeatTransSurf && (thisSurface.Class == SurfaceClass::Window || thisSurface.Class == SurfaceClass::GlassDoor ||
630 39223 : thisSurface.Class == SurfaceClass::Door || thisSurface.Class == SurfaceClass::TDD_Dome ||
631 38740 : thisSurface.Class == SurfaceClass::TDD_Diffuser)) {
632 6842 : ++state.dataHeatBal->Zone(ZoneNum).NumSubSurfaces;
633 : }
634 :
635 : } // surfaces
636 : } // zones
637 :
638 48091 : for (int const SurfNum : state.dataSurface->AllSurfaceListReportOrder) {
639 47290 : auto const &thisSurface = state.dataSurface->Surface(SurfNum);
640 47290 : Real64 NominalUwithConvCoeffs = 0.0;
641 47290 : if (thisSurface.Construction > 0 && thisSurface.Construction <= state.dataHeatBal->TotConstructs) {
642 45600 : bool isWithConvCoefValid = false;
643 45600 : NominalUwithConvCoeffs = DataHeatBalance::ComputeNominalUwithConvCoeffs(state, SurfNum, isWithConvCoefValid);
644 : }
645 :
646 : // populate the predefined report related to u-values with films
647 : // only exterior surfaces including underground
648 47290 : DataSurfaces::SurfaceClass const SurfaceClass(thisSurface.Class);
649 47290 : if ((thisSurface.ExtBoundCond == DataSurfaces::ExternalEnvironment) || (thisSurface.ExtBoundCond == DataSurfaces::Ground) ||
650 25183 : (thisSurface.ExtBoundCond == DataSurfaces::KivaFoundation) || (thisSurface.ExtBoundCond == DataSurfaces::GroundFCfactorMethod)) {
651 22331 : if ((SurfaceClass == SurfaceClass::Wall) || (SurfaceClass == SurfaceClass::Floor) || (SurfaceClass == SurfaceClass::Roof)) {
652 27786 : OutputReportPredefined::PreDefTableEntry(
653 41679 : state, state.dataOutRptPredefined->pdchOpUfactFilm, thisSurface.Name, NominalUwithConvCoeffs, 3);
654 8438 : } else if (SurfaceClass == SurfaceClass::Door) {
655 802 : OutputReportPredefined::PreDefTableEntry(
656 1203 : state, state.dataOutRptPredefined->pdchDrUfactFilm, thisSurface.Name, NominalUwithConvCoeffs, 3);
657 : }
658 : } else {
659 24959 : if ((SurfaceClass == SurfaceClass::Wall) || (SurfaceClass == SurfaceClass::Floor) || (SurfaceClass == SurfaceClass::Roof)) {
660 44656 : OutputReportPredefined::PreDefTableEntry(
661 66984 : state, state.dataOutRptPredefined->pdchIntOpUfactFilm, thisSurface.Name, NominalUwithConvCoeffs, 3);
662 2631 : } else if (SurfaceClass == SurfaceClass::Door) {
663 160 : OutputReportPredefined::PreDefTableEntry(
664 240 : state, state.dataOutRptPredefined->pdchIntDrUfactFilm, thisSurface.Name, NominalUwithConvCoeffs, 3);
665 : }
666 : }
667 801 : } // surfaces
668 :
669 : // Write number of shadings to initialization output file
670 801 : print(state.files.eio,
671 : "! <Shading Summary>, Number of Fixed Detached Shades, Number of Building Detached Shades, Number of Attached Shades\n");
672 :
673 801 : print(state.files.eio,
674 : " Shading Summary,{},{},{}\n",
675 801 : state.dataSurface->FixedShadingCount,
676 801 : state.dataSurface->BuildingShadingCount,
677 801 : state.dataSurface->AttachedShadingCount);
678 :
679 : // Write number of zones header to initialization output file
680 801 : print(state.files.eio, "! <Zone Summary>, Number of Zones, Number of Zone Surfaces, Number of SubSurfaces\n");
681 :
682 801 : print(state.files.eio,
683 : " Zone Summary,{},{},{}\n",
684 801 : state.dataGlobal->NumOfZones,
685 801 : state.dataSurface->TotSurfaces - state.dataSurface->FixedShadingCount - state.dataSurface->BuildingShadingCount -
686 801 : state.dataSurface->AttachedShadingCount,
687 801 : sum(state.dataHeatBal->Zone, &DataHeatBalance::ZoneData::NumSubSurfaces));
688 :
689 : // Write Zone Information header to the initialization output file
690 : static constexpr std::string_view Format_721(
691 : "! <Zone Information>,Zone Name,North Axis {deg},Origin X-Coordinate {m},Origin Y-Coordinate {m},Origin Z-Coordinate "
692 : "{m},Centroid X-Coordinate {m},Centroid Y-Coordinate {m},Centroid Z-Coordinate {m},Type,Zone Multiplier,Zone List "
693 : "Multiplier,Minimum X {m},Maximum X {m},Minimum Y {m},Maximum Y {m},Minimum Z {m},Maximum Z {m},Ceiling Height {m},Volume "
694 : "{m3},Zone Inside Convection Algorithm {Simple-Detailed-CeilingDiffuser-TrombeWall},Zone Outside Convection Algorithm "
695 : "{Simple-Detailed-Tarp-MoWitt-DOE-2-BLAST}, Floor Area {m2},Exterior Gross Wall Area {m2},Exterior Net Wall Area {m2},Exterior "
696 : "Window "
697 : "Area {m2}, Number of Surfaces, Number of SubSurfaces, Number of Shading SubSurfaces, Part of Total Building Area");
698 801 : print(state.files.eio, "{}\n", Format_721);
699 :
700 6002 : for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
701 : // Write Zone Information to the initialization output file
702 5201 : std::string String1;
703 5201 : std::string String2;
704 5201 : std::string String3;
705 :
706 5201 : switch (state.dataHeatBal->Zone(ZoneNum).IntConvAlgo) {
707 1094 : case Convect::HcInt::ASHRAESimple: {
708 1094 : String1 = "Simple";
709 1094 : } break;
710 4081 : case Convect::HcInt::ASHRAETARP: {
711 4081 : String1 = "TARP";
712 4081 : } break;
713 10 : case Convect::HcInt::CeilingDiffuser: {
714 10 : String1 = "CeilingDiffuser";
715 10 : } break;
716 1 : case Convect::HcInt::TrombeWall: {
717 1 : String1 = "TrombeWall";
718 1 : } break;
719 14 : case Convect::HcInt::AdaptiveConvectionAlgorithm: {
720 14 : String1 = "AdaptiveConvectionAlgorithm";
721 14 : } break;
722 1 : case Convect::HcInt::ASTMC1340: {
723 1 : String1 = "ASTMC1340";
724 1 : } break;
725 0 : default:
726 0 : break;
727 : }
728 :
729 5201 : switch (state.dataHeatBal->Zone(ZoneNum).ExtConvAlgo) {
730 1102 : case Convect::HcExt::ASHRAESimple: {
731 1102 : String2 = "Simple";
732 1102 : } break;
733 492 : case Convect::HcExt::ASHRAETARP: {
734 492 : String2 = "TARP";
735 492 : } break;
736 0 : case Convect::HcExt::TarpHcOutside: {
737 0 : String2 = "TARP";
738 0 : } break;
739 0 : case Convect::HcExt::MoWiTTHcOutside: {
740 0 : String2 = "MoWitt";
741 0 : } break;
742 3591 : case Convect::HcExt::DOE2HcOutside: {
743 3591 : String2 = "DOE-2";
744 3591 : } break;
745 16 : case Convect::HcExt::AdaptiveConvectionAlgorithm: {
746 16 : String2 = "AdaptiveConvectionAlgorithm";
747 16 : } break;
748 0 : default:
749 0 : break;
750 : }
751 :
752 5201 : String3 = (state.dataHeatBal->Zone(ZoneNum).isPartOfTotalArea) ? "Yes" : "No";
753 :
754 : static constexpr std::string_view Format_720(
755 : " Zone Information, "
756 : "{},{:.1R},{:.2R},{:.2R},{:.2R},{:.2R},{:.2R},{:.2R},{},{},{},{:.2R},{:.2R},{:.2R},{:.2R},{:.2R},{:.2R},"
757 : "{:.2R},{:.2R},{},{},{:.2R},{:.2R},{:.2R},{:.2R},{},{},{},{}\n");
758 :
759 5201 : print(state.files.eio,
760 : Format_720,
761 5201 : state.dataHeatBal->Zone(ZoneNum).Name,
762 5201 : state.dataHeatBal->Zone(ZoneNum).RelNorth,
763 5201 : state.dataHeatBal->Zone(ZoneNum).OriginX,
764 5201 : state.dataHeatBal->Zone(ZoneNum).OriginY,
765 5201 : state.dataHeatBal->Zone(ZoneNum).OriginZ,
766 5201 : state.dataHeatBal->Zone(ZoneNum).Centroid.x,
767 5201 : state.dataHeatBal->Zone(ZoneNum).Centroid.y,
768 5201 : state.dataHeatBal->Zone(ZoneNum).Centroid.z,
769 5201 : state.dataHeatBal->Zone(ZoneNum).OfType,
770 5201 : state.dataHeatBal->Zone(ZoneNum).Multiplier,
771 5201 : state.dataHeatBal->Zone(ZoneNum).ListMultiplier,
772 5201 : state.dataHeatBal->Zone(ZoneNum).MinimumX,
773 5201 : state.dataHeatBal->Zone(ZoneNum).MaximumX,
774 5201 : state.dataHeatBal->Zone(ZoneNum).MinimumY,
775 5201 : state.dataHeatBal->Zone(ZoneNum).MaximumY,
776 5201 : state.dataHeatBal->Zone(ZoneNum).MinimumZ,
777 5201 : state.dataHeatBal->Zone(ZoneNum).MaximumZ,
778 5201 : state.dataHeatBal->Zone(ZoneNum).CeilingHeight,
779 5201 : state.dataHeatBal->Zone(ZoneNum).Volume,
780 : String1,
781 : String2,
782 5201 : state.dataHeatBal->Zone(ZoneNum).FloorArea,
783 5201 : state.dataHeatBal->Zone(ZoneNum).ExtGrossWallArea,
784 5201 : state.dataHeatBal->Zone(ZoneNum).ExtNetWallArea,
785 5201 : state.dataHeatBal->Zone(ZoneNum).ExtWindowArea,
786 5201 : state.dataHeatBal->Zone(ZoneNum).NumSurfaces,
787 5201 : state.dataHeatBal->Zone(ZoneNum).NumSubSurfaces,
788 5201 : state.dataHeatBal->Zone(ZoneNum).NumShadingSurfaces,
789 : String3);
790 :
791 5201 : } // ZoneNum
792 :
793 : // Set up solar distribution enclosures allowing for any air boundaries
794 801 : SetupEnclosuresAndAirBoundaries(state, state.dataViewFactor->EnclSolInfo, SurfaceGeometry::enclosureType::SolarEnclosures, ErrorsFound);
795 :
796 : // Do the Stratosphere check
797 801 : DataHeatBalance::SetZoneOutBulbTempAt(state);
798 801 : DataHeatBalance::CheckZoneOutBulbTempAt(state);
799 : }
800 :
801 801 : void AllocateSurfaceArrays(EnergyPlusData &state)
802 : {
803 :
804 : // SUBROUTINE INFORMATION:
805 : // AUTHOR Rick Strand
806 : // DATE WRITTEN February 1998
807 :
808 : // PURPOSE OF THIS SUBROUTINE:
809 : // This subroutine allocates all of the arrays at the module level which require allocation.
810 :
811 : // METHODOLOGY EMPLOYED:
812 : // Allocation is dependent on the user input file.
813 :
814 801 : state.dataSurface->ShadeV.allocate(state.dataSurface->TotSurfaces);
815 48091 : for (auto &e : state.dataSurface->ShadeV) {
816 47290 : e.NVert = 0;
817 801 : }
818 : // Individual components (XV,YV,ZV) allocated in routine ProcessSurfaceVertices
819 801 : state.dataSurface->X0.dimension(state.dataSurface->TotSurfaces, 0.0);
820 801 : state.dataSurface->Y0.dimension(state.dataSurface->TotSurfaces, 0.0);
821 801 : state.dataSurface->Z0.dimension(state.dataSurface->TotSurfaces, 0.0);
822 :
823 : // Surface EMS arrays
824 801 : state.dataSurface->SurfEMSConstructionOverrideON.allocate(state.dataSurface->TotSurfaces);
825 801 : state.dataSurface->SurfEMSConstructionOverrideValue.allocate(state.dataSurface->TotSurfaces);
826 801 : state.dataSurface->SurfEMSOverrideIntConvCoef.allocate(state.dataSurface->TotSurfaces);
827 801 : state.dataSurface->SurfEMSValueForIntConvCoef.allocate(state.dataSurface->TotSurfaces);
828 801 : state.dataSurface->SurfEMSOverrideExtConvCoef.allocate(state.dataSurface->TotSurfaces);
829 801 : state.dataSurface->SurfEMSValueForExtConvCoef.allocate(state.dataSurface->TotSurfaces);
830 801 : state.dataSurface->SurfOutDryBulbTempEMSOverrideOn.allocate(state.dataSurface->TotSurfaces);
831 801 : state.dataSurface->SurfOutDryBulbTempEMSOverrideValue.allocate(state.dataSurface->TotSurfaces);
832 801 : state.dataSurface->SurfOutWetBulbTempEMSOverrideOn.allocate(state.dataSurface->TotSurfaces);
833 801 : state.dataSurface->SurfOutWetBulbTempEMSOverrideValue.allocate(state.dataSurface->TotSurfaces);
834 801 : state.dataSurface->SurfWindSpeedEMSOverrideOn.allocate(state.dataSurface->TotSurfaces);
835 801 : state.dataSurface->SurfWindSpeedEMSOverrideValue.allocate(state.dataSurface->TotSurfaces);
836 801 : state.dataSurface->SurfViewFactorGroundEMSOverrideOn.allocate(state.dataSurface->TotSurfaces);
837 801 : state.dataSurface->SurfViewFactorGroundEMSOverrideValue.allocate(state.dataSurface->TotSurfaces);
838 801 : state.dataSurface->SurfWindDirEMSOverrideOn.allocate(state.dataSurface->TotSurfaces);
839 801 : state.dataSurface->SurfWindDirEMSOverrideValue.allocate(state.dataSurface->TotSurfaces);
840 48091 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
841 47290 : state.dataSurface->SurfEMSConstructionOverrideON(SurfNum) = false;
842 47290 : state.dataSurface->SurfEMSConstructionOverrideValue(SurfNum) = 0.0;
843 47290 : state.dataSurface->SurfEMSOverrideIntConvCoef(SurfNum) = false;
844 47290 : state.dataSurface->SurfEMSValueForIntConvCoef(SurfNum) = 0.0;
845 47290 : state.dataSurface->SurfEMSOverrideExtConvCoef(SurfNum) = false;
846 47290 : state.dataSurface->SurfEMSValueForExtConvCoef(SurfNum) = 0.0;
847 47290 : state.dataSurface->SurfOutDryBulbTempEMSOverrideOn(SurfNum) = false;
848 47290 : state.dataSurface->SurfOutDryBulbTempEMSOverrideValue(SurfNum) = 0.0;
849 47290 : state.dataSurface->SurfOutWetBulbTempEMSOverrideOn(SurfNum) = false;
850 47290 : state.dataSurface->SurfOutWetBulbTempEMSOverrideValue(SurfNum) = 0.0;
851 47290 : state.dataSurface->SurfWindSpeedEMSOverrideOn(SurfNum) = false;
852 47290 : state.dataSurface->SurfWindSpeedEMSOverrideValue(SurfNum) = 0.0;
853 47290 : state.dataSurface->SurfViewFactorGroundEMSOverrideOn(SurfNum) = false;
854 47290 : state.dataSurface->SurfViewFactorGroundEMSOverrideValue(SurfNum) = 0.0;
855 47290 : state.dataSurface->SurfWindDirEMSOverrideOn(SurfNum) = false;
856 47290 : state.dataSurface->SurfWindDirEMSOverrideValue(SurfNum) = 0.0;
857 : }
858 : // Following are surface hb arrays
859 801 : state.dataSurface->SurfOutDryBulbTemp.allocate(state.dataSurface->TotSurfaces);
860 801 : state.dataSurface->SurfOutWetBulbTemp.allocate(state.dataSurface->TotSurfaces);
861 801 : state.dataSurface->SurfOutWindSpeed.allocate(state.dataSurface->TotSurfaces);
862 801 : state.dataSurface->SurfOutWindDir.allocate(state.dataSurface->TotSurfaces);
863 801 : state.dataSurface->SurfGenericContam.allocate(state.dataSurface->TotSurfaces);
864 801 : state.dataSurface->SurfPenumbraID.allocate(state.dataSurface->TotSurfaces);
865 801 : state.dataSurface->SurfAirSkyRadSplit.allocate(state.dataSurface->TotSurfaces);
866 48091 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
867 47290 : state.dataSurface->SurfOutDryBulbTemp(SurfNum) = 0.0;
868 47290 : state.dataSurface->SurfOutWetBulbTemp(SurfNum) = 0.0;
869 47290 : state.dataSurface->SurfOutWindSpeed(SurfNum) = 0.0;
870 47290 : state.dataSurface->SurfOutWindDir(SurfNum) = 0.0;
871 47290 : state.dataSurface->SurfGenericContam(SurfNum) = 0.0;
872 47290 : state.dataSurface->SurfPenumbraID(SurfNum) = -1;
873 47290 : state.dataSurface->SurfAirSkyRadSplit(SurfNum) = 0.0;
874 : }
875 : // Following are surface property arrays used in SurfaceGeometry
876 801 : state.dataSurface->SurfShadowRecSurfNum.allocate(state.dataSurface->TotSurfaces);
877 801 : state.dataSurface->SurfShadowDisabledZoneList.allocate(state.dataSurface->TotSurfaces);
878 801 : state.dataSurface->SurfShadowDiffuseSolRefl.allocate(state.dataSurface->TotSurfaces);
879 801 : state.dataSurface->SurfShadowDiffuseVisRefl.allocate(state.dataSurface->TotSurfaces);
880 801 : state.dataSurface->SurfShadowGlazingFrac.allocate(state.dataSurface->TotSurfaces);
881 801 : state.dataSurface->SurfShadowGlazingConstruct.allocate(state.dataSurface->TotSurfaces);
882 48091 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
883 47290 : state.dataSurface->SurfShadowRecSurfNum(SurfNum) = 0;
884 47290 : state.dataSurface->SurfShadowDiffuseSolRefl(SurfNum) = 0.0;
885 47290 : state.dataSurface->SurfShadowDiffuseVisRefl(SurfNum) = 0.0;
886 47290 : state.dataSurface->SurfShadowGlazingFrac(SurfNum) = 0.0;
887 47290 : state.dataSurface->SurfShadowGlazingConstruct(SurfNum) = 0;
888 : }
889 801 : state.dataSurface->SurfExtEcoRoof.allocate(state.dataSurface->TotSurfaces);
890 801 : state.dataSurface->SurfExtCavityPresent.allocate(state.dataSurface->TotSurfaces);
891 801 : state.dataSurface->SurfExtCavNum.allocate(state.dataSurface->TotSurfaces);
892 801 : state.dataSurface->SurfIsPV.allocate(state.dataSurface->TotSurfaces);
893 801 : state.dataSurface->SurfIsICS.allocate(state.dataSurface->TotSurfaces);
894 801 : state.dataSurface->SurfIsPool.allocate(state.dataSurface->TotSurfaces);
895 801 : state.dataSurface->SurfICSPtr.allocate(state.dataSurface->TotSurfaces);
896 801 : state.dataSurface->SurfIsRadSurfOrVentSlabOrPool.allocate(state.dataSurface->TotSurfaces);
897 801 : state.dataSurface->SurfDaylightingShelfInd.allocate(state.dataSurface->TotSurfaces);
898 48091 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
899 47290 : state.dataSurface->SurfExtEcoRoof(SurfNum) = false;
900 47290 : state.dataSurface->SurfExtCavityPresent(SurfNum) = false;
901 47290 : state.dataSurface->SurfExtCavNum(SurfNum) = 0;
902 47290 : state.dataSurface->SurfIsPV(SurfNum) = false;
903 47290 : state.dataSurface->SurfIsICS(SurfNum) = false;
904 47290 : state.dataSurface->SurfIsPool(SurfNum) = false;
905 47290 : state.dataSurface->SurfICSPtr(SurfNum) = 0;
906 47290 : state.dataSurface->SurfIsRadSurfOrVentSlabOrPool(SurfNum) = false;
907 47290 : state.dataSurface->SurfDaylightingShelfInd(SurfNum) = 0;
908 : }
909 801 : state.dataSurface->SurfLowTempErrCount.allocate(state.dataSurface->TotSurfaces);
910 801 : state.dataSurface->SurfHighTempErrCount.allocate(state.dataSurface->TotSurfaces);
911 801 : state.dataSurface->surfIntConv.allocate(state.dataSurface->TotSurfaces);
912 801 : state.dataSurface->SurfTAirRef.allocate(state.dataSurface->TotSurfaces);
913 801 : state.dataSurface->SurfTAirRefRpt.allocate(state.dataSurface->TotSurfaces);
914 801 : state.dataSurface->surfExtConv.allocate(state.dataSurface->TotSurfaces);
915 48091 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
916 47290 : state.dataSurface->SurfLowTempErrCount(SurfNum) = 0;
917 47290 : state.dataSurface->SurfHighTempErrCount(SurfNum) = 0;
918 47290 : state.dataSurface->surfIntConv(SurfNum) = DataSurfaces::SurfIntConv();
919 47290 : state.dataSurface->surfExtConv(SurfNum) = DataSurfaces::SurfExtConv();
920 47290 : state.dataSurface->SurfTAirRef(SurfNum) = DataSurfaces::RefAirTemp::Invalid;
921 47290 : state.dataSurface->SurfTAirRefRpt(SurfNum) = static_cast<int>(DataSurfaces::RefAirTemp::Invalid);
922 : }
923 :
924 801 : state.dataSurface->intMovInsuls.allocate(state.dataSurface->TotSurfaces);
925 801 : state.dataSurface->extMovInsuls.allocate(state.dataSurface->TotSurfaces);
926 801 : }
927 :
928 801 : void GetSurfaceData(EnergyPlusData &state, bool &ErrorsFound) // If errors found in input
929 : {
930 :
931 : // SUBROUTINE INFORMATION:
932 : // AUTHOR Richard Liesen
933 : // DATE WRITTEN November 1997
934 : // MODIFIED April 1999, Linda Lawrie
935 : // Dec. 2000, FW (add "one-wall zone" checks)
936 : // RE-ENGINEERED May 2000, Linda Lawrie (breakout surface type gets)
937 :
938 : // PURPOSE OF THIS SUBROUTINE:
939 : // The purpose of this subroutine is to read in the surface information
940 : // from the input data file and interpret and put in the derived type
941 :
942 : // METHODOLOGY EMPLOYED:
943 : // The order of surfaces does not matter and the surfaces are resorted into
944 : // the hierarchical order:
945 : // All Shading Surfaces
946 : // Airwalls for space x1
947 : // Base Surfaces for space x1
948 : // Opaque Subsurfaces for space x1
949 : // Window Subsurfaces for space x1
950 : // TDD Dome Surfaces for space x1
951 : // Airwalls for space x2
952 : // Base Surfaces for space x2
953 : // etc
954 : // Pointers are set in the spaces (AllSurfaceFirst/Last, HTSurfaceFirst/Last, OpaqOrIntMassSurfaceFirst/Last, WindowSurfaceFirst/Last,
955 : // OpaqOrWinSurfaceFirst/Last, TDDDomeFirst/Last)
956 :
957 : // REFERENCES:
958 : // This routine manages getting the input for the following Objects:
959 : // SurfaceGeometry
960 : // Surface:Shading:Detached
961 : // Surface:HeatTransfer
962 : // Surface:HeatTransfer:Sub
963 : // Surface:Shading:Attached
964 : // Surface:InternalMass
965 :
966 : // Vertex input:
967 : // N3 , \field Number of Surface Vertices -- Number of (X,Y,Z) groups in this surface
968 : // \note currently limited 3 or 4, later?
969 : // \min 3
970 : // \max 4
971 : // \memo vertices are given in SurfaceGeometry coordinates -- if relative, all surface coordinates
972 : // \memo are "relative" to the Zone Origin. if WCS, then building and zone origins are used
973 : // \memo for some internal calculations, but all coordinates are given in an "absolute" system.
974 : // N4, \field Vertex 1 X-coordinate
975 : // \units m
976 : // \type real
977 : // N5 , \field Vertex 1 Y-coordinate
978 : // \units m
979 : // \type real
980 : // N6 , \field Vertex 1 Z-coordinate
981 : // \units m
982 : // \type real
983 : // N7, \field Vertex 2 X-coordinate
984 : // \units m
985 : // \type real
986 : // N8, \field Vertex 2 Y-coordinate
987 : // \units m
988 : // \type real
989 : // N9, \field Vertex 2 Z-coordinate
990 : // \units m
991 : // \type real
992 : // N10, \field Vertex 3 X-coordinate
993 : // \units m
994 : // \type real
995 : // N11, \field Vertex 3 Y-coordinate
996 : // \units m
997 : // \type real
998 : // N12, \field Vertex 3 Z-coordinate
999 : // \units m
1000 : // \type real
1001 : // N13, \field Vertex 4 X-coordinate
1002 : // \units m
1003 : // \type real
1004 : // N14, \field Vertex 4 Y-coordinate
1005 : // \type real
1006 : // \units m
1007 : // N15; \field Vertex 4 Z-coordinate
1008 : // \units m
1009 : // \type real
1010 :
1011 : // The vertices are stored in the surface derived type.
1012 : // +(1)-------------------------(4)+
1013 : // | |
1014 : // | |
1015 : // | |
1016 : // +(2)-------------------------(3)+
1017 : // The above diagram shows the actual coordinate points of a typical wall
1018 : // (you're on the outside looking toward the wall) as stored into
1019 : // Surface%Vertex(1:<number-of-sides>)
1020 :
1021 : static constexpr std::string_view RoutineName = "GetSurfaceData: ";
1022 : using namespace Vectors;
1023 : using namespace DataErrorTracking;
1024 :
1025 : int ConstrNumFound; // Construction number of matching interzone surface
1026 801 : bool NonMatch(false); // Error for non-matching interzone surfaces
1027 : int MovedSurfs; // Number of Moved Surfaces (when sorting into hierarchical structure)
1028 801 : bool SurfError(false); // General Surface Error, causes fatal error at end of routine
1029 : int TotLay; // Total layers in a construction
1030 : int TotLayFound; // Total layers in the construction of a matching interzone surface
1031 : // Simple Surfaces (Rectangular)
1032 : int LayNumOutside; // Outside material numbers for a shaded construction
1033 : // entries with two glazing systems
1034 : int NeedToAddSurfaces; // Surfaces that will be added due to "unentered" other zone surface
1035 : int NeedToAddSubSurfaces; // SubSurfaces that will be added due to "unentered" other zone surface
1036 801 : int CurNewSurf = 0;
1037 : Real64 SurfWorldAz;
1038 : Real64 SurfTilt;
1039 :
1040 : int MultFound;
1041 : int MultSurfNum;
1042 : bool SubSurfaceSevereDisplayed;
1043 801 : bool subSurfaceError(false);
1044 : bool errFlag;
1045 :
1046 : bool izConstDiff; // differences in construction for IZ surfaces
1047 : bool izConstDiffMsg; // display message about hb diffs only once.
1048 :
1049 : // Get the total number of surfaces to allocate derived type and for surface loops
1050 :
1051 801 : if (state.dataSurfaceGeometry->GetSurfaceDataOneTimeFlag) {
1052 0 : return;
1053 : } else {
1054 801 : state.dataSurfaceGeometry->GetSurfaceDataOneTimeFlag = true;
1055 : }
1056 :
1057 801 : GetGeometryParameters(state, ErrorsFound);
1058 :
1059 801 : if (state.dataSurface->WorldCoordSystem) {
1060 357 : bool RelWarning = false;
1061 357 : if (state.dataHeatBal->BuildingAzimuth != 0.0) {
1062 1 : RelWarning = true;
1063 : }
1064 1392 : for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
1065 1035 : if (state.dataHeatBal->Zone(ZoneNum).RelNorth != 0.0) {
1066 2 : RelWarning = true;
1067 : }
1068 : }
1069 357 : if (RelWarning && !state.dataSurfaceGeometry->WarningDisplayed) {
1070 2 : ShowWarningError(
1071 : state,
1072 2 : format("{}World Coordinate System selected. Any non-zero Building/Zone North Axes or non-zero Zone Origins are ignored.",
1073 : RoutineName));
1074 2 : ShowContinueError(state,
1075 : "These may be used in daylighting reference point coordinate calculations but not in normal geometry inputs.");
1076 1 : state.dataSurfaceGeometry->WarningDisplayed = true;
1077 : }
1078 357 : RelWarning = false;
1079 1392 : for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
1080 1035 : if (state.dataHeatBal->Zone(ZoneNum).OriginX != 0.0) {
1081 31 : RelWarning = true;
1082 : }
1083 1035 : if (state.dataHeatBal->Zone(ZoneNum).OriginY != 0.0) {
1084 35 : RelWarning = true;
1085 : }
1086 1035 : if (state.dataHeatBal->Zone(ZoneNum).OriginZ != 0.0) {
1087 4 : RelWarning = true;
1088 : }
1089 : }
1090 357 : if (RelWarning && !state.dataSurfaceGeometry->WarningDisplayed) {
1091 24 : ShowWarningError(
1092 : state,
1093 24 : format("{}World Coordinate System selected. Any non-zero Building/Zone North Axes or non-zero Zone Origins are ignored.",
1094 : RoutineName));
1095 24 : ShowContinueError(state,
1096 : "These may be used in daylighting reference point coordinate calculations but not in normal geometry inputs.");
1097 12 : state.dataSurfaceGeometry->WarningDisplayed = true;
1098 : }
1099 : }
1100 :
1101 801 : int TotDetachedFixed = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Site:Detailed");
1102 801 : int TotDetachedBldg = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Building:Detailed");
1103 801 : int TotRectDetachedFixed = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Site");
1104 801 : int TotRectDetachedBldg = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Building");
1105 801 : int TotHTSurfs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "BuildingSurface:Detailed");
1106 801 : int TotDetailedWalls = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Wall:Detailed");
1107 801 : int TotDetailedRoofs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "RoofCeiling:Detailed");
1108 801 : int TotDetailedFloors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Floor:Detailed");
1109 801 : int TotHTSubs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "FenestrationSurface:Detailed");
1110 801 : int TotShdSubs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Zone:Detailed");
1111 801 : int TotOverhangs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Overhang");
1112 801 : int TotOverhangsProjection = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Overhang:Projection");
1113 801 : int TotFins = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Fin");
1114 801 : int TotFinsProjection = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Fin:Projection");
1115 801 : int TotRectWindows = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Window");
1116 801 : int TotRectDoors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Door");
1117 801 : int TotRectGlazedDoors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "GlazedDoor");
1118 801 : int TotRectIZWindows = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Window:Interzone");
1119 801 : int TotRectIZDoors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Door:Interzone");
1120 801 : int TotRectIZGlazedDoors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "GlazedDoor:Interzone");
1121 801 : int TotRectExtWalls = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Wall:Exterior");
1122 801 : int TotRectIntWalls = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Wall:Adiabatic");
1123 801 : int TotRectIZWalls = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Wall:Interzone");
1124 801 : int TotRectUGWalls = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Wall:Underground");
1125 801 : int TotRectRoofs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Roof");
1126 801 : int TotRectCeilings = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Ceiling:Adiabatic");
1127 801 : int TotRectIZCeilings = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Ceiling:Interzone");
1128 801 : int TotRectGCFloors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Floor:GroundContact");
1129 801 : int TotRectIntFloors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Floor:Adiabatic");
1130 801 : int TotRectIZFloors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Floor:Interzone");
1131 :
1132 801 : state.dataSurface->TotOSC = 0;
1133 :
1134 801 : int TotIntMassSurfaces = GetNumIntMassSurfaces(state);
1135 :
1136 1602 : state.dataSurface->TotSurfaces = (TotDetachedFixed + TotDetachedBldg + TotRectDetachedFixed + TotRectDetachedBldg) * 2 + TotHTSurfs +
1137 801 : TotHTSubs + TotShdSubs * 2 + TotIntMassSurfaces + TotOverhangs * 2 + TotOverhangsProjection * 2 +
1138 801 : TotFins * 4 + TotFinsProjection * 4 + TotDetailedWalls + TotDetailedRoofs + TotDetailedFloors +
1139 801 : TotRectWindows + TotRectDoors + TotRectGlazedDoors + TotRectIZWindows + TotRectIZDoors +
1140 801 : TotRectIZGlazedDoors + TotRectExtWalls + TotRectIntWalls + TotRectIZWalls + TotRectUGWalls + TotRectRoofs +
1141 801 : TotRectCeilings + TotRectIZCeilings + TotRectGCFloors + TotRectIntFloors + TotRectIZFloors;
1142 :
1143 801 : state.dataSurfaceGeometry->SurfaceTmp.allocate(state.dataSurface->TotSurfaces); // Allocate the Surface derived type appropriately
1144 801 : state.dataSurfaceGeometry->UniqueSurfaceNames.reserve(state.dataSurface->TotSurfaces);
1145 : // SurfaceTmp structure is allocated via derived type initialization.
1146 :
1147 801 : int NumSurfs = 0;
1148 801 : int AddedSubSurfaces = 0;
1149 801 : state.dataErrTracking->AskForSurfacesReport = true;
1150 :
1151 801 : GetDetShdSurfaceData(state, ErrorsFound, NumSurfs, TotDetachedFixed, TotDetachedBldg);
1152 :
1153 801 : GetRectDetShdSurfaceData(state, ErrorsFound, NumSurfs, TotRectDetachedFixed, TotRectDetachedBldg);
1154 :
1155 801 : GetHTSurfaceData(state,
1156 : ErrorsFound,
1157 : NumSurfs,
1158 : TotHTSurfs,
1159 : TotDetailedWalls,
1160 : TotDetailedRoofs,
1161 : TotDetailedFloors,
1162 801 : state.dataSurfaceGeometry->BaseSurfCls,
1163 801 : state.dataSurfaceGeometry->BaseSurfIDs,
1164 : NeedToAddSurfaces);
1165 :
1166 801 : GetRectSurfaces(state,
1167 : ErrorsFound,
1168 : NumSurfs,
1169 : TotRectExtWalls,
1170 : TotRectIntWalls,
1171 : TotRectIZWalls,
1172 : TotRectUGWalls,
1173 : TotRectRoofs,
1174 : TotRectCeilings,
1175 : TotRectIZCeilings,
1176 : TotRectGCFloors,
1177 : TotRectIntFloors,
1178 : TotRectIZFloors,
1179 801 : state.dataSurfaceGeometry->BaseSurfIDs,
1180 : NeedToAddSurfaces);
1181 :
1182 801 : GetHTSubSurfaceData(state,
1183 : ErrorsFound,
1184 : NumSurfs,
1185 : TotHTSubs,
1186 801 : state.dataSurfaceGeometry->SubSurfCls,
1187 801 : state.dataSurfaceGeometry->SubSurfIDs,
1188 : AddedSubSurfaces,
1189 : NeedToAddSubSurfaces);
1190 :
1191 801 : GetRectSubSurfaces(state,
1192 : ErrorsFound,
1193 : NumSurfs,
1194 : TotRectWindows,
1195 : TotRectDoors,
1196 : TotRectGlazedDoors,
1197 : TotRectIZWindows,
1198 : TotRectIZDoors,
1199 : TotRectIZGlazedDoors,
1200 801 : state.dataSurfaceGeometry->SubSurfIDs,
1201 : AddedSubSurfaces,
1202 : NeedToAddSubSurfaces);
1203 :
1204 801 : GetAttShdSurfaceData(state, ErrorsFound, NumSurfs, TotShdSubs);
1205 :
1206 801 : GetSimpleShdSurfaceData(state, ErrorsFound, NumSurfs, TotOverhangs, TotOverhangsProjection, TotFins, TotFinsProjection);
1207 :
1208 801 : GetIntMassSurfaceData(state, ErrorsFound, NumSurfs);
1209 :
1210 801 : state.dataSurface->TotSurfaces = NumSurfs + AddedSubSurfaces + NeedToAddSurfaces + NeedToAddSubSurfaces;
1211 :
1212 801 : if (ErrorsFound) {
1213 0 : ShowFatalError(state, format("{}Errors discovered, program terminates.", RoutineName));
1214 : }
1215 :
1216 801 : state.dataSurface->Surface.allocate(state.dataSurface->TotSurfaces); // Allocate the Surface derived type appropriately
1217 801 : state.dataSurface->SurfaceWindow.allocate(state.dataSurface->TotSurfaces);
1218 801 : state.dataSurface->surfShades.allocate(state.dataSurface->TotSurfaces);
1219 801 : AllocateSurfaceArrays(state);
1220 801 : AllocateSurfaceWindows(state, state.dataSurface->TotSurfaces);
1221 :
1222 : // Have to make room for added surfaces, if needed
1223 801 : int FirstTotalSurfaces = NumSurfs + AddedSubSurfaces;
1224 801 : if (NeedToAddSurfaces + NeedToAddSubSurfaces > 0) {
1225 31 : state.dataSurfaceGeometry->SurfaceTmp.redimension(state.dataSurface->TotSurfaces);
1226 31 : CurNewSurf = FirstTotalSurfaces;
1227 : }
1228 :
1229 : // add the "need to add" surfaces
1230 : // Debug write(outputfiledebug,*) ' need to add ',NeedtoAddSurfaces+NeedToAddSubSurfaces
1231 47721 : for (int SurfNum = 1; SurfNum <= FirstTotalSurfaces; ++SurfNum) {
1232 46920 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
1233 46920 : if ((surfTemp.ExtBoundCond != unenteredAdjacentZoneSurface) && (surfTemp.ExtBoundCond != unenteredAdjacentSpaceSurface)) {
1234 46550 : continue;
1235 : }
1236 : // Need to add surface
1237 370 : ++CurNewSurf;
1238 : // Debug write(outputfiledebug,*) ' adding surface=',curnewsurf
1239 370 : auto &newSurf = state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf);
1240 370 : newSurf = surfTemp;
1241 : // Basic parameters are the same for both surfaces.
1242 370 : if (surfTemp.ExtBoundCond == unenteredAdjacentZoneSurface) {
1243 370 : int Found = Util::FindItemInList(surfTemp.ExtBoundCondName, state.dataHeatBal->Zone, state.dataGlobal->NumOfZones);
1244 370 : if (Found == 0) {
1245 0 : continue;
1246 : }
1247 370 : newSurf.Zone = Found;
1248 370 : auto &newZone = state.dataHeatBal->Zone(Found);
1249 370 : newSurf.ZoneName = newZone.Name;
1250 370 : assert(newZone.spaceIndexes.size() >= 1);
1251 370 : newSurf.spaceNum = 0; // clear this here and set later
1252 0 : } else if (surfTemp.ExtBoundCond == unenteredAdjacentSpaceSurface) {
1253 0 : int Found = Util::FindItemInList(surfTemp.ExtBoundCondName, state.dataHeatBal->space, state.dataGlobal->numSpaces);
1254 0 : if (Found == 0) {
1255 0 : continue;
1256 : }
1257 0 : newSurf.spaceNum = Found;
1258 0 : int zoneNum = state.dataHeatBal->space(Found).zoneNum;
1259 0 : newSurf.Zone = zoneNum;
1260 0 : newSurf.ZoneName = state.dataHeatBal->Zone(zoneNum).Name;
1261 : }
1262 : // Reverse Construction
1263 370 : newSurf.Construction = DataHeatBalance::AssignReverseConstructionNumber(state, surfTemp.Construction, SurfError);
1264 370 : newSurf.ConstructionStoredInputValue = newSurf.Construction;
1265 : // Reverse Vertices
1266 370 : int NVert = surfTemp.Sides;
1267 1850 : for (int Vert = 1; Vert <= surfTemp.Sides; ++Vert) {
1268 1480 : newSurf.Vertex(Vert) = surfTemp.Vertex(NVert);
1269 1480 : --NVert;
1270 : }
1271 370 : if (newSurf.Sides > 2) {
1272 370 : Vectors::CreateNewellAreaVector(newSurf.Vertex, newSurf.Sides, newSurf.NewellAreaVector);
1273 370 : newSurf.GrossArea = Vectors::VecLength(newSurf.NewellAreaVector);
1274 370 : newSurf.Area = newSurf.GrossArea;
1275 370 : newSurf.NetAreaShadowCalc = newSurf.Area;
1276 370 : Vectors::CreateNewellSurfaceNormalVector(newSurf.Vertex, newSurf.Sides, newSurf.NewellSurfaceNormalVector);
1277 370 : Vectors::DetermineAzimuthAndTilt(
1278 370 : newSurf.Vertex, SurfWorldAz, SurfTilt, newSurf.lcsx, newSurf.lcsy, newSurf.lcsz, newSurf.NewellSurfaceNormalVector);
1279 370 : newSurf.Azimuth = SurfWorldAz;
1280 370 : newSurf.Tilt = SurfTilt;
1281 370 : newSurf.convOrientation = Convect::GetSurfConvOrientation(newSurf.Tilt);
1282 :
1283 : // Sine and cosine of azimuth and tilt
1284 370 : newSurf.SinAzim = std::sin(SurfWorldAz * Constant::DegToRad);
1285 370 : newSurf.CosAzim = std::cos(SurfWorldAz * Constant::DegToRad);
1286 370 : newSurf.SinTilt = std::sin(SurfTilt * Constant::DegToRad);
1287 370 : newSurf.CosTilt = std::cos(SurfTilt * Constant::DegToRad);
1288 : // Outward normal unit vector (pointing away from room)
1289 370 : newSurf.OutNormVec = newSurf.NewellSurfaceNormalVector;
1290 1480 : for (int n = 1; n <= 3; ++n) {
1291 1110 : if (std::abs(newSurf.OutNormVec(n) - 1.0) < 1.e-06) {
1292 87 : newSurf.OutNormVec(n) = +1.0;
1293 : }
1294 1110 : if (std::abs(newSurf.OutNormVec(n) + 1.0) < 1.e-06) {
1295 241 : newSurf.OutNormVec(n) = -1.0;
1296 : }
1297 1110 : if (std::abs(newSurf.OutNormVec(n)) < 1.e-06) {
1298 698 : newSurf.OutNormVec(n) = 0.0;
1299 : }
1300 : }
1301 :
1302 : // Can perform tests on this surface here
1303 370 : newSurf.ViewFactorSky = 0.5 * (1.0 + newSurf.CosTilt);
1304 370 : newSurf.ViewFactorGround = 0.5 * (1.0 - newSurf.CosTilt);
1305 :
1306 : // The following IR view factors are modified in subr. SkyDifSolarShading if there are shadowing
1307 : // surfaces
1308 370 : newSurf.ViewFactorSkyIR = newSurf.ViewFactorSky;
1309 370 : newSurf.ViewFactorGroundIR = 0.5 * (1.0 - newSurf.CosTilt);
1310 : }
1311 :
1312 : // Change Name
1313 370 : newSurf.Name = "iz-" + surfTemp.Name;
1314 : // Debug write(outputfiledebug,*) ' new surf name=',TRIM(SurfaceTmp(CurNewSurf)%Name)
1315 : // Debug write(outputfiledebug,*) ' new surf in zone=',TRIM(surfacetmp(curnewsurf)%zoneName)
1316 370 : newSurf.ExtBoundCond = unreconciledZoneSurface;
1317 370 : surfTemp.ExtBoundCond = unreconciledZoneSurface;
1318 370 : newSurf.ExtBoundCondName = surfTemp.Name;
1319 370 : surfTemp.ExtBoundCondName = newSurf.Name;
1320 370 : if (newSurf.Class == SurfaceClass::Roof || newSurf.Class == SurfaceClass::Wall || newSurf.Class == SurfaceClass::Floor) {
1321 : // base surface
1322 366 : if (surfTemp.Class == SurfaceClass::Roof) {
1323 96 : newSurf.Class = SurfaceClass::Floor;
1324 : // Debug write(outputfiledebug,*) ' new surfaces is a floor'
1325 270 : } else if (surfTemp.Class == SurfaceClass::Floor) {
1326 16 : newSurf.Class = SurfaceClass::Roof;
1327 : // Debug write(outputfiledebug,*) ' new surfaces is a roof'
1328 : }
1329 366 : newSurf.BaseSurf = CurNewSurf;
1330 366 : newSurf.BaseSurfName = newSurf.Name;
1331 : // Debug write(outputfiledebug,*) ' basesurf, extboundcondname=',TRIM(SurfaceTmp(CurNewSurf)%ExtBoundCondName)
1332 : } else {
1333 : // subsurface
1334 : int Found =
1335 4 : Util::FindItemInList("iz-" + surfTemp.BaseSurfName, state.dataSurfaceGeometry->SurfaceTmp, FirstTotalSurfaces + CurNewSurf - 1);
1336 4 : if (Found > 0) {
1337 4 : newSurf.BaseSurfName = "iz-" + surfTemp.BaseSurfName;
1338 4 : newSurf.BaseSurf = Found;
1339 4 : auto &foundBaseSurf = state.dataSurfaceGeometry->SurfaceTmp(Found);
1340 4 : foundBaseSurf.Area -= newSurf.Area;
1341 4 : if (newSurf.Class == SurfaceClass::Window || newSurf.Class == SurfaceClass::GlassDoor) {
1342 2 : foundBaseSurf.NetAreaShadowCalc -= newSurf.Area / newSurf.Multiplier;
1343 : } else { // Door, TDD:Diffuser, TDD:DOME
1344 2 : foundBaseSurf.NetAreaShadowCalc -= newSurf.Area;
1345 : }
1346 4 : newSurf.ExtBoundCond = foundBaseSurf.ExtBoundCond;
1347 4 : newSurf.ExtBoundCondName = surfTemp.Name;
1348 4 : newSurf.ExtSolar = foundBaseSurf.ExtSolar;
1349 4 : newSurf.ExtWind = foundBaseSurf.ExtWind;
1350 4 : newSurf.Zone = foundBaseSurf.Zone;
1351 4 : newSurf.ZoneName = foundBaseSurf.ZoneName;
1352 4 : newSurf.spaceNum = foundBaseSurf.spaceNum;
1353 4 : newSurf.OSCPtr = foundBaseSurf.OSCPtr;
1354 : // Debug write(outputfiledebug,*) ' subsurf, extboundcondname=',TRIM(SurfaceTmp(CurNewSurf)%ExtBoundCondName)
1355 : // Debug write(outputfiledebug,*) ' subsurf, basesurf=',TRIM('iz-'//SurfaceTmp(SurfNum)%BaseSurfName)
1356 : } else {
1357 0 : ShowSevereError(state,
1358 0 : format("{}Adding unentered subsurface, could not find base surface=iz-{}", RoutineName, surfTemp.BaseSurfName));
1359 0 : SurfError = true;
1360 : }
1361 : }
1362 : }
1363 : //**********************************************************************************
1364 : // After all of the surfaces have been defined then the base surfaces for the
1365 : // sub-surfaces can be defined. Loop through surfaces and match with the sub-surface
1366 : // names.
1367 48091 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
1368 47290 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
1369 47290 : if (!surfTemp.HeatTransSurf) {
1370 1690 : continue;
1371 : }
1372 :
1373 45600 : int Found = 0;
1374 : // why are we doing this again? this should have already been done.
1375 45600 : if (Util::SameString(surfTemp.BaseSurfName, surfTemp.Name)) {
1376 38758 : Found = SurfNum;
1377 : } else {
1378 6842 : Found = Util::FindItemInList(surfTemp.BaseSurfName, state.dataSurfaceGeometry->SurfaceTmp, state.dataSurface->TotSurfaces);
1379 : }
1380 45600 : if (Found > 0) {
1381 45600 : surfTemp.BaseSurf = Found;
1382 45600 : if (SurfNum != Found) { // for subsurfaces
1383 6842 : if (surfTemp.HeatTransSurf) {
1384 6842 : ++state.dataSurfaceGeometry->SurfaceTmp(Found).NumSubSurfaces;
1385 : }
1386 6842 : if (surfTemp.Class < SurfaceClass::Window || surfTemp.Class > SurfaceClass::TDD_Diffuser) {
1387 0 : if (surfTemp.Class == SurfaceClass::None) {
1388 0 : ShowSevereError(state, format("{}Invalid SubSurface detected, Surface={}", RoutineName, surfTemp.Name));
1389 : } else {
1390 0 : ShowSevereError(state,
1391 0 : format("{}Invalid SubSurface detected, Surface={}, class={} invalid class for subsurface",
1392 : RoutineName,
1393 0 : surfTemp.Name,
1394 0 : state.dataSurfaceGeometry->BaseSurfCls(int(surfTemp.Class))));
1395 0 : SurfError = true;
1396 : }
1397 : }
1398 : }
1399 : }
1400 :
1401 : } // ...end of the Surface DO loop for finding BaseSurf
1402 : //**********************************************************************************
1403 : // The surfaces need to be hierarchical by space. Input is allowed to be in any order. In
1404 : // this section the surfaces are reordered into:
1405 : // All shadowing surfaces (if mirrored, Mir- surface follows immediately after original)
1406 : // Shading:Site
1407 : // Shading:Building
1408 : // Shading:space (and variants)
1409 : // For each space:
1410 : // Walls
1411 : // Floors
1412 : // Roofs/Ceilings
1413 : // Internal Mass
1414 : // Non-Window subsurfaces (including doors)
1415 : // Window subsurfaces (including TubularDaylightingDiffusers)
1416 : // TubularDaylightingDomes
1417 : // After reordering, MovedSurfs should equal TotSurfaces
1418 :
1419 : // For reporting purposes, the legacy surface order is also saved in DataSurfaces::AllSurfaceListReportOrder:
1420 : // All shadowing surfaces (if mirrored, Mir- surface follows immediately after original)
1421 : // Shading:Site
1422 : // Shading:Building
1423 : // Shading:Zone (and variants)
1424 : // For each zone:
1425 : // Walls
1426 : // subsurfaces for each wall (windows, doors, in input order, not sorted) follow the base surface
1427 : // Floors
1428 : // subsurfaces for each floor (windows, doors, in input order, not sorted) follow the base surface
1429 : // Roofs/Ceilings
1430 : // subsurfaces for each roof/ceiling (windows, doors, in input order, not sorted) follow the base surface
1431 : // Internal Mass
1432 : // After reordering, MovedSurfs should equal TotSurfaces
1433 :
1434 801 : MovedSurfs = 0;
1435 801 : Array1D<bool> SurfaceTmpClassMoved; // Tmp class is moved
1436 801 : SurfaceTmpClassMoved.dimension(state.dataSurface->TotSurfaces, false);
1437 801 : state.dataSurface->AllSurfaceListReportOrder.reserve(state.dataSurface->TotSurfaces);
1438 :
1439 801 : CreateMissingSpaces(state, state.dataSurfaceGeometry->SurfaceTmp);
1440 :
1441 : // Old SurfNum to New SurfNum
1442 : // Old = order in state.dataSurfaceGeometry->SurfaceTmp
1443 : // New = order in state.dataSurface->Surface
1444 801 : EPVector<int> oldToNewSurfNums;
1445 801 : oldToNewSurfNums.resize(state.dataSurface->TotSurfaces, -1);
1446 :
1447 : // Move all shading Surfaces to Front
1448 48091 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
1449 47290 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
1450 47290 : if (surfTemp.Class != SurfaceClass::Detached_F && surfTemp.Class != SurfaceClass::Detached_B && surfTemp.Class != SurfaceClass::Shading) {
1451 45600 : continue;
1452 : }
1453 :
1454 : // A shading surface
1455 1690 : ++MovedSurfs;
1456 : // Store list of moved surface numbers in reporting order
1457 1690 : state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
1458 1690 : SurfaceTmpClassMoved(SurfNum) = true; //'Moved'
1459 1690 : state.dataSurface->AllSurfaceListReportOrder.push_back(SurfNum);
1460 1690 : oldToNewSurfNums(SurfNum) = MovedSurfs;
1461 : }
1462 :
1463 : // For each zone
1464 :
1465 6002 : for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
1466 10414 : for (int spaceNum : state.dataHeatBal->Zone(ZoneNum).spaceIndexes) {
1467 : // Group air boundary surfaces first within each space
1468 1420299 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
1469 1415086 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
1470 1415086 : if (SurfaceTmpClassMoved(SurfNum)) {
1471 689461 : continue;
1472 : }
1473 725625 : if (surfTemp.spaceNum != spaceNum) {
1474 680025 : continue;
1475 : }
1476 45600 : int constNum = surfTemp.Construction;
1477 45600 : if (constNum == 0) {
1478 0 : continue;
1479 : }
1480 45600 : if (!state.dataConstruction->Construct(constNum).TypeIsAirBoundary) {
1481 45582 : continue;
1482 : }
1483 :
1484 : // An air boundary surface
1485 18 : surfTemp.IsAirBoundarySurf = true;
1486 18 : ++MovedSurfs;
1487 18 : state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
1488 : // If base Surface Type (Wall, Floor, Roof/Ceiling)
1489 18 : if ((surfTemp.Class == state.dataSurfaceGeometry->BaseSurfIDs(1)) ||
1490 18 : (surfTemp.Class == state.dataSurfaceGeometry->BaseSurfIDs(2)) ||
1491 0 : (surfTemp.Class == state.dataSurfaceGeometry->BaseSurfIDs(3))) {
1492 : // Store list of moved surface numbers in reporting order. We use the old position, we'll reconcile later
1493 : // We don't do it for Air Door/Air Windows yet, we want them listed below each base surf they belong to
1494 18 : state.dataSurface->AllSurfaceListReportOrder.push_back(SurfNum);
1495 : }
1496 18 : oldToNewSurfNums(SurfNum) = MovedSurfs;
1497 18 : SurfaceTmpClassMoved(SurfNum) = true; //'Moved'
1498 : }
1499 :
1500 : // For each Base Surface Type (Wall, Floor, Roof/Ceiling) - put these first
1501 :
1502 20852 : for (const DataSurfaces::SurfaceClass Loop : state.dataSurfaceGeometry->BaseSurfIDs) {
1503 :
1504 4260897 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
1505 4245258 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
1506 :
1507 4245258 : if (SurfaceTmpClassMoved(SurfNum)) {
1508 2121887 : continue;
1509 : }
1510 2123371 : if (surfTemp.Zone == 0) {
1511 0 : continue;
1512 : }
1513 :
1514 2123371 : if (surfTemp.spaceNum != spaceNum) {
1515 2040075 : continue;
1516 : }
1517 83296 : if (surfTemp.Class != Loop) {
1518 47093 : continue;
1519 : }
1520 :
1521 36203 : ++MovedSurfs;
1522 36203 : state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
1523 36203 : oldToNewSurfNums(SurfNum) = MovedSurfs;
1524 36203 : SurfaceTmpClassMoved(SurfNum) = true; // 'Moved'
1525 : // Store list of moved surface numbers in order reporting order (subsurfaces follow their base surface)
1526 36203 : state.dataSurface->AllSurfaceListReportOrder.push_back(SurfNum);
1527 :
1528 : // Find all subsurfaces to this surface - just to update Report them in order
1529 10160930 : for (int SubSurfNum = 1; SubSurfNum <= state.dataSurface->TotSurfaces; ++SubSurfNum) {
1530 : // Gotta avoid pushing myself again!
1531 10124727 : if (SubSurfNum == SurfNum) {
1532 36203 : continue;
1533 : }
1534 : // We don't check if already moved, because we didn't add them to AllSurfaceListReportOrder above!
1535 10088524 : if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).Zone == 0) {
1536 116680 : continue;
1537 : }
1538 9971844 : if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).BaseSurf != SurfNum) {
1539 9965002 : continue;
1540 : }
1541 : // Add original sub-surface numbers as placeholders in surface list for reporting
1542 6842 : state.dataSurface->AllSurfaceListReportOrder.push_back(SubSurfNum);
1543 : }
1544 : }
1545 : }
1546 :
1547 : // Internal mass goes next
1548 1420299 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
1549 1415086 : if (SurfaceTmpClassMoved(SurfNum)) {
1550 725682 : continue;
1551 : }
1552 :
1553 689404 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
1554 689404 : if (surfTemp.spaceNum != spaceNum) {
1555 680025 : continue;
1556 : }
1557 9379 : if (surfTemp.Class != SurfaceClass::IntMass) {
1558 6842 : continue;
1559 : }
1560 2537 : ++MovedSurfs;
1561 2537 : state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
1562 2537 : oldToNewSurfNums(SurfNum) = MovedSurfs;
1563 2537 : SurfaceTmpClassMoved(SurfNum) = true; // 'Moved'
1564 : // Store list of moved surface numbers in reporting order
1565 2537 : state.dataSurface->AllSurfaceListReportOrder.push_back(SurfNum);
1566 : }
1567 :
1568 : // Opaque door goes next
1569 1420299 : for (int SubSurfNum = 1; SubSurfNum <= state.dataSurface->TotSurfaces; ++SubSurfNum) {
1570 :
1571 1415086 : if (SurfaceTmpClassMoved(SubSurfNum)) {
1572 728219 : continue;
1573 : }
1574 686867 : if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).spaceNum != spaceNum) {
1575 680025 : continue;
1576 : }
1577 6842 : if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).Class != SurfaceClass::Door) {
1578 6361 : continue;
1579 : }
1580 :
1581 481 : ++MovedSurfs;
1582 481 : state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum);
1583 481 : oldToNewSurfNums(SubSurfNum) = MovedSurfs;
1584 481 : SurfaceTmpClassMoved(SubSurfNum) = true; // 'Moved'
1585 : }
1586 :
1587 : // The exterior window subsurfaces (includes SurfaceClass::Window and SurfaceClass::GlassDoor) goes next
1588 1420299 : for (int SubSurfNum = 1; SubSurfNum <= state.dataSurface->TotSurfaces; ++SubSurfNum) {
1589 :
1590 1415086 : if (SurfaceTmpClassMoved(SubSurfNum)) {
1591 728700 : continue;
1592 : }
1593 686386 : if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).spaceNum != spaceNum) {
1594 680025 : continue;
1595 : }
1596 6361 : if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).ExtBoundCond > 0) {
1597 0 : continue; // Exterior window
1598 : }
1599 6906 : if ((state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).Class != SurfaceClass::Window) &&
1600 545 : (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).Class != SurfaceClass::GlassDoor)) {
1601 4 : continue;
1602 : }
1603 :
1604 6357 : ++MovedSurfs;
1605 6357 : state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum);
1606 6357 : oldToNewSurfNums(SubSurfNum) = MovedSurfs;
1607 6357 : SurfaceTmpClassMoved(SubSurfNum) = true; // 'Moved'
1608 : }
1609 :
1610 : // The interior window subsurfaces (includes SurfaceClass::Window and SurfaceClass::GlassDoor) goes next
1611 1420299 : for (int SubSurfNum = 1; SubSurfNum <= state.dataSurface->TotSurfaces; ++SubSurfNum) {
1612 :
1613 1415086 : if (SurfaceTmpClassMoved(SubSurfNum)) {
1614 735057 : continue;
1615 : }
1616 680029 : if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).spaceNum != spaceNum) {
1617 680025 : continue;
1618 : }
1619 4 : if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).ExtBoundCond <= 0) {
1620 4 : continue;
1621 : }
1622 0 : if ((state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).Class != SurfaceClass::Window) &&
1623 0 : (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).Class != SurfaceClass::GlassDoor)) {
1624 0 : continue;
1625 : }
1626 :
1627 0 : ++MovedSurfs;
1628 0 : state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum);
1629 0 : oldToNewSurfNums(SubSurfNum) = MovedSurfs;
1630 0 : SurfaceTmpClassMoved(SubSurfNum) = true; // 'Moved'
1631 : }
1632 :
1633 : // The SurfaceClass::TDD_Diffuser (OriginalClass = Window) goes next
1634 1420299 : for (int SubSurfNum = 1; SubSurfNum <= state.dataSurface->TotSurfaces; ++SubSurfNum) {
1635 :
1636 1415086 : if (SurfaceTmpClassMoved(SubSurfNum)) {
1637 735057 : continue;
1638 : }
1639 680029 : if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).spaceNum != spaceNum) {
1640 680025 : continue;
1641 : }
1642 4 : if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).Class != SurfaceClass::TDD_Diffuser) {
1643 2 : continue;
1644 : }
1645 :
1646 2 : ++MovedSurfs;
1647 2 : state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum);
1648 2 : oldToNewSurfNums(SubSurfNum) = MovedSurfs;
1649 2 : SurfaceTmpClassMoved(SubSurfNum) = true; // 'Moved'
1650 : }
1651 :
1652 : // Last but not least, SurfaceClass::TDD_Dome
1653 1420299 : for (int SubSurfNum = 1; SubSurfNum <= state.dataSurface->TotSurfaces; ++SubSurfNum) {
1654 :
1655 1415086 : if (SurfaceTmpClassMoved(SubSurfNum)) {
1656 735059 : continue;
1657 : }
1658 680027 : if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).spaceNum != spaceNum) {
1659 680025 : continue;
1660 : }
1661 2 : if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).Class != SurfaceClass::TDD_Dome) {
1662 0 : continue;
1663 : }
1664 :
1665 2 : ++MovedSurfs;
1666 2 : state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum);
1667 2 : oldToNewSurfNums(SubSurfNum) = MovedSurfs;
1668 2 : SurfaceTmpClassMoved(SubSurfNum) = true; // 'Moved'
1669 : }
1670 5201 : }
1671 : }
1672 :
1673 : // Validity checking
1674 801 : assert(state.dataSurface->TotSurfaces == MovedSurfs);
1675 801 : assert(state.dataSurface->TotSurfaces == static_cast<int>(state.dataSurface->AllSurfaceListReportOrder.size()));
1676 801 : assert(state.dataSurface->TotSurfaces == static_cast<int>(oldToNewSurfNums.size()));
1677 :
1678 : // Assert validity of indices
1679 48091 : assert(std::find_if(state.dataSurface->AllSurfaceListReportOrder.cbegin(), state.dataSurface->AllSurfaceListReportOrder.cend(), [](int i) {
1680 : return i < 1;
1681 : }) == state.dataSurface->AllSurfaceListReportOrder.cend());
1682 :
1683 48091 : assert(std::find_if(oldToNewSurfNums.cbegin(), oldToNewSurfNums.cend(), [](int i) { return i < 1; }) == oldToNewSurfNums.cend());
1684 :
1685 801 : if (MovedSurfs != state.dataSurface->TotSurfaces) {
1686 0 : ShowSevereError(
1687 : state,
1688 0 : format("{}Reordered # of Surfaces ({}) not = Total # of Surfaces ({})", RoutineName, MovedSurfs, state.dataSurface->TotSurfaces));
1689 0 : SurfError = true;
1690 0 : for (int Loop = 1; Loop <= state.dataSurface->TotSurfaces; ++Loop) {
1691 0 : if (!SurfaceTmpClassMoved(Loop) && state.dataSurfaceGeometry->SurfaceTmp(Loop).Class == SurfaceClass::Invalid) {
1692 0 : ShowSevereError(state,
1693 0 : format("{}Error in Surface= \"{} indicated Zone=\"{}\"",
1694 : RoutineName,
1695 0 : state.dataSurfaceGeometry->SurfaceTmp(Loop).Name,
1696 0 : state.dataSurfaceGeometry->SurfaceTmp(Loop).ZoneName));
1697 : }
1698 : }
1699 0 : ShowWarningError(
1700 0 : state, format("{}Remaining surface checks will use \"reordered number of surfaces\", not number of original surfaces", RoutineName));
1701 : }
1702 :
1703 : // Realign the relationship: surface to base surface
1704 48091 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
1705 47290 : auto &movedSurf = state.dataSurface->Surface(SurfNum);
1706 47290 : if (movedSurf.BaseSurf > 0) {
1707 45600 : int newBaseSurfNum = oldToNewSurfNums(movedSurf.BaseSurf);
1708 45600 : movedSurf.BaseSurf = newBaseSurfNum;
1709 :
1710 45600 : if (newBaseSurfNum < 1) {
1711 0 : ShowFatalError(
1712 : state,
1713 0 : format("{}Couldn't find the new Surface Number for surface index {} named '{}'. Looking for BaseSurf old index of {}",
1714 : RoutineName,
1715 : SurfNum,
1716 0 : movedSurf.Name,
1717 0 : movedSurf.BaseSurf));
1718 : }
1719 : }
1720 47290 : auto &reportOrderNum = state.dataSurface->AllSurfaceListReportOrder[SurfNum - 1];
1721 47290 : if (reportOrderNum > 0) {
1722 47290 : int newReportOrderNum = oldToNewSurfNums(reportOrderNum);
1723 47290 : reportOrderNum = newReportOrderNum;
1724 : }
1725 : }
1726 :
1727 801 : state.dataSurfaceGeometry->SurfaceTmp.deallocate(); // DeAllocate the Temp Surface derived type
1728 :
1729 801 : createSpaceSurfaceLists(state);
1730 :
1731 : // For each Base Surface Type (Wall, Floor, Roof)
1732 :
1733 3204 : for (const DataSurfaces::SurfaceClass Loop : state.dataSurfaceGeometry->BaseSurfIDs) {
1734 144273 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
1735 :
1736 141870 : if (state.dataSurface->Surface(SurfNum).Zone == 0) {
1737 5070 : continue;
1738 : }
1739 :
1740 136800 : if (state.dataSurface->Surface(SurfNum).Class != Loop) {
1741 100579 : continue;
1742 : }
1743 :
1744 : // Find all subsurfaces to this surface
1745 10161970 : for (int SubSurfNum = 1; SubSurfNum <= state.dataSurface->TotSurfaces; ++SubSurfNum) {
1746 :
1747 10125749 : if (SurfNum == SubSurfNum) {
1748 36221 : continue;
1749 : }
1750 10089528 : if (state.dataSurface->Surface(SubSurfNum).Zone == 0) {
1751 116752 : continue;
1752 : }
1753 9972776 : if (state.dataSurface->Surface(SubSurfNum).BaseSurf != SurfNum) {
1754 9965934 : continue;
1755 : }
1756 :
1757 : // Check facing angle of Sub compared to base
1758 6842 : checkSubSurfAzTiltNorm(state, state.dataSurface->Surface(SurfNum), state.dataSurface->Surface(SubSurfNum), subSurfaceError);
1759 6842 : if (subSurfaceError) {
1760 0 : SurfError = true;
1761 : }
1762 : }
1763 : }
1764 : }
1765 :
1766 : //**********************************************************************************
1767 : // Now, match up interzone surfaces
1768 801 : NonMatch = false;
1769 801 : izConstDiffMsg = false;
1770 48091 : for (int SurfNum = 1; SurfNum <= MovedSurfs; ++SurfNum) { // TotSurfaces
1771 : // Clean up Shading Surfaces, make sure they don't go through here.
1772 47290 : if (!state.dataSurface->Surface(SurfNum).HeatTransSurf) {
1773 1690 : continue;
1774 : }
1775 : // If other surface, match it up
1776 : // Both interzone and "internal" surfaces have this pointer set
1777 : // Internal surfaces point to themselves, Interzone to another
1778 45600 : if (state.dataSurface->Surface(SurfNum).ExtBoundCond == unreconciledZoneSurface) {
1779 15964 : if (not_blank(state.dataSurface->Surface(SurfNum).ExtBoundCondName)) {
1780 15964 : int Found = 0;
1781 15964 : if (state.dataSurface->Surface(SurfNum).ExtBoundCondName == state.dataSurface->Surface(SurfNum).Name) {
1782 7015 : Found = SurfNum;
1783 : } else {
1784 8949 : Found = Util::FindItemInList(state.dataSurface->Surface(SurfNum).ExtBoundCondName, state.dataSurface->Surface, MovedSurfs);
1785 : }
1786 15964 : if (Found != 0) {
1787 15964 : state.dataSurface->Surface(SurfNum).ExtBoundCond = Found;
1788 : // Check that matching surface is also "OtherZoneSurface"
1789 24878 : if (state.dataSurface->Surface(Found).ExtBoundCond <= 0 &&
1790 8914 : state.dataSurface->Surface(Found).ExtBoundCond != unreconciledZoneSurface) {
1791 0 : ShowSevereError(state, format("{}Potential \"OtherZoneSurface\" is not matched correctly:", RoutineName));
1792 :
1793 0 : ShowContinueError(state,
1794 0 : format("Surface={}, Zone={}",
1795 0 : state.dataSurface->Surface(SurfNum).Name,
1796 0 : state.dataSurface->Surface(SurfNum).ZoneName));
1797 0 : ShowContinueError(state,
1798 0 : format("Nonmatched Other/InterZone Surface={}, Zone={}",
1799 0 : state.dataSurface->Surface(Found).Name,
1800 0 : state.dataSurface->Surface(Found).ZoneName));
1801 0 : SurfError = true;
1802 : }
1803 : // Check that matching interzone surface has construction with reversed layers
1804 15964 : if (Found != SurfNum) { // Interzone surface
1805 : // Make sure different zones too (CR 4110)
1806 8949 : if (state.dataSurface->Surface(SurfNum).spaceNum == state.dataSurface->Surface(Found).spaceNum) {
1807 3 : ++state.dataSurfaceGeometry->ErrCount2;
1808 3 : if (state.dataSurfaceGeometry->ErrCount2 == 1 && !state.dataGlobal->DisplayExtraWarnings) {
1809 4 : ShowWarningError(state,
1810 4 : format("{}CAUTION -- Interspace surfaces are occurring in the same space(s).", RoutineName));
1811 6 : ShowContinueError(
1812 : state, "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on individual occurrences.");
1813 : }
1814 3 : if (state.dataGlobal->DisplayExtraWarnings) {
1815 0 : ShowWarningError(state, format("{}CAUTION -- Interspace surfaces are usually in different spaces", RoutineName));
1816 0 : ShowContinueError(state,
1817 0 : format("Surface={}, Space={}, Zone={}",
1818 0 : state.dataSurface->Surface(SurfNum).Name,
1819 0 : state.dataHeatBal->space(state.dataSurface->Surface(SurfNum).spaceNum).Name,
1820 0 : state.dataSurface->Surface(SurfNum).ZoneName));
1821 0 : ShowContinueError(state,
1822 0 : format("Surface={}, Space={}, Zone={}",
1823 0 : state.dataSurface->Surface(Found).Name,
1824 0 : state.dataHeatBal->space(state.dataSurface->Surface(Found).spaceNum).Name,
1825 0 : state.dataSurface->Surface(Found).ZoneName));
1826 : }
1827 : }
1828 8949 : int ConstrNum = state.dataSurface->Surface(SurfNum).Construction;
1829 8949 : int ConstrNumFound = state.dataSurface->Surface(Found).Construction;
1830 8949 : if (ConstrNum <= 0 || ConstrNumFound <= 0) {
1831 0 : continue;
1832 : }
1833 8949 : if (state.dataConstruction->Construct(ConstrNum).ReverseConstructionNumLayersWarning &&
1834 0 : state.dataConstruction->Construct(ConstrNumFound).ReverseConstructionNumLayersWarning) {
1835 0 : continue;
1836 : }
1837 8961 : if (state.dataConstruction->Construct(ConstrNum).ReverseConstructionLayersOrderWarning &&
1838 12 : state.dataConstruction->Construct(ConstrNumFound).ReverseConstructionLayersOrderWarning) {
1839 12 : continue;
1840 : }
1841 8937 : TotLay = state.dataConstruction->Construct(ConstrNum).TotLayers;
1842 8937 : TotLayFound = state.dataConstruction->Construct(ConstrNumFound).TotLayers;
1843 8937 : if (TotLay != TotLayFound) { // Different number of layers
1844 : // match on like Uvalues (nominal)
1845 0 : if (std::abs(state.dataHeatBal->NominalU(ConstrNum) - state.dataHeatBal->NominalU(ConstrNumFound)) > 0.001) {
1846 0 : ShowSevereError(state,
1847 0 : format("{}Construction {} of interzone surface {} does not have the same number of layers as the "
1848 : "construction {} of adjacent surface {}",
1849 : RoutineName,
1850 0 : state.dataConstruction->Construct(ConstrNum).Name,
1851 0 : state.dataSurface->Surface(SurfNum).Name,
1852 0 : state.dataConstruction->Construct(ConstrNumFound).Name,
1853 0 : state.dataSurface->Surface(Found).Name));
1854 0 : if (!state.dataConstruction->Construct(ConstrNum).ReverseConstructionNumLayersWarning ||
1855 0 : !state.dataConstruction->Construct(ConstrNumFound).ReverseConstructionNumLayersWarning) {
1856 0 : ShowContinueError(state, "...this problem for this pair will not be reported again.");
1857 0 : state.dataConstruction->Construct(ConstrNum).ReverseConstructionNumLayersWarning = true;
1858 0 : state.dataConstruction->Construct(ConstrNumFound).ReverseConstructionNumLayersWarning = true;
1859 : }
1860 0 : SurfError = true;
1861 : }
1862 : } else { // Same number of layers; check for reverse layers
1863 : // check layers as number of layers is the same
1864 8937 : izConstDiff = false;
1865 : // ok if same nominal U
1866 8937 : CheckForReversedLayers(state, izConstDiff, ConstrNum, ConstrNumFound, TotLay);
1867 8939 : if (izConstDiff &&
1868 2 : std::abs(state.dataHeatBal->NominalU(ConstrNum) - state.dataHeatBal->NominalU(ConstrNumFound)) > 0.001) {
1869 0 : ShowSevereError(state,
1870 0 : format("{}Construction {} of interzone surface {} does not have the same materials in the "
1871 : "reverse order as the construction {} of adjacent surface {}",
1872 : RoutineName,
1873 0 : state.dataConstruction->Construct(ConstrNum).Name,
1874 0 : state.dataSurface->Surface(SurfNum).Name,
1875 0 : state.dataConstruction->Construct(ConstrNumFound).Name,
1876 0 : state.dataSurface->Surface(Found).Name));
1877 0 : ShowContinueError(state,
1878 : "or the properties of the reversed layers are not correct due to differing layer front and "
1879 : "back side values");
1880 0 : if (!state.dataConstruction->Construct(ConstrNum).ReverseConstructionLayersOrderWarning ||
1881 0 : !state.dataConstruction->Construct(ConstrNumFound).ReverseConstructionLayersOrderWarning) {
1882 0 : ShowContinueError(state, "...this problem for this pair will not be reported again.");
1883 0 : state.dataConstruction->Construct(ConstrNum).ReverseConstructionLayersOrderWarning = true;
1884 0 : state.dataConstruction->Construct(ConstrNumFound).ReverseConstructionLayersOrderWarning = true;
1885 : }
1886 0 : SurfError = true;
1887 8937 : } else if (izConstDiff) {
1888 4 : ShowWarningError(state,
1889 4 : format("{}Construction {} of interzone surface {} does not have the same materials in the "
1890 : "reverse order as the construction {} of adjacent surface {}",
1891 : RoutineName,
1892 2 : state.dataConstruction->Construct(ConstrNum).Name,
1893 2 : state.dataSurface->Surface(SurfNum).Name,
1894 2 : state.dataConstruction->Construct(ConstrNumFound).Name,
1895 2 : state.dataSurface->Surface(Found).Name));
1896 4 : ShowContinueError(state,
1897 : "or the properties of the reversed layers are not correct due to differing layer front and "
1898 : "back side values");
1899 4 : ShowContinueError(
1900 : state,
1901 4 : format("...but Nominal U values are similar, diff=[{:.4R}] ... simulation proceeds.",
1902 2 : std::abs(state.dataHeatBal->NominalU(ConstrNum) - state.dataHeatBal->NominalU(ConstrNumFound))));
1903 2 : if (!izConstDiffMsg) {
1904 4 : ShowContinueError(state,
1905 : "...if the two zones are expected to have significantly different temperatures, the proper "
1906 : "\"reverse\" construction should be created.");
1907 2 : izConstDiffMsg = true;
1908 : }
1909 2 : if (!state.dataConstruction->Construct(ConstrNum).ReverseConstructionLayersOrderWarning ||
1910 0 : !state.dataConstruction->Construct(ConstrNumFound).ReverseConstructionLayersOrderWarning) {
1911 4 : ShowContinueError(state, "...this problem for this pair will not be reported again.");
1912 2 : state.dataConstruction->Construct(ConstrNum).ReverseConstructionLayersOrderWarning = true;
1913 2 : state.dataConstruction->Construct(ConstrNumFound).ReverseConstructionLayersOrderWarning = true;
1914 : }
1915 : }
1916 : }
1917 :
1918 : // If significantly different areas -- this would not be good
1919 8937 : MultFound = state.dataHeatBal->Zone(state.dataSurface->Surface(Found).Zone).Multiplier *
1920 8937 : state.dataHeatBal->Zone(state.dataSurface->Surface(Found).Zone).ListMultiplier;
1921 8937 : MultSurfNum = state.dataHeatBal->Zone(state.dataSurface->Surface(SurfNum).Zone).Multiplier *
1922 8937 : state.dataHeatBal->Zone(state.dataSurface->Surface(SurfNum).Zone).ListMultiplier;
1923 8937 : if (state.dataSurface->Surface(Found).Area > 0.0) {
1924 8937 : if (std::abs((state.dataSurface->Surface(Found).Area * MultFound -
1925 8937 : state.dataSurface->Surface(SurfNum).Area * MultSurfNum) /
1926 8937 : state.dataSurface->Surface(Found).Area * MultFound) > 0.02) { // 2% difference in areas
1927 0 : ++state.dataSurfaceGeometry->ErrCount4;
1928 0 : if (state.dataSurfaceGeometry->ErrCount4 == 1 && !state.dataGlobal->DisplayExtraWarnings) {
1929 0 : ShowWarningError(
1930 : state,
1931 0 : format("{}InterZone Surface Areas do not match as expected and might not satisfy conservation of energy:",
1932 : RoutineName));
1933 0 : ShowContinueError(
1934 : state, "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on individual mismatches.");
1935 : }
1936 0 : if (state.dataGlobal->DisplayExtraWarnings) {
1937 0 : ShowWarningError(
1938 : state,
1939 0 : format("{}InterZone Surface Areas do not match as expected and might not satisfy conservation of energy:",
1940 : RoutineName));
1941 :
1942 0 : if (MultFound == 1 && MultSurfNum == 1) {
1943 0 : ShowContinueError(state,
1944 0 : format(" Area={:.1T} in Surface={}, Zone={}",
1945 0 : state.dataSurface->Surface(SurfNum).Area,
1946 0 : state.dataSurface->Surface(SurfNum).Name,
1947 0 : state.dataSurface->Surface(SurfNum).ZoneName));
1948 0 : ShowContinueError(state,
1949 0 : format(" Area={:.1T} in Surface={}, Zone={}",
1950 0 : state.dataSurface->Surface(Found).Area,
1951 0 : state.dataSurface->Surface(Found).Name,
1952 0 : state.dataSurface->Surface(Found).ZoneName));
1953 : } else { // Show multiplier info
1954 0 : ShowContinueError(state,
1955 0 : format(" Area={:.1T}, Multipliers={}, Total Area={:.1T} in Surface={} Zone={}",
1956 0 : state.dataSurface->Surface(SurfNum).Area,
1957 : MultSurfNum,
1958 0 : state.dataSurface->Surface(SurfNum).Area * MultSurfNum,
1959 0 : state.dataSurface->Surface(SurfNum).Name,
1960 0 : state.dataSurface->Surface(SurfNum).ZoneName));
1961 :
1962 0 : ShowContinueError(state,
1963 0 : format(" Area={:.1T}, Multipliers={}, Total Area={:.1T} in Surface={} Zone={}",
1964 0 : state.dataSurface->Surface(Found).Area,
1965 : MultFound,
1966 0 : state.dataSurface->Surface(Found).Area * MultFound,
1967 0 : state.dataSurface->Surface(Found).Name,
1968 0 : state.dataSurface->Surface(Found).ZoneName));
1969 : }
1970 : }
1971 : }
1972 : }
1973 : // Check opposites Azimuth and Tilt
1974 : // Tilt
1975 8937 : if (std::abs(std::abs(state.dataSurface->Surface(Found).Tilt + state.dataSurface->Surface(SurfNum).Tilt) - 180.0) > 1.0) {
1976 0 : ShowWarningError(state, format("{}InterZone Surface Tilts do not match as expected.", RoutineName));
1977 0 : ShowContinueError(state,
1978 0 : format(" Tilt={:.1T} in Surface={}, Zone={}",
1979 0 : state.dataSurface->Surface(SurfNum).Tilt,
1980 0 : state.dataSurface->Surface(SurfNum).Name,
1981 0 : state.dataSurface->Surface(SurfNum).ZoneName));
1982 0 : ShowContinueError(state,
1983 0 : format(" Tilt={:.1T} in Surface={}, Zone={}",
1984 0 : state.dataSurface->Surface(Found).Tilt,
1985 0 : state.dataSurface->Surface(Found).Name,
1986 0 : state.dataSurface->Surface(Found).ZoneName));
1987 : }
1988 : // check surface class match. interzone surface.
1989 :
1990 8937 : if ((state.dataSurface->Surface(SurfNum).Class == SurfaceClass::Wall &&
1991 17874 : state.dataSurface->Surface(Found).Class != SurfaceClass::Wall) ||
1992 8937 : (state.dataSurface->Surface(SurfNum).Class != SurfaceClass::Wall &&
1993 3045 : state.dataSurface->Surface(Found).Class == SurfaceClass::Wall)) {
1994 0 : ShowWarningError(state, format("{}InterZone Surface Classes do not match as expected.", RoutineName));
1995 0 : ShowContinueError(state,
1996 0 : format("Surface=\"{}\", surface class={}",
1997 0 : state.dataSurface->Surface(SurfNum).Name,
1998 0 : cSurfaceClass(state.dataSurface->Surface(SurfNum).Class)));
1999 0 : ShowContinueError(state,
2000 0 : format("Adjacent Surface=\"{}\", surface class={}",
2001 0 : state.dataSurface->Surface(Found).Name,
2002 0 : cSurfaceClass(state.dataSurface->Surface(Found).Class)));
2003 0 : ShowContinueError(state, "Other errors/warnings may follow about these surfaces.");
2004 : }
2005 8937 : if ((state.dataSurface->Surface(SurfNum).Class == SurfaceClass::Roof &&
2006 17874 : state.dataSurface->Surface(Found).Class != SurfaceClass::Floor) ||
2007 8937 : (state.dataSurface->Surface(SurfNum).Class != SurfaceClass::Roof &&
2008 7464 : state.dataSurface->Surface(Found).Class == SurfaceClass::Floor)) {
2009 0 : ShowWarningError(state, format("{}InterZone Surface Classes do not match as expected.", RoutineName));
2010 0 : ShowContinueError(state,
2011 0 : format("Surface=\"{}\", surface class={}",
2012 0 : state.dataSurface->Surface(SurfNum).Name,
2013 0 : cSurfaceClass(state.dataSurface->Surface(SurfNum).Class)));
2014 0 : ShowContinueError(state,
2015 0 : format("Adjacent Surface=\"{}\", surface class={}",
2016 0 : state.dataSurface->Surface(Found).Name,
2017 0 : cSurfaceClass(state.dataSurface->Surface(Found).Class)));
2018 0 : ShowContinueError(state, "Other errors/warnings may follow about these surfaces.");
2019 : }
2020 16401 : if (state.dataSurface->Surface(SurfNum).Class != SurfaceClass::Roof &&
2021 7464 : state.dataSurface->Surface(SurfNum).Class != SurfaceClass::Floor) {
2022 : // Walls, Windows, Doors, Glass Doors
2023 5932 : if (state.dataSurface->Surface(SurfNum).Class != SurfaceClass::Wall) {
2024 : // Surface is a Door, Window or Glass Door
2025 40 : if (state.dataSurface->Surface(SurfNum).BaseSurf == 0) {
2026 0 : continue; // error detected elsewhere
2027 : }
2028 79 : if (state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Class == SurfaceClass::Roof ||
2029 39 : state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Class == SurfaceClass::Floor) {
2030 2 : continue;
2031 : }
2032 : }
2033 5930 : if (std::abs(std::abs(state.dataSurface->Surface(SurfNum).Azimuth - state.dataSurface->Surface(Found).Azimuth) -
2034 5930 : 180.0) > 1.0) {
2035 0 : if (std::abs(state.dataSurface->Surface(SurfNum).SinTilt) > 0.5 || state.dataGlobal->DisplayExtraWarnings) {
2036 : // if horizontal surfaces, then these are windows/doors/etc in those items.
2037 0 : ShowWarningError(state, format("{}InterZone Surface Azimuths do not match as expected.", RoutineName));
2038 0 : ShowContinueError(state,
2039 0 : format(" Azimuth={:.1T}, Tilt={:.1T}, in Surface={}, Zone={}",
2040 0 : state.dataSurface->Surface(SurfNum).Azimuth,
2041 0 : state.dataSurface->Surface(SurfNum).Tilt,
2042 0 : state.dataSurface->Surface(SurfNum).Name,
2043 0 : state.dataSurface->Surface(SurfNum).ZoneName));
2044 0 : ShowContinueError(state,
2045 0 : format(" Azimuth={:.1T}, Tilt={:.1T}, in Surface={}, Zone={}",
2046 0 : state.dataSurface->Surface(Found).Azimuth,
2047 0 : state.dataSurface->Surface(Found).Tilt,
2048 0 : state.dataSurface->Surface(Found).Name,
2049 0 : state.dataSurface->Surface(Found).ZoneName));
2050 0 : ShowContinueError(
2051 : state,
2052 0 : format("..surface class of first surface={}", cSurfaceClass(state.dataSurface->Surface(SurfNum).Class)));
2053 0 : ShowContinueError(
2054 : state,
2055 0 : format("..surface class of second surface={}", cSurfaceClass(state.dataSurface->Surface(Found).Class)));
2056 : }
2057 : }
2058 : }
2059 :
2060 : // Make sure exposures (Sun, Wind) are the same.....and are "not"
2061 8935 : if (state.dataSurface->Surface(SurfNum).ExtSolar || state.dataSurface->Surface(Found).ExtSolar) {
2062 0 : ShowWarningError(state, format("{}Interzone surfaces cannot be \"SunExposed\" -- removing SunExposed", RoutineName));
2063 0 : ShowContinueError(state,
2064 0 : format(" Surface={}, Zone={}",
2065 0 : state.dataSurface->Surface(SurfNum).Name,
2066 0 : state.dataSurface->Surface(SurfNum).ZoneName));
2067 0 : ShowContinueError(state,
2068 0 : format(" Surface={}, Zone={}",
2069 0 : state.dataSurface->Surface(Found).Name,
2070 0 : state.dataSurface->Surface(Found).ZoneName));
2071 0 : state.dataSurface->Surface(SurfNum).ExtSolar = false;
2072 0 : state.dataSurface->Surface(Found).ExtSolar = false;
2073 : }
2074 8935 : if (state.dataSurface->Surface(SurfNum).ExtWind || state.dataSurface->Surface(Found).ExtWind) {
2075 0 : ShowWarningError(state,
2076 0 : format("{}Interzone surfaces cannot be \"WindExposed\" -- removing WindExposed", RoutineName));
2077 0 : ShowContinueError(state,
2078 0 : format(" Surface={}, Zone={}",
2079 0 : state.dataSurface->Surface(SurfNum).Name,
2080 0 : state.dataSurface->Surface(SurfNum).ZoneName));
2081 0 : ShowContinueError(state,
2082 0 : format(" Surface={}, Zone={}",
2083 0 : state.dataSurface->Surface(Found).Name,
2084 0 : state.dataSurface->Surface(Found).ZoneName));
2085 0 : state.dataSurface->Surface(SurfNum).ExtWind = false;
2086 0 : state.dataSurface->Surface(Found).ExtWind = false;
2087 : }
2088 : }
2089 : // Set opposing surface back to this one (regardless of error)
2090 15950 : state.dataSurface->Surface(Found).ExtBoundCond = SurfNum;
2091 : // Check subsurfaces... make sure base surface is also an interzone surface
2092 15950 : if (state.dataSurface->Surface(SurfNum).BaseSurf != SurfNum) { // Subsurface
2093 76 : if ((state.dataSurface->Surface(SurfNum).ExtBoundCond != SurfNum) &&
2094 38 : not_blank(state.dataSurface->Surface(SurfNum).ExtBoundCondName)) {
2095 : // if not internal subsurface
2096 38 : if (state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond ==
2097 38 : state.dataSurface->Surface(SurfNum).BaseSurf) {
2098 : // base surface is not interzone surface
2099 0 : ShowSevereError(state,
2100 0 : format("{}SubSurface=\"{}\" is an interzone subsurface.",
2101 : RoutineName,
2102 0 : state.dataSurface->Surface(SurfNum).Name));
2103 0 : ShowContinueError(state,
2104 0 : format("..but the Base Surface is not an interzone surface, Surface=\"{}\".",
2105 0 : state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Name));
2106 0 : SurfError = true;
2107 : }
2108 : }
2109 : }
2110 : } else {
2111 : // Seems unlikely that an internal surface would be missing itself, so this message
2112 : // only indicates for adjacent (interzone) surfaces.
2113 0 : ShowSevereError(state,
2114 0 : format("{}Adjacent Surface not found: {} adjacent to surface {}",
2115 : RoutineName,
2116 0 : state.dataSurface->Surface(SurfNum).ExtBoundCondName,
2117 0 : state.dataSurface->Surface(SurfNum).Name));
2118 0 : NonMatch = true;
2119 0 : SurfError = true;
2120 : }
2121 0 : } else if (state.dataSurface->Surface(SurfNum).BaseSurf != SurfNum) { // Subsurface
2122 0 : if (state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond > 0 &&
2123 0 : state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond !=
2124 0 : state.dataSurface->Surface(SurfNum).BaseSurf) { // If Interzone surface, subsurface must be also.
2125 0 : ShowSevereError(state, format("{}SubSurface on Interzone Surface must be an Interzone SubSurface.", RoutineName));
2126 0 : ShowContinueError(state,
2127 0 : format("...OutsideFaceEnvironment is blank, in Surface={}", state.dataSurface->Surface(SurfNum).Name));
2128 0 : SurfError = true;
2129 : } else {
2130 0 : ++state.dataSurfaceGeometry->ErrCount3;
2131 0 : if (state.dataSurfaceGeometry->ErrCount3 == 1 && !state.dataGlobal->DisplayExtraWarnings) {
2132 0 : ShowWarningError(state, format("{}Blank name for Outside Boundary Condition Objects.", RoutineName));
2133 0 : ShowContinueError(state, "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on individual surfaces.");
2134 : }
2135 0 : if (state.dataGlobal->DisplayExtraWarnings) {
2136 0 : ShowWarningError(state,
2137 0 : format("{}Blank name for Outside Boundary Condition Object, in surface={}",
2138 : RoutineName,
2139 0 : state.dataSurface->Surface(SurfNum).Name));
2140 0 : ShowContinueError(state,
2141 0 : format("Resetting this surface to be an internal zone surface, zone={}",
2142 0 : state.dataSurface->Surface(SurfNum).ZoneName));
2143 : }
2144 0 : state.dataSurface->Surface(SurfNum).ExtBoundCondName = state.dataSurface->Surface(SurfNum).Name;
2145 0 : state.dataSurface->Surface(SurfNum).ExtBoundCond = SurfNum;
2146 : }
2147 : } else {
2148 0 : ++state.dataSurfaceGeometry->ErrCount3;
2149 0 : if (state.dataSurfaceGeometry->ErrCount3 == 1 && !state.dataGlobal->DisplayExtraWarnings) {
2150 0 : ShowSevereError(state, format("{}Blank name for Outside Boundary Condition Objects.", RoutineName));
2151 0 : ShowContinueError(state, "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on individual surfaces.");
2152 : }
2153 0 : if (state.dataGlobal->DisplayExtraWarnings) {
2154 0 : ShowWarningError(state,
2155 0 : format("{}Blank name for Outside Boundary Condition Object, in surface={}",
2156 : RoutineName,
2157 0 : state.dataSurface->Surface(SurfNum).Name));
2158 0 : ShowContinueError(state,
2159 0 : format("Resetting this surface to be an internal zone (adiabatic) surface, zone={}",
2160 0 : state.dataSurface->Surface(SurfNum).ZoneName));
2161 : }
2162 0 : state.dataSurface->Surface(SurfNum).ExtBoundCondName = state.dataSurface->Surface(SurfNum).Name;
2163 0 : state.dataSurface->Surface(SurfNum).ExtBoundCond = SurfNum;
2164 0 : SurfError = true;
2165 : }
2166 : }
2167 :
2168 : } // ...end of the Surface DO loop for finding BaseSurf
2169 801 : if (NonMatch) {
2170 0 : ShowSevereError(state, format("{}Non matching interzone surfaces found", RoutineName));
2171 : }
2172 :
2173 : //**********************************************************************************
2174 : // Warn about interzone surfaces that have adiabatic windows/vice versa
2175 801 : SubSurfaceSevereDisplayed = false;
2176 48091 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
2177 47290 : if (!state.dataSurface->Surface(SurfNum).HeatTransSurf) {
2178 1690 : continue;
2179 : }
2180 45600 : if (state.dataSurface->Surface(SurfNum).BaseSurf == SurfNum) {
2181 38758 : continue; // base surface
2182 : }
2183 : // not base surface. Check it.
2184 6842 : if (state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond <= 0) { // exterior or other base surface
2185 6762 : if (state.dataSurface->Surface(SurfNum).ExtBoundCond !=
2186 6762 : state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond) { // should match base surface
2187 0 : if (state.dataSurface->Surface(SurfNum).ExtBoundCond == SurfNum) {
2188 0 : ShowSevereError(
2189 : state,
2190 0 : format("{}Subsurface=\"{}\" exterior condition [adiabatic surface] in a base surface=\"{}\" with exterior condition [{}]",
2191 : RoutineName,
2192 0 : state.dataSurface->Surface(SurfNum).Name,
2193 0 : state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Name,
2194 : DataSurfaces::cExtBoundCondition(
2195 0 : state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond)));
2196 0 : SurfError = true;
2197 0 : } else if (state.dataSurface->Surface(SurfNum).ExtBoundCond > 0) {
2198 0 : ShowSevereError(
2199 : state,
2200 0 : format("{}Subsurface=\"{}\" exterior condition [interzone surface] in a base surface=\"{}\" with exterior condition [{}]",
2201 : RoutineName,
2202 0 : state.dataSurface->Surface(SurfNum).Name,
2203 0 : state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Name,
2204 : DataSurfaces::cExtBoundCondition(
2205 0 : state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond)));
2206 0 : SurfError = true;
2207 0 : } else if (state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond ==
2208 : DataSurfaces::OtherSideCondModeledExt) {
2209 0 : ShowWarningError(state,
2210 0 : format("{}Subsurface=\"{}\" exterior condition [{}] in a base surface=\"{}\" with exterior condition [{}]",
2211 : RoutineName,
2212 0 : state.dataSurface->Surface(SurfNum).Name,
2213 0 : DataSurfaces::cExtBoundCondition(state.dataSurface->Surface(SurfNum).ExtBoundCond),
2214 0 : state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Name,
2215 : DataSurfaces::cExtBoundCondition(
2216 0 : state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond)));
2217 0 : ShowContinueError(state, "...SubSurface will not use the exterior condition model of the base surface.");
2218 : } else {
2219 0 : ShowSevereError(state,
2220 0 : format("{}Subsurface=\"{}\" exterior condition [{}] in a base surface=\"{}\" with exterior condition [{}]",
2221 : RoutineName,
2222 0 : state.dataSurface->Surface(SurfNum).Name,
2223 0 : DataSurfaces::cExtBoundCondition(state.dataSurface->Surface(SurfNum).ExtBoundCond),
2224 0 : state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Name,
2225 : DataSurfaces::cExtBoundCondition(
2226 0 : state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond)));
2227 0 : SurfError = true;
2228 : }
2229 0 : if (!SubSurfaceSevereDisplayed && SurfError) {
2230 0 : ShowContinueError(state, "...calculations for heat balance would be compromised.");
2231 0 : SubSurfaceSevereDisplayed = true;
2232 : }
2233 : }
2234 80 : } else if (state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).BaseSurf ==
2235 80 : state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond) {
2236 : // adiabatic surface. make sure subsurfaces match
2237 0 : if (state.dataSurface->Surface(SurfNum).ExtBoundCond != SurfNum) { // not adiabatic surface
2238 0 : if (state.dataSurface->Surface(SurfNum).ExtBoundCond > 0) {
2239 0 : ShowSevereError(state,
2240 0 : format("{}Subsurface=\"{}\" exterior condition [interzone surface] in a base surface=\"{}\" with exterior "
2241 : "condition [adiabatic surface]",
2242 : RoutineName,
2243 0 : state.dataSurface->Surface(SurfNum).Name,
2244 0 : state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Name));
2245 : } else {
2246 0 : ShowSevereError(
2247 : state,
2248 0 : format("{}Subsurface=\"{}\" exterior condition [{}] in a base surface=\"{}\" with exterior condition [adiabatic surface]",
2249 : RoutineName,
2250 0 : state.dataSurface->Surface(SurfNum).Name,
2251 0 : DataSurfaces::cExtBoundCondition(state.dataSurface->Surface(SurfNum).ExtBoundCond),
2252 0 : state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Name));
2253 : }
2254 0 : if (!SubSurfaceSevereDisplayed) {
2255 0 : ShowContinueError(state, "...calculations for heat balance would be compromised.");
2256 0 : SubSurfaceSevereDisplayed = true;
2257 : }
2258 0 : SurfError = true;
2259 : }
2260 80 : } else if (state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond > 0) { // interzone surface
2261 80 : if (state.dataSurface->Surface(SurfNum).ExtBoundCond == SurfNum) {
2262 0 : ShowSevereError(state,
2263 0 : format("{}Subsurface=\"{}\" is an adiabatic surface in an Interzone base surface=\"{}\"",
2264 : RoutineName,
2265 0 : state.dataSurface->Surface(SurfNum).Name,
2266 0 : state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Name));
2267 0 : if (!SubSurfaceSevereDisplayed) {
2268 0 : ShowContinueError(state, "...calculations for heat balance would be compromised.");
2269 0 : SubSurfaceSevereDisplayed = true;
2270 : }
2271 : // SurfError=.TRUE.
2272 : }
2273 : }
2274 : }
2275 :
2276 801 : setSurfaceFirstLast(state);
2277 :
2278 : // Set up Floor Areas for Zones and Spaces
2279 801 : Real64 constexpr floorAreaTolerance(0.05);
2280 801 : Real64 constexpr floorAreaPercentTolerance(floorAreaTolerance * 100.0);
2281 801 : if (!SurfError) {
2282 801 : int ErrCount = 0;
2283 6014 : for (auto &thisSpace : state.dataHeatBal->space) {
2284 5213 : auto &thisZone = state.dataHeatBal->Zone(thisSpace.zoneNum);
2285 5213 : Real64 calcFloorArea = 0.0; // Calculated floor area used for this space
2286 50795 : for (int SurfNum = thisSpace.HTSurfaceFirst; SurfNum <= thisSpace.HTSurfaceLast; ++SurfNum) {
2287 45582 : auto const &thisSurf = state.dataSurface->Surface(SurfNum);
2288 45582 : if (thisSurf.Class == SurfaceClass::Floor) {
2289 7040 : thisZone.HasFloor = true;
2290 7040 : thisSpace.hasFloor = true;
2291 7040 : calcFloorArea += thisSurf.Area;
2292 : }
2293 45582 : if (thisSurf.Class == SurfaceClass::Roof) {
2294 5958 : thisZone.CeilingArea += thisSurf.Area;
2295 5958 : thisZone.HasRoof = true;
2296 : }
2297 : }
2298 5213 : if (thisSpace.userEnteredFloorArea != Constant::AutoCalculate) {
2299 : // Check entered vs calculated
2300 0 : if (thisSpace.userEnteredFloorArea > 0.0) { // User entered Space floor area,
2301 : // produce message if not near calculated
2302 0 : if (calcFloorArea > 0.0) {
2303 0 : Real64 diffp = std::abs(calcFloorArea - thisSpace.userEnteredFloorArea) / thisSpace.userEnteredFloorArea;
2304 0 : if (diffp > floorAreaTolerance) {
2305 0 : ++ErrCount;
2306 0 : if (ErrCount == 1 && !state.dataGlobal->DisplayExtraWarnings) {
2307 0 : ShowWarningError(
2308 : state,
2309 0 : format("{}Entered Space Floor Area(s) differ more than {:.0R}% from calculated Space Floor Area(s).",
2310 0 : std::string(RoutineName),
2311 : floorAreaPercentTolerance));
2312 0 : ShowContinueError(state,
2313 : "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on individual Spaces.");
2314 : }
2315 0 : if (state.dataGlobal->DisplayExtraWarnings) {
2316 : // Warn user of using specified Space Floor Area
2317 0 : ShowWarningError(
2318 : state,
2319 0 : format("{}Entered Floor Area for Space=\"{}\" is {:.1R}% different from the calculated Floor Area.",
2320 0 : std::string(RoutineName),
2321 0 : thisSpace.Name,
2322 0 : diffp * 100.0));
2323 0 : ShowContinueError(state,
2324 0 : format("Entered Space Floor Area={:.2R}, Calculated Space Floor Area={:.2R}, entered "
2325 : "Floor Area will be used.",
2326 0 : thisSpace.userEnteredFloorArea,
2327 : calcFloorArea));
2328 : }
2329 : }
2330 : }
2331 0 : thisSpace.FloorArea = thisSpace.userEnteredFloorArea;
2332 0 : thisSpace.hasFloor = true;
2333 : }
2334 : } else {
2335 5213 : thisSpace.FloorArea = calcFloorArea;
2336 : }
2337 801 : }
2338 801 : ErrCount = 0;
2339 6002 : for (auto &thisZone : state.dataHeatBal->Zone) {
2340 : // Calculate zone floor area as sum of space floor areas
2341 5201 : Real64 zoneCalcFloorArea = 0.0; // Calculated floor area excluding air boundary surfaces
2342 10414 : for (int spaceNum : thisZone.spaceIndexes) {
2343 5213 : zoneCalcFloorArea += state.dataHeatBal->space(spaceNum).FloorArea;
2344 5213 : thisZone.HasFloor |= state.dataHeatBal->space(spaceNum).hasFloor;
2345 5201 : }
2346 5201 : if (thisZone.UserEnteredFloorArea != Constant::AutoCalculate) {
2347 : // Check entered vs calculated
2348 4 : if (thisZone.UserEnteredFloorArea > 0.0) { // User entered zone floor area,
2349 : // produce message if not near calculated
2350 4 : if (zoneCalcFloorArea > 0.0) {
2351 4 : Real64 diffp = std::abs(zoneCalcFloorArea - thisZone.UserEnteredFloorArea) / thisZone.UserEnteredFloorArea;
2352 4 : if (diffp > 0.05) {
2353 1 : ++ErrCount;
2354 1 : if (ErrCount == 1 && !state.dataGlobal->DisplayExtraWarnings) {
2355 2 : ShowWarningError(
2356 : state,
2357 2 : format("{}Entered Zone Floor Area(s) differ more than {:.0R}% from the sum of the Space Floor Area(s).",
2358 2 : std::string(RoutineName),
2359 : floorAreaPercentTolerance));
2360 3 : ShowContinueError(state,
2361 : "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on individual zones.");
2362 : }
2363 1 : if (state.dataGlobal->DisplayExtraWarnings) {
2364 : // Warn user of using specified Zone Floor Area
2365 0 : ShowWarningError(state,
2366 0 : format("{}Entered Floor Area for Zone=\"{}\" is {:.1R}% different from the sum of the "
2367 : "Space Floor Area(s).",
2368 0 : std::string(RoutineName),
2369 0 : thisZone.Name,
2370 0 : diffp * 100.0));
2371 0 : ShowContinueError(state,
2372 0 : format("Entered Zone Floor Area={:.2R}, Sum of Space Floor Area(s)={:.2R}",
2373 0 : thisZone.UserEnteredFloorArea,
2374 : zoneCalcFloorArea));
2375 0 : ShowContinueError(
2376 : state, "Entered Zone Floor Area will be used and Space Floor Area(s) will be adjusted proportionately.");
2377 : }
2378 : }
2379 : }
2380 4 : thisZone.FloorArea = thisZone.UserEnteredFloorArea;
2381 4 : thisZone.HasFloor = true;
2382 :
2383 : // Adjust space floor areas to match zone floor area
2384 4 : if (thisZone.numSpaces == 1) {
2385 : // If the zone contains only one space, then set the Space area to the Zone area
2386 4 : int spaceNum = thisZone.spaceIndexes(1);
2387 4 : state.dataHeatBal->space(spaceNum).FloorArea = thisZone.FloorArea;
2388 0 : } else if (zoneCalcFloorArea > 0.0) {
2389 : // Adjust space areas proportionately
2390 0 : Real64 areaRatio = thisZone.FloorArea / zoneCalcFloorArea;
2391 0 : for (int spaceNum : thisZone.spaceIndexes) {
2392 0 : state.dataHeatBal->space(spaceNum).FloorArea *= areaRatio;
2393 0 : }
2394 : } else {
2395 0 : if (state.dataGlobal->DisplayExtraWarnings) {
2396 : // Warn if calculated floor area was zero and there is more than one Space
2397 0 : ShowWarningError(
2398 : state,
2399 0 : format("{}Entered Floor Area entered for Zone=\"{}\" significantly different from sum of Space Floor Areas",
2400 : RoutineName,
2401 0 : thisZone.Name));
2402 0 : ShowContinueError(state,
2403 : "But the sum of the Space Floor Areas is zero and there is more than one Space in the zone."
2404 : "Unable to apportion the zone floor area. Space Floor Areas are zero.");
2405 : }
2406 : }
2407 : } else {
2408 0 : if (zoneCalcFloorArea > 0.0) {
2409 0 : thisZone.FloorArea = zoneCalcFloorArea;
2410 : }
2411 : }
2412 : } else {
2413 5197 : thisZone.FloorArea = zoneCalcFloorArea;
2414 : }
2415 5201 : Real64 totSpacesFloorArea = 0.0;
2416 10414 : for (int spaceNum : thisZone.spaceIndexes) {
2417 5213 : totSpacesFloorArea += state.dataHeatBal->space(spaceNum).FloorArea;
2418 5201 : }
2419 5201 : if (totSpacesFloorArea > 0.0) {
2420 10410 : for (int spaceNum : thisZone.spaceIndexes) {
2421 5211 : state.dataHeatBal->space(spaceNum).fracZoneFloorArea = state.dataHeatBal->space(spaceNum).FloorArea / totSpacesFloorArea;
2422 5199 : }
2423 : } // else leave fractions at zero
2424 801 : }
2425 : }
2426 :
2427 48091 : for (int SurfNum = 1; SurfNum <= MovedSurfs; ++SurfNum) { // TotSurfaces
2428 47290 : if (state.dataSurface->Surface(SurfNum).Area < 1.e-06) {
2429 0 : ShowSevereError(state,
2430 0 : format("{}Zero or negative surface area[{:.5R}], Surface={}",
2431 : RoutineName,
2432 0 : state.dataSurface->Surface(SurfNum).Area,
2433 0 : state.dataSurface->Surface(SurfNum).Name));
2434 0 : SurfError = true;
2435 : }
2436 47290 : if (state.dataSurface->Surface(SurfNum).Area >= 1.e-06 && state.dataSurface->Surface(SurfNum).Area < 0.001) {
2437 0 : ShowWarningError(state,
2438 0 : format("{}Very small surface area[{:.5R}], Surface={}",
2439 : RoutineName,
2440 0 : state.dataSurface->Surface(SurfNum).Area,
2441 0 : state.dataSurface->Surface(SurfNum).Name));
2442 : }
2443 : }
2444 :
2445 48091 : for (int SurfNum = 1; SurfNum <= MovedSurfs; ++SurfNum) { // TotSurfaces
2446 47290 : auto &surf = state.dataSurface->Surface(SurfNum);
2447 : // GLASSDOORs and TDD:DIFFUSERs will be treated as windows in the subsequent heat transfer and daylighting
2448 : // calculations. Reset class to 'Window' after saving the original designation in SurfaceWindow.
2449 :
2450 47290 : surf.OriginalClass = surf.Class;
2451 :
2452 47290 : if (surf.Class == SurfaceClass::GlassDoor || surf.Class == SurfaceClass::TDD_Diffuser) {
2453 543 : surf.Class = SurfaceClass::Window;
2454 : }
2455 :
2456 47290 : if (surf.Class == SurfaceClass::TDD_Dome) {
2457 : // Reset the TDD:DOME subsurface to act as a base surface that can shade and be shaded
2458 : // NOTE: This must be set early so that subsequent shading calculations are done correctly
2459 2 : surf.BaseSurf = SurfNum;
2460 : }
2461 : }
2462 :
2463 801 : auto &s_mat = state.dataMaterial;
2464 :
2465 : // I don't think this entire loop matters
2466 801 : errFlag = false;
2467 801 : if (!SurfError) {
2468 48091 : for (int SurfNum = 1; SurfNum <= MovedSurfs; ++SurfNum) { // TotSurfaces
2469 47290 : auto &surf = state.dataSurface->Surface(SurfNum);
2470 47290 : if (!surf.HasShadeControl) {
2471 47139 : continue;
2472 : }
2473 :
2474 151 : int ConstrNumSh = surf.activeShadedConstruction;
2475 151 : if (ConstrNumSh <= 0) {
2476 0 : continue;
2477 : }
2478 :
2479 151 : auto &winShadeCtrl = state.dataSurface->WindowShadingControl(surf.activeWindowShadingControl);
2480 151 : if (!ANY_BLIND(winShadeCtrl.ShadingType)) {
2481 109 : continue;
2482 : }
2483 : // use first item since others should be identical
2484 :
2485 42 : auto &surfShade = state.dataSurface->surfShades(SurfNum);
2486 : // TH 1/7/2010. CR 7930
2487 : // The old code did not consider between-glass blind. Also there should not be two blinds - both interior and exterior
2488 : // Use the new generic code (assuming only one blind) as follows
2489 91 : for (int iMatNum = 1; iMatNum <= state.dataConstruction->Construct(ConstrNumSh).TotLayers; ++iMatNum) {
2490 91 : auto *mat = s_mat->materials(state.dataConstruction->Construct(ConstrNumSh).LayerPoint(iMatNum));
2491 :
2492 91 : if (mat->group != Material::Group::Blind) {
2493 49 : continue;
2494 : }
2495 :
2496 42 : auto *matBlind = dynamic_cast<Material::MaterialBlind *>(mat);
2497 42 : assert(matBlind != nullptr);
2498 :
2499 42 : surfShade.blind.matNum = mat->Num;
2500 42 : break;
2501 : }
2502 :
2503 42 : if (errFlag) {
2504 0 : ErrorsFound = true;
2505 0 : ShowContinueError(state, format("WindowShadingControl {} has errors, program will terminate.", winShadeCtrl.Name));
2506 : }
2507 :
2508 42 : if (winShadeCtrl.slatAngleControl != DataSurfaces::SlatAngleControl::Fixed) {
2509 3 : surfShade.blind.movableSlats = true;
2510 3 : state.dataSurface->AnyMovableSlat = true;
2511 3 : state.dataHeatBalSurf->SurfMovSlatsIndexList.push_back(SurfNum);
2512 : }
2513 : } // End of surface loop
2514 :
2515 : // final associate fenestration surfaces referenced in WindowShadingControl
2516 801 : FinalAssociateWindowShadingControlFenestration(state, ErrorsFound);
2517 801 : CheckWindowShadingControlSimilarForWindow(state, ErrorsFound);
2518 : }
2519 :
2520 : // Check for zones with not enough surfaces
2521 6002 : for (auto &thisZone : state.dataHeatBal->Zone) {
2522 5201 : int OpaqueHTSurfs = 0; // Number of floors, walls and roofs in a zone
2523 5201 : int OpaqueHTSurfsWithWin = 0; // Number of floors, walls and roofs with windows in a zone
2524 5201 : int InternalMassSurfs = 0; // Number of internal mass surfaces in a zone
2525 5201 : int priorBaseSurfNum = 0;
2526 :
2527 10414 : for (int spaceNum : thisZone.spaceIndexes) {
2528 5213 : auto const &thisSpace = state.dataHeatBal->space(spaceNum);
2529 5213 : if (thisSpace.HTSurfaceFirst == 0) {
2530 0 : continue; // Zone with no surfaces
2531 : }
2532 50795 : for (int SurfNum = thisSpace.HTSurfaceFirst; SurfNum <= thisSpace.HTSurfaceLast; ++SurfNum) {
2533 45582 : auto const &thisSurf = state.dataSurface->Surface(SurfNum);
2534 45582 : if (thisSurf.Class == SurfaceClass::Floor || thisSurf.Class == SurfaceClass::Wall || thisSurf.Class == SurfaceClass::Roof) {
2535 36203 : ++OpaqueHTSurfs;
2536 : }
2537 45582 : if (thisSurf.Class == SurfaceClass::IntMass) {
2538 2537 : ++InternalMassSurfs;
2539 : }
2540 45582 : if (thisSurf.Class == SurfaceClass::Window) {
2541 : // Count base surface only once for multiple windows on a wall
2542 6359 : int thisBaseSurfNum = thisSurf.BaseSurf;
2543 6359 : if (thisBaseSurfNum != priorBaseSurfNum) {
2544 4273 : ++OpaqueHTSurfsWithWin;
2545 4273 : priorBaseSurfNum = thisBaseSurfNum;
2546 : }
2547 : }
2548 : }
2549 5201 : }
2550 5201 : if (OpaqueHTSurfsWithWin == 1 && OpaqueHTSurfs == 1 && InternalMassSurfs == 0) {
2551 0 : SurfError = true;
2552 0 : ShowSevereError(state,
2553 0 : format("{}Zone {} has only one floor, wall or roof, and this surface has a window.", RoutineName, thisZone.Name));
2554 0 : ShowContinueError(state, "Add more floors, walls or roofs, or an internal mass surface.");
2555 : }
2556 801 : }
2557 :
2558 : // set up vertex of centroid for each surface.
2559 801 : CalcSurfaceCentroid(state);
2560 :
2561 801 : SetupShadeSurfacesForSolarCalcs(state); // if shading surfaces are solar collectors or PV, then we need full solar calc.
2562 :
2563 801 : GetMovableInsulationData(state, ErrorsFound);
2564 :
2565 801 : if (state.dataSurface->CalcSolRefl) {
2566 9 : GetShadingSurfReflectanceData(state, ErrorsFound);
2567 : }
2568 :
2569 801 : LayNumOutside = 0;
2570 :
2571 48091 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
2572 47290 : auto &surf = state.dataSurface->Surface(SurfNum);
2573 : // Check for EcoRoof and only 1 allowed to be used.
2574 47290 : if (surf.Construction > 0) {
2575 45600 : state.dataSurface->SurfExtEcoRoof(SurfNum) = state.dataConstruction->Construct(surf.Construction).TypeIsEcoRoof;
2576 : }
2577 47290 : if (!state.dataSurface->SurfExtEcoRoof(SurfNum)) {
2578 47270 : continue;
2579 : }
2580 20 : if (LayNumOutside == 0) {
2581 4 : LayNumOutside = state.dataConstruction->Construct(surf.Construction).LayerPoint(1);
2582 4 : continue;
2583 : }
2584 16 : if (LayNumOutside != state.dataConstruction->Construct(surf.Construction).LayerPoint(1)) {
2585 0 : ShowSevereError(state, format("{}Only one EcoRoof Material is currently allowed for all constructions.", RoutineName));
2586 0 : ShowContinueError(state, format("... first material={}", s_mat->materials(LayNumOutside)->Name));
2587 0 : ShowContinueError(state,
2588 0 : format("... conflicting Construction={} uses material={}",
2589 0 : state.dataConstruction->Construct(surf.Construction).Name,
2590 0 : s_mat->materials(state.dataConstruction->Construct(surf.Construction).LayerPoint(1))->Name));
2591 0 : ErrorsFound = true;
2592 : }
2593 : }
2594 :
2595 : // Reserve space to avoid excess allocations
2596 801 : state.dataSurface->AllHTSurfaceList.reserve(state.dataSurface->TotSurfaces);
2597 801 : state.dataSurface->AllExtSolarSurfaceList.reserve(state.dataSurface->TotSurfaces);
2598 801 : state.dataSurface->AllShadowPossObstrSurfaceList.reserve(state.dataSurface->TotSurfaces);
2599 801 : state.dataSurface->AllIZSurfaceList.reserve(state.dataSurface->TotSurfaces);
2600 801 : state.dataSurface->AllHTNonWindowSurfaceList.reserve(state.dataSurface->TotSurfaces - state.dataSurface->TotWindows);
2601 801 : state.dataSurface->AllHTWindowSurfaceList.reserve(state.dataSurface->TotWindows);
2602 801 : state.dataSurface->AllExtSolWindowSurfaceList.reserve(state.dataSurface->TotWindows);
2603 801 : state.dataSurface->AllExtSolWinWithFrameSurfaceList.reserve(state.dataSurface->TotWindows);
2604 801 : state.dataSurface->AllHTKivaSurfaceList.reserve(state.dataSurface->TotSurfaces);
2605 :
2606 : // Set flag that determines whether a surface can be an exterior obstruction
2607 : // Also set associated surfaces for Kiva foundations and build heat transfer surface lists
2608 48091 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
2609 47290 : auto &surf = state.dataSurface->Surface(SurfNum);
2610 47290 : surf.IsShadowPossibleObstruction = false;
2611 47290 : if (surf.ExtSolar) {
2612 : // This may include some attached shading surfaces
2613 19758 : state.dataSurface->AllExtSolarSurfaceList.push_back(SurfNum);
2614 : }
2615 47290 : if (surf.HeatTransSurf) {
2616 : // Outside light shelves get tagged later as HeatTransSurf=true but they haven't been processed yet
2617 45582 : state.dataSurface->AllHTSurfaceList.push_back(SurfNum);
2618 45582 : int const zoneNum(surf.Zone);
2619 45582 : auto &surfZone(state.dataHeatBal->Zone(zoneNum));
2620 45582 : surfZone.ZoneHTSurfaceList.push_back(SurfNum);
2621 : // Sort window vs non-window surfaces
2622 45582 : if (surf.Class == DataSurfaces::SurfaceClass::Window) {
2623 6359 : state.dataSurface->AllHTWindowSurfaceList.push_back(SurfNum);
2624 6359 : surfZone.ZoneHTWindowSurfaceList.push_back(SurfNum);
2625 6359 : if (surf.ExtSolar) {
2626 6343 : state.dataSurface->AllExtSolWindowSurfaceList.push_back(SurfNum);
2627 6343 : if (surf.FrameDivider > 0) {
2628 381 : state.dataSurface->AllExtSolWinWithFrameSurfaceList.push_back(SurfNum);
2629 : }
2630 : }
2631 : } else {
2632 39223 : state.dataSurface->AllHTNonWindowSurfaceList.push_back(SurfNum);
2633 39223 : surfZone.ZoneHTNonWindowSurfaceList.push_back(SurfNum);
2634 : }
2635 45582 : int const surfExtBoundCond(surf.ExtBoundCond);
2636 : // Build zone and interzone surface lists
2637 45582 : if ((surfExtBoundCond > 0) && (surfExtBoundCond != SurfNum)) {
2638 17850 : state.dataSurface->AllIZSurfaceList.push_back(SurfNum);
2639 17850 : surfZone.ZoneIZSurfaceList.push_back(SurfNum);
2640 17850 : auto &adjZone(state.dataHeatBal->Zone(state.dataSurface->Surface(surfExtBoundCond).Zone));
2641 17850 : adjZone.ZoneHTSurfaceList.push_back(SurfNum);
2642 17850 : adjZone.ZoneIZSurfaceList.push_back(SurfNum);
2643 : // Sort window vs non-window surfaces
2644 17850 : if (surf.Class == DataSurfaces::SurfaceClass::Window) {
2645 14 : adjZone.ZoneHTWindowSurfaceList.push_back(SurfNum);
2646 : } else {
2647 17836 : adjZone.ZoneHTNonWindowSurfaceList.push_back(SurfNum);
2648 : }
2649 : }
2650 : }
2651 :
2652 : // Exclude non-exterior heat transfer surfaces (but not OtherSideCondModeledExt = -4 CR7640)
2653 47290 : if (surf.HeatTransSurf && surf.ExtBoundCond > 0) {
2654 24853 : continue;
2655 : }
2656 22437 : if (surf.HeatTransSurf && surf.ExtBoundCond == DataSurfaces::Ground) {
2657 2246 : continue;
2658 : }
2659 20191 : if (surf.HeatTransSurf && surf.ExtBoundCond == DataSurfaces::KivaFoundation) {
2660 40 : state.dataSurface->AllHTKivaSurfaceList.push_back(SurfNum);
2661 40 : if (!ErrorsFound) {
2662 40 : state.dataSurfaceGeometry->kivaManager.foundationInputs[surf.OSCPtr].surfaces.push_back(SurfNum);
2663 : }
2664 40 : continue;
2665 : }
2666 20151 : if (surf.HeatTransSurf && surf.ExtBoundCond == DataSurfaces::OtherSideCoefNoCalcExt) {
2667 32 : continue;
2668 : }
2669 20119 : if (surf.HeatTransSurf && surf.ExtBoundCond == DataSurfaces::OtherSideCoefCalcExt) {
2670 1 : continue;
2671 : }
2672 : // Exclude windows and doors, i.e., consider only their base surfaces as possible obstructions
2673 20118 : if (surf.Class == SurfaceClass::Window || surf.Class == SurfaceClass::Door) {
2674 6745 : continue;
2675 : }
2676 : // Exclude duplicate shading surfaces
2677 13373 : if (surf.MirroredSurf) {
2678 845 : continue;
2679 : }
2680 : // Exclude air boundary surfaces
2681 12528 : if (surf.IsAirBoundarySurf) {
2682 18 : continue;
2683 : }
2684 :
2685 12510 : surf.IsShadowPossibleObstruction = true;
2686 12510 : state.dataSurface->AllShadowPossObstrSurfaceList.push_back(SurfNum);
2687 : } // for (SurfNum)
2688 :
2689 : // Check for IRT surfaces in invalid places.
2690 801 : if (std::any_of(state.dataConstruction->Construct.begin(),
2691 801 : state.dataConstruction->Construct.end(),
2692 6080 : [](Construction::ConstructionProps const &e) { return e.TypeIsIRT; })) {
2693 2 : int iTmp1 = 0;
2694 76 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
2695 74 : auto &surf = state.dataSurface->Surface(SurfNum);
2696 74 : if (!surf.HeatTransSurf) {
2697 0 : continue; // ignore shading surfaces
2698 : }
2699 74 : if (surf.ExtBoundCond > 0 && surf.ExtBoundCond != SurfNum) {
2700 28 : continue; // interzone, not adiabatic surface
2701 : }
2702 46 : if (!state.dataConstruction->Construct(surf.Construction).TypeIsIRT) {
2703 46 : continue;
2704 : }
2705 0 : if (!state.dataGlobal->DisplayExtraWarnings) {
2706 0 : ++iTmp1;
2707 : } else {
2708 0 : ShowWarningError(state,
2709 0 : format("{}Surface=\"{}\" uses InfraredTransparent construction in a non-interzone surface. (illegal use)",
2710 : RoutineName,
2711 0 : surf.Name));
2712 : }
2713 : }
2714 2 : if (iTmp1 > 0) {
2715 0 : ShowWarningError(
2716 : state,
2717 0 : format("{}Surfaces use InfraredTransparent constructions {} in non-interzone surfaces. (illegal use)", RoutineName, iTmp1));
2718 0 : ShowContinueError(state, "For explicit details on each use, use Output:Diagnostics,DisplayExtraWarnings;");
2719 : }
2720 : }
2721 :
2722 : // Populate SurfaceFilter lists
2723 8811 : for (int iSurfaceFilter = 1; iSurfaceFilter < static_cast<int>(DataSurfaces::SurfaceFilter::Num); ++iSurfaceFilter) {
2724 8010 : state.dataSurface->SurfaceFilterLists[iSurfaceFilter].reserve(state.dataSurface->TotSurfaces);
2725 : }
2726 :
2727 48091 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
2728 47290 : auto const &surf = state.dataSurface->Surface(SurfNum);
2729 47290 : if (!surf.HeatTransSurf) {
2730 1708 : continue;
2731 : }
2732 45582 : if (surf.ExtBoundCond > 0) {
2733 24853 : state.dataSurface->SurfaceFilterLists[static_cast<int>(DataSurfaces::SurfaceFilter::AllInteriorSurfaces)].push_back(SurfNum);
2734 24853 : if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) {
2735 14 : state.dataSurface->SurfaceFilterLists[static_cast<int>(DataSurfaces::SurfaceFilter::AllInteriorWindows)].push_back(SurfNum);
2736 24839 : } else if (surf.Class == SurfaceClass::Wall) {
2737 13917 : state.dataSurface->SurfaceFilterLists[static_cast<int>(DataSurfaces::SurfaceFilter::AllInteriorWalls)].push_back(SurfNum);
2738 10922 : } else if (surf.Class == SurfaceClass::Floor) {
2739 4652 : state.dataSurface->SurfaceFilterLists[static_cast<int>(DataSurfaces::SurfaceFilter::AllInteriorFloors)].push_back(SurfNum);
2740 6270 : } else if (surf.Class == SurfaceClass::Roof) {
2741 3669 : state.dataSurface->SurfaceFilterLists[static_cast<int>(DataSurfaces::SurfaceFilter::AllInteriorRoofs)].push_back(SurfNum);
2742 3669 : state.dataSurface->SurfaceFilterLists[static_cast<int>(DataSurfaces::SurfaceFilter::AllInteriorCeilings)].push_back(SurfNum);
2743 : }
2744 : } else {
2745 20729 : state.dataSurface->SurfaceFilterLists[static_cast<int>(DataSurfaces::SurfaceFilter::AllExteriorSurfaces)].push_back(SurfNum);
2746 20729 : if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) {
2747 6347 : state.dataSurface->SurfaceFilterLists[static_cast<int>(DataSurfaces::SurfaceFilter::AllExteriorWindows)].push_back(SurfNum);
2748 14382 : } else if (surf.Class == SurfaceClass::Wall) {
2749 9288 : state.dataSurface->SurfaceFilterLists[static_cast<int>(DataSurfaces::SurfaceFilter::AllExteriorWalls)].push_back(SurfNum);
2750 5094 : } else if (surf.Class == SurfaceClass::Floor) {
2751 2388 : state.dataSurface->SurfaceFilterLists[static_cast<int>(DataSurfaces::SurfaceFilter::AllExteriorFloors)].push_back(SurfNum);
2752 2706 : } else if (surf.Class == SurfaceClass::Roof) {
2753 2289 : state.dataSurface->SurfaceFilterLists[static_cast<int>(DataSurfaces::SurfaceFilter::AllExteriorRoofs)].push_back(SurfNum);
2754 2289 : state.dataSurface->SurfaceFilterLists[static_cast<int>(DataSurfaces::SurfaceFilter::AllInteriorCeilings)].push_back(SurfNum);
2755 : }
2756 : }
2757 : } // for (SurfNum)
2758 :
2759 : // Note, could do same for Window Area and detecting if Interzone Surface in Zone
2760 :
2761 801 : if (state.dataSurfaceGeometry->Warning1Count > 0) {
2762 10 : ShowWarningMessage(state,
2763 10 : format("{}Window dimensions differ from Window 5/6 data file dimensions, {} times.",
2764 : RoutineName,
2765 5 : state.dataSurfaceGeometry->Warning1Count));
2766 10 : ShowContinueError(state, "This will affect the frame heat transfer calculation if the frame in the Data File entry");
2767 10 : ShowContinueError(state, "is not uniform, i.e., has sections with different geometry and/or thermal properties.");
2768 15 : ShowContinueError(state, "For explicit details on each window, use Output:Diagnostics,DisplayExtraWarnings;");
2769 : }
2770 801 : if (state.dataSurfaceGeometry->Warning2Count > 0) {
2771 0 : ShowWarningMessage(state,
2772 0 : format("{}Exterior Windows have been replaced with Window 5/6 two glazing systems, {} times.",
2773 : RoutineName,
2774 0 : state.dataSurfaceGeometry->Warning2Count));
2775 0 : ShowContinueError(state, "Note that originally entered dimensions are overridden.");
2776 0 : ShowContinueError(state, "For explicit details on each window, use Output:Diagnostics,DisplayExtraWarnings;");
2777 : }
2778 801 : if (state.dataSurfaceGeometry->Warning3Count > 0) {
2779 0 : ShowWarningMessage(state,
2780 0 : format("{}Interior Windows have been replaced with Window 5/6 two glazing systems, {} times.",
2781 : RoutineName,
2782 0 : state.dataSurfaceGeometry->Warning3Count));
2783 0 : ShowContinueError(state, "Note that originally entered dimensions are overridden.");
2784 0 : ShowContinueError(state, "For explicit details on each window, use Output:Diagnostics,DisplayExtraWarnings;");
2785 : }
2786 :
2787 801 : if (state.dataErrTracking->TotalMultipliedWindows > 0) {
2788 2 : ShowWarningMessage(state,
2789 2 : format("{}There are {} window/glass door(s) that may cause inaccurate shadowing due to Solar Distribution.",
2790 : RoutineName,
2791 1 : state.dataErrTracking->TotalMultipliedWindows));
2792 2 : ShowContinueError(state, "For explicit details on each window, use Output:Diagnostics,DisplayExtraWarnings;");
2793 1 : state.dataErrTracking->TotalWarningErrors += state.dataErrTracking->TotalMultipliedWindows;
2794 : }
2795 801 : if (state.dataErrTracking->TotalCoincidentVertices > 0) {
2796 0 : ShowWarningMessage(state,
2797 0 : format("{}There are {} coincident/collinear vertices; These have been deleted unless the deletion would bring the "
2798 : "number of surface sides < 3.",
2799 : RoutineName,
2800 0 : state.dataErrTracking->TotalCoincidentVertices));
2801 0 : ShowContinueError(state, "For explicit details on each problem surface, use Output:Diagnostics,DisplayExtraWarnings;");
2802 0 : state.dataErrTracking->TotalWarningErrors += state.dataErrTracking->TotalCoincidentVertices;
2803 : }
2804 801 : if (state.dataErrTracking->TotalDegenerateSurfaces > 0) {
2805 0 : ShowSevereMessage(state,
2806 0 : format("{}There are {} degenerate surfaces; Degenerate surfaces are those with number of sides < 3.",
2807 : RoutineName,
2808 0 : state.dataErrTracking->TotalDegenerateSurfaces));
2809 0 : ShowContinueError(state, "These surfaces should be deleted.");
2810 0 : ShowContinueError(state, "For explicit details on each problem surface, use Output:Diagnostics,DisplayExtraWarnings;");
2811 0 : state.dataErrTracking->TotalSevereErrors += state.dataErrTracking->TotalDegenerateSurfaces;
2812 : }
2813 :
2814 801 : GetHTSurfExtVentedCavityData(state, ErrorsFound);
2815 :
2816 801 : state.dataSurfaceGeometry->exposedFoundationPerimeter.getData(state, ErrorsFound);
2817 :
2818 801 : GetSurfaceHeatTransferAlgorithmOverrides(state, ErrorsFound);
2819 :
2820 : // Set up enclosures, process Air Boundaries if any
2821 801 : SetupEnclosuresAndAirBoundaries(state, state.dataViewFactor->EnclRadInfo, SurfaceGeometry::enclosureType::RadiantEnclosures, ErrorsFound);
2822 :
2823 801 : GetSurfaceGroundSurfsData(state, ErrorsFound);
2824 :
2825 801 : GetSurfaceSrdSurfsData(state, ErrorsFound);
2826 :
2827 801 : GetSurfaceLocalEnvData(state, ErrorsFound);
2828 :
2829 801 : if (SurfError || ErrorsFound) {
2830 0 : ErrorsFound = true;
2831 0 : ShowFatalError(state, format("{}Errors discovered, program terminates.", RoutineName));
2832 : }
2833 :
2834 801 : int TotShadSurf = TotDetachedFixed + TotDetachedBldg + TotRectDetachedFixed + TotRectDetachedBldg + TotShdSubs + TotOverhangs +
2835 801 : TotOverhangsProjection + TotFins + TotFinsProjection;
2836 801 : int NumDElightCmplxFen = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Daylighting:DElight:ComplexFenestration");
2837 801 : if (TotShadSurf > 0 && (NumDElightCmplxFen > 0 || Dayltg::doesDayLightingUseDElight(state))) {
2838 0 : ShowWarningError(state, format("{}When using DElight daylighting the presence of exterior shading surfaces is ignored.", RoutineName));
2839 : }
2840 :
2841 48091 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; SurfNum++) {
2842 47290 : auto &surf = state.dataSurface->Surface(SurfNum);
2843 : // Initialize run time surface arrays
2844 47290 : state.dataSurface->SurfActiveConstruction(SurfNum) = surf.Construction;
2845 47290 : surf.RepresentativeCalcSurfNum = SurfNum;
2846 : }
2847 :
2848 : // Representative surface calculations: Assign representative heat transfer surfaces
2849 802 : if (state.dataSurface->UseRepresentativeSurfaceCalculations &&
2850 802 : state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "ZoneProperty:UserViewFactors:BySurfaceName") == 0) {
2851 47 : for (int zoneNum = 1; zoneNum <= state.dataGlobal->NumOfZones; ++zoneNum) {
2852 92 : for (int spaceNum : state.dataHeatBal->Zone(zoneNum).spaceIndexes) {
2853 46 : auto const &thisSpace = state.dataHeatBal->space(spaceNum);
2854 625 : for (int surfNum = thisSpace.HTSurfaceFirst; surfNum <= thisSpace.HTSurfaceLast; surfNum++) {
2855 579 : auto &surface(state.dataSurface->Surface(surfNum));
2856 : // Conditions where surface always needs to be unique
2857 1158 : bool forceUniqueSurface = surface.HasShadeControl ||
2858 579 : state.dataSurface->SurfWinAirflowSource(surfNum) != DataSurfaces::WindowAirFlowSource::Invalid ||
2859 579 : state.dataConstruction->Construct(surface.Construction).SourceSinkPresent ||
2860 1737 : surface.Class == SurfaceClass::TDD_Dome ||
2861 579 : (surface.Class == SurfaceClass::Window &&
2862 178 : (surface.OriginalClass == SurfaceClass::TDD_Diffuser ||
2863 178 : state.dataSurface->SurfWinWindowModelType(surfNum) != DataSurfaces::WindowModel::Detailed ||
2864 178 : state.dataWindowManager->inExtWindowModel->isExternalLibraryModel() ||
2865 178 : state.dataConstruction->Construct(surface.Construction).isTCWindow));
2866 579 : if (!forceUniqueSurface) {
2867 579 : state.dataSurface->Surface(surfNum).set_representative_surface(state, surfNum);
2868 : }
2869 : }
2870 46 : }
2871 : }
2872 : }
2873 :
2874 801 : if (SurfError || ErrorsFound) {
2875 0 : ErrorsFound = true;
2876 0 : ShowFatalError(state, format("{}Errors discovered, program terminates.", RoutineName));
2877 : }
2878 801 : }
2879 :
2880 801 : void CreateMissingSpaces(EnergyPlusData &state, Array1D<SurfaceGeometry::SurfaceData> &Surfaces)
2881 : {
2882 : static constexpr std::string_view RoutineName = "CreateMissingSpaces: ";
2883 : // Scan surfaces to see if Space was assigned in input
2884 801 : EPVector<bool> anySurfacesWithSpace; // True if any surfaces in a zone do not have a space assigned in input
2885 801 : EPVector<bool> anySurfacesWithoutSpace; // True if any surfaces in a zone have a space assigned in input
2886 801 : anySurfacesWithSpace.resize(state.dataGlobal->NumOfZones, false);
2887 801 : anySurfacesWithoutSpace.resize(state.dataGlobal->NumOfZones, false);
2888 :
2889 48091 : for (int surfNum = 1; surfNum <= state.dataSurface->TotSurfaces; ++surfNum) {
2890 47290 : auto &thisSurf = Surfaces(surfNum);
2891 47290 : if (!thisSurf.HeatTransSurf) {
2892 1690 : continue; // ignore shading surfaces
2893 : }
2894 45600 : if (thisSurf.Class == DataSurfaces::SurfaceClass::IntMass) {
2895 2537 : continue; // skip internal mass surfaces for this check
2896 : }
2897 43063 : if (thisSurf.BaseSurf != surfNum) {
2898 : // Set space for subsurfaces
2899 6842 : thisSurf.spaceNum = Surfaces(thisSurf.BaseSurf).spaceNum;
2900 : }
2901 43063 : if (thisSurf.spaceNum > 0) {
2902 122 : anySurfacesWithSpace(thisSurf.Zone) = true;
2903 42941 : } else if (thisSurf.ExtBoundCond != unreconciledZoneSurface) {
2904 20653 : anySurfacesWithoutSpace(thisSurf.Zone) = true;
2905 22288 : } else if (thisSurf.Name.substr(0, 3) != "iz-") {
2906 : // Only trigger a new space if the spaceless surface is not an autogenerated interzone surface
2907 21918 : anySurfacesWithoutSpace(thisSurf.Zone) = true;
2908 : }
2909 : }
2910 :
2911 : // Create any missing Spaces
2912 6002 : for (int zoneNum = 1; zoneNum <= state.dataGlobal->NumOfZones; ++zoneNum) {
2913 5201 : auto &thisZone = state.dataHeatBal->Zone(zoneNum);
2914 5201 : if (anySurfacesWithoutSpace(zoneNum)) {
2915 : // If any surfaces in the zone are not assigned to a space, may need to create a new space
2916 : // Every zone has at least one space, created in HeatBalanceManager::GetSpaceData
2917 : // If no surfaces have a space assigned, then the default space will be used, otherwise, create a new space
2918 5193 : if (anySurfacesWithSpace(zoneNum)) {
2919 : // Add new space
2920 3 : ++state.dataGlobal->numSpaces;
2921 3 : assert(state.dataHeatBal->space.size() >= state.dataGlobal->numSpaces);
2922 3 : state.dataHeatBal->space(state.dataGlobal->numSpaces).zoneNum = zoneNum;
2923 : // Add to zone's list of spaces
2924 3 : thisZone.spaceIndexes.emplace_back(state.dataGlobal->numSpaces);
2925 3 : ++state.dataHeatBal->Zone(zoneNum).numSpaces;
2926 3 : assert(state.dataHeatBal->Zone(zoneNum).numSpaces == int(state.dataHeatBal->Zone(zoneNum).spaceIndexes.size()));
2927 : // If some surfaces in the zone are assigned to a space, the new space is the remainder of the zone
2928 3 : state.dataHeatBal->space(state.dataGlobal->numSpaces).Name =
2929 6 : thisZone.Name + "-REMAINDER"; // Make UPPERcase so it can be referenced in input
2930 3 : state.dataHeatBal->space(state.dataGlobal->numSpaces).isRemainderSpace = true;
2931 3 : state.dataHeatBal->space(state.dataGlobal->numSpaces).spaceType = "GENERAL";
2932 3 : state.dataHeatBal->space(state.dataGlobal->numSpaces).spaceTypeNum = HeatBalanceManager::GetGeneralSpaceTypeNum(state);
2933 : }
2934 : }
2935 : }
2936 : // Right-size space vector
2937 801 : state.dataHeatBal->space.resize(state.dataGlobal->numSpaces);
2938 :
2939 : // Assign Spaces to surfaces without one
2940 48091 : for (int surfNum = 1; surfNum <= state.dataSurface->TotSurfaces; ++surfNum) {
2941 47290 : auto &thisSurf = Surfaces(surfNum);
2942 47290 : if (!thisSurf.HeatTransSurf) {
2943 1690 : continue; // ignore shading surfaces
2944 : }
2945 45600 : if (thisSurf.spaceNum == 0) {
2946 45464 : int const numSpaces = state.dataHeatBal->Zone(thisSurf.Zone).numSpaces;
2947 45464 : int const lastSpaceForZone = state.dataHeatBal->Zone(thisSurf.Zone).spaceIndexes(numSpaces);
2948 45464 : thisSurf.spaceNum = lastSpaceForZone;
2949 45464 : if ((thisSurf.ExtBoundCond == unreconciledZoneSurface) && (thisSurf.Name.substr(0, 3) == "iz-")) {
2950 370 : if (state.dataHeatBal->Zone(thisSurf.Zone).numSpaces > 1) {
2951 : // Only trigger warning if the spaceless surface is an autogenerated interzone surface
2952 0 : ShowWarningError(state,
2953 0 : format("{}Surface=\"{}\" has Outside Boundary Condition=Zone, but Zone=\"{}\" has more than 1 Space.",
2954 : RoutineName,
2955 0 : thisSurf.Name.substr(3),
2956 0 : thisSurf.ZoneName));
2957 0 : ShowContinueError(state,
2958 0 : format("Auto-generated surface=\"{}\" will be assigned to Space=\"{}\"",
2959 0 : thisSurf.Name,
2960 0 : state.dataHeatBal->space(thisSurf.spaceNum).Name));
2961 0 : ShowContinueError(state, "Use Outside Boundary Condition = Space to specify the exact Space for the outside boundary.");
2962 : }
2963 : }
2964 : }
2965 : }
2966 801 : }
2967 :
2968 801 : void createSpaceSurfaceLists(EnergyPlusData &state)
2969 : {
2970 : static constexpr std::string_view RoutineName("createSpaceSurfaceLists: ");
2971 : // Build Space surface lists now that all of the surface sorting is complete
2972 48091 : for (int surfNum = 1; surfNum <= state.dataSurface->TotSurfaces; ++surfNum) {
2973 47290 : auto &thisSurf = state.dataSurface->Surface(surfNum);
2974 47290 : if (!thisSurf.HeatTransSurf) {
2975 1690 : continue; // ignore shading surfaces
2976 : }
2977 : // Add to Space's list of surfaces
2978 45600 : state.dataHeatBal->space(thisSurf.spaceNum).surfaces.emplace_back(surfNum);
2979 : }
2980 6014 : for (int spaceNum = 1; spaceNum <= state.dataGlobal->numSpaces; ++spaceNum) {
2981 5213 : if (int(state.dataHeatBal->space(spaceNum).surfaces.size()) == 0) {
2982 0 : ShowWarningError(state, format("{}Space={} has no surfaces.", RoutineName, state.dataHeatBal->space(spaceNum).Name));
2983 : }
2984 : }
2985 801 : }
2986 :
2987 801 : void setSurfaceFirstLast(EnergyPlusData &state)
2988 : {
2989 : // Set Zone and Space Surface First/Last Pointers
2990 : // Space surface lists have been built earlier in createSpaceSurfaceLists
2991 6002 : for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
2992 10414 : for (int spaceNum : state.dataHeatBal->Zone(ZoneNum).spaceIndexes) {
2993 5213 : auto &thisSpace = state.dataHeatBal->space(spaceNum);
2994 50813 : for (int SurfNum : thisSpace.surfaces) {
2995 45600 : auto &surf = state.dataSurface->Surface(SurfNum);
2996 45600 : if (thisSpace.AllSurfaceFirst == 0) {
2997 5213 : thisSpace.AllSurfaceFirst = SurfNum;
2998 : }
2999 45600 : thisSpace.AllSurfaceLast = SurfNum;
3000 :
3001 45600 : if (surf.IsAirBoundarySurf) {
3002 18 : surf.HeatTransSurf = false;
3003 18 : continue;
3004 : }
3005 : // Non window surfaces are grouped next within each space
3006 45582 : if (thisSpace.HTSurfaceFirst == 0) {
3007 5213 : thisSpace.HTSurfaceFirst = SurfNum;
3008 5213 : thisSpace.OpaqOrIntMassSurfaceFirst = SurfNum;
3009 5213 : thisSpace.OpaqOrWinSurfaceFirst = SurfNum;
3010 : }
3011 45582 : thisSpace.HTSurfaceLast = SurfNum;
3012 :
3013 : // Window surfaces are grouped next within each space
3014 45582 : if ((surf.Class == DataSurfaces::SurfaceClass::Window) || (surf.Class == DataSurfaces::SurfaceClass::GlassDoor) ||
3015 39225 : (surf.Class == DataSurfaces::SurfaceClass::TDD_Diffuser)) {
3016 6359 : if (thisSpace.WindowSurfaceFirst == 0) {
3017 3249 : thisSpace.WindowSurfaceFirst = SurfNum;
3018 : }
3019 6359 : thisSpace.WindowSurfaceLast = SurfNum;
3020 39223 : } else if (surf.Class != DataSurfaces::SurfaceClass::TDD_Dome) {
3021 39221 : thisSpace.OpaqOrIntMassSurfaceLast = SurfNum;
3022 : }
3023 :
3024 : // TDDDome surfaces are grouped last within each space
3025 45582 : if (surf.Class == DataSurfaces::SurfaceClass::TDD_Dome) {
3026 2 : if (thisSpace.TDDDomeFirst == 0) {
3027 1 : thisSpace.TDDDomeFirst = SurfNum;
3028 : }
3029 2 : thisSpace.TDDDomeLast = SurfNum;
3030 : } else {
3031 45580 : thisSpace.OpaqOrWinSurfaceLast = SurfNum;
3032 : }
3033 5213 : }
3034 5213 : state.dataHeatBal->Zone(ZoneNum).AllSurfaceLast = thisSpace.AllSurfaceLast;
3035 5201 : }
3036 5201 : int firstSpaceNum = state.dataHeatBal->Zone(ZoneNum).spaceIndexes(1);
3037 5201 : state.dataHeatBal->Zone(ZoneNum).AllSurfaceFirst = state.dataHeatBal->space(firstSpaceNum).AllSurfaceFirst;
3038 : }
3039 801 : }
3040 :
3041 6842 : void checkSubSurfAzTiltNorm(EnergyPlusData &state,
3042 : SurfaceData &baseSurface, // Base surface data (in)
3043 : SurfaceData &subSurface, // Subsurface data (in)
3044 : bool &surfaceError // True if surface azimuths or tilts differ by more than error tolerance
3045 : )
3046 : {
3047 6842 : bool sameSurfNormal = false; // True if surface has the same surface normal within tolerance
3048 6842 : Real64 constexpr warningTolerance = 30.0;
3049 6842 : Real64 constexpr errorTolerance = 90.0;
3050 :
3051 6842 : surfaceError = false; // True if surface has the same surface normal within tolerance
3052 :
3053 : // Check if base surface and subsurface have the same normal
3054 6842 : Vectors::CompareTwoVectors(baseSurface.NewellSurfaceNormalVector, subSurface.NewellSurfaceNormalVector, sameSurfNormal, 0.001);
3055 6842 : if (sameSurfNormal) { // copy lcs vectors
3056 : // Prior logic tested for azimuth difference < 30 and then skipped this - this caused large diffs in
3057 : // CmplxGlz_MeasuredDeflectionAndShading Restoring that check here but will require further investigation (MJW Dec 2015)
3058 : // if (std::abs(baseSurface.Azimuth - subSurface.Azimuth) > warningTolerance) {
3059 6841 : subSurface.lcsx = baseSurface.lcsx;
3060 6841 : subSurface.lcsy = baseSurface.lcsy;
3061 6841 : subSurface.lcsz = baseSurface.lcsz;
3062 : // }
3063 : } else {
3064 1 : bool baseSurfHoriz = false; // True if base surface is near horizontal
3065 : // // Not sure what this does, but keeping for now (MJW Dec 2015)
3066 : // if (std::abs(subSurface.Azimuth - 360.0) < 0.01) {
3067 : // subSurface.Azimuth = 360.0 - subSurface.Azimuth;
3068 : // }
3069 : // if (std::abs(baseSurface.Azimuth - 360.0) < 0.01) {
3070 : // baseSurface.Azimuth = 360.0 - baseSurface.Azimuth;
3071 : // }
3072 :
3073 : // Is base surface horizontal? If so, ignore azimuth differences
3074 1 : if (std::abs(baseSurface.Tilt) <= 1.0e-5 || std::abs(baseSurface.Tilt - 180.0) <= 1.0e-5) {
3075 0 : baseSurfHoriz = true;
3076 : }
3077 :
3078 2 : if (((General::rotAzmDiffDeg(baseSurface.Azimuth, subSurface.Azimuth) > errorTolerance) && !baseSurfHoriz) ||
3079 1 : (std::abs(baseSurface.Tilt - subSurface.Tilt) > errorTolerance)) {
3080 0 : surfaceError = true;
3081 0 : ShowSevereError(
3082 : state,
3083 0 : format("checkSubSurfAzTiltNorm: Outward facing angle of subsurface differs more than {:.1R} degrees from base surface.",
3084 : errorTolerance));
3085 0 : ShowContinueError(state,
3086 0 : format("Subsurface=\"{}\" Tilt = {:.1R} Azimuth = {:.1R}", subSurface.Name, subSurface.Tilt, subSurface.Azimuth));
3087 0 : ShowContinueError(
3088 0 : state, format("Base surface=\"{}\" Tilt = {:.1R} Azimuth = {:.1R}", baseSurface.Name, baseSurface.Tilt, baseSurface.Azimuth));
3089 2 : } else if (((General::rotAzmDiffDeg(baseSurface.Azimuth, subSurface.Azimuth) > warningTolerance) && !baseSurfHoriz) ||
3090 1 : (std::abs(baseSurface.Tilt - subSurface.Tilt) > warningTolerance)) {
3091 0 : ++state.dataSurfaceGeometry->checkSubSurfAzTiltNormErrCount;
3092 0 : if (state.dataSurfaceGeometry->checkSubSurfAzTiltNormErrCount == 1 && !state.dataGlobal->DisplayExtraWarnings) {
3093 0 : ShowWarningError(state,
3094 0 : format("checkSubSurfAzTiltNorm: Some Outward Facing angles of subsurfaces differ more than {:.1R} "
3095 : "degrees from base surface.",
3096 : warningTolerance));
3097 0 : ShowContinueError(state, "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on individual surfaces.");
3098 : }
3099 0 : if (state.dataGlobal->DisplayExtraWarnings) {
3100 0 : ShowWarningError(
3101 : state,
3102 0 : format("checkSubSurfAzTiltNorm: Outward facing angle of subsurface differs more than {:.1R} degrees from base surface.",
3103 : warningTolerance));
3104 0 : ShowContinueError(
3105 0 : state, format("Subsurface=\"{}\" Tilt = {:.1R} Azimuth = {:.1R}", subSurface.Name, subSurface.Tilt, subSurface.Azimuth));
3106 0 : ShowContinueError(
3107 : state,
3108 0 : format("Base surface=\"{}\" Tilt = {:.1R} Azimuth = {:.1R}", baseSurface.Name, baseSurface.Tilt, baseSurface.Azimuth));
3109 : }
3110 : }
3111 : }
3112 6842 : }
3113 :
3114 801 : void GetGeometryParameters(EnergyPlusData &state, bool &ErrorsFound) // set to true if errors found during input
3115 : {
3116 :
3117 : // SUBROUTINE INFORMATION:
3118 : // AUTHOR Linda Lawrie
3119 : // DATE WRITTEN May 2000
3120 :
3121 : // PURPOSE OF THIS SUBROUTINE:
3122 : // This subroutine reads in the "Surface Geometry" parameters, verifies them,
3123 : // and sets "global" variables that will tell other routines how the surface
3124 : // vertices are expected in input.
3125 :
3126 : // REFERENCES:
3127 : // GlobalGeometryRules Definition
3128 : // GlobalGeometryRules,
3129 : // \required-object
3130 : // \unique-object
3131 : // A1, \field Starting Vertex Position
3132 : // \required-field
3133 : // \note Specified as entry for a 4 sided surface/rectangle
3134 : // \note Surfaces are specified as viewed from outside the surface
3135 : // \note Shading surfaces as viewed from behind. (towards what they are shading)
3136 : // \type choice
3137 : // \key UpperLeftCorner
3138 : // \key LowerLeftCorner
3139 : // \key UpperRightCorner
3140 : // \key LowerRightCorner
3141 : // A2, \field Vertex Entry Direction
3142 : // \required-field
3143 : // \type choice
3144 : // \key Counterclockwise
3145 : // \key Clockwise
3146 : // A3, \field Coordinate System
3147 : // \required-field
3148 : // \note relative -- coordinates are entered relative to zone origin
3149 : // \note world -- all coordinates entered are "absolute" for this facility
3150 : // \note absolute -- same as world
3151 : // \type choice
3152 : // \key Relative
3153 : // \key World
3154 : // \key Absolute
3155 : // A4, \field Daylighting Reference Point Coordinate System
3156 : // \type choice
3157 : // \key Relative
3158 : // \default Relative
3159 : // \note Relative -- coordinates are entered relative to zone origin
3160 : // \key World
3161 : // \note World -- all coordinates entered are "absolute" for this facility
3162 : // \key Absolute
3163 : // \note absolute -- same as world
3164 : // A5; \field Rectangular Surface Coordinate System
3165 : // \type choice
3166 : // \key Relative
3167 : // \default Relative
3168 : // \note Relative -- Starting corner is entered relative to zone origin
3169 : // \key World
3170 : // \note World -- Starting corner is entered in "absolute"
3171 : // \key Absolute
3172 : // \note absolute -- same as world
3173 :
3174 : // SUBROUTINE PARAMETER DEFINITIONS:
3175 801 : static Array1D_string const FlCorners(4, {"UpperLeftCorner", "LowerLeftCorner", "LowerRightCorner", "UpperRightCorner"});
3176 :
3177 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
3178 801 : Array1D_string GAlphas(5);
3179 801 : Array1D<Real64> GNum(1);
3180 :
3181 801 : auto &s_ipsc = state.dataIPShortCut;
3182 :
3183 801 : s_ipsc->cCurrentModuleObject = "GlobalGeometryRules";
3184 801 : int NumStmt = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
3185 801 : std::string OutMsg = " Surface Geometry,";
3186 :
3187 : {
3188 801 : int const SELECT_CASE_var = NumStmt;
3189 :
3190 801 : if (SELECT_CASE_var == 1) {
3191 : int NNum;
3192 : int IOStat;
3193 : int NAlphas;
3194 : // This is the valid case
3195 2403 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
3196 801 : s_ipsc->cCurrentModuleObject,
3197 : 1,
3198 : GAlphas,
3199 : NAlphas,
3200 : GNum,
3201 : NNum,
3202 : IOStat,
3203 801 : s_ipsc->lNumericFieldBlanks,
3204 801 : s_ipsc->lAlphaFieldBlanks,
3205 801 : s_ipsc->cAlphaFieldNames,
3206 801 : s_ipsc->cNumericFieldNames);
3207 :
3208 : // Even though these will be validated, set defaults in case error here -- wont
3209 : // cause aborts in later surface gets (hopefully)
3210 801 : state.dataSurface->Corner = DataSurfaces::UpperLeftCorner;
3211 801 : state.dataSurface->WorldCoordSystem = true;
3212 801 : state.dataSurface->CCW = true;
3213 :
3214 801 : int Found = Util::FindItem(GAlphas(1), FlCorners, 4);
3215 801 : if (Found == 0) {
3216 0 : ShowSevereError(state, format("{}: Invalid {}={}", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaFieldNames(1), GAlphas(1)));
3217 0 : ErrorsFound = true;
3218 : } else {
3219 801 : state.dataSurface->Corner = Found;
3220 801 : OutMsg += FlCorners(state.dataSurface->Corner) + ',';
3221 : }
3222 :
3223 801 : bool OK = false;
3224 801 : if (Util::SameString(GAlphas(2), "CCW") || Util::SameString(GAlphas(2), "Counterclockwise")) {
3225 798 : state.dataSurface->CCW = true;
3226 798 : OutMsg += "Counterclockwise,";
3227 798 : OK = true;
3228 : }
3229 801 : if (Util::SameString(GAlphas(2), "CW") || Util::SameString(GAlphas(2), "Clockwise")) {
3230 3 : state.dataSurface->CCW = false;
3231 3 : OutMsg += "Clockwise,";
3232 3 : OK = true;
3233 : }
3234 801 : if (!OK) {
3235 0 : ShowSevereError(state, format("{}: Invalid {}={}", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaFieldNames(2), GAlphas(2)));
3236 0 : ErrorsFound = true;
3237 : }
3238 :
3239 801 : OK = false;
3240 801 : if (Util::SameString(GAlphas(3), "World") || Util::SameString(GAlphas(3), "Absolute")) {
3241 357 : state.dataSurface->WorldCoordSystem = true;
3242 357 : OutMsg += "WorldCoordinateSystem,";
3243 357 : OK = true;
3244 : }
3245 801 : if (Util::SameString(GAlphas(3), "Relative")) {
3246 444 : state.dataSurface->WorldCoordSystem = false;
3247 444 : OutMsg += "RelativeCoordinateSystem,";
3248 444 : OK = true;
3249 : }
3250 801 : if (!OK) {
3251 0 : ShowWarningError(state, format("{}: Invalid {}={}", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaFieldNames(3), GAlphas(3)));
3252 0 : ShowContinueError(state, format("{} defaults to \"WorldCoordinateSystem\"", s_ipsc->cAlphaFieldNames(3)));
3253 0 : state.dataSurface->WorldCoordSystem = true;
3254 0 : OutMsg += "WorldCoordinateSystem,";
3255 : }
3256 :
3257 801 : OK = false;
3258 801 : if (Util::SameString(GAlphas(4), "World") || Util::SameString(GAlphas(4), "Absolute")) {
3259 8 : state.dataSurface->DaylRefWorldCoordSystem = true;
3260 8 : OutMsg += "WorldCoordinateSystem,";
3261 8 : OK = true;
3262 : }
3263 801 : if (Util::SameString(GAlphas(4), "Relative") || GAlphas(4).empty()) {
3264 793 : state.dataSurface->DaylRefWorldCoordSystem = false;
3265 793 : OutMsg += "RelativeCoordinateSystem,";
3266 793 : OK = true;
3267 : }
3268 801 : if (!OK) {
3269 0 : ShowWarningError(state, format("{}: Invalid {}={}", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaFieldNames(4), GAlphas(4)));
3270 0 : ShowContinueError(state, format("{} defaults to \"RelativeToZoneOrigin\"", s_ipsc->cAlphaFieldNames(4)));
3271 0 : state.dataSurface->DaylRefWorldCoordSystem = false;
3272 0 : OutMsg += "RelativeToZoneOrigin,";
3273 : }
3274 :
3275 801 : OK = false;
3276 801 : if (Util::SameString(GAlphas(5), "World") || Util::SameString(GAlphas(5), "Absolute")) {
3277 18 : state.dataSurfaceGeometry->RectSurfRefWorldCoordSystem = true;
3278 18 : OutMsg += "WorldCoordinateSystem";
3279 18 : OK = true;
3280 : }
3281 801 : if (Util::SameString(GAlphas(5), "Relative") || GAlphas(5).empty()) {
3282 783 : state.dataSurfaceGeometry->RectSurfRefWorldCoordSystem = false;
3283 783 : OutMsg += "RelativeToZoneOrigin";
3284 783 : OK = true;
3285 : }
3286 801 : if (!OK) {
3287 0 : ShowWarningError(state, format("{}: Invalid {}={}", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaFieldNames(5), GAlphas(5)));
3288 0 : ShowContinueError(state, format("{} defaults to \"RelativeToZoneOrigin\"", s_ipsc->cAlphaFieldNames(5)));
3289 0 : state.dataSurfaceGeometry->RectSurfRefWorldCoordSystem = false;
3290 0 : OutMsg += "RelativeToZoneOrigin";
3291 : }
3292 :
3293 0 : } else if (SELECT_CASE_var == 0) {
3294 :
3295 0 : ShowSevereError(state, format("{}: Required object not found.", s_ipsc->cCurrentModuleObject));
3296 0 : OutMsg += "None found in input";
3297 0 : ErrorsFound = true;
3298 :
3299 : } else {
3300 :
3301 0 : ShowSevereError(state, format("{}: Too many objects entered. Only one allowed.", s_ipsc->cCurrentModuleObject));
3302 0 : ErrorsFound = true;
3303 : }
3304 : }
3305 :
3306 801 : if (!state.dataSurface->WorldCoordSystem) {
3307 444 : if (state.dataSurface->DaylRefWorldCoordSystem) {
3308 0 : ShowWarningError(state, format("{}: Potential mismatch of coordinate specifications.", s_ipsc->cCurrentModuleObject));
3309 0 : ShowContinueError(state, format("{}=\"{}\"; while ", s_ipsc->cAlphaFieldNames(3), GAlphas(3)));
3310 0 : ShowContinueError(state, format("{}=\"{}\".", s_ipsc->cAlphaFieldNames(4), GAlphas(4)));
3311 : }
3312 444 : if (state.dataSurfaceGeometry->RectSurfRefWorldCoordSystem) {
3313 0 : ShowWarningError(state, format("{}: Potential mismatch of coordinate specifications.", s_ipsc->cCurrentModuleObject));
3314 0 : ShowContinueError(state, format("{}=\"{}\"; while ", s_ipsc->cAlphaFieldNames(3), GAlphas(3)));
3315 0 : ShowContinueError(state, format("{}=\"{}\".", s_ipsc->cAlphaFieldNames(5), GAlphas(5)));
3316 : }
3317 : } else {
3318 357 : bool RelWarning = false;
3319 1392 : for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
3320 1035 : if (state.dataHeatBal->Zone(ZoneNum).OriginX != 0.0) {
3321 31 : RelWarning = true;
3322 : }
3323 1035 : if (state.dataHeatBal->Zone(ZoneNum).OriginY != 0.0) {
3324 35 : RelWarning = true;
3325 : }
3326 1035 : if (state.dataHeatBal->Zone(ZoneNum).OriginZ != 0.0) {
3327 4 : RelWarning = true;
3328 : }
3329 : }
3330 357 : if (RelWarning && !state.dataSurfaceGeometry->RectSurfRefWorldCoordSystem) {
3331 0 : ShowWarningError(state,
3332 0 : format("{}: Potential mismatch of coordinate specifications. Note that the rectangular surfaces are relying on the "
3333 : "default SurfaceGeometry for 'Relative to zone' coordinate.",
3334 0 : s_ipsc->cCurrentModuleObject));
3335 0 : ShowContinueError(state, format("{}=\"{}\"; while ", s_ipsc->cAlphaFieldNames(3), GAlphas(3)));
3336 0 : if (GAlphas(5) == "RELATIVE") {
3337 0 : ShowContinueError(state, format("{}=\"{}\".", s_ipsc->cAlphaFieldNames(5), GAlphas(5)));
3338 0 : } else if (GAlphas(5) != "ABSOLUTE") {
3339 0 : ShowContinueError(state, format("{}=\"defaults to RELATIVE\".", s_ipsc->cAlphaFieldNames(5)));
3340 : }
3341 : }
3342 : }
3343 :
3344 801 : print(state.files.eio,
3345 : "! <Surface Geometry>,Starting Corner,Vertex Input Direction,Coordinate System,Daylight Reference "
3346 : "Point Coordinate System,Rectangular (Simple) Surface Coordinate System\n");
3347 801 : print(state.files.eio, "{}\n", OutMsg);
3348 801 : }
3349 :
3350 801 : void GetDetShdSurfaceData(EnergyPlusData &state,
3351 : bool &ErrorsFound, // Error flag indicator (true if errors found)
3352 : int &SurfNum, // Count of Current SurfaceNumber
3353 : int const TotDetachedFixed, // Number of Fixed Detached Shading Surfaces to obtain
3354 : int const TotDetachedBldg // Number of Building Detached Shading Surfaces to obtain
3355 : )
3356 : {
3357 : // SUBROUTINE INFORMATION:
3358 : // AUTHOR Linda Lawrie
3359 : // DATE WRITTEN May 2000
3360 :
3361 : // PURPOSE OF THIS SUBROUTINE:
3362 : // This subroutine gets the Detached Shading Surface Data,
3363 : // checks it for errors, etc.
3364 :
3365 : static constexpr std::string_view routineName = "GetDetShdSurfaceData";
3366 : // SUBROUTINE PARAMETER DEFINITIONS:
3367 801 : static Array1D_string const cModuleObjects(2, {"Shading:Site:Detailed", "Shading:Building:Detailed"});
3368 :
3369 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
3370 : int IOStat; // IO Status when calling get input subroutine
3371 : int NumAlphas; // Number of material alpha names being passed
3372 : int NumNumbers; // Number of material properties being passed
3373 : int Loop;
3374 : int ItemsToGet;
3375 : SurfaceClass ClassItem;
3376 : int numSides;
3377 : Real64 SchedMinValue;
3378 : Real64 SchedMaxValue;
3379 :
3380 801 : auto &s_ipsc = state.dataIPShortCut;
3381 :
3382 801 : if ((TotDetachedFixed + TotDetachedBldg) > 0 && state.dataHeatBal->SolarDistribution == DataHeatBalance::Shadowing::Minimal) {
3383 0 : ShowWarningError(state, "Detached shading effects are ignored when Solar Distribution = MinimalShadowing");
3384 : }
3385 :
3386 801 : if ((TotDetachedFixed + TotDetachedBldg) == 0) {
3387 781 : return;
3388 : }
3389 :
3390 60 : for (int Item = 1; Item <= 2; ++Item) {
3391 :
3392 40 : s_ipsc->cCurrentModuleObject = cModuleObjects(Item);
3393 40 : if (Item == 1) {
3394 20 : ItemsToGet = TotDetachedFixed;
3395 20 : ClassItem = SurfaceClass::Detached_F;
3396 : } else { // IF (Item == 2) THEN
3397 20 : ItemsToGet = TotDetachedBldg;
3398 20 : ClassItem = SurfaceClass::Detached_B;
3399 : }
3400 :
3401 40 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, s_ipsc->cCurrentModuleObject, Loop, NumAlphas, NumNumbers);
3402 40 : if (NumAlphas != 2) {
3403 0 : ShowSevereError(
3404 : state,
3405 0 : format("{}: Object Definition indicates not = 2 Alpha Objects, Number Indicated={}", s_ipsc->cCurrentModuleObject, NumAlphas));
3406 0 : ErrorsFound = true;
3407 : }
3408 :
3409 96 : for (Loop = 1; Loop <= ItemsToGet; ++Loop) {
3410 112 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
3411 56 : s_ipsc->cCurrentModuleObject,
3412 : Loop,
3413 56 : s_ipsc->cAlphaArgs,
3414 : NumAlphas,
3415 56 : s_ipsc->rNumericArgs,
3416 : NumNumbers,
3417 : IOStat,
3418 56 : s_ipsc->lNumericFieldBlanks,
3419 56 : s_ipsc->lAlphaFieldBlanks,
3420 56 : s_ipsc->cAlphaFieldNames,
3421 56 : s_ipsc->cNumericFieldNames);
3422 :
3423 56 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
3424 :
3425 112 : if (GlobalNames::VerifyUniqueInterObjectName(state,
3426 56 : state.dataSurfaceGeometry->UniqueSurfaceNames,
3427 56 : s_ipsc->cAlphaArgs(1),
3428 56 : s_ipsc->cCurrentModuleObject,
3429 56 : s_ipsc->cAlphaFieldNames(1),
3430 : ErrorsFound)) {
3431 0 : continue;
3432 : }
3433 :
3434 56 : ++SurfNum;
3435 :
3436 56 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
3437 56 : surfTemp.Name = s_ipsc->cAlphaArgs(1); // Set the Surface Name in the Derived Type
3438 56 : surfTemp.Class = ClassItem;
3439 56 : surfTemp.HeatTransSurf = false;
3440 56 : surfTemp.ExtSolar = true;
3441 : // Base transmittance of a shadowing (sub)surface
3442 :
3443 56 : if (s_ipsc->lAlphaFieldBlanks(2)) {
3444 30 : surfTemp.shadowSurfSched =
3445 : nullptr; // Leaving this as nullptr rather than making AlwaysOff because the uses and tests are too varied
3446 26 : } else if ((surfTemp.shadowSurfSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(2))) == nullptr) {
3447 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2));
3448 0 : ErrorsFound = true;
3449 26 : } else if (!surfTemp.shadowSurfSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 1.0)) {
3450 0 : Sched::ShowSevereBadMinMax(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2), Clusive::In, 0.0, Clusive::In, 1.0);
3451 0 : ErrorsFound = true;
3452 : } else {
3453 26 : SchedMinValue = surfTemp.shadowSurfSched->getMinVal(state);
3454 26 : surfTemp.SchedMinValue = SchedMinValue;
3455 26 : SchedMaxValue = surfTemp.shadowSurfSched->getCurrentVal();
3456 26 : if (SchedMinValue == 1.0) {
3457 : // Set transparent for now, check for EMS actuators later in SolarShading::resetShadingSurfaceTransparency
3458 0 : surfTemp.IsTransparent = true;
3459 : }
3460 26 : if (SchedMinValue < 0.0) {
3461 0 : ShowSevereError(state,
3462 0 : format("{}=\"{}\", {}=\"{}\", has schedule values < 0.",
3463 0 : s_ipsc->cCurrentModuleObject,
3464 0 : surfTemp.Name,
3465 0 : s_ipsc->cAlphaFieldNames(2),
3466 0 : s_ipsc->cAlphaArgs(2)));
3467 0 : ShowContinueError(state, "...Schedule values < 0 have no meaning for shading elements.");
3468 : }
3469 26 : if (SchedMaxValue > 0.0) {
3470 26 : state.dataSolarShading->anyScheduledShadingSurface = true;
3471 : }
3472 26 : if (SchedMaxValue > 1.0) {
3473 0 : ShowSevereError(state,
3474 0 : format("{}=\"{}\", {}=\"{}\", has schedule values > 1.",
3475 0 : s_ipsc->cCurrentModuleObject,
3476 0 : surfTemp.Name,
3477 0 : s_ipsc->cAlphaFieldNames(2),
3478 0 : s_ipsc->cAlphaArgs(2)));
3479 0 : ShowContinueError(state, "...Schedule values > 1 have no meaning for shading elements.");
3480 : }
3481 26 : if (std::abs(SchedMinValue - SchedMaxValue) > Constant::OneMillionth) {
3482 0 : state.dataSurface->ShadingTransmittanceVaries = true;
3483 : }
3484 : }
3485 56 : if (s_ipsc->lNumericFieldBlanks(1) || s_ipsc->rNumericArgs(1) == Constant::AutoCalculate) {
3486 0 : numSides = (NumNumbers - 1) / 3;
3487 0 : surfTemp.Sides = numSides;
3488 0 : if (mod(NumNumbers - 1, 3) != 0) {
3489 0 : ShowWarningError(state,
3490 0 : format("{}=\"{}\", {}",
3491 0 : s_ipsc->cCurrentModuleObject,
3492 0 : surfTemp.Name,
3493 0 : format("{} not even multiple of 3. Will read in {}", s_ipsc->cNumericFieldNames(1), surfTemp.Sides)));
3494 : }
3495 0 : if (numSides < 3) {
3496 0 : ShowSevereError(state,
3497 0 : format("{}=\"{}\", {} (autocalculate) must be >= 3. Only {} provided.",
3498 0 : s_ipsc->cCurrentModuleObject,
3499 0 : surfTemp.Name,
3500 0 : s_ipsc->cNumericFieldNames(1),
3501 0 : surfTemp.Sides));
3502 0 : ErrorsFound = true;
3503 0 : continue;
3504 : }
3505 : } else {
3506 56 : numSides = (NumNumbers - 1) / 3;
3507 56 : surfTemp.Sides = s_ipsc->rNumericArgs(1);
3508 56 : if (numSides > surfTemp.Sides) {
3509 0 : ShowWarningError(state,
3510 0 : format("{}=\"{}\", field {}={}",
3511 0 : s_ipsc->cCurrentModuleObject,
3512 0 : surfTemp.Name,
3513 0 : s_ipsc->cNumericFieldNames(1),
3514 0 : fmt::to_string(surfTemp.Sides)));
3515 0 : ShowContinueError(
3516 0 : state, format("...but {} were entered. Only the indicated {} will be used.", numSides, s_ipsc->cNumericFieldNames(1)));
3517 : }
3518 : }
3519 56 : surfTemp.Vertex.allocate(surfTemp.Sides);
3520 224 : GetVertices(state, SurfNum, surfTemp.Sides, s_ipsc->rNumericArgs({2, _}));
3521 56 : CheckConvexity(state, SurfNum, surfTemp.Sides);
3522 56 : if (state.dataReportFlag->MakeMirroredDetachedShading) {
3523 56 : MakeMirrorSurface(state, SurfNum);
3524 : }
3525 : }
3526 :
3527 : } // Item Loop
3528 56 : }
3529 :
3530 801 : void GetRectDetShdSurfaceData(EnergyPlusData &state,
3531 : bool &ErrorsFound, // Error flag indicator (true if errors found)
3532 : int &SurfNum, // Count of Current SurfaceNumber
3533 : int const TotRectDetachedFixed, // Number of Fixed Detached Shading Surfaces to obtain
3534 : int const TotRectDetachedBldg // Number of Building Detached Shading Surfaces to obtain
3535 : )
3536 : {
3537 :
3538 : // SUBROUTINE INFORMATION:
3539 : // AUTHOR Linda Lawrie
3540 : // DATE WRITTEN January 2009
3541 :
3542 : // PURPOSE OF THIS SUBROUTINE:
3543 : // Gets the simple, rectangular detached surfaces.
3544 :
3545 : // SUBROUTINE PARAMETER DEFINITIONS:
3546 801 : static Array1D_string const cModuleObjects(2, {"Shading:Site", "Shading:Building"});
3547 :
3548 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
3549 : int IOStat; // IO Status when calling get input subroutine
3550 : int NumAlphas; // Number of material alpha names being passed
3551 : int NumNumbers; // Number of material properties being passed
3552 : int Loop;
3553 : int ItemsToGet;
3554 : SurfaceClass ClassItem;
3555 :
3556 801 : auto &s_ipsc = state.dataIPShortCut;
3557 :
3558 801 : if ((TotRectDetachedFixed + TotRectDetachedBldg) > 0 && state.dataHeatBal->SolarDistribution == DataHeatBalance::Shadowing::Minimal) {
3559 0 : ShowWarningError(state, "Detached shading effects are ignored when Solar Distribution = MinimalShadowing");
3560 : }
3561 :
3562 801 : if (TotRectDetachedFixed + TotRectDetachedBldg == 0) {
3563 795 : return;
3564 : }
3565 18 : for (int Item = 1; Item <= 2; ++Item) {
3566 :
3567 12 : s_ipsc->cCurrentModuleObject = cModuleObjects(Item);
3568 12 : if (Item == 1) {
3569 6 : ItemsToGet = TotRectDetachedFixed;
3570 6 : ClassItem = SurfaceClass::Detached_F;
3571 : } else { // IF (Item == 2) THEN
3572 6 : ItemsToGet = TotRectDetachedBldg;
3573 6 : ClassItem = SurfaceClass::Detached_B;
3574 : }
3575 :
3576 12 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, s_ipsc->cCurrentModuleObject, Loop, NumAlphas, NumNumbers);
3577 12 : if (NumAlphas != 1) {
3578 0 : ShowSevereError(
3579 : state,
3580 0 : format("{}: Object Definition indicates not = 1 Alpha Objects, Number Indicated={}", s_ipsc->cCurrentModuleObject, NumAlphas));
3581 0 : ErrorsFound = true;
3582 : }
3583 :
3584 32 : for (Loop = 1; Loop <= ItemsToGet; ++Loop) {
3585 40 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
3586 20 : s_ipsc->cCurrentModuleObject,
3587 : Loop,
3588 20 : s_ipsc->cAlphaArgs,
3589 : NumAlphas,
3590 20 : s_ipsc->rNumericArgs,
3591 : NumNumbers,
3592 : IOStat,
3593 20 : s_ipsc->lNumericFieldBlanks,
3594 20 : s_ipsc->lAlphaFieldBlanks,
3595 20 : s_ipsc->cAlphaFieldNames,
3596 20 : s_ipsc->cNumericFieldNames);
3597 :
3598 40 : if (GlobalNames::VerifyUniqueInterObjectName(state,
3599 20 : state.dataSurfaceGeometry->UniqueSurfaceNames,
3600 20 : s_ipsc->cAlphaArgs(1),
3601 20 : s_ipsc->cCurrentModuleObject,
3602 20 : s_ipsc->cAlphaFieldNames(1),
3603 : ErrorsFound)) {
3604 0 : continue;
3605 : }
3606 :
3607 20 : ++SurfNum;
3608 :
3609 20 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
3610 20 : surfTemp.Name = s_ipsc->cAlphaArgs(1); // Set the Surface Name in the Derived Type
3611 20 : surfTemp.Class = ClassItem;
3612 20 : surfTemp.HeatTransSurf = false;
3613 20 : surfTemp.ExtSolar = true;
3614 :
3615 20 : surfTemp.Azimuth = s_ipsc->rNumericArgs(1);
3616 20 : if (surfTemp.Class == SurfaceClass::Detached_B && !state.dataSurface->WorldCoordSystem) {
3617 4 : surfTemp.Azimuth += state.dataHeatBal->BuildingAzimuth;
3618 : }
3619 20 : if (surfTemp.Class == SurfaceClass::Detached_B) {
3620 6 : surfTemp.Azimuth += state.dataHeatBal->BuildingRotationAppendixG;
3621 : }
3622 20 : surfTemp.Tilt = s_ipsc->rNumericArgs(2);
3623 20 : surfTemp.convOrientation = Convect::GetSurfConvOrientation(surfTemp.Tilt);
3624 :
3625 20 : surfTemp.Sides = 4;
3626 20 : surfTemp.Vertex.allocate(surfTemp.Sides);
3627 :
3628 120 : MakeRectangularVertices(state,
3629 : SurfNum,
3630 20 : s_ipsc->rNumericArgs(3),
3631 20 : s_ipsc->rNumericArgs(4),
3632 20 : s_ipsc->rNumericArgs(5),
3633 20 : s_ipsc->rNumericArgs(6),
3634 20 : s_ipsc->rNumericArgs(7),
3635 20 : state.dataSurfaceGeometry->RectSurfRefWorldCoordSystem);
3636 :
3637 20 : if (surfTemp.Area <= 0.0) {
3638 0 : ShowSevereError(
3639 : state,
3640 0 : format("{}=\"{}\", Surface Area <= 0.0; Entered Area={:.2T}", s_ipsc->cCurrentModuleObject, surfTemp.Name, surfTemp.Area));
3641 0 : ErrorsFound = true;
3642 : }
3643 :
3644 20 : if (state.dataReportFlag->MakeMirroredDetachedShading) {
3645 20 : MakeMirrorSurface(state, SurfNum);
3646 : }
3647 : }
3648 :
3649 : } // Item Loop
3650 : }
3651 :
3652 801 : void GetHTSurfaceData(EnergyPlusData &state,
3653 : bool &ErrorsFound, // Error flag indicator (true if errors found)
3654 : int &SurfNum, // Count of Current SurfaceNumber
3655 : int const TotHTSurfs, // Number of Heat Transfer Base Surfaces to obtain
3656 : int const TotDetailedWalls, // Number of Wall:Detailed items to obtain
3657 : int const TotDetailedRoofs, // Number of RoofCeiling:Detailed items to obtain
3658 : int const TotDetailedFloors, // Number of Floor:Detailed items to obtain
3659 : const Array1D_string &BaseSurfCls, // Valid Classes for Base Surfaces
3660 : const Array1D<SurfaceClass> &BaseSurfIDs,
3661 : int &NeedToAddSurfaces // Number of surfaces to add, based on unentered IZ surfaces
3662 : )
3663 : {
3664 :
3665 : // SUBROUTINE INFORMATION:
3666 : // AUTHOR Linda Lawrie
3667 : // DATE WRITTEN May 2000
3668 :
3669 : // PURPOSE OF THIS SUBROUTINE:
3670 : // This subroutine gets the HeatTransfer Surface Data, checks it for errors, etc.
3671 :
3672 : // REFERENCES:
3673 : // Heat Transfer Surface Definition
3674 : // BuildingSurface:Detailed,
3675 : // \extensible:3 -- duplicate last set of x,y,z coordinates (last 3 fields), remembering to remove ; from "inner" fields.
3676 : // \format vertices
3677 : // A1 , \field Name
3678 : // \required-field
3679 : // \type alpha
3680 : // \reference SurfaceNames
3681 : // \reference SurfAndSubSurfNames
3682 : // \reference AllHeatTranSurfNames
3683 : // \reference HeatTranBaseSurfNames
3684 : // \reference OutFaceEnvNames
3685 : // \reference AllHeatTranAngFacNames
3686 : // \reference RadGroupAndSurfNames
3687 : // \reference SurfGroupAndHTSurfNames
3688 : // \reference AllShadingAndHTSurfNames
3689 : // A2 , \field Surface Type
3690 : // \required-field
3691 : // \type choice
3692 : // \key Floor
3693 : // \key Wall
3694 : // \key Ceiling
3695 : // \key Roof
3696 : // A3 , \field Construction Name
3697 : // \required-field
3698 : // \note To be matched with a construction in this input file
3699 : // \type object-list
3700 : // \object-list ConstructionNames
3701 : // A4 , \field Zone Name
3702 : // \required-field
3703 : // \note Zone the surface is a part of
3704 : // \type object-list
3705 : // \object-list ZoneNames
3706 : // A5 , \field Outside Boundary Condition
3707 : // \required-field
3708 : // \type choice
3709 : // \key Adiabatic
3710 : // \key Surface
3711 : // \key Zone
3712 : // \key Outdoors
3713 : // \key Ground
3714 : // \key GroundFCfactorMethod
3715 : // \key OtherSideCoefficients
3716 : // \key OtherSideConditionsModel
3717 : // \key GroundSlabPreprocessorAverage
3718 : // \key GroundSlabPreprocessorCore
3719 : // \key GroundSlabPreprocessorPerimeter
3720 : // \key GroundBasementPreprocessorAverageWall
3721 : // \key GroundBasementPreprocessorAverageFloor
3722 : // \key GroundBasementPreprocessorUpperWall
3723 : // \key GroundBasementPreprocessorLowerWall
3724 : // A6, \field Outside Boundary Condition Object
3725 : // \type object-list
3726 : // \object-list OutFaceEnvNames
3727 : // \note Non-blank only if the field Outside Boundary Condition is Surface,
3728 : // \note Zone, OtherSideCoefficients or OtherSideConditionsModel
3729 : // \note If Surface, specify name of corresponding surface in adjacent zone or
3730 : // \note specify current surface name for internal partition separating like zones
3731 : // \note If Zone, specify the name of the corresponding zone and
3732 : // \note the program will generate the corresponding interzone surface
3733 : // \note If OtherSideCoefficients, specify name of SurfaceProperty:OtherSideCoefficients
3734 : // \note If OtherSideConditionsModel, specify name of SurfaceProperty:OtherSideConditionsModel
3735 : // A7 , \field Sun Exposure
3736 : // \required-field
3737 : // \type choice
3738 : // \key SunExposed
3739 : // \key NoSun
3740 : // \default SunExposed
3741 : // A8, \field Wind Exposure
3742 : // \required-field
3743 : // \type choice
3744 : // \key WindExposed
3745 : // \key NoWind
3746 : // \default WindExposed
3747 : // N1, \field View Factor to Ground
3748 : // \type real
3749 : // \note From the exterior of the surface
3750 : // \note Unused if one uses the "reflections" options in Solar Distribution in Building input
3751 : // \note unless a DaylightingDevice:Shelf or DaylightingDevice:Tubular object has been specified.
3752 : // \note autocalculate will automatically calculate this value from the tilt of the surface
3753 : // \autocalculatable
3754 : // \minimum 0.0
3755 : // \maximum 1.0
3756 : // \default autocalculate
3757 : // N2 , \field Number of Vertices
3758 : // \note shown with 120 vertex coordinates -- extensible object
3759 : // \note "extensible" -- duplicate last set of x,y,z coordinates (last 3 fields),
3760 : // \note remembering to remove ; from "inner" fields.
3761 : // \note for clarity in any error messages, renumber the fields as well.
3762 : // \note (and changing z terminator to a comma "," for all but last one which needs a semi-colon ";")
3763 : // \autocalculatable
3764 : // \minimum 3
3765 : // \default autocalculate
3766 : // \note vertices are given in GlobalGeometryRules coordinates -- if relative, all surface coordinates
3767 : // \note are "relative" to the Zone Origin. If world, then building and zone origins are used
3768 : // \note for some internal calculations, but all coordinates are given in an "absolute" system.
3769 : // N3-xx as indicated by the N3 value
3770 :
3771 : // Using/Aliasing
3772 :
3773 : // SUBROUTINE PARAMETER DEFINITIONS:
3774 801 : static Array1D_string const cModuleObjects(4, {"BuildingSurface:Detailed", "Wall:Detailed", "Floor:Detailed", "RoofCeiling:Detailed"});
3775 :
3776 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
3777 : int IOStat; // IO Status when calling get input subroutine
3778 : int SurfaceNumAlpha; // Number of material alpha names being passed
3779 : int SurfaceNumProp; // Number of material properties being passed
3780 : int ZoneNum; // DO loop counter (zones)
3781 : int Found; // For matching interzone surfaces
3782 : int Loop;
3783 : int ItemsToGet;
3784 : int ClassItem;
3785 : int ArgPointer;
3786 : int numSides;
3787 :
3788 801 : auto &s_ipsc = state.dataIPShortCut;
3789 :
3790 801 : GetOSCData(state, ErrorsFound);
3791 801 : GetOSCMData(state, ErrorsFound);
3792 801 : GetFoundationData(state, ErrorsFound);
3793 :
3794 801 : NeedToAddSurfaces = 0;
3795 4005 : for (int Item = 1; Item <= 4; ++Item) {
3796 :
3797 3204 : s_ipsc->cCurrentModuleObject = cModuleObjects(Item);
3798 3204 : if (Item == 1) {
3799 801 : ItemsToGet = TotHTSurfs;
3800 801 : ClassItem = 0;
3801 2403 : } else if (Item == 2) {
3802 801 : ItemsToGet = TotDetailedWalls;
3803 801 : ClassItem = 1;
3804 1602 : } else if (Item == 3) {
3805 801 : ItemsToGet = TotDetailedFloors;
3806 801 : ClassItem = 2;
3807 : } else { // IF (Item == 4) THEN
3808 801 : ItemsToGet = TotDetailedRoofs;
3809 801 : ClassItem = 3;
3810 : }
3811 :
3812 6408 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(
3813 3204 : state, s_ipsc->cCurrentModuleObject, Loop, SurfaceNumAlpha, SurfaceNumProp);
3814 3204 : if (Item == 1) {
3815 801 : if (SurfaceNumAlpha != 9) {
3816 0 : ShowSevereError(state,
3817 0 : format("{}: Object Definition indicates not = 9 Alpha Objects, Number Indicated={}",
3818 0 : s_ipsc->cCurrentModuleObject,
3819 : SurfaceNumAlpha));
3820 0 : ErrorsFound = true;
3821 : }
3822 : } else {
3823 2403 : if (SurfaceNumAlpha != 8) {
3824 0 : ShowSevereError(state,
3825 0 : format("{}: Object Definition indicates not = 8 Alpha Objects, Number Indicated={}",
3826 0 : s_ipsc->cCurrentModuleObject,
3827 : SurfaceNumAlpha));
3828 0 : ErrorsFound = true;
3829 : }
3830 : }
3831 :
3832 38940 : for (Loop = 1; Loop <= ItemsToGet; ++Loop) {
3833 71472 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
3834 35736 : s_ipsc->cCurrentModuleObject,
3835 : Loop,
3836 35736 : s_ipsc->cAlphaArgs,
3837 : SurfaceNumAlpha,
3838 35736 : s_ipsc->rNumericArgs,
3839 : SurfaceNumProp,
3840 : IOStat,
3841 35736 : s_ipsc->lNumericFieldBlanks,
3842 35736 : s_ipsc->lAlphaFieldBlanks,
3843 35736 : s_ipsc->cAlphaFieldNames,
3844 35736 : s_ipsc->cNumericFieldNames);
3845 :
3846 71472 : if (GlobalNames::VerifyUniqueInterObjectName(state,
3847 35736 : state.dataSurfaceGeometry->UniqueSurfaceNames,
3848 35736 : s_ipsc->cAlphaArgs(1),
3849 35736 : s_ipsc->cCurrentModuleObject,
3850 35736 : s_ipsc->cAlphaFieldNames(1),
3851 : ErrorsFound)) {
3852 0 : continue;
3853 : }
3854 :
3855 35736 : ++SurfNum;
3856 :
3857 35736 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
3858 35736 : surfTemp.Name = s_ipsc->cAlphaArgs(1); // Set the Surface Name in the Derived Type
3859 35736 : ArgPointer = 2;
3860 35736 : if (Item == 1) {
3861 35712 : if (s_ipsc->cAlphaArgs(2) == "CEILING") {
3862 3634 : s_ipsc->cAlphaArgs(2) = "ROOF";
3863 : }
3864 35712 : ClassItem = Util::FindItemInList(s_ipsc->cAlphaArgs(2), BaseSurfCls, 3);
3865 35712 : if (ClassItem == 0) {
3866 0 : ShowSevereError(state,
3867 0 : format("{}=\"{}\", invalid {}=\"{}",
3868 0 : s_ipsc->cCurrentModuleObject,
3869 0 : surfTemp.Name,
3870 0 : s_ipsc->cAlphaFieldNames(2),
3871 0 : s_ipsc->cAlphaArgs(2)));
3872 0 : ErrorsFound = true;
3873 : } else {
3874 35712 : surfTemp.Class = BaseSurfIDs(ClassItem);
3875 : }
3876 35712 : ++ArgPointer;
3877 : } else {
3878 24 : surfTemp.Class = BaseSurfIDs(ClassItem);
3879 : }
3880 :
3881 35736 : surfTemp.Construction =
3882 35736 : Util::FindItemInList(s_ipsc->cAlphaArgs(ArgPointer), state.dataConstruction->Construct, state.dataHeatBal->TotConstructs);
3883 :
3884 35736 : if (surfTemp.Construction == 0) {
3885 0 : ErrorsFound = true;
3886 0 : ShowSevereError(state,
3887 0 : format("{}=\"{}\", invalid {}=\"{}\".",
3888 0 : s_ipsc->cCurrentModuleObject,
3889 0 : surfTemp.Name,
3890 0 : s_ipsc->cAlphaFieldNames(ArgPointer),
3891 0 : s_ipsc->cAlphaArgs(ArgPointer)));
3892 35736 : } else if (state.dataConstruction->Construct(surfTemp.Construction).TypeIsWindow) {
3893 0 : ErrorsFound = true;
3894 0 : ShowSevereError(state,
3895 0 : format("{}=\"{}\", invalid {}=\"{}\" - has Window materials.",
3896 0 : s_ipsc->cCurrentModuleObject,
3897 0 : surfTemp.Name,
3898 0 : s_ipsc->cAlphaFieldNames(ArgPointer),
3899 0 : s_ipsc->cAlphaArgs(ArgPointer)));
3900 0 : if (Item == 1) {
3901 0 : ShowContinueError(state, format("...because {}={}", s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2)));
3902 : } else {
3903 0 : ShowContinueError(state, format("...because Surface Type={}", BaseSurfCls(ClassItem)));
3904 : }
3905 : } else {
3906 35736 : state.dataConstruction->Construct(surfTemp.Construction).IsUsed = true;
3907 35736 : surfTemp.ConstructionStoredInputValue = surfTemp.Construction;
3908 : }
3909 35736 : surfTemp.HeatTransSurf = true;
3910 35736 : surfTemp.BaseSurf = SurfNum;
3911 35736 : surfTemp.BaseSurfName = surfTemp.Name;
3912 :
3913 35736 : ++ArgPointer;
3914 35736 : surfTemp.ZoneName = s_ipsc->cAlphaArgs(ArgPointer);
3915 35736 : ZoneNum = Util::FindItemInList(surfTemp.ZoneName, state.dataHeatBal->Zone, state.dataGlobal->NumOfZones);
3916 :
3917 35736 : if (ZoneNum != 0) {
3918 35736 : surfTemp.Zone = ZoneNum;
3919 : } else {
3920 0 : ShowSevereError(state,
3921 0 : format("{}=\"{}\", invalid {}=\"{}\".",
3922 0 : s_ipsc->cCurrentModuleObject,
3923 0 : surfTemp.Name,
3924 0 : s_ipsc->cAlphaFieldNames(ArgPointer),
3925 0 : s_ipsc->cAlphaArgs(ArgPointer)));
3926 0 : surfTemp.Class = SurfaceClass::Invalid;
3927 0 : surfTemp.ZoneName = "Unknown Zone";
3928 0 : ErrorsFound = true;
3929 : }
3930 :
3931 35736 : ++ArgPointer;
3932 35736 : if (!s_ipsc->lAlphaFieldBlanks(ArgPointer)) {
3933 107 : int spaceNum = Util::FindItemInList(s_ipsc->cAlphaArgs(ArgPointer), state.dataHeatBal->space);
3934 :
3935 107 : if (spaceNum != 0) {
3936 107 : surfTemp.spaceNum = spaceNum;
3937 107 : if (surfTemp.Zone != state.dataHeatBal->space(spaceNum).zoneNum) {
3938 0 : ShowSevereError(state,
3939 0 : format("{}=\"{}\", invalid {}=\"{}\" is not in the same zone as the surface.",
3940 0 : s_ipsc->cCurrentModuleObject,
3941 0 : surfTemp.Name,
3942 0 : s_ipsc->cAlphaFieldNames(ArgPointer),
3943 0 : s_ipsc->cAlphaArgs(ArgPointer)));
3944 0 : surfTemp.Class = SurfaceClass::Invalid;
3945 0 : ErrorsFound = true;
3946 : }
3947 : } else {
3948 0 : ShowSevereError(state,
3949 0 : format("{}=\"{}\", invalid {}=\"{}\" not found.",
3950 0 : s_ipsc->cCurrentModuleObject,
3951 0 : surfTemp.Name,
3952 0 : s_ipsc->cAlphaFieldNames(ArgPointer),
3953 0 : s_ipsc->cAlphaArgs(ArgPointer)));
3954 0 : surfTemp.Class = SurfaceClass::Invalid;
3955 0 : ErrorsFound = true;
3956 : }
3957 : }
3958 : // Get the ExteriorBoundaryCondition flag from input There are 4 conditions that
3959 : // can take place. The conditions are set with a 0, -1, or -2, or all of the
3960 : // zone names have to be looked at and generate the interzone array number
3961 35736 : ++ArgPointer;
3962 35736 : surfTemp.ExtBoundCondName = s_ipsc->cAlphaArgs(ArgPointer + 1);
3963 :
3964 35736 : if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "Outdoors")) {
3965 11358 : surfTemp.ExtBoundCond = DataSurfaces::ExternalEnvironment;
3966 24378 : } else if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "Adiabatic")) {
3967 1860 : surfTemp.ExtBoundCond = unreconciledZoneSurface;
3968 1860 : surfTemp.ExtBoundCondName = surfTemp.Name;
3969 :
3970 22518 : } else if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "Ground")) {
3971 2239 : surfTemp.ExtBoundCond = DataSurfaces::Ground;
3972 2239 : if (state.dataSurfaceGeometry->NoGroundTempObjWarning) {
3973 439 : if (!state.dataEnvrn->GroundTempInputs[(int)DataEnvironment::GroundTempType::BuildingSurface]) {
3974 4 : ShowWarningError(state,
3975 : "GetHTSurfaceData: Surfaces with interface to Ground found but no \"Ground Temperatures\" were input.");
3976 2 : ShowContinueError(state, format("Found first in surface={}", s_ipsc->cAlphaArgs(1)));
3977 4 : ShowContinueError(state,
3978 4 : format("Defaults, constant throughout the year of ({:.1R}) will be used.",
3979 2 : state.dataEnvrn->GroundTemp[(int)DataEnvironment::GroundTempType::BuildingSurface]));
3980 : }
3981 439 : state.dataSurfaceGeometry->NoGroundTempObjWarning = false;
3982 : }
3983 :
3984 : // Added for FCfactor method
3985 20279 : } else if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "GroundFCfactorMethod")) {
3986 184 : surfTemp.ExtBoundCond = DataSurfaces::GroundFCfactorMethod;
3987 184 : if (state.dataSurfaceGeometry->NoFCGroundTempObjWarning) {
3988 184 : if (!state.dataEnvrn->GroundTempInputs[(int)DataEnvironment::GroundTempType::FCFactorMethod]) {
3989 0 : ShowSevereError(state,
3990 : "GetHTSurfaceData: Surfaces with interface to GroundFCfactorMethod found but no \"FC Ground "
3991 : "Temperatures\" were input.");
3992 0 : ShowContinueError(state, format("Found first in surface={}", s_ipsc->cAlphaArgs(1)));
3993 0 : ShowContinueError(state,
3994 : "Either add a \"Site:GroundTemperature:FCfactorMethod\" object or use a weather file with "
3995 : "Ground Temperatures.");
3996 0 : ErrorsFound = true;
3997 0 : state.dataSurfaceGeometry->NoFCGroundTempObjWarning = false;
3998 : }
3999 : }
4000 184 : if (surfTemp.Construction > 0) {
4001 184 : if (surfTemp.Class == SurfaceClass::Wall && !state.dataConstruction->Construct(surfTemp.Construction).TypeIsCfactorWall) {
4002 0 : ShowSevereError(
4003 : state,
4004 0 : format("{}=\"{}\", invalid {}", s_ipsc->cCurrentModuleObject, surfTemp.Name, s_ipsc->cAlphaFieldNames(ArgPointer)));
4005 0 : ShowContinueError(state,
4006 0 : format("Construction=\"{}\" is not type Construction:CfactorUndergroundWall.",
4007 0 : state.dataConstruction->Construct(surfTemp.Construction).Name));
4008 0 : ErrorsFound = true;
4009 : }
4010 184 : if (surfTemp.Class == SurfaceClass::Floor && !state.dataConstruction->Construct(surfTemp.Construction).TypeIsFfactorFloor) {
4011 0 : ShowSevereError(
4012 : state,
4013 0 : format("{}=\"{}\", invalid {}", s_ipsc->cCurrentModuleObject, surfTemp.Name, s_ipsc->cAlphaFieldNames(ArgPointer)));
4014 0 : ShowContinueError(state,
4015 0 : format("Construction=\"{}\" is not type Construction:FfactorGroundFloor.",
4016 0 : state.dataConstruction->Construct(surfTemp.Construction).Name));
4017 0 : ErrorsFound = true;
4018 : }
4019 : }
4020 :
4021 20095 : } else if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "OtherSideCoefficients")) {
4022 17 : Found = Util::FindItemInList(surfTemp.ExtBoundCondName, state.dataSurface->OSC, state.dataSurface->TotOSC);
4023 17 : if (Found == 0) {
4024 0 : ShowSevereError(state,
4025 0 : format("{}=\"{}\", invalid {}=\"{}\".",
4026 0 : s_ipsc->cCurrentModuleObject,
4027 0 : surfTemp.Name,
4028 0 : s_ipsc->cAlphaFieldNames(ArgPointer + 1),
4029 0 : s_ipsc->cAlphaArgs(ArgPointer + 1)));
4030 0 : ShowContinueError(state, " no OtherSideCoefficients of that name.");
4031 0 : ErrorsFound = true;
4032 : } else {
4033 17 : surfTemp.OSCPtr = Found;
4034 17 : if (state.dataSurface->OSC(Found).SurfFilmCoef > 0.0) {
4035 1 : surfTemp.ExtBoundCond = DataSurfaces::OtherSideCoefCalcExt;
4036 : } else {
4037 16 : surfTemp.ExtBoundCond = DataSurfaces::OtherSideCoefNoCalcExt;
4038 : }
4039 : }
4040 :
4041 20078 : } else if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "Surface")) {
4042 : // it has to be another surface which needs to be found
4043 : // this will be found on the second pass through the surface input
4044 : // for flagging, set the value to UnreconciledZoneSurface
4045 : // name (ExtBoundCondName) will be validated later.
4046 19618 : surfTemp.ExtBoundCond = unreconciledZoneSurface;
4047 19618 : if (s_ipsc->lAlphaFieldBlanks(ArgPointer + 1)) {
4048 6 : surfTemp.ExtBoundCondName = surfTemp.Name;
4049 12 : ShowSevereError(state,
4050 18 : format("{}=\"{}\", invalid {}=<blank>.",
4051 6 : s_ipsc->cCurrentModuleObject,
4052 6 : surfTemp.Name,
4053 6 : s_ipsc->cAlphaFieldNames(ArgPointer + 1)));
4054 6 : ShowContinueError(state, format("..{}=\"Surface\" must be non-blank.", s_ipsc->cAlphaFieldNames(ArgPointer)));
4055 18 : ShowContinueError(state, "..This surface will become an adiabatic surface - no doors/windows allowed.");
4056 : }
4057 :
4058 460 : } else if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "Zone")) {
4059 : // This is the code for an unmatched "other surface"
4060 : // will be set up later.
4061 365 : surfTemp.ExtBoundCond = unenteredAdjacentZoneSurface;
4062 : // check OutsideFaceEnvironment for legal zone
4063 365 : Found = Util::FindItemInList(surfTemp.ExtBoundCondName, state.dataHeatBal->Zone, state.dataGlobal->NumOfZones);
4064 365 : ++NeedToAddSurfaces;
4065 :
4066 365 : if (Found == 0) {
4067 0 : ShowSevereError(state,
4068 0 : format("{}=\"{}\", invalid {}=\"{}\".",
4069 0 : s_ipsc->cCurrentModuleObject,
4070 0 : surfTemp.Name,
4071 0 : s_ipsc->cAlphaFieldNames(ArgPointer),
4072 0 : s_ipsc->cAlphaArgs(ArgPointer)));
4073 0 : ShowContinueError(state, "..Referenced as Zone for this surface.");
4074 0 : ErrorsFound = true;
4075 : }
4076 :
4077 95 : } else if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "Space")) {
4078 : // This is the code for an unmatched "other surface"
4079 : // will be set up later.
4080 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond = unenteredAdjacentSpaceSurface;
4081 : // check OutsideFaceEnvironment for legal zone
4082 0 : Found = Util::FindItemInList(
4083 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCondName, state.dataHeatBal->space, state.dataGlobal->numSpaces);
4084 0 : ++NeedToAddSurfaces;
4085 :
4086 0 : if (Found == 0) {
4087 0 : ShowSevereError(state,
4088 0 : format("{}=\"{}\", invalid {}=\"{}\".",
4089 0 : s_ipsc->cCurrentModuleObject,
4090 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
4091 0 : s_ipsc->cAlphaFieldNames(ArgPointer),
4092 0 : s_ipsc->cAlphaArgs(ArgPointer)));
4093 0 : ShowContinueError(state, "..Referenced as Space for this surface.");
4094 0 : ErrorsFound = true;
4095 : }
4096 :
4097 95 : } else if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "Foundation")) {
4098 :
4099 40 : if (!state.dataWeather->WeatherFileExists) {
4100 0 : ShowSevereError(
4101 : state,
4102 0 : format("{}=\"{}\", using \"Foundation\" type Outside Boundary Condition requires specification of a weather file",
4103 0 : s_ipsc->cCurrentModuleObject,
4104 0 : surfTemp.Name));
4105 0 : ShowContinueError(state,
4106 : "Either place in.epw in the working directory or specify a weather file on the command line using -w "
4107 : "/path/to/weather.epw");
4108 0 : ErrorsFound = true;
4109 : }
4110 :
4111 : // Find foundation object, if blank use default
4112 40 : if (s_ipsc->lAlphaFieldBlanks(ArgPointer + 1)) {
4113 :
4114 8 : if (!state.dataSurfaceGeometry->kivaManager.defaultAdded) {
4115 : // Add default foundation if no other foundation object specified
4116 2 : state.dataSurfaceGeometry->kivaManager.addDefaultFoundation();
4117 : }
4118 8 : surfTemp.OSCPtr =
4119 8 : state.dataSurfaceGeometry->kivaManager.defaultIndex; // Reuse OSC pointer...shouldn't be used for non OSC surfaces anyway.
4120 : } else {
4121 32 : Found = state.dataSurfaceGeometry->kivaManager.findFoundation(surfTemp.ExtBoundCondName);
4122 32 : if (Found != (int)state.dataSurfaceGeometry->kivaManager.foundationInputs.size()) {
4123 32 : surfTemp.OSCPtr = Found;
4124 : } else {
4125 0 : ShowSevereError(state,
4126 0 : format("{}=\"{}\", invalid {}=\"{}\".",
4127 0 : s_ipsc->cCurrentModuleObject,
4128 0 : surfTemp.Name,
4129 0 : s_ipsc->cAlphaFieldNames(ArgPointer + 1),
4130 0 : s_ipsc->cAlphaArgs(ArgPointer + 1)));
4131 0 : ErrorsFound = true;
4132 : }
4133 : }
4134 :
4135 40 : if (state.dataConstruction->Construct(surfTemp.Construction).SourceSinkPresent) {
4136 0 : ShowSevereError(
4137 : state,
4138 0 : format("{}=\"{}\", construction may not have an internal source/sink", s_ipsc->cCurrentModuleObject, surfTemp.Name));
4139 0 : ErrorsFound = true;
4140 : }
4141 40 : surfTemp.ExtBoundCond = DataSurfaces::KivaFoundation;
4142 55 : } else if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "OtherSideConditionsModel")) {
4143 55 : Found = Util::FindItemInList(surfTemp.ExtBoundCondName, state.dataSurface->OSCM, state.dataSurface->TotOSCM);
4144 55 : if (Found == 0) {
4145 0 : ShowSevereError(state,
4146 0 : format("{}=\"{}\", invalid {}=\"{}\".",
4147 0 : s_ipsc->cCurrentModuleObject,
4148 0 : surfTemp.Name,
4149 0 : s_ipsc->cAlphaFieldNames(ArgPointer + 1),
4150 0 : s_ipsc->cAlphaArgs(ArgPointer + 1)));
4151 0 : ErrorsFound = true;
4152 : }
4153 55 : surfTemp.OSCMPtr = Found;
4154 55 : surfTemp.ExtBoundCond = DataSurfaces::OtherSideCondModeledExt;
4155 :
4156 0 : } else if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "GroundSlabPreprocessorAverage") ||
4157 0 : Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "GroundSlabPreprocessorCore") ||
4158 0 : Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "GroundSlabPreprocessorPerimeter") ||
4159 0 : Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "GroundBasementPreprocessorAverageFloor") ||
4160 0 : Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "GroundBasementPreprocessorAverageWall") ||
4161 0 : Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "GroundBasementPreprocessorUpperWall") ||
4162 0 : Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "GroundBasementPreprocessorLowerWall")) {
4163 0 : ShowSevereError(state,
4164 0 : format("{}=\"{}\", invalid {}=\"{}\".",
4165 0 : s_ipsc->cCurrentModuleObject,
4166 0 : surfTemp.Name,
4167 0 : s_ipsc->cAlphaFieldNames(ArgPointer),
4168 0 : s_ipsc->cAlphaArgs(ArgPointer)));
4169 0 : ShowContinueError(state, "The ExpandObjects program has not been run or is not in your EnergyPlus.exe folder.");
4170 0 : ErrorsFound = true;
4171 :
4172 : } else {
4173 0 : ShowSevereError(state,
4174 0 : format("{}=\"{}\", invalid {}=\"{}\".",
4175 0 : s_ipsc->cCurrentModuleObject,
4176 0 : surfTemp.Name,
4177 0 : s_ipsc->cAlphaFieldNames(ArgPointer),
4178 0 : s_ipsc->cAlphaArgs(ArgPointer)));
4179 0 : ShowContinueError(state,
4180 : "Should be one of \"Outdoors\", \"Adiabatic\", Ground\", \"Surface\", \"OtherSideCoefficients\", "
4181 : "\"OtherSideConditionsModel\" or \"Zone\"");
4182 0 : ErrorsFound = true;
4183 : } // ... End of the ExtBoundCond logical IF Block
4184 :
4185 35736 : ArgPointer += 2;
4186 : // Set the logical flag for the exterior solar
4187 35736 : if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "SunExposed")) {
4188 11263 : if ((surfTemp.ExtBoundCond != DataSurfaces::ExternalEnvironment) &&
4189 29 : (surfTemp.ExtBoundCond != DataSurfaces::OtherSideCondModeledExt)) {
4190 0 : ShowWarningError(state,
4191 0 : format("{}=\"{}\", {}=\"{}\".",
4192 0 : s_ipsc->cCurrentModuleObject,
4193 0 : surfTemp.Name,
4194 0 : s_ipsc->cAlphaFieldNames(ArgPointer),
4195 0 : s_ipsc->cAlphaArgs(ArgPointer)));
4196 0 : ShowContinueError(state, "..This surface is not exposed to External Environment. Sun exposure has no effect.");
4197 : } else {
4198 11263 : surfTemp.ExtSolar = true;
4199 : }
4200 24473 : } else if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "NoSun")) {
4201 24473 : surfTemp.ExtSolar = false;
4202 : } else {
4203 0 : ShowSevereError(state,
4204 0 : format("{}=\"{}\", invalid {}=\"{}\".",
4205 0 : s_ipsc->cCurrentModuleObject,
4206 0 : surfTemp.Name,
4207 0 : s_ipsc->cAlphaFieldNames(ArgPointer),
4208 0 : s_ipsc->cAlphaArgs(ArgPointer)));
4209 0 : ErrorsFound = true;
4210 : }
4211 :
4212 35736 : ++ArgPointer;
4213 : // Set the logical flag for the exterior wind
4214 35736 : if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "WindExposed")) {
4215 11331 : surfTemp.ExtWind = true;
4216 24405 : } else if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "NoWind")) {
4217 24405 : surfTemp.ExtWind = false;
4218 : } else {
4219 0 : ShowSevereError(state,
4220 0 : format("{}=\"{}\", invalid {}=\"{}\".",
4221 0 : s_ipsc->cCurrentModuleObject,
4222 0 : surfTemp.Name,
4223 0 : s_ipsc->cAlphaFieldNames(ArgPointer),
4224 0 : s_ipsc->cAlphaArgs(ArgPointer)));
4225 0 : ErrorsFound = true;
4226 : }
4227 :
4228 : // Set the logical flag for the EcoRoof presented, this is only based on the flag in the construction type
4229 : // if (surfTemp.Construction > 0)
4230 : // surfTemp.ExtEcoRoof =
4231 : // state.dataConstruction->Construct(surfTemp.Construction).TypeIsEcoRoof;
4232 :
4233 35736 : surfTemp.ViewFactorGround = s_ipsc->rNumericArgs(1);
4234 35736 : if (s_ipsc->lNumericFieldBlanks(1)) {
4235 685 : surfTemp.ViewFactorGround = Constant::AutoCalculate;
4236 : }
4237 35736 : if (s_ipsc->lNumericFieldBlanks(2) || s_ipsc->rNumericArgs(2) == Constant::AutoCalculate) {
4238 794 : numSides = (SurfaceNumProp - 2) / 3;
4239 794 : surfTemp.Sides = numSides;
4240 794 : if (mod(SurfaceNumProp - 2, 3) != 0) {
4241 0 : ShowWarningError(state,
4242 0 : format("{}=\"{}\", {}",
4243 0 : s_ipsc->cCurrentModuleObject,
4244 0 : surfTemp.Name,
4245 0 : format("{} not even multiple of 3. Will read in {}", s_ipsc->cNumericFieldNames(2), surfTemp.Sides)));
4246 : }
4247 794 : if (numSides < 3) {
4248 0 : ShowSevereError(state,
4249 0 : format("{}=\"{}\", {} (autocalculate) must be >= 3. Only {} provided.",
4250 0 : s_ipsc->cCurrentModuleObject,
4251 0 : surfTemp.Name,
4252 0 : s_ipsc->cNumericFieldNames(2),
4253 0 : surfTemp.Sides));
4254 0 : ErrorsFound = true;
4255 0 : continue;
4256 : }
4257 : } else {
4258 34942 : numSides = (SurfaceNumProp - 2) / 3;
4259 34942 : surfTemp.Sides = s_ipsc->rNumericArgs(2);
4260 34942 : if (numSides > surfTemp.Sides) {
4261 0 : ShowWarningError(state,
4262 0 : format("{}=\"{}\", field {}={}",
4263 0 : s_ipsc->cCurrentModuleObject,
4264 0 : surfTemp.Name,
4265 0 : s_ipsc->cNumericFieldNames(2),
4266 0 : fmt::to_string(surfTemp.Sides)));
4267 0 : ShowContinueError(
4268 0 : state, format("...but {} were entered. Only the indicated {} will be used.", numSides, s_ipsc->cNumericFieldNames(2)));
4269 : }
4270 : }
4271 35736 : surfTemp.Vertex.allocate(surfTemp.Sides);
4272 35736 : surfTemp.NewVertex.allocate(surfTemp.Sides);
4273 142944 : GetVertices(state, SurfNum, surfTemp.Sides, s_ipsc->rNumericArgs({3, _}));
4274 35736 : if (surfTemp.Area <= 0.0) {
4275 0 : ShowSevereError(
4276 : state,
4277 0 : format("{}=\"{}\", Surface Area <= 0.0; Entered Area={:.2T}", s_ipsc->cCurrentModuleObject, surfTemp.Name, surfTemp.Area));
4278 0 : ErrorsFound = true;
4279 : }
4280 :
4281 35736 : CheckConvexity(state, SurfNum, surfTemp.Sides);
4282 35736 : if (Util::SameString(s_ipsc->cAlphaArgs(5), "Surface")) {
4283 8 : if (surfTemp.Sides != static_cast<int>(surfTemp.Vertex.size())) {
4284 0 : ShowSevereError(state,
4285 0 : format("{}=\"{}\", After CheckConvexity, mismatch between Sides ({}) and size of Vertex ({}).",
4286 0 : s_ipsc->cCurrentModuleObject,
4287 0 : surfTemp.Name,
4288 0 : surfTemp.Sides,
4289 0 : surfTemp.Vertex.size()));
4290 0 : ShowContinueError(state, "CheckConvexity is used to verify the convexity of a surface and detect collinear points.");
4291 0 : ErrorsFound = true;
4292 : }
4293 : }
4294 35736 : if (surfTemp.Construction > 0) {
4295 : // Check wall height for the CFactor walls
4296 :
4297 35736 : if (surfTemp.Class == SurfaceClass::Wall && state.dataConstruction->Construct(surfTemp.Construction).TypeIsCfactorWall) {
4298 34 : if (std::abs(surfTemp.Height - state.dataConstruction->Construct(surfTemp.Construction).Height) > 0.05) {
4299 0 : ShowWarningError(
4300 : state,
4301 0 : format("{}=\"{}\", underground Wall Height = {:.2T}", s_ipsc->cCurrentModuleObject, surfTemp.Name, surfTemp.Height));
4302 0 : ShowContinueError(state, "..which does not match its construction height.");
4303 : }
4304 : }
4305 :
4306 : // Check area and perimeter for the FFactor floors
4307 35736 : if (surfTemp.Class == SurfaceClass::Floor && state.dataConstruction->Construct(surfTemp.Construction).TypeIsFfactorFloor) {
4308 184 : if (std::abs(surfTemp.Area - state.dataConstruction->Construct(surfTemp.Construction).Area) > 0.1) {
4309 0 : ShowWarningError(
4310 : state,
4311 0 : format("{}=\"{}\", underground Floor Area = {:.2T}", s_ipsc->cCurrentModuleObject, surfTemp.Name, surfTemp.Area));
4312 0 : ShowContinueError(state, "..which does not match its construction area.");
4313 : }
4314 184 : if (surfTemp.Perimeter < state.dataConstruction->Construct(surfTemp.Construction).PerimeterExposed - 0.1) {
4315 0 : ShowWarningError(state,
4316 0 : format("{}=\"{}\", underground Floor Perimeter = {:.2T}",
4317 0 : s_ipsc->cCurrentModuleObject,
4318 0 : surfTemp.Name,
4319 0 : surfTemp.Perimeter));
4320 0 : ShowContinueError(state, "..which is less than its construction exposed perimeter.");
4321 : }
4322 : }
4323 : }
4324 : // Not sure if it's better to add this or guard in SolarShading.cc
4325 : // surfTemp.shadowSurfSched = nullptr
4326 : }
4327 : } // Item Looop
4328 : // Check number of Vertex between base surface and Outside Boundary surface
4329 : int ExtSurfNum;
4330 36689 : for (int i = 1; i <= SurfNum; i++) {
4331 57366 : if (state.dataSurfaceGeometry->SurfaceTmp(i).ExtBoundCond == unreconciledZoneSurface &&
4332 21478 : state.dataSurfaceGeometry->SurfaceTmp(i).ExtBoundCondName != "") {
4333 21478 : ExtSurfNum = Util::FindItemInList(state.dataSurfaceGeometry->SurfaceTmp(i).ExtBoundCondName, state.dataSurfaceGeometry->SurfaceTmp);
4334 : // If we cannot find the referenced surface
4335 21478 : if (ExtSurfNum == 0) {
4336 0 : ShowSevereError(state,
4337 0 : format("{}=\"{}\" references an outside boundary surface that cannot be found:{}",
4338 0 : s_ipsc->cCurrentModuleObject,
4339 0 : state.dataSurfaceGeometry->SurfaceTmp(i).Name,
4340 0 : state.dataSurfaceGeometry->SurfaceTmp(i).ExtBoundCondName));
4341 0 : ErrorsFound = true;
4342 : // If vertex size mismatch
4343 42956 : } else if (state.dataSurfaceGeometry->SurfaceTmp(i).Vertex.size() !=
4344 21478 : state.dataSurfaceGeometry->SurfaceTmp(ExtSurfNum).Vertex.size()) {
4345 0 : ShowSevereError(state,
4346 0 : format("{}=\"{}\", Vertex size mismatch between base surface :{} and outside boundary surface: {}",
4347 0 : s_ipsc->cCurrentModuleObject,
4348 0 : state.dataSurfaceGeometry->SurfaceTmp(i).Name,
4349 0 : state.dataSurfaceGeometry->SurfaceTmp(i).Name,
4350 0 : state.dataSurfaceGeometry->SurfaceTmp(ExtSurfNum).Name));
4351 0 : ShowContinueError(state,
4352 0 : format("The vertex sizes are {} for base surface and {} for outside boundary surface. Please check inputs.",
4353 0 : state.dataSurfaceGeometry->SurfaceTmp(i).Vertex.size(),
4354 0 : state.dataSurfaceGeometry->SurfaceTmp(ExtSurfNum).Vertex.size()));
4355 0 : ErrorsFound = true;
4356 : }
4357 : }
4358 : }
4359 36537 : }
4360 :
4361 801 : void GetRectSurfaces(EnergyPlusData &state,
4362 : bool &ErrorsFound, // Error flag indicator (true if errors found)
4363 : int &SurfNum, // Count of Current SurfaceNumber
4364 : int const TotRectExtWalls, // Number of Exterior Walls to obtain
4365 : int const TotRectIntWalls, // Number of Adiabatic Walls to obtain
4366 : int const TotRectIZWalls, // Number of Interzone Walls to obtain
4367 : int const TotRectUGWalls, // Number of Underground to obtain
4368 : int const TotRectRoofs, // Number of Roofs to obtain
4369 : int const TotRectCeilings, // Number of Adiabatic Ceilings to obtain
4370 : int const TotRectIZCeilings, // Number of Interzone Ceilings to obtain
4371 : int const TotRectGCFloors, // Number of Floors with Ground Contact to obtain
4372 : int const TotRectIntFloors, // Number of Adiabatic Walls to obtain
4373 : int const TotRectIZFloors, // Number of Interzone Floors to obtain
4374 : const Array1D<SurfaceClass> &BaseSurfIDs, // ID Assignments for valid surface classes
4375 : int &NeedToAddSurfaces // Number of surfaces to add, based on unentered IZ surfaces
4376 : )
4377 : {
4378 :
4379 : // SUBROUTINE INFORMATION:
4380 : // AUTHOR Linda Lawrie
4381 : // DATE WRITTEN December 2008
4382 :
4383 : // PURPOSE OF THIS SUBROUTINE:
4384 : // Get simple (rectangular, LLC corner specified) walls
4385 :
4386 : // SUBROUTINE PARAMETER DEFINITIONS:
4387 : static Array1D_string const cModuleObjects(10,
4388 : {"Wall:Exterior",
4389 : "Wall:Adiabatic",
4390 : "Wall:Interzone",
4391 : "Wall:Underground",
4392 : "Roof",
4393 : "Ceiling:Adiabatic",
4394 : "Ceiling:Interzone",
4395 : "Floor:GroundContact",
4396 : "Floor:Adiabatic",
4397 801 : "Floor:Interzone"});
4398 :
4399 : int ItemsToGet;
4400 : int NumAlphas;
4401 : int NumNumbers;
4402 : int IOStat; // IO Status when calling get input subroutine
4403 : int Found; // For matching base surfaces
4404 : bool GettingIZSurfaces;
4405 : int OtherSurfaceField;
4406 : int ExtBoundCondition;
4407 : int ClassItem;
4408 : int ZoneNum;
4409 :
4410 801 : auto &s_ipsc = state.dataIPShortCut;
4411 :
4412 8811 : for (int Item = 1; Item <= 10; ++Item) {
4413 :
4414 8010 : s_ipsc->cCurrentModuleObject = cModuleObjects(Item);
4415 8010 : if (Item == 1) {
4416 801 : ItemsToGet = TotRectExtWalls;
4417 801 : GettingIZSurfaces = false;
4418 801 : OtherSurfaceField = 0;
4419 801 : ExtBoundCondition = DataSurfaces::ExternalEnvironment;
4420 801 : ClassItem = 1;
4421 7209 : } else if (Item == 2) {
4422 801 : ItemsToGet = TotRectIntWalls;
4423 801 : GettingIZSurfaces = false;
4424 801 : OtherSurfaceField = 0;
4425 801 : ExtBoundCondition = unreconciledZoneSurface;
4426 801 : ClassItem = 1;
4427 6408 : } else if (Item == 3) {
4428 801 : ItemsToGet = TotRectIZWalls;
4429 801 : GettingIZSurfaces = true;
4430 801 : OtherSurfaceField = 5;
4431 801 : ExtBoundCondition = unreconciledZoneSurface;
4432 801 : ClassItem = 1;
4433 5607 : } else if (Item == 4) {
4434 801 : ItemsToGet = TotRectUGWalls;
4435 801 : GettingIZSurfaces = false;
4436 801 : OtherSurfaceField = 0;
4437 801 : ExtBoundCondition = DataSurfaces::Ground;
4438 801 : ClassItem = 1;
4439 4806 : } else if (Item == 5) {
4440 801 : ItemsToGet = TotRectRoofs;
4441 801 : GettingIZSurfaces = false;
4442 801 : OtherSurfaceField = 0;
4443 801 : ExtBoundCondition = DataSurfaces::ExternalEnvironment;
4444 801 : ClassItem = 3;
4445 4005 : } else if (Item == 6) {
4446 801 : ItemsToGet = TotRectCeilings;
4447 801 : GettingIZSurfaces = false;
4448 801 : OtherSurfaceField = 0;
4449 801 : ExtBoundCondition = unreconciledZoneSurface;
4450 801 : ClassItem = 3;
4451 3204 : } else if (Item == 7) {
4452 801 : ItemsToGet = TotRectIZCeilings;
4453 801 : GettingIZSurfaces = false;
4454 801 : OtherSurfaceField = 5;
4455 801 : ExtBoundCondition = unreconciledZoneSurface;
4456 801 : ClassItem = 3;
4457 2403 : } else if (Item == 8) {
4458 801 : ItemsToGet = TotRectGCFloors;
4459 801 : GettingIZSurfaces = false;
4460 801 : OtherSurfaceField = 0;
4461 801 : ExtBoundCondition = DataSurfaces::Ground;
4462 801 : ClassItem = 2;
4463 1602 : } else if (Item == 9) {
4464 801 : ItemsToGet = TotRectIntFloors;
4465 801 : GettingIZSurfaces = false;
4466 801 : OtherSurfaceField = 0;
4467 801 : ExtBoundCondition = unreconciledZoneSurface;
4468 801 : ClassItem = 2;
4469 : } else { // IF (Item == 10) THEN
4470 801 : ItemsToGet = TotRectIZFloors;
4471 801 : GettingIZSurfaces = true;
4472 801 : OtherSurfaceField = 5;
4473 801 : ExtBoundCondition = unreconciledZoneSurface;
4474 801 : ClassItem = 2;
4475 : }
4476 :
4477 8129 : for (int Loop = 1; Loop <= ItemsToGet; ++Loop) {
4478 238 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
4479 119 : s_ipsc->cCurrentModuleObject,
4480 : Loop,
4481 119 : s_ipsc->cAlphaArgs,
4482 : NumAlphas,
4483 119 : s_ipsc->rNumericArgs,
4484 : NumNumbers,
4485 : IOStat,
4486 119 : s_ipsc->lNumericFieldBlanks,
4487 119 : s_ipsc->lAlphaFieldBlanks,
4488 119 : s_ipsc->cAlphaFieldNames,
4489 119 : s_ipsc->cNumericFieldNames);
4490 :
4491 238 : if (GlobalNames::VerifyUniqueInterObjectName(state,
4492 119 : state.dataSurfaceGeometry->UniqueSurfaceNames,
4493 119 : s_ipsc->cAlphaArgs(1),
4494 119 : s_ipsc->cCurrentModuleObject,
4495 119 : s_ipsc->cAlphaFieldNames(1),
4496 : ErrorsFound)) {
4497 0 : continue;
4498 : }
4499 :
4500 119 : if (NumNumbers < 7) {
4501 0 : ShowSevereError(
4502 : state,
4503 0 : format("{}=\"{}\", Too few number of numeric args=[{}].", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1), NumNumbers));
4504 0 : ErrorsFound = true;
4505 : }
4506 :
4507 119 : ++SurfNum;
4508 :
4509 119 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
4510 119 : surfTemp.Name = s_ipsc->cAlphaArgs(1); // Set the Surface Name in the Derived Type
4511 119 : surfTemp.Class = BaseSurfIDs(ClassItem); // Set class number
4512 :
4513 119 : surfTemp.Construction =
4514 119 : Util::FindItemInList(s_ipsc->cAlphaArgs(2), state.dataConstruction->Construct, state.dataHeatBal->TotConstructs);
4515 :
4516 119 : if (surfTemp.Construction == 0) {
4517 0 : ErrorsFound = true;
4518 0 : ShowSevereError(state,
4519 0 : format("{}=\"{}\", invalid {}=\"{}\".",
4520 0 : s_ipsc->cCurrentModuleObject,
4521 0 : surfTemp.Name,
4522 0 : s_ipsc->cAlphaFieldNames(2),
4523 0 : s_ipsc->cAlphaArgs(2)));
4524 119 : } else if (state.dataConstruction->Construct(surfTemp.Construction).TypeIsWindow) {
4525 0 : ErrorsFound = true;
4526 0 : ShowSevereError(state,
4527 0 : format("{}=\"{}\", invalid {}=\"{}\" - has Window materials.",
4528 0 : s_ipsc->cCurrentModuleObject,
4529 0 : surfTemp.Name,
4530 0 : s_ipsc->cAlphaFieldNames(3),
4531 0 : s_ipsc->cAlphaArgs(2)));
4532 0 : ShowContinueError(state, format("...because {}={}", s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2)));
4533 : } else {
4534 119 : state.dataConstruction->Construct(surfTemp.Construction).IsUsed = true;
4535 119 : surfTemp.ConstructionStoredInputValue = surfTemp.Construction;
4536 : }
4537 119 : surfTemp.HeatTransSurf = true;
4538 119 : surfTemp.BaseSurf = SurfNum;
4539 119 : surfTemp.BaseSurfName = surfTemp.Name;
4540 :
4541 119 : surfTemp.ZoneName = s_ipsc->cAlphaArgs(3);
4542 119 : ZoneNum = Util::FindItemInList(surfTemp.ZoneName, state.dataHeatBal->Zone, state.dataGlobal->NumOfZones);
4543 :
4544 119 : if (ZoneNum != 0) {
4545 119 : surfTemp.Zone = ZoneNum;
4546 : } else {
4547 0 : ShowSevereError(state,
4548 0 : format("{}=\"{}\", invalid {}=\"{}\".",
4549 0 : s_ipsc->cCurrentModuleObject,
4550 0 : surfTemp.Name,
4551 0 : s_ipsc->cAlphaFieldNames(3),
4552 0 : s_ipsc->cAlphaArgs(3)));
4553 0 : surfTemp.Class = SurfaceClass::Invalid;
4554 0 : surfTemp.ZoneName = "Unknown Zone";
4555 0 : ErrorsFound = true;
4556 : }
4557 :
4558 119 : if (!s_ipsc->lAlphaFieldBlanks(4)) {
4559 0 : int spaceNum = Util::FindItemInList(s_ipsc->cAlphaArgs(4), state.dataHeatBal->space);
4560 :
4561 0 : if (spaceNum != 0) {
4562 0 : surfTemp.spaceNum = spaceNum;
4563 : } else {
4564 0 : ShowSevereError(state,
4565 0 : format("{}=\"{}\", invalid {}=\"{}\".",
4566 0 : s_ipsc->cCurrentModuleObject,
4567 0 : surfTemp.Name,
4568 0 : s_ipsc->cAlphaFieldNames(4),
4569 0 : s_ipsc->cAlphaArgs(4)));
4570 0 : surfTemp.Class = SurfaceClass::Invalid;
4571 0 : ErrorsFound = true;
4572 : }
4573 : }
4574 :
4575 119 : surfTemp.ExtBoundCond = ExtBoundCondition;
4576 119 : if (surfTemp.Construction > 0) {
4577 119 : if (surfTemp.Class == SurfaceClass::Wall && state.dataConstruction->Construct(surfTemp.Construction).TypeIsCfactorWall &&
4578 0 : surfTemp.ExtBoundCond == DataSurfaces::Ground) {
4579 0 : surfTemp.ExtBoundCond = DataSurfaces::GroundFCfactorMethod;
4580 119 : } else if (state.dataConstruction->Construct(surfTemp.Construction).TypeIsCfactorWall) {
4581 0 : ErrorsFound = true;
4582 0 : ShowSevereError(state,
4583 0 : format("{}=\"{}\", Construction type is \"Construction:CfactorUndergroundWall\" but invalid for this object.",
4584 0 : s_ipsc->cCurrentModuleObject,
4585 0 : surfTemp.Name));
4586 : }
4587 :
4588 119 : if (surfTemp.Class == SurfaceClass::Floor && state.dataConstruction->Construct(surfTemp.Construction).TypeIsFfactorFloor &&
4589 0 : surfTemp.ExtBoundCond == DataSurfaces::Ground) {
4590 0 : surfTemp.ExtBoundCond = DataSurfaces::GroundFCfactorMethod;
4591 119 : } else if (state.dataConstruction->Construct(surfTemp.Construction).TypeIsFfactorFloor) {
4592 0 : ErrorsFound = true;
4593 0 : ShowSevereError(state,
4594 0 : format("{}=\"{}\", Construction type is \"Construction:FfactorGroundFloor\" but invalid for this object.",
4595 0 : s_ipsc->cCurrentModuleObject,
4596 0 : surfTemp.Name));
4597 : }
4598 : }
4599 119 : surfTemp.ExtSolar = false;
4600 119 : surfTemp.ExtWind = false;
4601 119 : surfTemp.ViewFactorGround = Constant::AutoCalculate;
4602 :
4603 119 : if (surfTemp.ExtBoundCond == DataSurfaces::ExternalEnvironment) {
4604 66 : surfTemp.ExtSolar = true;
4605 66 : surfTemp.ExtWind = true;
4606 :
4607 : // Set the logical flag for the EcoRoof presented, this is only based on the flag in the construction type
4608 : // if (surfTemp.Construction > 0)
4609 : // surfTemp.ExtEcoRoof =
4610 : // state.dataConstruction->Construct(surfTemp.Construction).TypeIsEcoRoof;
4611 :
4612 53 : } else if (surfTemp.ExtBoundCond == unreconciledZoneSurface) {
4613 47 : if (GettingIZSurfaces) {
4614 19 : surfTemp.ExtBoundCondName = s_ipsc->cAlphaArgs(OtherSurfaceField);
4615 19 : Found = Util::FindItemInList(surfTemp.ExtBoundCondName, state.dataHeatBal->Zone, state.dataGlobal->NumOfZones);
4616 : // see if match to zone, then it's an unentered other surface, else reconciled later
4617 19 : if (Found > 0) {
4618 1 : ++NeedToAddSurfaces;
4619 1 : surfTemp.ExtBoundCond = unenteredAdjacentZoneSurface;
4620 : }
4621 : } else {
4622 28 : surfTemp.ExtBoundCondName = surfTemp.Name;
4623 : }
4624 :
4625 6 : } else if (surfTemp.ExtBoundCond == DataSurfaces::Ground) {
4626 6 : if (state.dataSurfaceGeometry->NoGroundTempObjWarning) {
4627 1 : if (!state.dataEnvrn->GroundTempInputs[(int)DataEnvironment::GroundTempType::BuildingSurface]) {
4628 0 : ShowWarningError(state,
4629 : "GetRectSurfaces: Surfaces with interface to Ground found but no \"Ground Temperatures\" were input.");
4630 0 : ShowContinueError(state, format("Found first in surface={}", s_ipsc->cAlphaArgs(1)));
4631 0 : ShowContinueError(state,
4632 0 : format("Defaults, constant throughout the year of ({:.1R}) will be used.",
4633 0 : state.dataEnvrn->GroundTemp[(int)DataEnvironment::GroundTempType::BuildingSurface]));
4634 : }
4635 1 : state.dataSurfaceGeometry->NoGroundTempObjWarning = false;
4636 : }
4637 :
4638 0 : } else if (surfTemp.ExtBoundCond == DataSurfaces::GroundFCfactorMethod) {
4639 0 : if (state.dataSurfaceGeometry->NoFCGroundTempObjWarning) {
4640 0 : if (!state.dataEnvrn->GroundTempInputs[(int)DataEnvironment::GroundTempType::FCFactorMethod]) {
4641 0 : ShowSevereError(state,
4642 : "GetRectSurfaces: Surfaces with interface to GroundFCfactorMethod found but no \"FC Ground "
4643 : "Temperatures\" were input.");
4644 0 : ShowContinueError(state, format("Found first in surface={}", s_ipsc->cAlphaArgs(1)));
4645 0 : ShowContinueError(state,
4646 : "Either add a \"Site:GroundTemperature:FCfactorMethod\" object or use a weather file with "
4647 : "Ground Temperatures.");
4648 0 : ErrorsFound = true;
4649 0 : state.dataSurfaceGeometry->NoFCGroundTempObjWarning = false;
4650 : }
4651 : }
4652 :
4653 : } // ... End of the ExtBoundCond logical IF Block
4654 :
4655 119 : surfTemp.Azimuth = s_ipsc->rNumericArgs(1);
4656 119 : surfTemp.Tilt = s_ipsc->rNumericArgs(2);
4657 119 : surfTemp.convOrientation = Convect::GetSurfConvOrientation(surfTemp.Tilt);
4658 119 : if (!state.dataSurface->WorldCoordSystem) {
4659 95 : if (ZoneNum != 0) {
4660 95 : surfTemp.Azimuth += state.dataHeatBal->BuildingAzimuth + state.dataHeatBal->Zone(ZoneNum).RelNorth;
4661 : }
4662 : }
4663 119 : if (ZoneNum != 0) {
4664 119 : surfTemp.Azimuth += state.dataHeatBal->BuildingRotationAppendixG;
4665 : }
4666 :
4667 119 : surfTemp.Sides = 4;
4668 119 : surfTemp.Vertex.allocate(surfTemp.Sides);
4669 :
4670 714 : MakeRectangularVertices(state,
4671 : SurfNum,
4672 119 : s_ipsc->rNumericArgs(3),
4673 119 : s_ipsc->rNumericArgs(4),
4674 119 : s_ipsc->rNumericArgs(5),
4675 119 : s_ipsc->rNumericArgs(6),
4676 119 : s_ipsc->rNumericArgs(7),
4677 119 : state.dataSurfaceGeometry->RectSurfRefWorldCoordSystem);
4678 :
4679 119 : if (surfTemp.Area <= 0.0) {
4680 0 : ShowSevereError(
4681 : state,
4682 0 : format("{}=\"{}\", Surface Area <= 0.0; Entered Area={:.2T}", s_ipsc->cCurrentModuleObject, surfTemp.Name, surfTemp.Area));
4683 0 : ErrorsFound = true;
4684 : }
4685 :
4686 : // Check wall height for the CFactor walls
4687 119 : if (surfTemp.Class == SurfaceClass::Wall && surfTemp.ExtBoundCond == DataSurfaces::GroundFCfactorMethod) {
4688 0 : if (std::abs(surfTemp.Height - state.dataConstruction->Construct(surfTemp.Construction).Height) > 0.05) {
4689 0 : ShowWarningError(
4690 : state,
4691 0 : format("{}=\"{}\", underground Wall Height = {:.2T}", s_ipsc->cCurrentModuleObject, surfTemp.Name, surfTemp.Height));
4692 0 : ShowContinueError(state, "..which deos not match its construction height.");
4693 : }
4694 : }
4695 :
4696 : // Check area and perimeter for the FFactor floors
4697 119 : if (surfTemp.Class == SurfaceClass::Floor && surfTemp.ExtBoundCond == DataSurfaces::GroundFCfactorMethod) {
4698 0 : if (std::abs(surfTemp.Area - state.dataConstruction->Construct(surfTemp.Construction).Area) > 0.1) {
4699 0 : ShowWarningError(
4700 0 : state, format("{}=\"{}\", underground Floor Area = {:.2T}", s_ipsc->cCurrentModuleObject, surfTemp.Name, surfTemp.Area));
4701 0 : ShowContinueError(state, "..which does not match its construction area.");
4702 : }
4703 0 : if (surfTemp.Perimeter < state.dataConstruction->Construct(surfTemp.Construction).PerimeterExposed - 0.1) {
4704 0 : ShowWarningError(
4705 : state,
4706 0 : format(
4707 0 : "{}=\"{}\", underground Floor Perimeter = {:.2T}", s_ipsc->cCurrentModuleObject, surfTemp.Name, surfTemp.Perimeter));
4708 0 : ShowContinueError(state, "..which is less than its construction exposed perimeter.");
4709 : }
4710 : }
4711 : } // Getting Items
4712 : }
4713 801 : }
4714 :
4715 139 : void MakeRectangularVertices(EnergyPlusData &state,
4716 : int const SurfNum,
4717 : Real64 const XCoord,
4718 : Real64 const YCoord,
4719 : Real64 const ZCoord,
4720 : Real64 const Length,
4721 : Real64 const Height,
4722 : bool const SurfWorldCoordSystem)
4723 : {
4724 :
4725 : // SUBROUTINE INFORMATION:
4726 : // AUTHOR Linda Lawrie
4727 : // DATE WRITTEN December 2008
4728 :
4729 : // PURPOSE OF THIS SUBROUTINE:
4730 : // This routine creates world/3d coordinates for rectangular surfaces using azimuth, tilt, LLC (X,Y,Z), length & height.
4731 :
4732 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
4733 : Real64 XLLC;
4734 : Real64 YLLC;
4735 : Real64 ZLLC;
4736 139 : Array1D<Real64> XX(4);
4737 139 : Array1D<Real64> YY(4);
4738 : Real64 Xb;
4739 : Real64 Yb;
4740 : Real64 Perimeter;
4741 : int Vrt;
4742 :
4743 139 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
4744 :
4745 139 : if (surfTemp.Zone == 0 && (surfTemp.Class != SurfaceClass::Detached_F && surfTemp.Class != SurfaceClass::Detached_B)) {
4746 0 : return;
4747 : }
4748 :
4749 139 : surfTemp.Height = Height;
4750 139 : surfTemp.Width = Length;
4751 :
4752 139 : Real64 SurfAzimuth = surfTemp.Azimuth;
4753 139 : Real64 SurfTilt = surfTemp.Tilt;
4754 139 : Real64 CosSurfAzimuth = std::cos(SurfAzimuth * Constant::DegToRad);
4755 139 : Real64 SinSurfAzimuth = std::sin(SurfAzimuth * Constant::DegToRad);
4756 139 : Real64 CosSurfTilt = std::cos(SurfTilt * Constant::DegToRad);
4757 139 : Real64 SinSurfTilt = std::sin(SurfTilt * Constant::DegToRad);
4758 :
4759 139 : if (!SurfWorldCoordSystem) {
4760 111 : if (surfTemp.Zone > 0) {
4761 95 : Xb = XCoord * state.dataSurfaceGeometry->CosZoneRelNorth(surfTemp.Zone) -
4762 95 : YCoord * state.dataSurfaceGeometry->SinZoneRelNorth(surfTemp.Zone) + state.dataHeatBal->Zone(surfTemp.Zone).OriginX;
4763 95 : Yb = XCoord * state.dataSurfaceGeometry->SinZoneRelNorth(surfTemp.Zone) +
4764 95 : YCoord * state.dataSurfaceGeometry->CosZoneRelNorth(surfTemp.Zone) + state.dataHeatBal->Zone(surfTemp.Zone).OriginY;
4765 95 : XLLC = Xb * state.dataSurfaceGeometry->CosBldgRelNorth - Yb * state.dataSurfaceGeometry->SinBldgRelNorth;
4766 95 : YLLC = Xb * state.dataSurfaceGeometry->SinBldgRelNorth + Yb * state.dataSurfaceGeometry->CosBldgRelNorth;
4767 95 : ZLLC = ZCoord + state.dataHeatBal->Zone(surfTemp.Zone).OriginZ;
4768 : } else {
4769 16 : if (surfTemp.Class == SurfaceClass::Detached_B) {
4770 5 : Xb = XCoord;
4771 5 : Yb = YCoord;
4772 5 : XLLC = Xb * state.dataSurfaceGeometry->CosBldgRelNorth - Yb * state.dataSurfaceGeometry->SinBldgRelNorth;
4773 5 : YLLC = Xb * state.dataSurfaceGeometry->SinBldgRelNorth + Yb * state.dataSurfaceGeometry->CosBldgRelNorth;
4774 5 : ZLLC = ZCoord;
4775 : } else {
4776 11 : XLLC = XCoord;
4777 11 : YLLC = YCoord;
4778 11 : ZLLC = ZCoord;
4779 : }
4780 : }
4781 : } else {
4782 : // for world coordinates, only rotate for appendix G
4783 28 : Xb = XCoord;
4784 28 : Yb = YCoord;
4785 28 : ZLLC = ZCoord;
4786 28 : if (surfTemp.Class != SurfaceClass::Detached_F) {
4787 25 : XLLC = Xb * state.dataSurfaceGeometry->CosBldgRotAppGonly - Yb * state.dataSurfaceGeometry->SinBldgRotAppGonly;
4788 25 : YLLC = Xb * state.dataSurfaceGeometry->SinBldgRotAppGonly + Yb * state.dataSurfaceGeometry->CosBldgRotAppGonly;
4789 : } else {
4790 3 : XLLC = Xb;
4791 3 : YLLC = Yb;
4792 : }
4793 : }
4794 :
4795 139 : XX(1) = 0.0;
4796 139 : XX(2) = 0.0;
4797 139 : XX(3) = Length;
4798 139 : XX(4) = Length;
4799 139 : YY(1) = Height;
4800 139 : YY(4) = Height;
4801 139 : YY(3) = 0.0;
4802 139 : YY(2) = 0.0;
4803 :
4804 695 : for (int n = 1; n <= surfTemp.Sides; ++n) {
4805 556 : Vrt = n;
4806 556 : surfTemp.Vertex(Vrt).x = XLLC - XX(n) * CosSurfAzimuth - YY(n) * CosSurfTilt * SinSurfAzimuth;
4807 556 : surfTemp.Vertex(Vrt).y = YLLC + XX(n) * SinSurfAzimuth - YY(n) * CosSurfTilt * CosSurfAzimuth;
4808 556 : surfTemp.Vertex(Vrt).z = ZLLC + YY(n) * SinSurfTilt;
4809 : }
4810 :
4811 139 : Vectors::CreateNewellAreaVector(surfTemp.Vertex, surfTemp.Sides, surfTemp.NewellAreaVector);
4812 139 : surfTemp.GrossArea = Vectors::VecLength(surfTemp.NewellAreaVector);
4813 139 : surfTemp.Area = surfTemp.GrossArea;
4814 139 : surfTemp.NetAreaShadowCalc = surfTemp.Area;
4815 139 : Vectors::CreateNewellSurfaceNormalVector(surfTemp.Vertex, surfTemp.Sides, surfTemp.NewellSurfaceNormalVector);
4816 139 : Vectors::DetermineAzimuthAndTilt(
4817 139 : surfTemp.Vertex, SurfAzimuth, SurfTilt, surfTemp.lcsx, surfTemp.lcsy, surfTemp.lcsz, surfTemp.NewellSurfaceNormalVector);
4818 139 : surfTemp.Azimuth = SurfAzimuth;
4819 139 : surfTemp.Tilt = SurfTilt;
4820 139 : surfTemp.convOrientation = Convect::GetSurfConvOrientation(surfTemp.Tilt);
4821 : // Sine and cosine of azimuth and tilt
4822 139 : surfTemp.SinAzim = SinSurfAzimuth;
4823 139 : surfTemp.CosAzim = CosSurfAzimuth;
4824 139 : surfTemp.SinTilt = SinSurfTilt;
4825 139 : surfTemp.CosTilt = CosSurfTilt;
4826 139 : surfTemp.ViewFactorGround = 0.5 * (1.0 - surfTemp.CosTilt);
4827 : // Outward normal unit vector (pointing away from room)
4828 :
4829 139 : surfTemp.OutNormVec = surfTemp.NewellSurfaceNormalVector;
4830 556 : for (int n = 1; n <= 3; ++n) {
4831 417 : if (std::abs(surfTemp.OutNormVec(n) - 1.0) < 1.e-06) {
4832 71 : surfTemp.OutNormVec(n) = +1.0;
4833 : }
4834 417 : if (std::abs(surfTemp.OutNormVec(n) + 1.0) < 1.e-06) {
4835 68 : surfTemp.OutNormVec(n) = -1.0;
4836 : }
4837 417 : if (std::abs(surfTemp.OutNormVec(n)) < 1.e-06) {
4838 278 : surfTemp.OutNormVec(n) = 0.0;
4839 : }
4840 : }
4841 :
4842 : // Can perform tests on this surface here
4843 139 : surfTemp.ViewFactorSky = 0.5 * (1.0 + surfTemp.CosTilt);
4844 : // The following IR view factors are modified in subr. SkyDifSolarShading if there are shadowing
4845 : // surfaces
4846 139 : surfTemp.ViewFactorSkyIR = surfTemp.ViewFactorSky;
4847 139 : surfTemp.ViewFactorGroundIR = 0.5 * (1.0 - surfTemp.CosTilt);
4848 :
4849 139 : Perimeter = distance(surfTemp.Vertex(surfTemp.Sides), surfTemp.Vertex(1));
4850 556 : for (Vrt = 2; Vrt <= surfTemp.Sides; ++Vrt) {
4851 417 : Perimeter += distance(surfTemp.Vertex(Vrt), surfTemp.Vertex(Vrt - 1));
4852 : }
4853 139 : surfTemp.Perimeter = Perimeter;
4854 :
4855 : // Call to transform vertices
4856 :
4857 139 : TransformVertsByAspect(state, SurfNum, surfTemp.Sides);
4858 139 : }
4859 :
4860 801 : void GetHTSubSurfaceData(EnergyPlusData &state,
4861 : bool &ErrorsFound, // Error flag indicator (true if errors found)
4862 : int &SurfNum, // Count of Current SurfaceNumber
4863 : int const TotHTSubs, // Number of Heat Transfer SubSurfaces to obtain
4864 : const Array1D_string &SubSurfCls, // Valid Classes for Sub Surfaces
4865 : const Array1D<SurfaceClass> &SubSurfIDs, // ID Assignments for valid sub surface classes
4866 : int &AddedSubSurfaces, // Subsurfaces added when windows reference Window5
4867 : int &NeedToAddSurfaces // Number of surfaces to add, based on unentered IZ surfaces
4868 : )
4869 : {
4870 :
4871 : // SUBROUTINE INFORMATION:
4872 : // AUTHOR Linda Lawrie
4873 : // DATE WRITTEN May 2000
4874 : // MODIFIED August 2012 - line up subsurfaces with base surface types
4875 :
4876 : // PURPOSE OF THIS SUBROUTINE:
4877 : // This subroutine gets the HeatTransfer Sub Surface Data, checks it for errors, etc.
4878 :
4879 : // REFERENCES:
4880 : // Heat Transfer Subsurface Definition
4881 : // FenestrationSurface:Detailed,
4882 : // \min-fields 19
4883 : // \memo Used for windows, doors, glass doors, tubular daylighting devices
4884 : // \format vertices
4885 : // A1 , \field Name
4886 : // \required-field
4887 : // \type alpha
4888 : // A2 , \field Surface Type
4889 : // \required-field
4890 : // \type choice
4891 : // \key Window
4892 : // \key Door
4893 : // \key GlassDoor
4894 : // \key TubularDaylightDome
4895 : // \key TubularDaylightDiffuser
4896 : // A3 , \field Construction Name
4897 : // \required-field
4898 : // \note To be matched with a construction in this input file
4899 : // \type object-list
4900 : // \object-list ConstructionNames
4901 : // A4 , \field Building Surface Name
4902 : // \required-field
4903 : // \type object-list
4904 : // \object-list SurfaceNames
4905 : // A5, \field Outside Boundary Condition Object
4906 : // \type object-list
4907 : // \object-list OutFaceEnvNames
4908 : // \note Non-blank only if base surface field Outside Boundary Condition is
4909 : // \note Surface or OtherSideCoefficients
4910 : // \note If Base Surface's Surface, specify name of corresponding subsurface in adjacent zone or
4911 : // \note specify current subsurface name for internal partition separating like zones
4912 : // \note If OtherSideCoefficients, specify name of SurfaceProperty:OtherSideCoefficients
4913 : // \note or leave blank to inherit Base Surface's OtherSide Coefficients
4914 : // N1, \field View Factor to Ground
4915 : // \type real
4916 : // \note From the exterior of the surface
4917 : // \note Unused if one uses the "reflections" options in Solar Distribution in Building input
4918 : // \note unless a DaylightingDevice:Shelf or DaylightingDevice:Tubular object has been specified.
4919 : // \note autocalculate will automatically calculate this value from the tilt of the surface
4920 : // \autocalculatable
4921 : // \minimum 0.0
4922 : // \maximum 1.0
4923 : // \default autocalculate
4924 : // A6, \field Frame and Divider Name
4925 : // \note Enter the name of a WindowProperty:FrameAndDivider object
4926 : // \type object-list
4927 : // \object-list WindowFrameAndDividerNames
4928 : // \note Used only for exterior windows (rectangular) and glass doors.
4929 : // \note Unused for triangular windows.
4930 : // \note If not specified (blank), window or glass door has no frame or divider
4931 : // \note and no beam solar reflection from reveal surfaces.
4932 : // N2 , \field Multiplier
4933 : // \note Used only for Surface Type = WINDOW, GLASSDOOR or DOOR
4934 : // \note Non-integer values will be truncated to integer
4935 : // \default 1.0
4936 : // \minimum 1.0
4937 : // N3 , \field Number of Vertices
4938 : // \minimum 3
4939 : // \maximum 4
4940 : // \autocalculatable
4941 : // \default autocalculate
4942 : // \note vertices are given in GlobalGeometryRules coordinates -- if relative, all surface coordinates
4943 : // \note are "relative" to the Zone Origin. If world, then building and zone origins are used
4944 : // \note for some internal calculations, but all coordinates are given in an "absolute" system.
4945 : // N4-15 as indicated by the N3 value
4946 :
4947 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
4948 : int IOStat; // IO Status when calling get input subroutine
4949 : int SurfaceNumAlpha; // Number of material alpha names being passed
4950 : int SurfaceNumProp; // Number of material properties being passed
4951 : int Found; // For matching interzone surfaces
4952 : int Loop;
4953 : int ValidChk;
4954 : int numSides;
4955 :
4956 801 : auto &s_ipsc = state.dataIPShortCut;
4957 :
4958 801 : GetWindowShadingControlData(state, ErrorsFound);
4959 801 : s_ipsc->cCurrentModuleObject = "FenestrationSurface:Detailed";
4960 801 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, s_ipsc->cCurrentModuleObject, Loop, SurfaceNumAlpha, SurfaceNumProp);
4961 :
4962 801 : if (SurfaceNumAlpha != 6) {
4963 0 : ShowSevereError(
4964 : state,
4965 0 : format("{}: Object Definition indicates not = 6 Alpha Objects, Number Indicated={}", s_ipsc->cCurrentModuleObject, SurfaceNumAlpha));
4966 0 : ErrorsFound = true;
4967 : }
4968 :
4969 801 : if (SurfaceNumProp != 15) {
4970 0 : ShowSevereError(
4971 : state,
4972 0 : format("{}: Object Definition indicates > 15 Numeric Objects, Number Indicated={}", s_ipsc->cCurrentModuleObject, SurfaceNumAlpha));
4973 0 : ErrorsFound = true;
4974 : }
4975 801 : NeedToAddSurfaces = 0;
4976 :
4977 7565 : for (Loop = 1; Loop <= TotHTSubs; ++Loop) {
4978 13528 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
4979 6764 : s_ipsc->cCurrentModuleObject,
4980 : Loop,
4981 6764 : s_ipsc->cAlphaArgs,
4982 : SurfaceNumAlpha,
4983 6764 : s_ipsc->rNumericArgs,
4984 : SurfaceNumProp,
4985 : IOStat,
4986 6764 : s_ipsc->lNumericFieldBlanks,
4987 6764 : s_ipsc->lAlphaFieldBlanks,
4988 6764 : s_ipsc->cAlphaFieldNames,
4989 6764 : s_ipsc->cNumericFieldNames);
4990 :
4991 13528 : if (GlobalNames::VerifyUniqueInterObjectName(state,
4992 6764 : state.dataSurfaceGeometry->UniqueSurfaceNames,
4993 6764 : s_ipsc->cAlphaArgs(1),
4994 6764 : s_ipsc->cCurrentModuleObject,
4995 6764 : s_ipsc->cAlphaFieldNames(1),
4996 : ErrorsFound)) {
4997 0 : continue;
4998 : }
4999 :
5000 6764 : ++SurfNum;
5001 :
5002 6764 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
5003 :
5004 6764 : if (SurfaceNumProp < 12) {
5005 0 : ShowSevereError(
5006 0 : state, format("{}=\"{}\", Too few number of numeric args=[{}].", s_ipsc->cCurrentModuleObject, surfTemp.Name, SurfaceNumProp));
5007 0 : ErrorsFound = true;
5008 : }
5009 :
5010 6764 : surfTemp.Name = s_ipsc->cAlphaArgs(1); // Set the Surface Name in the Derived Type
5011 6764 : ValidChk = Util::FindItemInList(s_ipsc->cAlphaArgs(2), SubSurfCls, 6);
5012 6764 : if (ValidChk == 0) {
5013 0 : ShowSevereError(state,
5014 0 : format("{}=\"{}\", invalid {}=\"{}",
5015 0 : s_ipsc->cCurrentModuleObject,
5016 0 : surfTemp.Name,
5017 0 : s_ipsc->cAlphaFieldNames(2),
5018 0 : s_ipsc->cAlphaArgs(2)));
5019 0 : ErrorsFound = true;
5020 : } else {
5021 6764 : surfTemp.Class = SubSurfIDs(ValidChk); // Set class number
5022 : }
5023 :
5024 6764 : surfTemp.Construction = Util::FindItemInList(s_ipsc->cAlphaArgs(3), state.dataConstruction->Construct, state.dataHeatBal->TotConstructs);
5025 :
5026 6764 : if (surfTemp.Construction == 0) {
5027 0 : ShowSevereError(state,
5028 0 : format("{}=\"{}\", invalid {}=\"{}\".",
5029 0 : s_ipsc->cCurrentModuleObject,
5030 0 : surfTemp.Name,
5031 0 : s_ipsc->cAlphaFieldNames(3),
5032 0 : s_ipsc->cAlphaArgs(3)));
5033 0 : ErrorsFound = true;
5034 0 : continue;
5035 : } else {
5036 6764 : state.dataConstruction->Construct(surfTemp.Construction).IsUsed = true;
5037 6764 : surfTemp.ConstructionStoredInputValue = surfTemp.Construction;
5038 : }
5039 :
5040 6764 : if (surfTemp.Class == SurfaceClass::Window || surfTemp.Class == SurfaceClass::GlassDoor || surfTemp.Class == SurfaceClass::TDD_Diffuser ||
5041 472 : surfTemp.Class == SurfaceClass::TDD_Dome) {
5042 :
5043 6294 : if (surfTemp.Construction != 0) {
5044 6294 : auto const &construction = state.dataConstruction->Construct(surfTemp.Construction);
5045 6294 : if (!construction.TypeIsWindow && !construction.TypeIsAirBoundary) {
5046 0 : ErrorsFound = true;
5047 0 : ShowSevereError(state,
5048 0 : format("{}=\"{}\" has an opaque surface construction; it should have a window construction.",
5049 0 : s_ipsc->cCurrentModuleObject,
5050 0 : surfTemp.Name));
5051 : }
5052 6294 : if (state.dataConstruction->Construct(surfTemp.Construction).SourceSinkPresent) {
5053 0 : ErrorsFound = true;
5054 0 : ShowSevereError(
5055 : state,
5056 0 : format("{}=\"{}\": Windows are not allowed to have embedded sources/sinks", s_ipsc->cCurrentModuleObject, surfTemp.Name));
5057 : }
5058 : }
5059 :
5060 6764 : } else if (surfTemp.Construction != 0) {
5061 470 : if (state.dataConstruction->Construct(surfTemp.Construction).TypeIsWindow) {
5062 0 : ErrorsFound = true;
5063 0 : ShowSevereError(state,
5064 0 : format("{}=\"{}\", invalid {}=\"{}\" - has Window materials.",
5065 0 : s_ipsc->cCurrentModuleObject,
5066 0 : surfTemp.Name,
5067 0 : s_ipsc->cAlphaFieldNames(3),
5068 0 : s_ipsc->cAlphaArgs(3)));
5069 0 : ShowContinueError(state, format("...because {}={}", s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2)));
5070 : }
5071 : }
5072 :
5073 6764 : surfTemp.HeatTransSurf = true;
5074 :
5075 6764 : surfTemp.BaseSurfName = s_ipsc->cAlphaArgs(4);
5076 : // The subsurface inherits properties from the base surface
5077 : // Exterior conditions, Zone, etc.
5078 : // We can figure out the base surface though, because they've all been entered
5079 6764 : Found = Util::FindItemInList(surfTemp.BaseSurfName, state.dataSurfaceGeometry->SurfaceTmp, state.dataSurface->TotSurfaces);
5080 6764 : if (Found > 0) {
5081 6764 : surfTemp.BaseSurf = Found;
5082 6764 : surfTemp.ExtBoundCond = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCond;
5083 6764 : surfTemp.ExtBoundCondName = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCondName;
5084 6764 : surfTemp.ExtSolar = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtSolar;
5085 6764 : surfTemp.ExtWind = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtWind;
5086 6764 : surfTemp.Zone = state.dataSurfaceGeometry->SurfaceTmp(Found).Zone;
5087 6764 : surfTemp.ZoneName = state.dataSurfaceGeometry->SurfaceTmp(Found).ZoneName;
5088 6764 : surfTemp.OSCPtr = state.dataSurfaceGeometry->SurfaceTmp(Found).OSCPtr;
5089 6828 : if (state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCond == unreconciledZoneSurface &&
5090 64 : state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCondName ==
5091 64 : state.dataSurfaceGeometry->SurfaceTmp(Found).Name) { // Adiabatic surface, no windows or doors allowed
5092 0 : ShowSevereError(state,
5093 0 : format("{}=\"{}\", invalid {}=\"{}\".",
5094 0 : s_ipsc->cCurrentModuleObject,
5095 0 : surfTemp.Name,
5096 0 : s_ipsc->cAlphaFieldNames(4),
5097 0 : s_ipsc->cAlphaArgs(4)));
5098 0 : ShowContinueError(state, "... adiabatic surfaces cannot have windows or doors.");
5099 0 : ShowContinueError(state,
5100 : "... no solar transmission will result for these windows or doors. You must have interior windows or doors on "
5101 : "Interzone surfaces for transmission to result.");
5102 : }
5103 : } else {
5104 0 : ShowSevereError(state,
5105 0 : format("{}=\"{}\", invalid {}=\"{}",
5106 0 : s_ipsc->cCurrentModuleObject,
5107 0 : surfTemp.Name,
5108 0 : s_ipsc->cAlphaFieldNames(4),
5109 0 : s_ipsc->cAlphaArgs(4)));
5110 0 : surfTemp.ZoneName = "Unknown Zone";
5111 0 : ErrorsFound = true;
5112 : }
5113 6764 : if (surfTemp.Class == SurfaceClass::TDD_Dome || surfTemp.Class == SurfaceClass::TDD_Diffuser) {
5114 4 : surfTemp.ExtBoundCond = DataSurfaces::ExternalEnvironment;
5115 : }
5116 :
5117 6764 : if (surfTemp.ExtBoundCond == DataSurfaces::ExternalEnvironment) {
5118 6685 : if (!s_ipsc->lAlphaFieldBlanks(5)) {
5119 0 : ShowWarningError(state,
5120 0 : format("{}=\"{}\", invalid field {}", s_ipsc->cCurrentModuleObject, surfTemp.Name, s_ipsc->cAlphaFieldNames(5)));
5121 0 : ShowContinueError(
5122 : state,
5123 0 : format("...when Base surface uses \"Outdoors\" as {}, subsurfaces need to be blank to inherit the outdoor characteristics.",
5124 0 : s_ipsc->cAlphaFieldNames(5)));
5125 0 : ShowContinueError(state, "...Surface external characteristics changed to reflect base surface.");
5126 : }
5127 : }
5128 :
5129 6764 : if (surfTemp.ExtBoundCond == unreconciledZoneSurface) { // "Surface" Base Surface
5130 62 : if (!s_ipsc->lAlphaFieldBlanks(5)) {
5131 62 : surfTemp.ExtBoundCondName = s_ipsc->cAlphaArgs(5);
5132 : } else {
5133 0 : ShowSevereError(state,
5134 0 : format("{}=\"{}\", invalid blank {}", s_ipsc->cCurrentModuleObject, surfTemp.Name, s_ipsc->cAlphaFieldNames(5)));
5135 0 : ShowContinueError(
5136 : state,
5137 0 : format("...when Base surface uses \"Surface\" as {}, subsurfaces must also specify specific surfaces in the adjacent zone.",
5138 0 : s_ipsc->cAlphaFieldNames(5)));
5139 0 : surfTemp.ExtBoundCondName = s_ipsc->cAlphaArgs(5); // putting it as blank will not confuse things later.
5140 0 : ErrorsFound = true;
5141 : }
5142 : }
5143 :
5144 6764 : if ((surfTemp.ExtBoundCond == unenteredAdjacentZoneSurface) ||
5145 6763 : (surfTemp.ExtBoundCond == unenteredAdjacentSpaceSurface)) { // "Zone" - unmatched interior surface
5146 1 : ++NeedToAddSurfaces;
5147 : // ignoring window5datafiles for now -- will need to add.
5148 : }
5149 :
5150 6764 : if (surfTemp.ExtBoundCond == DataSurfaces::OtherSideCoefNoCalcExt || surfTemp.ExtBoundCond == DataSurfaces::OtherSideCoefCalcExt) {
5151 16 : if (!s_ipsc->lAlphaFieldBlanks(5)) { // Otherside Coef special Name
5152 2 : Found = Util::FindItemInList(s_ipsc->cAlphaArgs(5), state.dataSurface->OSC, state.dataSurface->TotOSC);
5153 2 : if (Found == 0) {
5154 0 : ShowSevereError(state,
5155 0 : format("{}=\"{}\", invalid {}=\"{}\".",
5156 0 : s_ipsc->cCurrentModuleObject,
5157 0 : surfTemp.Name,
5158 0 : s_ipsc->cAlphaFieldNames(5),
5159 0 : s_ipsc->cAlphaArgs(5)));
5160 0 : ShowContinueError(state, "...base surface requires that this subsurface have OtherSideCoefficients -- not found.");
5161 0 : ErrorsFound = true;
5162 : } else { // found
5163 : // The following allows for a subsurface that has different characteristics than
5164 : // the base surface with OtherSide Coeff -- do we want that or is it an error?
5165 2 : surfTemp.OSCPtr = Found;
5166 2 : surfTemp.ExtBoundCondName = s_ipsc->cAlphaArgs(5);
5167 2 : if (state.dataSurface->OSC(Found).SurfFilmCoef > 0.0) {
5168 0 : surfTemp.ExtBoundCond = DataSurfaces::OtherSideCoefCalcExt;
5169 : } else {
5170 2 : surfTemp.ExtBoundCond = DataSurfaces::OtherSideCoefNoCalcExt;
5171 : }
5172 : }
5173 : }
5174 : }
5175 :
5176 6764 : if (surfTemp.ExtBoundCond == DataSurfaces::OtherSideCondModeledExt) {
5177 0 : surfTemp.ExtBoundCond = DataSurfaces::ExternalEnvironment;
5178 : }
5179 :
5180 6764 : if (surfTemp.ExtBoundCondName == BlankString) {
5181 6675 : surfTemp.ExtBoundCondName = surfTemp.Name;
5182 : }
5183 6764 : surfTemp.ViewFactorGround = s_ipsc->rNumericArgs(1);
5184 6764 : if (s_ipsc->lNumericFieldBlanks(1)) {
5185 408 : surfTemp.ViewFactorGround = Constant::AutoCalculate;
5186 : }
5187 :
5188 6764 : if (s_ipsc->lNumericFieldBlanks(3) || s_ipsc->rNumericArgs(3) == Constant::AutoCalculate) {
5189 106 : s_ipsc->rNumericArgs(3) = (SurfaceNumProp - 3) / 3;
5190 106 : surfTemp.Sides = s_ipsc->rNumericArgs(3);
5191 106 : if (mod(SurfaceNumProp - 3, 3) != 0) {
5192 0 : ShowWarningError(state,
5193 0 : format("{}=\"{}\", {}",
5194 0 : s_ipsc->cCurrentModuleObject,
5195 0 : surfTemp.Name,
5196 0 : format("{} not even multiple of 3. Will read in {}", s_ipsc->cNumericFieldNames(3), surfTemp.Sides)));
5197 : }
5198 106 : if (s_ipsc->rNumericArgs(3) < 3) {
5199 0 : ShowSevereError(state,
5200 0 : format("{}=\"{}\", {} (autocalculate) must be >= 3. Only {} provided.",
5201 0 : s_ipsc->cCurrentModuleObject,
5202 0 : surfTemp.Name,
5203 0 : s_ipsc->cNumericFieldNames(3),
5204 0 : surfTemp.Sides));
5205 0 : ErrorsFound = true;
5206 0 : continue;
5207 : }
5208 : } else {
5209 6658 : numSides = (SurfaceNumProp - 2) / 3;
5210 6658 : surfTemp.Sides = s_ipsc->rNumericArgs(3);
5211 6658 : if (numSides > surfTemp.Sides) {
5212 0 : ShowWarningError(state,
5213 0 : format("{}=\"{}\", field {}={}",
5214 0 : s_ipsc->cCurrentModuleObject,
5215 0 : surfTemp.Name,
5216 0 : s_ipsc->cNumericFieldNames(3),
5217 0 : fmt::to_string(surfTemp.Sides)));
5218 0 : ShowContinueError(state,
5219 0 : format("...but {} were entered. Only the indicated {} will be used.", numSides, s_ipsc->cNumericFieldNames(3)));
5220 : }
5221 : }
5222 6764 : surfTemp.Vertex.allocate(surfTemp.Sides);
5223 6764 : if (surfTemp.Class == SurfaceClass::Window || surfTemp.Class == SurfaceClass::GlassDoor || surfTemp.Class == SurfaceClass::Door) {
5224 6760 : surfTemp.Multiplier = int(s_ipsc->rNumericArgs(2));
5225 : }
5226 : // Only windows, glass doors and doors can have Multiplier > 1:
5227 6768 : if ((surfTemp.Class != SurfaceClass::Window && surfTemp.Class != SurfaceClass::GlassDoor && surfTemp.Class != SurfaceClass::Door) &&
5228 4 : s_ipsc->rNumericArgs(2) > 1.0) {
5229 0 : ShowWarningError(state,
5230 0 : format("{}=\"{}\", invalid {}=[{:.1T}].",
5231 0 : s_ipsc->cCurrentModuleObject,
5232 0 : surfTemp.Name,
5233 0 : s_ipsc->cNumericFieldNames(2),
5234 0 : s_ipsc->rNumericArgs(2)));
5235 0 : ShowContinueError(state,
5236 0 : format("...because {}={} multiplier will be set to 1.0.", s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2)));
5237 0 : surfTemp.Multiplier = 1.0;
5238 : }
5239 :
5240 27056 : GetVertices(state, SurfNum, surfTemp.Sides, s_ipsc->rNumericArgs({4, _}));
5241 :
5242 6764 : CheckConvexity(state, SurfNum, surfTemp.Sides);
5243 6764 : surfTemp.windowShadingControlList.clear();
5244 6764 : surfTemp.activeWindowShadingControl = 0;
5245 6764 : surfTemp.HasShadeControl = false;
5246 :
5247 6764 : surfTemp.shadedConstructionList.clear();
5248 6764 : surfTemp.activeShadedConstruction = 0;
5249 6764 : surfTemp.shadedStormWinConstructionList.clear();
5250 :
5251 6764 : if (surfTemp.Class == SurfaceClass::Window || surfTemp.Class == SurfaceClass::GlassDoor || surfTemp.Class == SurfaceClass::TDD_Diffuser ||
5252 472 : surfTemp.Class == SurfaceClass::TDD_Dome) {
5253 :
5254 6294 : if (surfTemp.ExtBoundCond == DataSurfaces::OtherSideCoefNoCalcExt || surfTemp.ExtBoundCond == DataSurfaces::OtherSideCoefCalcExt) {
5255 0 : ShowSevereError(
5256 : state,
5257 0 : format("{}=\"{}\", Other side coefficients are not allowed with windows.", s_ipsc->cCurrentModuleObject, surfTemp.Name));
5258 0 : ErrorsFound = true;
5259 : }
5260 :
5261 6294 : if (surfTemp.ExtBoundCond == DataSurfaces::Ground) {
5262 0 : ShowSevereError(state,
5263 0 : format("{}=\"{}\", Exterior boundary condition = Ground is not allowed with windows.",
5264 0 : s_ipsc->cCurrentModuleObject,
5265 0 : surfTemp.Name));
5266 0 : ErrorsFound = true;
5267 : }
5268 :
5269 6294 : if (surfTemp.ExtBoundCond == DataSurfaces::KivaFoundation) {
5270 0 : ShowSevereError(state,
5271 0 : format("{}=\"{}\", Exterior boundary condition = Foundation is not allowed with windows.",
5272 0 : s_ipsc->cCurrentModuleObject,
5273 0 : surfTemp.Name));
5274 0 : ErrorsFound = true;
5275 : }
5276 :
5277 6294 : InitialAssociateWindowShadingControlFenestration(state, ErrorsFound, SurfNum);
5278 :
5279 6294 : CheckWindowShadingControlFrameDivider(state, "GetHTSubSurfaceData", ErrorsFound, SurfNum, 6);
5280 :
5281 6294 : if (surfTemp.Sides == 3) { // Triangular window
5282 2 : if (!s_ipsc->cAlphaArgs(6).empty()) {
5283 0 : ShowWarningError(state,
5284 0 : format("{}=\"{}\", invalid {}=\"{}\".",
5285 0 : s_ipsc->cCurrentModuleObject,
5286 0 : surfTemp.Name,
5287 0 : s_ipsc->cAlphaFieldNames(6),
5288 0 : s_ipsc->cAlphaArgs(6)));
5289 0 : ShowContinueError(state, ".. because it is a triangular window and cannot have a frame or divider or reveal reflection.");
5290 0 : ShowContinueError(state, "Frame, divider and reveal reflection will be ignored for this window.");
5291 : }
5292 2 : surfTemp.FrameDivider = 0;
5293 : } // End of check if window is triangular or rectangular
5294 :
5295 : } // check on non-opaquedoor subsurfaces
5296 :
5297 6764 : CheckSubSurfaceMiscellaneous(
5298 6764 : state, "GetHTSubSurfaceData", ErrorsFound, SurfNum, s_ipsc->cAlphaArgs(1), s_ipsc->cAlphaArgs(3), AddedSubSurfaces);
5299 :
5300 : } // End of main loop over subsurfaces
5301 7565 : }
5302 :
5303 801 : void GetRectSubSurfaces(EnergyPlusData &state,
5304 : bool &ErrorsFound, // Error flag indicator (true if errors found)
5305 : int &SurfNum, // Count of Current SurfaceNumber
5306 : int const TotWindows, // Number of Window SubSurfaces to obtain
5307 : int const TotDoors, // Number of Door SubSurfaces to obtain
5308 : int const TotGlazedDoors, // Number of Glass Door SubSurfaces to obtain
5309 : int const TotIZWindows, // Number of Interzone Window SubSurfaces to obtain
5310 : int const TotIZDoors, // Number of Interzone Door SubSurfaces to obtain
5311 : int const TotIZGlazedDoors, // Number of Interzone Glass Door SubSurfaces to obtain
5312 : const Array1D<SurfaceClass> &SubSurfIDs, // ID Assignments for valid sub surface classes
5313 : int &AddedSubSurfaces, // Subsurfaces added when windows reference Window5
5314 : int &NeedToAddSubSurfaces // Number of surfaces to add, based on unentered IZ surfaces
5315 : )
5316 : {
5317 :
5318 : // SUBROUTINE INFORMATION:
5319 : // AUTHOR Linda Lawrie
5320 : // DATE WRITTEN December 2008
5321 :
5322 : // PURPOSE OF THIS SUBROUTINE:
5323 : // Get simple (rectangular, relative origin to base surface) windows, doors, glazed doors.
5324 :
5325 : // SUBROUTINE PARAMETER DEFINITIONS:
5326 801 : static Array1D_string const cModuleObjects(6, {"Window", "Door", "GlazedDoor", "Window:Interzone", "Door:Interzone", "GlazedDoor:Interzone"});
5327 :
5328 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
5329 : int ItemsToGet;
5330 : int Loop;
5331 : int NumAlphas;
5332 : int NumNumbers;
5333 : int IOStat; // IO Status when calling get input subroutine
5334 : int Found; // For matching base surfaces
5335 : bool GettingIZSurfaces;
5336 : int FrameField;
5337 : int OtherSurfaceField;
5338 : int ClassItem;
5339 : int IZFound;
5340 :
5341 801 : auto &s_ipsc = state.dataIPShortCut;
5342 5607 : for (int Item = 1; Item <= 6; ++Item) {
5343 :
5344 4806 : s_ipsc->cCurrentModuleObject = cModuleObjects(Item);
5345 4806 : if (Item == 1) {
5346 801 : ItemsToGet = TotWindows;
5347 801 : GettingIZSurfaces = false;
5348 801 : FrameField = 5;
5349 801 : OtherSurfaceField = 0;
5350 801 : ClassItem = 1;
5351 4005 : } else if (Item == 2) {
5352 801 : ItemsToGet = TotDoors;
5353 801 : GettingIZSurfaces = false;
5354 801 : FrameField = 0;
5355 801 : OtherSurfaceField = 0;
5356 801 : ClassItem = 2;
5357 3204 : } else if (Item == 3) {
5358 801 : ItemsToGet = TotGlazedDoors;
5359 801 : GettingIZSurfaces = false;
5360 801 : FrameField = 5;
5361 801 : OtherSurfaceField = 0;
5362 801 : ClassItem = 3;
5363 2403 : } else if (Item == 4) {
5364 801 : ItemsToGet = TotIZWindows;
5365 801 : GettingIZSurfaces = true;
5366 801 : FrameField = 0;
5367 801 : OtherSurfaceField = 4;
5368 801 : ClassItem = 1;
5369 1602 : } else if (Item == 5) {
5370 801 : ItemsToGet = TotIZDoors;
5371 801 : GettingIZSurfaces = true;
5372 801 : FrameField = 0;
5373 801 : OtherSurfaceField = 4;
5374 801 : ClassItem = 2;
5375 : } else { // Item = 6
5376 801 : ItemsToGet = TotIZGlazedDoors;
5377 801 : GettingIZSurfaces = true;
5378 801 : FrameField = 0;
5379 801 : OtherSurfaceField = 4;
5380 801 : ClassItem = 3;
5381 : }
5382 :
5383 4880 : for (Loop = 1; Loop <= ItemsToGet; ++Loop) {
5384 148 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
5385 74 : s_ipsc->cCurrentModuleObject,
5386 : Loop,
5387 74 : s_ipsc->cAlphaArgs,
5388 : NumAlphas,
5389 74 : s_ipsc->rNumericArgs,
5390 : NumNumbers,
5391 : IOStat,
5392 74 : s_ipsc->lNumericFieldBlanks,
5393 74 : s_ipsc->lAlphaFieldBlanks,
5394 74 : s_ipsc->cAlphaFieldNames,
5395 74 : s_ipsc->cNumericFieldNames);
5396 :
5397 148 : if (GlobalNames::VerifyUniqueInterObjectName(state,
5398 74 : state.dataSurfaceGeometry->UniqueSurfaceNames,
5399 74 : s_ipsc->cAlphaArgs(1),
5400 74 : s_ipsc->cCurrentModuleObject,
5401 74 : s_ipsc->cAlphaFieldNames(1),
5402 : ErrorsFound)) {
5403 0 : continue;
5404 : }
5405 :
5406 74 : if (NumNumbers < 5) {
5407 0 : ShowSevereError(
5408 : state,
5409 0 : format("{}=\"{}\", Too few number of numeric args=[{}].", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1), NumNumbers));
5410 0 : ErrorsFound = true;
5411 : }
5412 :
5413 74 : ++SurfNum;
5414 74 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
5415 :
5416 74 : surfTemp.Name = s_ipsc->cAlphaArgs(1); // Set the Surface Name in the Derived Type
5417 74 : surfTemp.Class = SubSurfIDs(ClassItem); // Set class number
5418 :
5419 74 : surfTemp.Construction =
5420 74 : Util::FindItemInList(s_ipsc->cAlphaArgs(2), state.dataConstruction->Construct, state.dataHeatBal->TotConstructs);
5421 :
5422 74 : if (surfTemp.Construction == 0) {
5423 0 : ErrorsFound = true;
5424 0 : ShowSevereError(state,
5425 0 : format("{}=\"{}\", invalid {}=\"{}\".",
5426 0 : s_ipsc->cCurrentModuleObject,
5427 0 : surfTemp.Name,
5428 0 : s_ipsc->cAlphaFieldNames(2),
5429 0 : s_ipsc->cAlphaArgs(2)));
5430 : } else {
5431 74 : state.dataConstruction->Construct(surfTemp.Construction).IsUsed = true;
5432 74 : surfTemp.ConstructionStoredInputValue = surfTemp.Construction;
5433 : }
5434 :
5435 74 : if (surfTemp.Class == SurfaceClass::Window || surfTemp.Class == SurfaceClass::GlassDoor) {
5436 :
5437 65 : if (surfTemp.Construction != 0) {
5438 65 : auto const &construction = state.dataConstruction->Construct(surfTemp.Construction);
5439 :
5440 65 : if (!construction.TypeIsWindow && !construction.TypeIsAirBoundary) {
5441 0 : ErrorsFound = true;
5442 0 : ShowSevereError(state,
5443 0 : format("{}=\"{}\" has an opaque surface construction; it should have a window construction.",
5444 0 : s_ipsc->cCurrentModuleObject,
5445 0 : surfTemp.Name));
5446 : }
5447 65 : if (state.dataConstruction->Construct(surfTemp.Construction).SourceSinkPresent) {
5448 0 : ErrorsFound = true;
5449 0 : ShowSevereError(state,
5450 0 : format("{}=\"{}\": Windows are not allowed to have embedded sources/sinks",
5451 0 : s_ipsc->cCurrentModuleObject,
5452 0 : surfTemp.Name));
5453 : }
5454 : }
5455 :
5456 74 : } else if (surfTemp.Construction != 0) {
5457 9 : if (state.dataConstruction->Construct(surfTemp.Construction).TypeIsWindow) {
5458 0 : ErrorsFound = true;
5459 0 : ShowSevereError(state,
5460 0 : format("{}=\"{}\", invalid {}=\"{}\" - has Window materials.",
5461 0 : s_ipsc->cCurrentModuleObject,
5462 0 : surfTemp.Name,
5463 0 : s_ipsc->cAlphaFieldNames(2),
5464 0 : s_ipsc->cAlphaArgs(2)));
5465 : }
5466 : }
5467 :
5468 74 : surfTemp.HeatTransSurf = true;
5469 :
5470 74 : surfTemp.BaseSurfName = s_ipsc->cAlphaArgs(3);
5471 : // The subsurface inherits properties from the base surface
5472 : // Exterior conditions, Zone, etc.
5473 : // We can figure out the base surface though, because they've all been entered
5474 74 : Found = Util::FindItemInList(surfTemp.BaseSurfName, state.dataSurfaceGeometry->SurfaceTmp, state.dataSurface->TotSurfaces);
5475 74 : if (Found > 0) {
5476 74 : surfTemp.BaseSurf = Found;
5477 74 : surfTemp.ExtBoundCond = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCond;
5478 74 : surfTemp.ExtBoundCondName = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCondName;
5479 74 : surfTemp.ExtSolar = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtSolar;
5480 74 : surfTemp.ExtWind = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtWind;
5481 74 : surfTemp.Tilt = state.dataSurfaceGeometry->SurfaceTmp(Found).Tilt;
5482 74 : surfTemp.convOrientation = Convect::GetSurfConvOrientation(surfTemp.Tilt);
5483 74 : surfTemp.Azimuth = state.dataSurfaceGeometry->SurfaceTmp(Found).Azimuth;
5484 74 : surfTemp.Zone = state.dataSurfaceGeometry->SurfaceTmp(Found).Zone;
5485 74 : surfTemp.ZoneName = state.dataSurfaceGeometry->SurfaceTmp(Found).ZoneName;
5486 74 : surfTemp.OSCPtr = state.dataSurfaceGeometry->SurfaceTmp(Found).OSCPtr;
5487 74 : surfTemp.ViewFactorGround = state.dataSurfaceGeometry->SurfaceTmp(Found).ViewFactorGround;
5488 74 : surfTemp.ViewFactorSky = state.dataSurfaceGeometry->SurfaceTmp(Found).ViewFactorSky;
5489 : } else {
5490 0 : ShowSevereError(state,
5491 0 : format("{}=\"{}\", invalid {}=\"{}",
5492 0 : s_ipsc->cCurrentModuleObject,
5493 0 : surfTemp.Name,
5494 0 : s_ipsc->cAlphaFieldNames(3),
5495 0 : s_ipsc->cAlphaArgs(3)));
5496 0 : surfTemp.ZoneName = "Unknown Zone";
5497 0 : ErrorsFound = true;
5498 0 : continue;
5499 : }
5500 82 : if (state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCond == unreconciledZoneSurface &&
5501 8 : state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCondName ==
5502 8 : state.dataSurfaceGeometry->SurfaceTmp(Found).Name) { // Adiabatic surface, no windows or doors allowed
5503 0 : ShowSevereError(state,
5504 0 : format("{}=\"{}\", invalid {}=\"{}\".",
5505 0 : s_ipsc->cCurrentModuleObject,
5506 0 : surfTemp.Name,
5507 0 : s_ipsc->cAlphaFieldNames(3),
5508 0 : s_ipsc->cAlphaArgs(3)));
5509 0 : ShowContinueError(state, "... adiabatic surfaces cannot have windows or doors.");
5510 0 : ShowContinueError(state,
5511 : "... no solar transmission will result for these windows or doors. You must have interior windows or doors on "
5512 : "Interzone surfaces for transmission to result.");
5513 : }
5514 :
5515 74 : if (surfTemp.ExtBoundCond == unreconciledZoneSurface) { // "Surface" Base Surface
5516 8 : if (!GettingIZSurfaces) {
5517 0 : ShowSevereError(state, format("{}=\"{}\", invalid use of object", s_ipsc->cCurrentModuleObject, surfTemp.Name));
5518 0 : ShowContinueError(
5519 : state,
5520 0 : format(
5521 : "...when Base surface uses \"Surface\" as {}, subsurfaces must also specify specific surfaces in the adjacent zone.",
5522 0 : s_ipsc->cAlphaFieldNames(5)));
5523 0 : ShowContinueError(state, format("...Please use {}:Interzone to enter this surface.", s_ipsc->cCurrentModuleObject));
5524 0 : surfTemp.ExtBoundCondName = BlankString; // putting it as blank will not confuse things later.
5525 0 : ErrorsFound = true;
5526 : }
5527 : }
5528 :
5529 74 : if (surfTemp.ExtBoundCond == unreconciledZoneSurface) { // "Surface" Base Surface
5530 8 : if (GettingIZSurfaces) {
5531 8 : surfTemp.ExtBoundCondName = s_ipsc->cAlphaArgs(OtherSurfaceField);
5532 8 : IZFound = Util::FindItemInList(surfTemp.ExtBoundCondName, state.dataHeatBal->Zone, state.dataGlobal->NumOfZones);
5533 8 : if (IZFound > 0) {
5534 0 : surfTemp.ExtBoundCond = unenteredAdjacentZoneSurface;
5535 : }
5536 : } else { // Interior Window
5537 0 : surfTemp.ExtBoundCondName = surfTemp.Name;
5538 : }
5539 : }
5540 :
5541 : // This is the parent's property:
5542 74 : if (surfTemp.ExtBoundCond == unenteredAdjacentZoneSurface) { // OtherZone - unmatched interior surface
5543 3 : if (GettingIZSurfaces) {
5544 3 : ++NeedToAddSubSurfaces;
5545 : } else { // Interior Window
5546 0 : ShowSevereError(state,
5547 0 : format("{}=\"{}\", invalid Interzone Surface, specify {}:InterZone",
5548 0 : s_ipsc->cCurrentModuleObject,
5549 0 : surfTemp.Name,
5550 0 : s_ipsc->cCurrentModuleObject));
5551 0 : ShowContinueError(state, "...when base surface is an interzone surface, subsurface must also be an interzone surface.");
5552 0 : ++NeedToAddSubSurfaces;
5553 0 : ErrorsFound = true;
5554 : }
5555 : }
5556 :
5557 74 : if (GettingIZSurfaces) {
5558 11 : if (s_ipsc->lAlphaFieldBlanks(OtherSurfaceField)) {
5559 : // blank -- set it up for unentered adjacent zone
5560 0 : if (surfTemp.ExtBoundCond == unenteredAdjacentZoneSurface) { // already set but need Zone
5561 0 : surfTemp.ExtBoundCondName = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCondName; // base surface has it
5562 0 : } else if (surfTemp.ExtBoundCond == unreconciledZoneSurface) {
5563 0 : surfTemp.ExtBoundCondName = state.dataSurfaceGeometry->SurfaceTmp(Found).ZoneName; // base surface has it
5564 0 : surfTemp.ExtBoundCond = unenteredAdjacentZoneSurface;
5565 : } else { // not correct boundary condition for interzone subsurface
5566 0 : ShowSevereError(
5567 : state,
5568 0 : format("{}=\"{}\", invalid Base Surface type for Interzone Surface", s_ipsc->cCurrentModuleObject, surfTemp.Name));
5569 0 : ShowContinueError(state,
5570 : "...when base surface is not an interzone surface, subsurface must also not be an interzone surface.");
5571 0 : ErrorsFound = true;
5572 : }
5573 : }
5574 : }
5575 :
5576 74 : if (surfTemp.ExtBoundCond == DataSurfaces::OtherSideCondModeledExt) {
5577 0 : surfTemp.ExtBoundCond = DataSurfaces::ExternalEnvironment;
5578 : }
5579 :
5580 : // SurfaceTmp(SurfNum)%ViewFactorGround = AutoCalculate
5581 :
5582 74 : surfTemp.Sides = 4;
5583 74 : surfTemp.Vertex.allocate(surfTemp.Sides);
5584 74 : if (surfTemp.Class == SurfaceClass::Window || surfTemp.Class == SurfaceClass::GlassDoor || surfTemp.Class == SurfaceClass::Door) {
5585 74 : surfTemp.Multiplier = int(s_ipsc->rNumericArgs(1));
5586 0 : } else if (s_ipsc->rNumericArgs(1) > 1.0) {
5587 0 : ShowWarningError(state,
5588 0 : format("{}=\"{}\", invalid {}=[{:.1T}].",
5589 0 : s_ipsc->cCurrentModuleObject,
5590 0 : surfTemp.Name,
5591 0 : s_ipsc->cNumericFieldNames(1),
5592 0 : s_ipsc->rNumericArgs(1)));
5593 0 : ShowContinueError(state,
5594 0 : format("...because {}={} multiplier will be set to 1.0.", s_ipsc->cAlphaFieldNames(1), s_ipsc->cAlphaArgs(1)));
5595 0 : surfTemp.Multiplier = 1.0;
5596 : }
5597 :
5598 296 : MakeRelativeRectangularVertices(state,
5599 : surfTemp.BaseSurf,
5600 : SurfNum,
5601 74 : s_ipsc->rNumericArgs(2),
5602 74 : s_ipsc->rNumericArgs(3),
5603 74 : s_ipsc->rNumericArgs(4),
5604 74 : s_ipsc->rNumericArgs(5));
5605 :
5606 74 : if (surfTemp.Area <= 0.0) {
5607 0 : ShowSevereError(
5608 : state,
5609 0 : format("{}=\"{}\", Surface Area <= 0.0; Entered Area={:.2T}", s_ipsc->cCurrentModuleObject, surfTemp.Name, surfTemp.Area));
5610 0 : ErrorsFound = true;
5611 : }
5612 :
5613 74 : surfTemp.windowShadingControlList.clear();
5614 74 : surfTemp.activeWindowShadingControl = 0;
5615 74 : surfTemp.HasShadeControl = false;
5616 :
5617 74 : surfTemp.shadedConstructionList.clear();
5618 74 : surfTemp.activeShadedConstruction = 0;
5619 74 : surfTemp.shadedStormWinConstructionList.clear();
5620 :
5621 74 : InitialAssociateWindowShadingControlFenestration(state, ErrorsFound, SurfNum);
5622 :
5623 74 : if (!GettingIZSurfaces && (surfTemp.Class == SurfaceClass::Window || surfTemp.Class == SurfaceClass::GlassDoor)) {
5624 :
5625 55 : if (surfTemp.ExtBoundCond == DataSurfaces::OtherSideCoefNoCalcExt ||
5626 55 : surfTemp.ExtBoundCond == DataSurfaces::OtherSideCoefCalcExt) {
5627 0 : ShowSevereError(
5628 : state,
5629 0 : format("{}=\"{}\", Other side coefficients are not allowed with windows.", s_ipsc->cCurrentModuleObject, surfTemp.Name));
5630 0 : ErrorsFound = true;
5631 : }
5632 :
5633 55 : if (surfTemp.ExtBoundCond == DataSurfaces::Ground) {
5634 0 : ShowSevereError(state,
5635 0 : format("{}=\"{}\", Exterior boundary condition = Ground is not allowed with windows.",
5636 0 : s_ipsc->cCurrentModuleObject,
5637 0 : surfTemp.Name));
5638 0 : ErrorsFound = true;
5639 : }
5640 :
5641 55 : CheckWindowShadingControlFrameDivider(state, "GetRectSubSurfaces", ErrorsFound, SurfNum, FrameField);
5642 :
5643 : } // check on non-opaquedoor subsurfaces
5644 :
5645 74 : CheckSubSurfaceMiscellaneous(
5646 74 : state, "GetRectSubSurfaces", ErrorsFound, SurfNum, s_ipsc->cAlphaArgs(1), s_ipsc->cAlphaArgs(2), AddedSubSurfaces);
5647 :
5648 : } // Getting Items
5649 : }
5650 801 : }
5651 :
5652 6349 : void CheckWindowShadingControlFrameDivider(EnergyPlusData &state,
5653 : std::string_view const cRoutineName, // routine name calling this one (for error messages)
5654 : bool &ErrorsFound, // true if errors have been found or are found here
5655 : int const SurfNum, // current surface number
5656 : int const FrameField // field number for frame/divider
5657 : )
5658 : {
5659 :
5660 : // SUBROUTINE INFORMATION:
5661 : // AUTHOR Linda Lawrie
5662 : // DATE WRITTEN December 2008
5663 :
5664 : // PURPOSE OF THIS SUBROUTINE:
5665 : // This routine performs checks on WindowShadingControl settings and Frame/Divider Settings.
5666 :
5667 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
5668 : int ConstrNumSh; // Construction number with Shade
5669 : int ShDevNum; // Shading Device number
5670 : int Lay; // Layer number
5671 : int TotGlassLayers; // Number of glass layers in window construction
5672 : int TotLayers; // Number of layers in unshaded construction
5673 : int TotShLayers; // Number of layers in shaded construction
5674 : int MatGap; // Gap material number
5675 : int MatGap1; // Material number of gap to left (outer side) of between-glass shade/blind
5676 : int MatGap2; // Material number of gap to right (inner side) of between-glass shade/blind
5677 : int MatSh; // Between-glass shade/blind material number
5678 : Real64 MatGapCalc; // Calculated MatGap diff for shaded vs non-shaded constructions
5679 :
5680 : // If WindowShadingControl has been specified for this window --
5681 : // Set shaded construction number if shaded construction was specified in WindowShadingControl.
5682 : // Otherwise, create shaded construction if WindowShadingControl for this window has
5683 : // interior or exterior shade/blind (but not between-glass shade/blind) specified.
5684 :
5685 6349 : auto &s_ipsc = state.dataIPShortCut;
5686 6349 : auto &s_mat = state.dataMaterial;
5687 :
5688 6349 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
5689 :
5690 6504 : for (std::size_t shadeControlIndex = 0; shadeControlIndex < surfTemp.windowShadingControlList.size(); ++shadeControlIndex) {
5691 155 : int WSCPtr = surfTemp.windowShadingControlList[shadeControlIndex];
5692 155 : ConstrNumSh = 0;
5693 155 : if (!ErrorsFound && surfTemp.HasShadeControl) {
5694 155 : ConstrNumSh = surfTemp.shadedConstructionList[shadeControlIndex];
5695 155 : if (ConstrNumSh > 0) {
5696 137 : surfTemp.activeShadedConstruction = ConstrNumSh;
5697 18 : } else if (ANY_INTERIOR_SHADE_BLIND(state.dataSurface->WindowShadingControl(WSCPtr).ShadingType) ||
5698 0 : ANY_EXTERIOR_SHADE_BLIND_SCREEN(state.dataSurface->WindowShadingControl(WSCPtr).ShadingType)) {
5699 18 : ShDevNum = state.dataSurface->WindowShadingControl(WSCPtr).ShadingDevice;
5700 18 : if (ShDevNum > 0) {
5701 18 : CreateShadedWindowConstruction(state, SurfNum, WSCPtr, ShDevNum, shadeControlIndex);
5702 18 : ConstrNumSh = surfTemp.activeShadedConstruction;
5703 : }
5704 : }
5705 : }
5706 :
5707 : // Error checks for shades and blinds
5708 :
5709 155 : int ConstrNum = surfTemp.Construction;
5710 155 : if (!ErrorsFound && WSCPtr > 0 && ConstrNum > 0 && ConstrNumSh > 0) {
5711 :
5712 155 : if (ANY_INTERIOR_SHADE_BLIND(state.dataSurface->WindowShadingControl(WSCPtr).ShadingType)) {
5713 88 : TotLayers = state.dataConstruction->Construct(ConstrNum).TotLayers;
5714 88 : TotShLayers = state.dataConstruction->Construct(ConstrNumSh).TotLayers;
5715 88 : if (TotShLayers - 1 != TotLayers) {
5716 0 : ShowWarningError(
5717 : state,
5718 : "WindowShadingControl: Interior shade or blind: Potential problem in match of unshaded/shaded constructions, "
5719 : "shaded should have 1 more layers than unshaded.");
5720 0 : ShowContinueError(state, format("Unshaded construction={}", state.dataConstruction->Construct(ConstrNum).Name));
5721 0 : ShowContinueError(state, format("Shaded construction={}", state.dataConstruction->Construct(ConstrNumSh).Name));
5722 0 : ShowContinueError(state,
5723 : "If preceding two constructions are same name, you have likely specified a WindowShadingControl (Field #3) "
5724 : "with the Window Construction rather than a shaded construction.");
5725 : }
5726 248 : for (Lay = 1; Lay <= state.dataConstruction->Construct(ConstrNum).TotLayers; ++Lay) {
5727 160 : if (state.dataConstruction->Construct(ConstrNum).LayerPoint(Lay) !=
5728 160 : state.dataConstruction->Construct(ConstrNumSh).LayerPoint(Lay)) {
5729 0 : ErrorsFound = true;
5730 0 : ShowSevereError(state,
5731 0 : format(" The glass and gas layers in the shaded and unshaded constructions do not match for window={}",
5732 0 : surfTemp.Name));
5733 0 : ShowContinueError(state, format("Unshaded construction={}", state.dataConstruction->Construct(ConstrNum).Name));
5734 0 : ShowContinueError(state, format("Shaded construction={}", state.dataConstruction->Construct(ConstrNumSh).Name));
5735 0 : break;
5736 : }
5737 : }
5738 : }
5739 :
5740 155 : if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(state.dataSurface->WindowShadingControl(WSCPtr).ShadingType)) {
5741 28 : TotLayers = state.dataConstruction->Construct(ConstrNum).TotLayers;
5742 28 : TotShLayers = state.dataConstruction->Construct(ConstrNumSh).TotLayers;
5743 28 : if (TotShLayers - 1 != TotLayers) {
5744 0 : ShowWarningError(state,
5745 : "WindowShadingControl: Exterior shade, screen or blind: Potential problem in match of unshaded/shaded "
5746 : "constructions, shaded should have 1 more layer than unshaded.");
5747 0 : ShowContinueError(state, format("Unshaded construction={}", state.dataConstruction->Construct(ConstrNum).Name));
5748 0 : ShowContinueError(state, format("Shaded construction={}", state.dataConstruction->Construct(ConstrNumSh).Name));
5749 0 : ShowContinueError(
5750 : state,
5751 : "If preceding two constructions have the same name, you have likely specified a WindowShadingControl (Field "
5752 : "#3) with the Window Construction rather than a shaded construction.");
5753 : }
5754 76 : for (Lay = 1; Lay <= state.dataConstruction->Construct(ConstrNum).TotLayers; ++Lay) {
5755 48 : if (state.dataConstruction->Construct(ConstrNum).LayerPoint(Lay) !=
5756 48 : state.dataConstruction->Construct(ConstrNumSh).LayerPoint(Lay + 1)) {
5757 0 : ErrorsFound = true;
5758 0 : ShowSevereError(state,
5759 0 : format(" The glass and gas layers in the shaded and unshaded constructions do not match for window={}",
5760 0 : surfTemp.Name));
5761 0 : ShowContinueError(state, format("Unshaded construction={}", state.dataConstruction->Construct(ConstrNum).Name));
5762 0 : ShowContinueError(state, format("Shaded construction={}", state.dataConstruction->Construct(ConstrNumSh).Name));
5763 0 : break;
5764 : }
5765 : }
5766 : }
5767 :
5768 155 : if (ANY_BETWEENGLASS_SHADE_BLIND(state.dataSurface->WindowShadingControl(WSCPtr).ShadingType)) {
5769 : // Divider not allowed with between-glass shade or blind
5770 9 : if (surfTemp.FrameDivider > 0) {
5771 0 : if (state.dataSurface->FrameDivider(surfTemp.FrameDivider).DividerWidth > 0.0) {
5772 0 : ShowWarningError(state, format("A divider cannot be specified for window {}", surfTemp.Name));
5773 0 : ShowContinueError(state, ", which has a between-glass shade or blind.");
5774 0 : ShowContinueError(state, "Calculation will proceed without the divider for this window.");
5775 0 : state.dataSurface->FrameDivider(surfTemp.FrameDivider).DividerWidth = 0.0;
5776 : }
5777 : }
5778 : // Check consistency of gap widths between unshaded and shaded constructions
5779 9 : TotGlassLayers = state.dataConstruction->Construct(ConstrNum).TotGlassLayers;
5780 9 : TotLayers = state.dataConstruction->Construct(ConstrNum).TotLayers;
5781 9 : TotShLayers = state.dataConstruction->Construct(ConstrNumSh).TotLayers;
5782 9 : if (TotShLayers - 2 != TotLayers) {
5783 0 : ShowWarningError(
5784 : state,
5785 : "WindowShadingControl: Between Glass Shade/Blind: Potential problem in match of unshaded/shaded constructions, "
5786 : "shaded should have 2 more layers than unshaded.");
5787 0 : ShowContinueError(state, format("Unshaded construction={}", state.dataConstruction->Construct(ConstrNum).Name));
5788 0 : ShowContinueError(state, format("Shaded construction={}", state.dataConstruction->Construct(ConstrNumSh).Name));
5789 0 : ShowContinueError(state,
5790 : "If preceding two constructions are same name, you have likely specified a WindowShadingControl (Field #3) "
5791 : "with the Window Construction rather than a shaded construction.");
5792 : }
5793 9 : if (state.dataConstruction->Construct(ConstrNum).LayerPoint(TotLayers) !=
5794 9 : state.dataConstruction->Construct(ConstrNumSh).LayerPoint(TotShLayers)) {
5795 0 : ShowSevereError(state, format("{}: Mis-match in unshaded/shaded inside layer materials. These should match.", cRoutineName));
5796 0 : ShowContinueError(state,
5797 0 : format("Unshaded construction={}, Material={}",
5798 0 : state.dataConstruction->Construct(ConstrNum).Name,
5799 0 : s_mat->materials(state.dataConstruction->Construct(ConstrNum).LayerPoint(TotLayers))->Name));
5800 0 : ShowContinueError(state,
5801 0 : format("Shaded construction={}, Material={}",
5802 0 : state.dataConstruction->Construct(ConstrNumSh).Name,
5803 0 : s_mat->materials(state.dataConstruction->Construct(ConstrNumSh).LayerPoint(TotShLayers))->Name));
5804 0 : ErrorsFound = true;
5805 : }
5806 9 : if (state.dataConstruction->Construct(ConstrNum).LayerPoint(1) != state.dataConstruction->Construct(ConstrNumSh).LayerPoint(1)) {
5807 0 : ShowSevereError(state, format("{}: Mis-match in unshaded/shaded inside layer materials. These should match.", cRoutineName));
5808 0 : ShowContinueError(state,
5809 0 : format("Unshaded construction={}, Material={}",
5810 0 : state.dataConstruction->Construct(ConstrNum).Name,
5811 0 : s_mat->materials(state.dataConstruction->Construct(ConstrNum).LayerPoint(1))->Name));
5812 0 : ShowContinueError(state,
5813 0 : format("Shaded construction={}, Material={}",
5814 0 : state.dataConstruction->Construct(ConstrNumSh).Name,
5815 0 : s_mat->materials(state.dataConstruction->Construct(ConstrNumSh).LayerPoint(1))->Name));
5816 0 : ErrorsFound = true;
5817 : }
5818 9 : if (TotGlassLayers == 2 || TotGlassLayers == 3) {
5819 9 : MatGap = state.dataConstruction->Construct(ConstrNum).LayerPoint(2 * TotGlassLayers - 2);
5820 9 : MatGap1 = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(2 * TotGlassLayers - 2);
5821 9 : MatGap2 = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(2 * TotGlassLayers);
5822 9 : MatSh = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(2 * TotGlassLayers - 1);
5823 9 : if (state.dataSurface->WindowShadingControl(WSCPtr).ShadingType == DataSurfaces::WinShadingType::BGBlind) {
5824 5 : MatGapCalc = std::abs(s_mat->materials(MatGap)->Thickness -
5825 5 : (s_mat->materials(MatGap1)->Thickness + s_mat->materials(MatGap2)->Thickness));
5826 5 : if (MatGapCalc > 0.001) {
5827 0 : ShowSevereError(state,
5828 0 : format("{}: The gap width(s) for the unshaded window construction {}",
5829 : cRoutineName,
5830 0 : state.dataConstruction->Construct(ConstrNum).Name));
5831 0 : ShowContinueError(state,
5832 0 : "are inconsistent with the gap widths for shaded window construction " +
5833 0 : state.dataConstruction->Construct(ConstrNumSh).Name);
5834 0 : ShowContinueError(state, "for window " + surfTemp.Name + ", which has a between-glass blind.");
5835 0 : ShowContinueError(
5836 : state,
5837 0 : format("..Material={} thickness={:.3R} -", s_mat->materials(MatGap)->Name, s_mat->materials(MatGap)->Thickness));
5838 0 : ShowContinueError(state,
5839 0 : format("..( Material={} thickness={:.3R} +",
5840 0 : s_mat->materials(MatGap1)->Name,
5841 0 : s_mat->materials(MatGap1)->Thickness));
5842 0 : ShowContinueError(state,
5843 0 : format("..Material={} thickness={:.3R} )=[{:.3R}] >.001",
5844 0 : s_mat->materials(MatGap2)->Name,
5845 0 : s_mat->materials(MatGap2)->Thickness,
5846 : MatGapCalc));
5847 0 : ErrorsFound = true;
5848 : }
5849 : } else { // Between-glass shade
5850 8 : MatGapCalc = std::abs(
5851 4 : s_mat->materials(MatGap)->Thickness -
5852 4 : (s_mat->materials(MatGap1)->Thickness + s_mat->materials(MatGap2)->Thickness + s_mat->materials(MatSh)->Thickness));
5853 4 : if (MatGapCalc > 0.001) {
5854 0 : ShowSevereError(state,
5855 0 : format("{}: The gap width(s) for the unshaded window construction {}",
5856 : cRoutineName,
5857 0 : state.dataConstruction->Construct(ConstrNum).Name));
5858 0 : ShowContinueError(state,
5859 0 : "are inconsistent with the gap widths for shaded window construction " +
5860 0 : state.dataConstruction->Construct(ConstrNumSh).Name);
5861 0 : ShowContinueError(state, "for window " + surfTemp.Name + ", which has a between-glass shade.");
5862 0 : ShowContinueError(
5863 : state,
5864 0 : format("..Material={} thickness={:.3R} -", s_mat->materials(MatGap)->Name, s_mat->materials(MatGap)->Thickness));
5865 0 : ShowContinueError(state,
5866 0 : format("...( Material={} thickness={:.3R} +",
5867 0 : s_mat->materials(MatGap1)->Name,
5868 0 : s_mat->materials(MatGap1)->Thickness));
5869 0 : ShowContinueError(state,
5870 0 : format("..Material={} thickness={:.3R} +",
5871 0 : s_mat->materials(MatGap2)->Name,
5872 0 : s_mat->materials(MatGap2)->Thickness));
5873 0 : ShowContinueError(state,
5874 0 : format("..Material={} thickness={:.3R} )=[{:.3R}] >.001",
5875 0 : s_mat->materials(MatSh)->Name,
5876 0 : s_mat->materials(MatSh)->Thickness,
5877 : MatGapCalc));
5878 0 : ErrorsFound = true;
5879 : }
5880 : }
5881 : }
5882 : }
5883 : }
5884 : }
5885 :
5886 6349 : if (surfTemp.Sides != 3) { // Rectangular Window
5887 : // Initialize the FrameDivider number for this window. W5FrameDivider will be positive if
5888 : // this window's construction came from the Window5 data file and that construction had an
5889 : // associated frame or divider. It will be zero if the window's construction is not from the
5890 : // Window5 data file, or the construction is from the data file, but the construction has no
5891 : // associated frame or divider. Note that if there is a FrameDivider candidate for this
5892 : // window from the Window5 data file it is used instead of the window's input FrameDivider.
5893 :
5894 6347 : if (surfTemp.Construction != 0) {
5895 6347 : surfTemp.FrameDivider = state.dataConstruction->Construct(surfTemp.Construction).W5FrameDivider;
5896 :
5897 : // Warning if FrameAndDivider for this window is over-ridden by one from Window5 Data File
5898 6347 : if (surfTemp.FrameDivider > 0 && !s_ipsc->lAlphaFieldBlanks(FrameField)) {
5899 0 : ShowSevereError(state,
5900 0 : format("{}=\"{}\", {}=\"{}\"",
5901 0 : s_ipsc->cCurrentModuleObject,
5902 0 : surfTemp.Name,
5903 0 : s_ipsc->cAlphaFieldNames(FrameField),
5904 0 : s_ipsc->cAlphaArgs(FrameField)));
5905 0 : ShowContinueError(state,
5906 0 : format("will be replaced with FrameAndDivider from Window5 Data File entry {}",
5907 0 : state.dataConstruction->Construct(surfTemp.Construction).Name));
5908 : }
5909 :
5910 6347 : if (!s_ipsc->lAlphaFieldBlanks(FrameField) && surfTemp.FrameDivider == 0) {
5911 373 : surfTemp.FrameDivider = Util::FindItemInList(s_ipsc->cAlphaArgs(FrameField), state.dataSurface->FrameDivider);
5912 373 : if (surfTemp.FrameDivider == 0) {
5913 0 : if (!state.dataConstruction->Construct(surfTemp.Construction).WindowTypeEQL) {
5914 0 : ShowSevereError(state,
5915 0 : format("{}=\"{}\", invalid {}=\"{}\"",
5916 0 : s_ipsc->cCurrentModuleObject,
5917 0 : surfTemp.Name,
5918 0 : s_ipsc->cAlphaFieldNames(FrameField),
5919 0 : s_ipsc->cAlphaArgs(FrameField)));
5920 0 : ErrorsFound = true;
5921 : } else {
5922 0 : ShowSevereError(state,
5923 0 : format("{}=\"{}\", invalid {}=\"{}\"",
5924 0 : s_ipsc->cCurrentModuleObject,
5925 0 : surfTemp.Name,
5926 0 : s_ipsc->cAlphaFieldNames(FrameField),
5927 0 : s_ipsc->cAlphaArgs(FrameField)));
5928 0 : ShowContinueError(state, "...Frame/Divider is not supported in Equivalent Layer Window model.");
5929 : }
5930 : }
5931 : // Divider not allowed with between-glass shade or blind
5932 414 : for (int WSCPtr : surfTemp.windowShadingControlList) {
5933 41 : if (!ErrorsFound && WSCPtr > 0 && ConstrNumSh > 0) {
5934 41 : if (ANY_BETWEENGLASS_SHADE_BLIND(state.dataSurface->WindowShadingControl(WSCPtr).ShadingType)) {
5935 1 : if (surfTemp.FrameDivider > 0) {
5936 1 : if (state.dataSurface->FrameDivider(surfTemp.FrameDivider).DividerWidth > 0.0) {
5937 0 : ShowSevereError(state,
5938 0 : format("{}=\"{}\", invalid {}=\"{}\"",
5939 0 : s_ipsc->cCurrentModuleObject,
5940 0 : surfTemp.Name,
5941 0 : s_ipsc->cAlphaFieldNames(FrameField),
5942 0 : s_ipsc->cAlphaArgs(FrameField)));
5943 0 : ShowContinueError(state,
5944 : "Divider cannot be specified because the construction has a between-glass shade or blind.");
5945 0 : ShowContinueError(state, "Calculation will proceed without the divider for this window.");
5946 0 : ShowContinueError(
5947 : state,
5948 0 : format("Divider width = [{:.2R}].", state.dataSurface->FrameDivider(surfTemp.FrameDivider).DividerWidth));
5949 0 : state.dataSurface->FrameDivider(surfTemp.FrameDivider).DividerWidth = 0.0;
5950 : }
5951 : } // End of check if window has divider
5952 : } // End of check if window has a between-glass shade or blind
5953 : } // End of check if window has a shaded construction
5954 373 : } // end of looping through window shading controls of window
5955 : } // End of check if window has an associated FrameAndDivider
5956 : } // End of check if window has a construction
5957 : }
5958 :
5959 6349 : if (state.dataConstruction->Construct(surfTemp.Construction).WindowTypeEQL) {
5960 3 : if (surfTemp.FrameDivider > 0) {
5961 : // Equivalent Layer window does not have frame/divider model
5962 0 : ShowSevereError(state,
5963 0 : format("{}=\"{}\", invalid {}=\"{}\"",
5964 0 : s_ipsc->cCurrentModuleObject,
5965 0 : surfTemp.Name,
5966 0 : s_ipsc->cAlphaFieldNames(FrameField),
5967 0 : s_ipsc->cAlphaArgs(FrameField)));
5968 0 : ShowContinueError(state, "Frame/Divider is not supported in Equivalent Layer Window model.");
5969 0 : surfTemp.FrameDivider = 0;
5970 : }
5971 : }
5972 6349 : }
5973 :
5974 6838 : void CheckSubSurfaceMiscellaneous(EnergyPlusData &state,
5975 : std::string_view const cRoutineName, // routine name calling this one (for error messages)
5976 : bool &ErrorsFound, // true if errors have been found or are found here
5977 : int const SurfNum, // current surface number
5978 : std::string const &SubSurfaceName, // name of the surface
5979 : std::string const &SubSurfaceConstruction, // name of the construction
5980 : int &AddedSubSurfaces)
5981 : {
5982 :
5983 : // SUBROUTINE INFORMATION:
5984 : // AUTHOR Linda Lawrie
5985 : // DATE WRITTEN December 2008
5986 :
5987 : // PURPOSE OF THIS SUBROUTINE:
5988 : // This routine performs miscellaneous checks on subsurfaces: Windows, GlassDoors, Doors, Tubular Devices.
5989 :
5990 6838 : auto &s_mat = state.dataMaterial;
5991 : // Warning if window has multiplier > 1 and SolarDistribution = FullExterior or FullInteriorExterior
5992 :
5993 6838 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
5994 1023 : if ((surfTemp.Class == SurfaceClass::Window || surfTemp.Class == SurfaceClass::GlassDoor) &&
5995 13417 : static_cast<int>(state.dataHeatBal->SolarDistribution) > static_cast<int>(DataHeatBalance::Shadowing::Minimal) &&
5996 5556 : surfTemp.Multiplier > 1.0) {
5997 6 : if (state.dataGlobal->DisplayExtraWarnings) {
5998 0 : ShowWarningError(state, format("{}: A Multiplier > 1.0 for window/glass door {}", cRoutineName, surfTemp.Name));
5999 0 : ShowContinueError(state, "in conjunction with SolarDistribution = FullExterior or FullInteriorExterior");
6000 0 : ShowContinueError(state, "can cause inaccurate shadowing on the window and/or");
6001 0 : ShowContinueError(state, "inaccurate interior solar distribution from the window.");
6002 : }
6003 6 : ++state.dataErrTracking->TotalMultipliedWindows;
6004 : }
6005 :
6006 : // Require that a construction referenced by a surface that is a window
6007 : // NOT have a shading device layer; use WindowShadingControl to specify a shading device.
6008 :
6009 6838 : int ConstrNum = surfTemp.Construction;
6010 6838 : if (ConstrNum > 0) {
6011 6838 : int NumShades = 0;
6012 17886 : for (int Lay = 1; Lay <= state.dataConstruction->Construct(ConstrNum).TotLayers; ++Lay) {
6013 11048 : int LayerPtr = state.dataConstruction->Construct(ConstrNum).LayerPoint(Lay);
6014 11048 : if (LayerPtr == 0) {
6015 0 : continue; // Error is caught already, will terminate later
6016 : }
6017 22096 : if (s_mat->materials(LayerPtr)->group == Material::Group::Shade || s_mat->materials(LayerPtr)->group == Material::Group::Blind ||
6018 11048 : s_mat->materials(LayerPtr)->group == Material::Group::Screen) {
6019 0 : ++NumShades;
6020 : }
6021 : }
6022 6838 : if (NumShades != 0) {
6023 0 : ShowSevereError(state, format("{}: Window \"{}\" must not directly reference", cRoutineName, SubSurfaceName));
6024 0 : ShowContinueError(state, format("a Construction (i.e, \"{}\") with a shading device.", SubSurfaceConstruction));
6025 0 : ShowContinueError(state, "Use WindowShadingControl to specify a shading device for a window.");
6026 0 : ErrorsFound = true;
6027 : }
6028 : }
6029 :
6030 : // Disallow glass transmittance dirt factor for interior windows and glass doors
6031 :
6032 6838 : if (surfTemp.ExtBoundCond != DataSurfaces::ExternalEnvironment &&
6033 91 : (surfTemp.Class == SurfaceClass::Window || surfTemp.Class == SurfaceClass::GlassDoor)) {
6034 12 : ConstrNum = surfTemp.Construction;
6035 12 : if (ConstrNum > 0) {
6036 24 : for (int Lay = 1; Lay <= state.dataConstruction->Construct(ConstrNum).TotLayers; ++Lay) {
6037 12 : int LayerPtr = state.dataConstruction->Construct(ConstrNum).LayerPoint(Lay);
6038 12 : auto const *mat = s_mat->materials(LayerPtr);
6039 12 : if (mat->group != Material::Group::Glass) {
6040 0 : continue;
6041 : }
6042 :
6043 12 : if (dynamic_cast<Material::MaterialGlass const *>(mat)->GlassTransDirtFactor < 1.0) {
6044 0 : ShowSevereError(state, format("{}: Interior Window or GlassDoor {} has a glass layer with", cRoutineName, SubSurfaceName));
6045 0 : ShowContinueError(state, "Dirt Correction Factor for Solar and Visible Transmittance < 1.0");
6046 0 : ShowContinueError(state, "A value less than 1.0 for this factor is only allowed for exterior windows and glass doors.");
6047 0 : ErrorsFound = true;
6048 : }
6049 : }
6050 : }
6051 : }
6052 :
6053 : // If this is a window with a construction from the Window5DataFile, call routine that will
6054 : // (1) if one glazing system on Data File, give warning message if window height or width
6055 : // differ by more than 10% from those of the glazing system on the Data File;
6056 : // (2) if two glazing systems (separated by a mullion) on Data File, create a second window
6057 : // and adjust the dimensions of the original and second windows to those on the Data File
6058 :
6059 6838 : if (surfTemp.Construction != 0) {
6060 :
6061 6838 : if (state.dataConstruction->Construct(surfTemp.Construction).FromWindow5DataFile) {
6062 :
6063 8 : ModifyWindow(state, SurfNum, ErrorsFound, AddedSubSurfaces);
6064 :
6065 : } else {
6066 : // Calculate net area for base surface (note that ModifyWindow, above, adjusts net area of
6067 : // base surface for case where window construction is from Window5 Data File
6068 : // In case there is in error in this window's base surface (i.e. none)..
6069 6830 : if (surfTemp.BaseSurf > 0) {
6070 6830 : state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).Area -= surfTemp.Area;
6071 :
6072 : // Subtract TDD:DIFFUSER area from other side interzone surface
6073 6832 : if ((surfTemp.Class == SurfaceClass::TDD_Diffuser) &&
6074 2 : not_blank(
6075 2 : state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).ExtBoundCondName)) { // Base surface is an interzone surface
6076 : // Lookup interzone surface of the base surface
6077 : // (Interzone surfaces have not been assigned yet, but all base surfaces should already be loaded.)
6078 2 : int Found = Util::FindItemInList(state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).ExtBoundCondName,
6079 2 : state.dataSurfaceGeometry->SurfaceTmp,
6080 : SurfNum);
6081 2 : if (Found != 0) {
6082 2 : state.dataSurfaceGeometry->SurfaceTmp(Found).Area -= surfTemp.Area;
6083 : }
6084 : }
6085 6830 : if (state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).Area <= 0.0) {
6086 0 : ShowSevereError(state,
6087 0 : format("{}: Surface Openings have too much area for base surface={}",
6088 : cRoutineName,
6089 0 : state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).Name));
6090 0 : ShowContinueError(state, format("Opening Surface creating error={}", surfTemp.Name));
6091 0 : ErrorsFound = true;
6092 : }
6093 : // Net area of base surface with unity window multipliers (used in shadowing checks)
6094 : // For Windows, Glass Doors and Doors, just one area is subtracted. For the rest, should be
6095 : // full area.
6096 6830 : if (surfTemp.Class == SurfaceClass::Window || surfTemp.Class == SurfaceClass::GlassDoor) {
6097 6347 : state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).NetAreaShadowCalc -= surfTemp.Area / surfTemp.Multiplier;
6098 483 : } else if (surfTemp.Class == SurfaceClass::Door) { // Door, TDD:Diffuser, TDD:DOME
6099 479 : state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).NetAreaShadowCalc -= surfTemp.Area / surfTemp.Multiplier;
6100 : } else {
6101 4 : state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).NetAreaShadowCalc -= surfTemp.Area;
6102 : }
6103 : }
6104 : }
6105 : }
6106 6838 : }
6107 :
6108 118 : void MakeRelativeRectangularVertices(EnergyPlusData &state,
6109 : int const BaseSurfNum, // Base surface
6110 : int const SurfNum,
6111 : Real64 const XCoord,
6112 : Real64 const ZCoord,
6113 : Real64 const Length,
6114 : Real64 const Height)
6115 : {
6116 :
6117 : // SUBROUTINE INFORMATION:
6118 : // AUTHOR Linda Lawrie
6119 : // DATE WRITTEN December 2008
6120 :
6121 : // PURPOSE OF THIS SUBROUTINE:
6122 : // This routine creates world/3d coordinates for rectangular surfaces using relative X and Z, length & height.
6123 :
6124 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
6125 118 : Array1D<Real64> XX(4);
6126 118 : Array1D<Real64> YY(4);
6127 : Real64 Perimeter;
6128 : int Vrt;
6129 :
6130 118 : if (BaseSurfNum == 0) {
6131 0 : return; // invalid base surface, don't bother
6132 : }
6133 :
6134 : // Tilt and Facing (Azimuth) will be same as the Base Surface
6135 :
6136 118 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
6137 118 : surfTemp.Height = Height;
6138 118 : surfTemp.Width = Length;
6139 :
6140 118 : Real64 SurfAzimuth = surfTemp.Azimuth;
6141 118 : Real64 SurfTilt = surfTemp.Tilt;
6142 118 : Real64 CosSurfAzimuth = std::cos(SurfAzimuth * Constant::DegToRad);
6143 118 : Real64 SinSurfAzimuth = std::sin(SurfAzimuth * Constant::DegToRad);
6144 118 : Real64 CosSurfTilt = std::cos(SurfTilt * Constant::DegToRad);
6145 118 : Real64 SinSurfTilt = std::sin(SurfTilt * Constant::DegToRad);
6146 118 : Real64 BaseCosSurfAzimuth = state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosAzim;
6147 118 : Real64 BaseSinSurfAzimuth = state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).SinAzim;
6148 118 : Real64 BaseCosSurfTilt = state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosTilt;
6149 118 : Real64 BaseSinSurfTilt = state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).SinTilt;
6150 :
6151 118 : Real64 XLLC = state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).x - XCoord * BaseCosSurfAzimuth -
6152 118 : ZCoord * BaseCosSurfTilt * BaseSinSurfAzimuth;
6153 118 : Real64 YLLC = state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).y + XCoord * BaseSinSurfAzimuth -
6154 118 : ZCoord * BaseCosSurfTilt * BaseCosSurfAzimuth;
6155 118 : Real64 ZLLC = state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).z + ZCoord * BaseSinSurfTilt;
6156 :
6157 118 : XX(1) = 0.0;
6158 118 : XX(2) = 0.0;
6159 118 : XX(3) = Length;
6160 118 : XX(4) = Length;
6161 118 : YY(1) = Height;
6162 118 : YY(4) = Height;
6163 118 : YY(3) = 0.0;
6164 118 : YY(2) = 0.0;
6165 :
6166 590 : for (int n = 1; n <= surfTemp.Sides; ++n) {
6167 472 : Vrt = n;
6168 472 : surfTemp.Vertex(Vrt).x = XLLC - XX(n) * CosSurfAzimuth - YY(n) * CosSurfTilt * SinSurfAzimuth;
6169 472 : surfTemp.Vertex(Vrt).y = YLLC + XX(n) * SinSurfAzimuth - YY(n) * CosSurfTilt * CosSurfAzimuth;
6170 472 : surfTemp.Vertex(Vrt).z = ZLLC + YY(n) * SinSurfTilt;
6171 : }
6172 :
6173 118 : Vectors::CreateNewellAreaVector(surfTemp.Vertex, surfTemp.Sides, surfTemp.NewellAreaVector);
6174 118 : surfTemp.GrossArea = Vectors::VecLength(surfTemp.NewellAreaVector);
6175 118 : surfTemp.Area = surfTemp.GrossArea;
6176 118 : surfTemp.NetAreaShadowCalc = surfTemp.Area;
6177 118 : Vectors::CreateNewellSurfaceNormalVector(surfTemp.Vertex, surfTemp.Sides, surfTemp.NewellSurfaceNormalVector);
6178 118 : Vectors::DetermineAzimuthAndTilt(
6179 118 : surfTemp.Vertex, SurfAzimuth, SurfTilt, surfTemp.lcsx, surfTemp.lcsy, surfTemp.lcsz, surfTemp.NewellSurfaceNormalVector);
6180 118 : surfTemp.Azimuth = SurfAzimuth;
6181 118 : surfTemp.Tilt = SurfTilt;
6182 118 : surfTemp.convOrientation = Convect::GetSurfConvOrientation(surfTemp.Tilt);
6183 : // Sine and cosine of azimuth and tilt
6184 118 : surfTemp.SinAzim = SinSurfAzimuth;
6185 118 : surfTemp.CosAzim = CosSurfAzimuth;
6186 118 : surfTemp.SinTilt = SinSurfTilt;
6187 118 : surfTemp.CosTilt = CosSurfTilt;
6188 118 : if (surfTemp.Class != SurfaceClass::Window && surfTemp.Class != SurfaceClass::GlassDoor && surfTemp.Class != SurfaceClass::Door) {
6189 44 : surfTemp.ViewFactorGround = 0.5 * (1.0 - surfTemp.CosTilt);
6190 : }
6191 : // Outward normal unit vector (pointing away from room)
6192 118 : surfTemp.OutNormVec = surfTemp.NewellSurfaceNormalVector;
6193 472 : for (int n = 1; n <= 3; ++n) {
6194 354 : if (std::abs(surfTemp.OutNormVec(n) - 1.0) < 1.e-06) {
6195 27 : surfTemp.OutNormVec(n) = +1.0;
6196 : }
6197 354 : if (std::abs(surfTemp.OutNormVec(n) + 1.0) < 1.e-06) {
6198 91 : surfTemp.OutNormVec(n) = -1.0;
6199 : }
6200 354 : if (std::abs(surfTemp.OutNormVec(n)) < 1.e-06) {
6201 236 : surfTemp.OutNormVec(n) = 0.0;
6202 : }
6203 : }
6204 :
6205 : // IF (SurfaceTmp(SurfNum)%Class == SurfaceClass::Roof .and. SurfTilt > 80.) THEN
6206 : // WRITE(TiltString,'(F5.1)') SurfTilt
6207 : // TiltString=ADJUSTL(TiltString)
6208 : // CALL ShowWarningError(state, format("Roof/Ceiling Tilt={}{}{}{}{}{}{}{}{}{} for Surface={}{}{}, in
6209 : // Zone={}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}", //TRIM(TiltString)//',,
6210 : // much, greater, than, expected, tilt, of, 0,'//, &, //, //TRIM(SurfaceTmp(SurfNum)%Name)//, &, //, //TRIM(SurfaceTmp(SurfNum)%ZoneName)),
6211 : // //, ENDIF, //, IF, (SurfaceTmp(SurfNum)%Class, ==, SurfaceClass::Floor, .and., SurfTilt, <, 170.), THEN, //, WRITE(TiltString,'(F5.1)'),
6212 : // SurfTilt, //, TiltString=ADJUSTL(TiltString), //, CALL, ShowWarningError(state, 'Floor Tilt='//TRIM(TiltString)//', much less than
6213 : // expected tilt of 180,'// &
6214 : // ' for Surface='//TRIM(SurfaceTmp(SurfNum)%Name)// &
6215 : // ', in Zone='//TRIM(SurfaceTmp(SurfNum)%ZoneName)), //, ENDIF, if,
6216 : // (surfTemp.Class, ==, SurfaceClass::Window, ||,
6217 : // surfTemp.Class, ==, SurfaceClass::GlassDoor, ||,
6218 : // surfTemp.Class, ==, SurfaceClass::Door),
6219 : // surfTemp.Area, *=,
6220 : // surfTemp.Multiplier;, //, Can, perform, tests, on, this, surface, here,
6221 : // surfTemp.ViewFactorSky, =, 0.5, *, (1.0,
6222 : // surfTemp.CosTilt));
6223 : // The following IR view factors are modified in subr. SkyDifSolarShading if there are shadowing
6224 : // surfaces
6225 118 : surfTemp.ViewFactorSkyIR = surfTemp.ViewFactorSky;
6226 118 : surfTemp.ViewFactorGroundIR = 0.5 * (1.0 - surfTemp.CosTilt);
6227 :
6228 118 : Perimeter = distance(surfTemp.Vertex(surfTemp.Sides), surfTemp.Vertex(1));
6229 472 : for (Vrt = 2; Vrt <= surfTemp.Sides; ++Vrt) {
6230 354 : Perimeter += distance(surfTemp.Vertex(Vrt), surfTemp.Vertex(Vrt - 1));
6231 : }
6232 118 : surfTemp.Perimeter = Perimeter;
6233 :
6234 : // Call to transform vertices
6235 :
6236 118 : TransformVertsByAspect(state, SurfNum, surfTemp.Sides);
6237 118 : }
6238 :
6239 801 : void GetAttShdSurfaceData(EnergyPlusData &state,
6240 : bool &ErrorsFound, // Error flag indicator (true if errors found)
6241 : int &SurfNum, // Count of Current SurfaceNumber
6242 : int const TotShdSubs // Number of Attached Shading SubSurfaces to obtain
6243 : )
6244 : {
6245 : // SUBROUTINE INFORMATION:
6246 : // AUTHOR Linda Lawrie
6247 : // DATE WRITTEN May 2000
6248 :
6249 : // PURPOSE OF THIS SUBROUTINE:
6250 : // This subroutine gets the HeatTransfer Surface Data,
6251 : // checks it for errors, etc.
6252 :
6253 : static constexpr std::string_view routineName = "GetAttShdSurfaceData";
6254 :
6255 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
6256 : int IOStat; // IO Status when calling get input subroutine
6257 : int NumAlphas; // Number of alpha names being passed
6258 : int NumNumbers; // Number of properties being passed
6259 : int Found; // For matching interzone surfaces
6260 : int Loop;
6261 : Real64 SchedMinValue;
6262 : Real64 SchedMaxValue;
6263 :
6264 801 : auto &s_ipsc = state.dataIPShortCut;
6265 :
6266 801 : if (TotShdSubs > 0 && state.dataHeatBal->SolarDistribution == DataHeatBalance::Shadowing::Minimal) {
6267 3 : ShowWarningError(state, "Shading effects of Fins and Overhangs are ignored when Solar Distribution = MinimalShadowing");
6268 : }
6269 801 : s_ipsc->cCurrentModuleObject = "Shading:Zone:Detailed";
6270 801 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, s_ipsc->cCurrentModuleObject, Loop, NumAlphas, NumNumbers);
6271 801 : if (NumAlphas != 3) {
6272 0 : ShowSevereError(
6273 0 : state, format("{}: Object Definition indicates not = 3 Alpha Objects, Number Indicated={}", s_ipsc->cCurrentModuleObject, NumAlphas));
6274 0 : ErrorsFound = true;
6275 : }
6276 :
6277 1526 : for (Loop = 1; Loop <= TotShdSubs; ++Loop) {
6278 1450 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
6279 725 : s_ipsc->cCurrentModuleObject,
6280 : Loop,
6281 725 : s_ipsc->cAlphaArgs,
6282 : NumAlphas,
6283 725 : s_ipsc->rNumericArgs,
6284 : NumNumbers,
6285 : IOStat,
6286 725 : s_ipsc->lNumericFieldBlanks,
6287 725 : s_ipsc->lAlphaFieldBlanks,
6288 725 : s_ipsc->cAlphaFieldNames,
6289 725 : s_ipsc->cNumericFieldNames);
6290 :
6291 725 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
6292 :
6293 1450 : if (GlobalNames::VerifyUniqueInterObjectName(state,
6294 725 : state.dataSurfaceGeometry->UniqueSurfaceNames,
6295 725 : s_ipsc->cAlphaArgs(1),
6296 725 : s_ipsc->cCurrentModuleObject,
6297 725 : s_ipsc->cAlphaFieldNames(1),
6298 : ErrorsFound)) {
6299 0 : continue;
6300 : }
6301 :
6302 725 : ++SurfNum;
6303 725 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
6304 :
6305 725 : surfTemp.Name = s_ipsc->cAlphaArgs(1); // Set the Surface Name in the Derived Type
6306 725 : surfTemp.Class = SurfaceClass::Shading;
6307 725 : surfTemp.HeatTransSurf = false;
6308 725 : surfTemp.BaseSurfName = s_ipsc->cAlphaArgs(2);
6309 : // The subsurface inherits properties from the base surface
6310 : // Exterior conditions, Zone, etc.
6311 : // We can figure out the base surface though, because they've all been entered
6312 725 : Found = Util::FindItemInList(surfTemp.BaseSurfName, state.dataSurfaceGeometry->SurfaceTmp, state.dataSurface->TotSurfaces);
6313 725 : if (Found > 0) {
6314 : // SurfaceTmp(SurfNum)%BaseSurf=Found
6315 725 : surfTemp.ExtBoundCond = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCond;
6316 725 : surfTemp.ExtSolar = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtSolar;
6317 725 : surfTemp.ExtWind = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtWind;
6318 725 : surfTemp.Zone = state.dataSurfaceGeometry->SurfaceTmp(Found).Zone; // Necessary to do relative coordinates in GetVertices below
6319 725 : surfTemp.ZoneName = state.dataSurfaceGeometry->SurfaceTmp(Found).ZoneName; // Necessary to have surface drawn in OutputReports
6320 : } else {
6321 0 : ShowSevereError(state,
6322 0 : format("{}=\"{}\", invalid {}=\"{}",
6323 0 : s_ipsc->cCurrentModuleObject,
6324 0 : surfTemp.Name,
6325 0 : s_ipsc->cAlphaFieldNames(2),
6326 0 : s_ipsc->cAlphaArgs(2)));
6327 0 : ErrorsFound = true;
6328 : }
6329 725 : if (surfTemp.ExtBoundCond == unenteredAdjacentZoneSurface) {
6330 0 : ShowSevereError(state,
6331 0 : format("{}=\"{}\", invalid {}=\"{}",
6332 0 : s_ipsc->cCurrentModuleObject,
6333 0 : surfTemp.Name,
6334 0 : s_ipsc->cAlphaFieldNames(2),
6335 0 : s_ipsc->cAlphaArgs(2)));
6336 0 : ShowContinueError(state, "...trying to attach a shading device to an interzone surface.");
6337 0 : ErrorsFound = true;
6338 :
6339 0 : surfTemp.ExtBoundCond = DataSurfaces::ExternalEnvironment; // reset so program won't crash during "add surfaces"
6340 : }
6341 725 : if (surfTemp.ExtBoundCond == unreconciledZoneSurface) {
6342 0 : ShowSevereError(state,
6343 0 : format("{}=\"{}\", invalid {}=\"{}",
6344 0 : s_ipsc->cCurrentModuleObject,
6345 0 : surfTemp.Name,
6346 0 : s_ipsc->cAlphaFieldNames(2),
6347 0 : s_ipsc->cAlphaArgs(2)));
6348 0 : ShowContinueError(state, "...trying to attach a shading device to an interior surface.");
6349 0 : ErrorsFound = true;
6350 :
6351 0 : surfTemp.ExtBoundCond = DataSurfaces::ExternalEnvironment; // reset so program won't crash during "add surfaces"
6352 : }
6353 :
6354 725 : if (s_ipsc->lAlphaFieldBlanks(3)) {
6355 : // Defaults to constant-0.0, but leave this as nullptr for now
6356 637 : } else if ((surfTemp.shadowSurfSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(3))) == nullptr) {
6357 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3));
6358 0 : ErrorsFound = true;
6359 637 : } else if (!surfTemp.shadowSurfSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 1.0)) {
6360 0 : Sched::ShowSevereBadMinMax(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3), Clusive::In, 0.0, Clusive::In, 1.0);
6361 0 : ErrorsFound = true;
6362 : } else {
6363 :
6364 637 : SchedMinValue = surfTemp.shadowSurfSched->getMinVal(state);
6365 637 : surfTemp.SchedMinValue = SchedMinValue;
6366 637 : SchedMaxValue = surfTemp.shadowSurfSched->getMaxVal(state);
6367 637 : if (SchedMinValue == 1.0) {
6368 : // Set transparent for now, check for EMS actuators later in SolarShading::resetShadingSurfaceTransparency
6369 0 : surfTemp.IsTransparent = true;
6370 : }
6371 637 : if (SchedMaxValue > 0.0) {
6372 8 : state.dataSolarShading->anyScheduledShadingSurface = true;
6373 : }
6374 637 : if (SchedMaxValue - SchedMinValue > Constant::OneMillionth) {
6375 0 : state.dataSurface->ShadingTransmittanceVaries = true;
6376 : }
6377 : }
6378 :
6379 725 : if (s_ipsc->lNumericFieldBlanks(1) || s_ipsc->rNumericArgs(1) == Constant::AutoCalculate) {
6380 2 : s_ipsc->rNumericArgs(1) = (NumNumbers - 1) / 3;
6381 2 : surfTemp.Sides = s_ipsc->rNumericArgs(1);
6382 2 : if (mod(NumNumbers - 1, 3) != 0) {
6383 0 : ShowWarningError(state,
6384 0 : format("{}=\"{}\", {}",
6385 0 : s_ipsc->cCurrentModuleObject,
6386 0 : surfTemp.Name,
6387 0 : format("{} not even multiple of 3. Will read in {}", s_ipsc->cNumericFieldNames(1), surfTemp.Sides)));
6388 : }
6389 2 : if (s_ipsc->rNumericArgs(1) < 3) {
6390 0 : ShowSevereError(state,
6391 0 : format("{}=\"{}\", {} (autocalculate) must be >= 3. Only {} provided.",
6392 0 : s_ipsc->cCurrentModuleObject,
6393 0 : surfTemp.Name,
6394 0 : s_ipsc->cNumericFieldNames(1),
6395 0 : surfTemp.Sides));
6396 0 : ErrorsFound = true;
6397 0 : continue;
6398 : }
6399 : } else {
6400 723 : surfTemp.Sides = s_ipsc->rNumericArgs(1);
6401 : }
6402 725 : surfTemp.Vertex.allocate(surfTemp.Sides);
6403 2900 : GetVertices(state, SurfNum, surfTemp.Sides, s_ipsc->rNumericArgs({2, _}));
6404 725 : CheckConvexity(state, SurfNum, surfTemp.Sides);
6405 : // IF (SurfaceTmp(SurfNum)%Sides == 3) THEN
6406 : // CALL ShowWarningError(state, TRIM(s_ipsc->cCurrentModuleObject)//'="'//TRIM(SurfaceTmp(SurfNum)%Name)// &
6407 : // ' should not be triangular.')
6408 : // CALL ShowContinueError(state, '...Check results carefully.')
6409 : // ErrorsFound=.TRUE.
6410 : // ENDIF
6411 : // Reset surface to be "detached"
6412 725 : surfTemp.BaseSurf = 0;
6413 : // SurfaceTmp(SurfNum)%BaseSurfName=' '
6414 725 : surfTemp.Zone = 0;
6415 : // SurfaceTmp(SurfNum)%ZoneName=' '
6416 725 : if (state.dataReportFlag->MakeMirroredAttachedShading) {
6417 725 : MakeMirrorSurface(state, SurfNum);
6418 : }
6419 : }
6420 1526 : }
6421 :
6422 801 : void GetSimpleShdSurfaceData(EnergyPlusData &state,
6423 : bool &ErrorsFound, // Error flag indicator (true if errors found)
6424 : int &SurfNum, // Count of Current SurfaceNumber
6425 : int const TotOverhangs, // Number of Overhangs to obtain
6426 : int const TotOverhangsProjection, // Number of Overhangs (projection) to obtain
6427 : int const TotFins, // Number of Fins to obtain
6428 : int const TotFinsProjection // Number of Fins (projection) to obtain
6429 : )
6430 : {
6431 :
6432 : // SUBROUTINE INFORMATION:
6433 : // AUTHOR Linda Lawrie
6434 : // DATE WRITTEN January 2009
6435 :
6436 : // PURPOSE OF THIS SUBROUTINE:
6437 : // Get simple overhang and fin descriptions.
6438 :
6439 : // SUBROUTINE PARAMETER DEFINITIONS:
6440 801 : static Array1D_string const cModuleObjects(4, {"Shading:Overhang", "Shading:Overhang:Projection", "Shading:Fin", "Shading:Fin:Projection"});
6441 :
6442 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
6443 : int ItemsToGet;
6444 : int NumAlphas;
6445 : int NumNumbers;
6446 : int IOStat; // IO Status when calling get input subroutine
6447 : Real64 Depth;
6448 : Real64 Length;
6449 : Real64 Xp;
6450 : Real64 Yp;
6451 : Real64 Zp;
6452 : Real64 XLLC;
6453 : Real64 YLLC;
6454 : int BaseSurfNum;
6455 : Real64 TiltAngle;
6456 : bool MakeFin;
6457 :
6458 801 : auto &s_ipsc = state.dataIPShortCut;
6459 :
6460 810 : if ((TotOverhangs + TotOverhangsProjection + TotFins + TotFinsProjection) > 0 &&
6461 9 : state.dataHeatBal->SolarDistribution == DataHeatBalance::Shadowing::Minimal) {
6462 0 : ShowWarningError(state, "Shading effects of Fins and Overhangs are ignored when Solar Distribution = MinimalShadowing");
6463 : }
6464 4005 : for (int Item = 1; Item <= 4; ++Item) {
6465 :
6466 3204 : s_ipsc->cCurrentModuleObject = cModuleObjects(Item);
6467 3204 : if (Item == 1) {
6468 801 : ItemsToGet = TotOverhangs;
6469 2403 : } else if (Item == 2) {
6470 801 : ItemsToGet = TotOverhangsProjection;
6471 1602 : } else if (Item == 3) {
6472 801 : ItemsToGet = TotFins;
6473 : } else { // ! (Item == 4) THEN
6474 801 : ItemsToGet = TotFinsProjection;
6475 : }
6476 :
6477 3239 : for (int Loop = 1; Loop <= ItemsToGet; ++Loop) {
6478 70 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
6479 35 : s_ipsc->cCurrentModuleObject,
6480 : Loop,
6481 35 : s_ipsc->cAlphaArgs,
6482 : NumAlphas,
6483 35 : s_ipsc->rNumericArgs,
6484 : NumNumbers,
6485 : IOStat,
6486 35 : s_ipsc->lNumericFieldBlanks,
6487 35 : s_ipsc->lAlphaFieldBlanks,
6488 35 : s_ipsc->cAlphaFieldNames,
6489 35 : s_ipsc->cNumericFieldNames);
6490 :
6491 70 : if (GlobalNames::VerifyUniqueInterObjectName(state,
6492 35 : state.dataSurfaceGeometry->UniqueSurfaceNames,
6493 35 : s_ipsc->cAlphaArgs(1),
6494 35 : s_ipsc->cCurrentModuleObject,
6495 35 : s_ipsc->cAlphaFieldNames(1),
6496 : ErrorsFound)) {
6497 0 : continue;
6498 : }
6499 :
6500 35 : ++SurfNum;
6501 35 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
6502 :
6503 35 : surfTemp.Name = s_ipsc->cAlphaArgs(1); // Set the Surface Name in the Derived Type
6504 35 : surfTemp.Class = SurfaceClass::Shading;
6505 35 : surfTemp.HeatTransSurf = false;
6506 : // this object references a window or door....
6507 35 : int Found = Util::FindItemInList(s_ipsc->cAlphaArgs(2), state.dataSurfaceGeometry->SurfaceTmp, state.dataSurface->TotSurfaces);
6508 35 : if (Found > 0) {
6509 35 : BaseSurfNum = state.dataSurfaceGeometry->SurfaceTmp(Found).BaseSurf;
6510 35 : surfTemp.BaseSurfName = state.dataSurfaceGeometry->SurfaceTmp(Found).BaseSurfName;
6511 35 : surfTemp.ExtBoundCond = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCond;
6512 35 : surfTemp.ExtSolar = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtSolar;
6513 35 : surfTemp.ExtWind = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtWind;
6514 35 : surfTemp.Zone = state.dataSurfaceGeometry->SurfaceTmp(Found).Zone; // Necessary to do relative coordinates in GetVertices below
6515 35 : surfTemp.ZoneName = state.dataSurfaceGeometry->SurfaceTmp(Found).ZoneName; // Necessary to have surface drawn in OutputReports
6516 : } else {
6517 0 : ShowSevereError(state,
6518 0 : format("{}=\"{}\", invalid {}=\"{}",
6519 0 : s_ipsc->cCurrentModuleObject,
6520 0 : surfTemp.Name,
6521 0 : s_ipsc->cAlphaFieldNames(2),
6522 0 : s_ipsc->cAlphaArgs(2)));
6523 0 : ErrorsFound = true;
6524 0 : continue;
6525 : }
6526 35 : if (surfTemp.ExtBoundCond == unenteredAdjacentZoneSurface) {
6527 0 : ShowSevereError(state,
6528 0 : format("{}=\"{}\", invalid {}=\"{}",
6529 0 : s_ipsc->cCurrentModuleObject,
6530 0 : surfTemp.Name,
6531 0 : s_ipsc->cAlphaFieldNames(2),
6532 0 : s_ipsc->cAlphaArgs(2)));
6533 0 : ShowContinueError(state, "...trying to attach a shading device to an interzone surface.");
6534 0 : ErrorsFound = true;
6535 0 : surfTemp.ExtBoundCond = DataSurfaces::ExternalEnvironment; // reset so program won't crash during "add surfaces"
6536 : }
6537 35 : if (surfTemp.ExtBoundCond == unreconciledZoneSurface) {
6538 0 : ShowSevereError(state,
6539 0 : format("{}=\"{}\", invalid {}=\"{}",
6540 0 : s_ipsc->cCurrentModuleObject,
6541 0 : surfTemp.Name,
6542 0 : s_ipsc->cAlphaFieldNames(2),
6543 0 : s_ipsc->cAlphaArgs(2)));
6544 0 : ShowContinueError(state, "...trying to attach a shading device to an interior surface.");
6545 0 : ErrorsFound = true;
6546 0 : surfTemp.ExtBoundCond = DataSurfaces::ExternalEnvironment; // reset so program won't crash during "add surfaces"
6547 : }
6548 :
6549 35 : surfTemp.shadowSurfSched = nullptr;
6550 :
6551 : //===== Overhang =====
6552 :
6553 35 : if (Item < 3) {
6554 : // Found is the surface window or door.
6555 : // N1, \field Height above Window or Door
6556 : // \units m
6557 : // N2, \field Tilt Angle from Window/Door
6558 : // \units deg
6559 : // \default 90
6560 : // \minimum 0
6561 : // \maximum 180
6562 : // N3, \field Left extension from Window/Door Width
6563 : // \units m
6564 : // N4, \field Right extension from Window/Door Width
6565 : // \note N3 + N4 + Window/Door Width is Overhang Length
6566 : // \units m
6567 : // N5; \field Depth
6568 : // \units m
6569 : // for projection option:
6570 : // N5; \field Depth as Fraction of Window/Door Height
6571 : // \units m
6572 26 : Length = s_ipsc->rNumericArgs(3) + s_ipsc->rNumericArgs(4) + state.dataSurfaceGeometry->SurfaceTmp(Found).Width;
6573 26 : if (Item == 1) {
6574 25 : Depth = s_ipsc->rNumericArgs(5);
6575 1 : } else if (Item == 2) {
6576 1 : Depth = s_ipsc->rNumericArgs(5) * state.dataSurfaceGeometry->SurfaceTmp(Found).Height;
6577 : }
6578 :
6579 26 : if (Length * Depth <= 0.0) {
6580 0 : ShowSevereError(state,
6581 0 : format("{}=\"{}\", illegal surface area=[{:.2R}]. Surface will NOT be entered.",
6582 0 : s_ipsc->cCurrentModuleObject,
6583 0 : s_ipsc->cAlphaArgs(1),
6584 0 : Length * Depth));
6585 0 : continue;
6586 : }
6587 :
6588 26 : TiltAngle = state.dataSurfaceGeometry->SurfaceTmp(Found).Tilt + s_ipsc->rNumericArgs(2);
6589 26 : surfTemp.Tilt = TiltAngle;
6590 26 : surfTemp.convOrientation = Convect::GetSurfConvOrientation(surfTemp.Tilt);
6591 26 : surfTemp.Azimuth = state.dataSurfaceGeometry->SurfaceTmp(Found).Azimuth;
6592 :
6593 : // Make it relative to surface origin.....
6594 26 : Xp = state.dataSurfaceGeometry->SurfaceTmp(Found).Vertex(2).x - state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).x;
6595 26 : Yp = state.dataSurfaceGeometry->SurfaceTmp(Found).Vertex(2).y - state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).y;
6596 26 : Zp = state.dataSurfaceGeometry->SurfaceTmp(Found).Vertex(2).z - state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).z;
6597 :
6598 26 : XLLC = -Xp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosAzim +
6599 26 : Yp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).SinAzim;
6600 :
6601 26 : YLLC =
6602 26 : -Xp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).SinAzim *
6603 26 : state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosTilt -
6604 26 : Yp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosAzim * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosTilt +
6605 26 : Zp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).SinTilt;
6606 :
6607 26 : surfTemp.Sides = 4;
6608 26 : surfTemp.Vertex.allocate(surfTemp.Sides);
6609 :
6610 52 : MakeRelativeRectangularVertices(state,
6611 : BaseSurfNum,
6612 : SurfNum,
6613 26 : XLLC - s_ipsc->rNumericArgs(3),
6614 26 : YLLC + state.dataSurfaceGeometry->SurfaceTmp(Found).Height + s_ipsc->rNumericArgs(1),
6615 : Length,
6616 : Depth);
6617 :
6618 : // Reset surface to be "detached"
6619 : // SurfaceTmp(SurfNum)%BaseSurfName=' '
6620 : // SurfaceTmp(SurfNum)%ZoneName=' '
6621 :
6622 26 : surfTemp.BaseSurf = 0;
6623 26 : surfTemp.Zone = 0;
6624 :
6625 : // and mirror
6626 26 : if (state.dataReportFlag->MakeMirroredAttachedShading) {
6627 26 : MakeMirrorSurface(state, SurfNum);
6628 : }
6629 :
6630 : } else { // Fins
6631 :
6632 : //===== Fins =====
6633 :
6634 : //===== Left Fin =====
6635 :
6636 : // N1, \field Left Extension from Window/Door
6637 : // \units m
6638 : // N2, \field Left Distance Above Top of Window
6639 : // \units m
6640 : // N3, \field Left Distance Below Bottom of Window
6641 : // \units m
6642 : // \note N2 + N3 + height of Window/Door is height of Fin
6643 : // N4, \field Left Tilt Angle from Window/Door
6644 : // \units deg
6645 : // \default 90
6646 : // \minimum 0
6647 : // \maximum 180
6648 : // N5, \field Left Depth
6649 : // \units m
6650 : // for projection option:
6651 : // N5, \field Left Depth as Fraction of Window/Door Width
6652 : // \units m
6653 9 : surfTemp.Name = surfTemp.Name + " Left";
6654 9 : Length = s_ipsc->rNumericArgs(2) + s_ipsc->rNumericArgs(3) + state.dataSurfaceGeometry->SurfaceTmp(Found).Height;
6655 9 : if (Item == 3) {
6656 8 : Depth = s_ipsc->rNumericArgs(5);
6657 1 : } else if (Item == 4) {
6658 1 : Depth = s_ipsc->rNumericArgs(5) * state.dataSurfaceGeometry->SurfaceTmp(Found).Width;
6659 : }
6660 :
6661 9 : MakeFin = true;
6662 9 : if (Length * Depth <= 0.0) {
6663 0 : ShowWarningError(state,
6664 0 : format("{}=Left Fin of \"{}\", illegal surface area=[{:.2R}]. Surface will NOT be entered.",
6665 0 : s_ipsc->cCurrentModuleObject,
6666 0 : s_ipsc->cAlphaArgs(1),
6667 0 : Length * Depth));
6668 0 : MakeFin = false;
6669 : }
6670 :
6671 9 : if (MakeFin) {
6672 9 : TiltAngle = state.dataSurfaceGeometry->SurfaceTmp(Found).Tilt;
6673 9 : surfTemp.Tilt = TiltAngle;
6674 9 : surfTemp.convOrientation = Convect::GetSurfConvOrientation(surfTemp.Tilt);
6675 9 : surfTemp.Azimuth = state.dataSurfaceGeometry->SurfaceTmp(Found).Azimuth - (180.0 - s_ipsc->rNumericArgs(4));
6676 :
6677 : // Make it relative to surface origin.....
6678 :
6679 9 : Xp =
6680 9 : state.dataSurfaceGeometry->SurfaceTmp(Found).Vertex(2).x - state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).x;
6681 9 : Yp =
6682 9 : state.dataSurfaceGeometry->SurfaceTmp(Found).Vertex(2).y - state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).y;
6683 9 : Zp =
6684 9 : state.dataSurfaceGeometry->SurfaceTmp(Found).Vertex(2).z - state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).z;
6685 :
6686 9 : XLLC = -Xp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosAzim +
6687 9 : Yp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).SinAzim;
6688 :
6689 9 : YLLC = -Xp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).SinAzim *
6690 9 : state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosTilt -
6691 9 : Yp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosAzim *
6692 9 : state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosTilt +
6693 9 : Zp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).SinTilt;
6694 :
6695 9 : surfTemp.CosAzim = std::cos(surfTemp.Azimuth * Constant::DegToRad);
6696 9 : surfTemp.SinAzim = std::sin(surfTemp.Azimuth * Constant::DegToRad);
6697 9 : surfTemp.CosTilt = std::cos(surfTemp.Tilt * Constant::DegToRad);
6698 9 : surfTemp.SinTilt = std::sin(surfTemp.Tilt * Constant::DegToRad);
6699 :
6700 9 : surfTemp.Sides = 4;
6701 9 : surfTemp.Vertex.allocate(surfTemp.Sides);
6702 :
6703 27 : MakeRelativeRectangularVertices(
6704 9 : state, BaseSurfNum, SurfNum, XLLC - s_ipsc->rNumericArgs(1), YLLC - s_ipsc->rNumericArgs(3), -Depth, Length);
6705 :
6706 : // Reset surface to be "detached"
6707 : // SurfaceTmp(SurfNum)%BaseSurfName=' '
6708 : // SurfaceTmp(SurfNum)%ZoneName=' '
6709 :
6710 9 : surfTemp.BaseSurf = 0;
6711 9 : surfTemp.Zone = 0;
6712 :
6713 : // and mirror
6714 9 : if (state.dataReportFlag->MakeMirroredAttachedShading) {
6715 9 : MakeMirrorSurface(state, SurfNum);
6716 : }
6717 : } else {
6718 0 : --SurfNum;
6719 : }
6720 :
6721 : //===== Right Fin =====
6722 :
6723 : // N6, \field Right Extension from Window/Door
6724 : // \units m
6725 : // N7, \field Right Distance Above Top of Window
6726 : // \units m
6727 : // N8, \field Right Distance Below Bottom of Window
6728 : // \note N7 + N8 + height of Window/Door is height of Fin
6729 : // \units m
6730 : // N9, \field Right Tilt Angle from Window/Door
6731 : // \units deg
6732 : // \default 90
6733 : // \minimum 0
6734 : // \maximum 180
6735 : // N10; \field Right Depth
6736 : // \units m
6737 : // for projection option:
6738 : // N10; \field Right Depth as Fraction of Window/Door Width
6739 : // \units m
6740 :
6741 9 : ++SurfNum;
6742 9 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
6743 9 : surfTemp.Name = s_ipsc->cAlphaArgs(1) + " Right"; // Set the Surface Name in the Derived Type
6744 9 : surfTemp.Class = SurfaceClass::Shading;
6745 9 : surfTemp.HeatTransSurf = false;
6746 9 : BaseSurfNum = state.dataSurfaceGeometry->SurfaceTmp(Found).BaseSurf;
6747 9 : surfTemp.BaseSurfName = state.dataSurfaceGeometry->SurfaceTmp(Found).BaseSurfName;
6748 9 : surfTemp.ExtBoundCond = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCond;
6749 9 : surfTemp.ExtSolar = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtSolar;
6750 9 : surfTemp.ExtWind = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtWind;
6751 9 : surfTemp.Zone = state.dataSurfaceGeometry->SurfaceTmp(Found).Zone; // Necessary to do relative coordinates in GetVertices below
6752 9 : surfTemp.ZoneName = state.dataSurfaceGeometry->SurfaceTmp(Found).ZoneName; // Necessary to have surface drawn in OutputReports
6753 :
6754 9 : surfTemp.shadowSurfSched = nullptr;
6755 9 : Length = s_ipsc->rNumericArgs(7) + s_ipsc->rNumericArgs(8) + state.dataSurfaceGeometry->SurfaceTmp(Found).Height;
6756 9 : if (Item == 3) {
6757 8 : Depth = s_ipsc->rNumericArgs(10);
6758 1 : } else if (Item == 4) {
6759 1 : Depth = s_ipsc->rNumericArgs(10) * state.dataSurfaceGeometry->SurfaceTmp(Found).Width;
6760 : }
6761 :
6762 9 : MakeFin = true;
6763 9 : if (Length * Depth <= 0.0) {
6764 0 : ShowWarningError(state,
6765 0 : format("{}=Right Fin of \"{}\", illegal surface area=[{:.2R}]. Surface will NOT be entered.",
6766 0 : s_ipsc->cCurrentModuleObject,
6767 0 : s_ipsc->cAlphaArgs(1),
6768 0 : Length * Depth));
6769 0 : MakeFin = false;
6770 : }
6771 :
6772 9 : if (MakeFin) {
6773 : // Make it relative to surface origin.....
6774 :
6775 9 : Xp =
6776 9 : state.dataSurfaceGeometry->SurfaceTmp(Found).Vertex(2).x - state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).x;
6777 9 : Yp =
6778 9 : state.dataSurfaceGeometry->SurfaceTmp(Found).Vertex(2).y - state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).y;
6779 9 : Zp =
6780 9 : state.dataSurfaceGeometry->SurfaceTmp(Found).Vertex(2).z - state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).z;
6781 :
6782 9 : XLLC = -Xp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosAzim +
6783 9 : Yp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).SinAzim;
6784 :
6785 9 : YLLC = -Xp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).SinAzim *
6786 9 : state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosTilt -
6787 9 : Yp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosAzim *
6788 9 : state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosTilt +
6789 9 : Zp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).SinTilt;
6790 :
6791 9 : TiltAngle = state.dataSurfaceGeometry->SurfaceTmp(Found).Tilt;
6792 9 : surfTemp.Tilt = TiltAngle;
6793 9 : surfTemp.convOrientation = Convect::GetSurfConvOrientation(surfTemp.Tilt);
6794 9 : surfTemp.Azimuth = state.dataSurfaceGeometry->SurfaceTmp(Found).Azimuth - (180.0 - s_ipsc->rNumericArgs(9));
6795 9 : surfTemp.CosAzim = std::cos(surfTemp.Azimuth * Constant::DegToRad);
6796 9 : surfTemp.SinAzim = std::sin(surfTemp.Azimuth * Constant::DegToRad);
6797 9 : surfTemp.CosTilt = std::cos(surfTemp.Tilt * Constant::DegToRad);
6798 9 : surfTemp.SinTilt = std::sin(surfTemp.Tilt * Constant::DegToRad);
6799 :
6800 9 : surfTemp.Sides = 4;
6801 9 : surfTemp.Vertex.allocate(surfTemp.Sides);
6802 :
6803 27 : MakeRelativeRectangularVertices(state,
6804 : BaseSurfNum,
6805 : SurfNum,
6806 9 : XLLC + state.dataSurfaceGeometry->SurfaceTmp(Found).Width + s_ipsc->rNumericArgs(6),
6807 9 : YLLC - s_ipsc->rNumericArgs(8),
6808 : -Depth,
6809 : Length);
6810 :
6811 : // Reset surface to be "detached"
6812 : // SurfaceTmp(SurfNum)%BaseSurfName=' '
6813 : // SurfaceTmp(SurfNum)%ZoneName=' '
6814 :
6815 9 : surfTemp.BaseSurf = 0;
6816 9 : surfTemp.Zone = 0;
6817 :
6818 : // and mirror
6819 9 : if (state.dataReportFlag->MakeMirroredAttachedShading) {
6820 9 : MakeMirrorSurface(state, SurfNum);
6821 : }
6822 : } else {
6823 0 : --SurfNum;
6824 : }
6825 : }
6826 : }
6827 : }
6828 801 : }
6829 :
6830 801 : void GetIntMassSurfaceData(EnergyPlusData &state,
6831 : bool &ErrorsFound, // Error flag indicator (true if errors found)
6832 : int &SurfNum // Count of Current SurfaceNumber
6833 : )
6834 : {
6835 :
6836 : // SUBROUTINE INFORMATION:
6837 : // AUTHOR Linda Lawrie
6838 : // DATE WRITTEN May 2000
6839 :
6840 : // PURPOSE OF THIS SUBROUTINE:
6841 : // This subroutine gets the Internal Surface Data,
6842 : // checks it for errors, etc.
6843 :
6844 : // REFERENCES:
6845 : // Internal Mass Surface Definition
6846 : // Surface:HeatTransfer:InternalMass,
6847 : // \note used to describe internal zone surface area that does not need to be part of geometric representation
6848 : // A1 , \field User Supplied Surface Name
6849 : // \type alpha
6850 : // \reference SurfaceNames
6851 : // A2 , \field Construction Name of the Surface
6852 : // \note To be matched with a construction in this input file
6853 : // \type object-list
6854 : // \object-list ConstructionNames
6855 : // A3 , \field Interior Environment
6856 : // \note Zone the surface is a part of
6857 : // \type object-list
6858 : // \object-list ZoneNames
6859 : // N1, \field View factor to Person (to people?)
6860 : // \type real
6861 : // \note from the interior of the surface
6862 : // N2 ; \field Surface area
6863 : // \units m2
6864 :
6865 : // SUBROUTINE PARAMETER DEFINITIONS:
6866 : static constexpr std::string_view RoutineName("GetIntMassSurfaceData: ");
6867 :
6868 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
6869 : int IOStat; // IO Status when calling get input subroutine
6870 : int SurfaceNumAlpha; // Number of material alpha names being passed
6871 : int SurfaceNumArg; // Number of material properties being passed
6872 :
6873 801 : auto &s_ipsc = state.dataIPShortCut;
6874 801 : s_ipsc->cCurrentModuleObject = "InternalMass";
6875 801 : int TotIntMass = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
6876 801 : if (TotIntMass == 0) {
6877 627 : return;
6878 : }
6879 :
6880 174 : state.dataSurface->IntMassObjects.allocate(TotIntMass);
6881 :
6882 : // scan for use of Zone lists in InternalMass objects
6883 174 : bool errFlag = false;
6884 174 : int NumIntMassSurfaces = 0;
6885 2698 : for (int Item = 1; Item <= TotIntMass; ++Item) {
6886 5048 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
6887 2524 : s_ipsc->cCurrentModuleObject,
6888 : Item,
6889 2524 : s_ipsc->cAlphaArgs,
6890 : SurfaceNumAlpha,
6891 2524 : s_ipsc->rNumericArgs,
6892 : SurfaceNumArg,
6893 : IOStat,
6894 2524 : s_ipsc->lNumericFieldBlanks,
6895 2524 : s_ipsc->lAlphaFieldBlanks,
6896 2524 : s_ipsc->cAlphaFieldNames,
6897 2524 : s_ipsc->cNumericFieldNames);
6898 :
6899 5048 : if (GlobalNames::VerifyUniqueInterObjectName(state,
6900 2524 : state.dataSurfaceGeometry->UniqueSurfaceNames,
6901 2524 : s_ipsc->cAlphaArgs(1),
6902 2524 : s_ipsc->cCurrentModuleObject,
6903 2524 : s_ipsc->cAlphaFieldNames(1),
6904 : ErrorsFound)) {
6905 0 : continue;
6906 : }
6907 :
6908 2524 : state.dataSurface->IntMassObjects(Item).Name = s_ipsc->cAlphaArgs(1);
6909 2524 : state.dataSurface->IntMassObjects(Item).GrossArea = s_ipsc->rNumericArgs(1);
6910 2524 : state.dataSurface->IntMassObjects(Item).Construction =
6911 2524 : Util::FindItemInList(s_ipsc->cAlphaArgs(2), state.dataConstruction->Construct, state.dataHeatBal->TotConstructs);
6912 2524 : state.dataSurface->IntMassObjects(Item).ZoneOrZoneListName = s_ipsc->cAlphaArgs(3);
6913 2524 : int Item1 = Util::FindItemInList(s_ipsc->cAlphaArgs(3), state.dataHeatBal->Zone, state.dataGlobal->NumOfZones);
6914 2524 : int ZLItem = 0;
6915 2524 : if (Item1 == 0 && state.dataHeatBal->NumOfZoneLists > 0) {
6916 5 : ZLItem = Util::FindItemInList(s_ipsc->cAlphaArgs(3), state.dataHeatBal->ZoneList);
6917 : }
6918 2524 : if (Item1 > 0) {
6919 2519 : if (s_ipsc->lAlphaFieldBlanks(4)) {
6920 2515 : ++NumIntMassSurfaces;
6921 : }
6922 2519 : state.dataSurface->IntMassObjects(Item).NumOfZones = 1;
6923 2519 : state.dataSurface->IntMassObjects(Item).ZoneListActive = false;
6924 2519 : state.dataSurface->IntMassObjects(Item).ZoneOrZoneListPtr = Item1;
6925 5 : } else if (ZLItem > 0) {
6926 2 : NumIntMassSurfaces += state.dataHeatBal->ZoneList(ZLItem).NumOfZones;
6927 2 : state.dataSurface->IntMassObjects(Item).NumOfZones = state.dataHeatBal->ZoneList(ZLItem).NumOfZones;
6928 2 : state.dataSurface->IntMassObjects(Item).ZoneListActive = true;
6929 2 : state.dataSurface->IntMassObjects(Item).ZoneOrZoneListPtr = ZLItem;
6930 3 : } else if (state.dataIPShortCut->lAlphaFieldBlanks(4)) {
6931 : // If Space or SpaceList Name is blank, then throw error.
6932 0 : ShowSevereError(state,
6933 0 : format("{}=\"{}\" invalid {}=\"{}\" not found.",
6934 0 : s_ipsc->cCurrentModuleObject,
6935 0 : s_ipsc->cAlphaArgs(1),
6936 0 : s_ipsc->cAlphaFieldNames(3),
6937 0 : s_ipsc->cAlphaArgs(3)));
6938 0 : ++SurfNum;
6939 0 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
6940 0 : surfTemp.Class = SurfaceClass::Invalid;
6941 0 : surfTemp.ZoneName = "Unknown Zone";
6942 0 : ErrorsFound = true;
6943 0 : errFlag = true;
6944 : }
6945 :
6946 2524 : if (!s_ipsc->lAlphaFieldBlanks(4)) {
6947 7 : state.dataSurface->IntMassObjects(Item).spaceOrSpaceListName = s_ipsc->cAlphaArgs(4);
6948 7 : Item1 = Util::FindItemInList(s_ipsc->cAlphaArgs(4), state.dataHeatBal->space);
6949 7 : int SLItem = 0;
6950 7 : if (Item1 == 0 && int(state.dataHeatBal->spaceList.size()) > 0) {
6951 1 : SLItem = Util::FindItemInList(s_ipsc->cAlphaArgs(4), state.dataHeatBal->spaceList);
6952 : }
6953 7 : if (Item1 > 0) {
6954 6 : ++NumIntMassSurfaces;
6955 6 : state.dataSurface->IntMassObjects(Item).numOfSpaces = 1;
6956 6 : state.dataSurface->IntMassObjects(Item).spaceListActive = false;
6957 6 : state.dataSurface->IntMassObjects(Item).spaceOrSpaceListPtr = Item1;
6958 6 : state.dataSurface->IntMassObjects(Item).NumOfZones = 1;
6959 6 : state.dataSurface->IntMassObjects(Item).ZoneListActive = false;
6960 6 : state.dataSurface->IntMassObjects(Item).ZoneOrZoneListPtr = state.dataHeatBal->space(Item1).zoneNum;
6961 1 : } else if (SLItem > 0) {
6962 1 : int numOfSpaces = int(state.dataHeatBal->spaceList(SLItem).numListSpaces);
6963 1 : NumIntMassSurfaces += numOfSpaces;
6964 1 : state.dataSurface->IntMassObjects(Item).numOfSpaces = numOfSpaces;
6965 1 : state.dataSurface->IntMassObjects(Item).spaceListActive = true;
6966 1 : state.dataSurface->IntMassObjects(Item).spaceOrSpaceListPtr = SLItem;
6967 : } else {
6968 0 : ShowSevereError(state,
6969 0 : format("{}=\"{}\" invalid {}=\"{}\" not found.",
6970 0 : s_ipsc->cCurrentModuleObject,
6971 0 : s_ipsc->cAlphaArgs(1),
6972 0 : s_ipsc->cAlphaFieldNames(4),
6973 0 : s_ipsc->cAlphaArgs(4)));
6974 0 : ++SurfNum;
6975 0 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
6976 0 : surfTemp.Class = SurfaceClass::Invalid;
6977 0 : ErrorsFound = true;
6978 0 : errFlag = true;
6979 : }
6980 : }
6981 :
6982 2524 : if (errFlag) {
6983 0 : ShowSevereError(state, format("{}Errors with invalid names in {} objects.", RoutineName, s_ipsc->cCurrentModuleObject));
6984 0 : ShowContinueError(state, "...These will not be read in. Other errors may occur.");
6985 0 : NumIntMassSurfaces = 0;
6986 : }
6987 :
6988 2524 : if (state.dataSurface->IntMassObjects(Item).Construction == 0) {
6989 0 : ErrorsFound = true;
6990 0 : ShowSevereError(state,
6991 0 : format("{}=\"{}\", {} not found={}",
6992 0 : s_ipsc->cCurrentModuleObject,
6993 0 : s_ipsc->cAlphaArgs(1),
6994 0 : s_ipsc->cAlphaFieldNames(2),
6995 0 : s_ipsc->cAlphaArgs(2)));
6996 2524 : } else if (state.dataConstruction->Construct(state.dataSurface->IntMassObjects(Item).Construction).TypeIsWindow) {
6997 0 : ErrorsFound = true;
6998 0 : ShowSevereError(state,
6999 0 : format("{}=\"{}\", invalid {}=\"{}\" - has Window materials.",
7000 0 : s_ipsc->cCurrentModuleObject,
7001 0 : s_ipsc->cAlphaArgs(1),
7002 0 : s_ipsc->cAlphaFieldNames(2),
7003 0 : s_ipsc->cAlphaArgs(2)));
7004 : } else {
7005 2524 : state.dataConstruction->Construct(state.dataSurface->IntMassObjects(Item).Construction).IsUsed = true;
7006 : }
7007 : }
7008 :
7009 174 : if (NumIntMassSurfaces > 0) {
7010 2698 : for (int Loop = 1; Loop <= TotIntMass; ++Loop) {
7011 2524 : int numberOfZonesOrSpaces = 1;
7012 2524 : if (state.dataSurface->IntMassObjects(Loop).ZoneListActive) {
7013 2 : numberOfZonesOrSpaces = state.dataSurface->IntMassObjects(Loop).NumOfZones;
7014 2522 : } else if (state.dataSurface->IntMassObjects(Loop).spaceListActive) {
7015 1 : numberOfZonesOrSpaces = state.dataSurface->IntMassObjects(Loop).numOfSpaces;
7016 : }
7017 :
7018 5061 : for (int Item1 = 1; Item1 <= numberOfZonesOrSpaces; ++Item1) {
7019 :
7020 2537 : ++SurfNum;
7021 :
7022 2537 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
7023 2537 : surfTemp.Construction = state.dataSurface->IntMassObjects(Loop).Construction;
7024 2537 : if (!state.dataSurface->IntMassObjects(Loop).ZoneListActive && !state.dataSurface->IntMassObjects(Loop).spaceListActive) {
7025 2521 : surfTemp.Zone = state.dataSurface->IntMassObjects(Loop).ZoneOrZoneListPtr;
7026 2521 : surfTemp.spaceNum = state.dataSurface->IntMassObjects(Loop).spaceOrSpaceListPtr;
7027 2521 : surfTemp.Name = state.dataSurface->IntMassObjects(Loop).Name;
7028 2521 : surfTemp.Class = SurfaceClass::IntMass;
7029 2521 : surfTemp.ZoneName = state.dataSurface->IntMassObjects(Loop).ZoneOrZoneListName;
7030 2521 : surfTemp.HeatTransSurf = true;
7031 : } else {
7032 16 : int ZoneNum = 0; // index to a zone
7033 16 : if (state.dataSurface->IntMassObjects(Loop).ZoneListActive) {
7034 24 : General::CheckCreatedZoneItemName(
7035 : state,
7036 : RoutineName,
7037 8 : s_ipsc->cCurrentModuleObject,
7038 : state.dataHeatBal
7039 8 : ->Zone(state.dataHeatBal->ZoneList(state.dataSurface->IntMassObjects(Loop).ZoneOrZoneListPtr).Zone(Item1))
7040 8 : .Name,
7041 8 : state.dataHeatBal->ZoneList(state.dataSurface->IntMassObjects(Loop).ZoneOrZoneListPtr).MaxZoneNameLength,
7042 8 : state.dataSurface->IntMassObjects(Loop).Name,
7043 8 : state.dataSurfaceGeometry->SurfaceTmp,
7044 8 : SurfNum - 1,
7045 8 : surfTemp.Name,
7046 : errFlag);
7047 :
7048 8 : ZoneNum = state.dataHeatBal->ZoneList(state.dataSurface->IntMassObjects(Loop).ZoneOrZoneListPtr).Zone(Item1);
7049 8 : } else if (state.dataSurface->IntMassObjects(Loop).spaceListActive) {
7050 8 : int spaceNum = state.dataHeatBal->spaceList(state.dataSurface->IntMassObjects(Loop).spaceOrSpaceListPtr).spaces(Item1);
7051 8 : ZoneNum = state.dataHeatBal->space(spaceNum).zoneNum;
7052 8 : const std::string spaceName = state.dataHeatBal->space(spaceNum).Name;
7053 8 : surfTemp.Name = spaceName + ' ' + state.dataSurface->IntMassObjects(Loop).Name;
7054 8 : surfTemp.spaceNum = spaceNum;
7055 8 : }
7056 16 : surfTemp.Zone = ZoneNum;
7057 16 : surfTemp.Class = SurfaceClass::IntMass;
7058 16 : surfTemp.ZoneName = state.dataHeatBal->Zone(ZoneNum).Name;
7059 16 : surfTemp.HeatTransSurf = true;
7060 16 : if (errFlag) {
7061 0 : ErrorsFound = true;
7062 : }
7063 : }
7064 :
7065 2537 : if (state.dataSurface->IntMassObjects(Loop).Construction > 0) {
7066 2537 : if (state.dataConstruction->Construct(state.dataSurface->IntMassObjects(Loop).Construction).IsUsed) {
7067 2537 : surfTemp.ConstructionStoredInputValue = state.dataSurface->IntMassObjects(Loop).Construction;
7068 : }
7069 : }
7070 2537 : surfTemp.GrossArea = state.dataSurface->IntMassObjects(Loop).GrossArea;
7071 2537 : surfTemp.Area = surfTemp.GrossArea;
7072 2537 : surfTemp.NetAreaShadowCalc = surfTemp.Area;
7073 2537 : surfTemp.Width = surfTemp.Area;
7074 2537 : surfTemp.Height = 1.0;
7075 2537 : surfTemp.Tilt = 90.0;
7076 2537 : surfTemp.convOrientation = Convect::GetSurfConvOrientation(surfTemp.Tilt);
7077 2537 : surfTemp.CosTilt = 0.0; // Tuned Was std::cos( 90.0 * DegToRadians )
7078 2537 : surfTemp.SinTilt = 1.0; // Tuned Was std::sin( 90.0 * DegToRadians )
7079 2537 : surfTemp.Azimuth = 0.0;
7080 2537 : surfTemp.CosAzim = 1.0; // Tuned Was std::cos( 0.0 )
7081 2537 : surfTemp.SinAzim = 0.0; // Tuned Was std::sin( 0.0 )
7082 : // Outward normal unit vector (pointing away from room)
7083 2537 : surfTemp.OutNormVec = surfTemp.lcsz;
7084 2537 : surfTemp.ViewFactorSky = 0.5;
7085 2537 : surfTemp.ExtSolar = false;
7086 2537 : surfTemp.ExtWind = false;
7087 2537 : surfTemp.BaseSurf = SurfNum;
7088 2537 : surfTemp.BaseSurfName = surfTemp.Name;
7089 2537 : surfTemp.ExtBoundCondName = surfTemp.Name;
7090 2537 : surfTemp.ExtBoundCond = unreconciledZoneSurface;
7091 : }
7092 : }
7093 : }
7094 : }
7095 :
7096 801 : int GetNumIntMassSurfaces(EnergyPlusData &state) // Number of Internal Mass Surfaces to obtain
7097 :
7098 : {
7099 : // Counts internal mass surfaces applied to zones and zone lists
7100 :
7101 : int IOStat; // IO Status when calling get input subroutine
7102 : int SurfaceNumAlpha; // Number of material alpha names being passed
7103 : int SurfaceNumArg; // Number of material properties being passed
7104 :
7105 801 : auto &s_ipsc = state.dataIPShortCut;
7106 801 : s_ipsc->cCurrentModuleObject = "InternalMass";
7107 :
7108 801 : int NumIntMassSurf = 0;
7109 801 : int TotIntMass = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "InternalMass");
7110 :
7111 801 : if (TotIntMass == 0) {
7112 627 : return NumIntMassSurf;
7113 : }
7114 : // scan for zones and zone lists in InternalMass objects
7115 2698 : for (int Item = 1; Item <= TotIntMass; ++Item) {
7116 5048 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
7117 2524 : s_ipsc->cCurrentModuleObject,
7118 : Item,
7119 2524 : s_ipsc->cAlphaArgs,
7120 : SurfaceNumAlpha,
7121 2524 : s_ipsc->rNumericArgs,
7122 : SurfaceNumArg,
7123 : IOStat,
7124 2524 : s_ipsc->lNumericFieldBlanks,
7125 2524 : s_ipsc->lAlphaFieldBlanks,
7126 2524 : s_ipsc->cAlphaFieldNames,
7127 2524 : s_ipsc->cNumericFieldNames);
7128 :
7129 2524 : int Item1 = Util::FindItemInList(s_ipsc->cAlphaArgs(3), state.dataHeatBal->Zone, state.dataGlobal->NumOfZones);
7130 2524 : int ZLItem = 0;
7131 2524 : if (Item1 == 0 && state.dataHeatBal->NumOfZoneLists > 0) {
7132 5 : ZLItem = Util::FindItemInList(s_ipsc->cAlphaArgs(3), state.dataHeatBal->ZoneList);
7133 : }
7134 2524 : if (Item1 > 0) {
7135 2519 : if (s_ipsc->lAlphaFieldBlanks(4)) {
7136 2515 : ++NumIntMassSurf;
7137 : }
7138 5 : } else if (ZLItem > 0) {
7139 2 : NumIntMassSurf += state.dataHeatBal->ZoneList(ZLItem).NumOfZones;
7140 : }
7141 :
7142 2524 : if (!s_ipsc->lAlphaFieldBlanks(4)) {
7143 7 : Item1 = Util::FindItemInList(s_ipsc->cAlphaArgs(4), state.dataHeatBal->space);
7144 7 : int SLItem = 0;
7145 7 : if (Item1 == 0 && int(state.dataHeatBal->spaceList.size()) > 0) {
7146 1 : SLItem = Util::FindItemInList(s_ipsc->cAlphaArgs(4), state.dataHeatBal->spaceList);
7147 : }
7148 7 : if (Item1 > 0) {
7149 6 : ++NumIntMassSurf;
7150 1 : } else if (SLItem > 0) {
7151 1 : int numOfSpaces = int(state.dataHeatBal->spaceList(SLItem).numListSpaces);
7152 1 : NumIntMassSurf += numOfSpaces;
7153 : }
7154 : }
7155 : }
7156 174 : NumIntMassSurf = max(NumIntMassSurf, TotIntMass);
7157 174 : return NumIntMassSurf;
7158 : }
7159 :
7160 9 : void GetShadingSurfReflectanceData(EnergyPlusData &state, bool &ErrorsFound) // If errors found in input
7161 : {
7162 :
7163 : // SUBROUTINE INFORMATION:
7164 : // AUTHOR Fred Winkelmann
7165 : // DATE WRITTEN Sept 2003
7166 :
7167 : // PURPOSE OF THIS SUBROUTINE:
7168 : // Gets data for a Shading Surface Reflectance object. This is only called when the
7169 : // Solar Distribution is to be calculated for reflectances.
7170 :
7171 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
7172 : int IOStat; // IO Status when calling get input subroutine
7173 : int NumAlpha; // Number of alpha names being passed
7174 : int NumProp; // Number of properties being passed
7175 : int TotShadingSurfaceReflectance; // Total Shading Surface Reflectance statements
7176 : int Loop; // DO loop index
7177 : int SurfNum; // Surface number
7178 : int GlConstrNum; // Glazing construction number
7179 : bool WrongSurfaceType;
7180 :
7181 9 : auto &s_ipsc = state.dataIPShortCut;
7182 : // For shading surfaces, initialize value of reflectance values to default values. These values
7183 : // may be overridden below for shading surfaces with an associated Shading Surface Reflectance object.
7184 101 : for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
7185 92 : auto const &surf = state.dataSurface->Surface(SurfNum);
7186 92 : if (!(surf.Class == SurfaceClass::Shading || surf.Class == SurfaceClass::Detached_F || surf.Class == SurfaceClass::Detached_B ||
7187 86 : surf.Class == SurfaceClass::Overhang || surf.Class == SurfaceClass::Fin)) {
7188 86 : continue;
7189 : }
7190 6 : state.dataSurface->SurfShadowDiffuseSolRefl(SurfNum) = 0.2;
7191 6 : state.dataSurface->SurfShadowDiffuseVisRefl(SurfNum) = 0.2;
7192 6 : state.dataSurface->SurfShadowGlazingFrac(SurfNum) = 0.0;
7193 6 : state.dataSurface->SurfShadowGlazingConstruct(SurfNum) = 0;
7194 : }
7195 :
7196 : // Get the total number of Shading Surface Reflectance objects
7197 9 : s_ipsc->cCurrentModuleObject = "ShadingProperty:Reflectance";
7198 9 : TotShadingSurfaceReflectance = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
7199 : // IF(TotShadingSurfaceReflectance.EQ.0) RETURN
7200 :
7201 10 : for (Loop = 1; Loop <= TotShadingSurfaceReflectance; ++Loop) {
7202 :
7203 2 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
7204 1 : s_ipsc->cCurrentModuleObject,
7205 : Loop,
7206 1 : s_ipsc->cAlphaArgs,
7207 : NumAlpha,
7208 1 : s_ipsc->rNumericArgs,
7209 : NumProp,
7210 : IOStat,
7211 1 : s_ipsc->lNumericFieldBlanks,
7212 1 : s_ipsc->lAlphaFieldBlanks,
7213 1 : s_ipsc->cAlphaFieldNames,
7214 1 : s_ipsc->cNumericFieldNames);
7215 1 : SurfNum = Util::FindItemInList(s_ipsc->cAlphaArgs(1), state.dataSurface->Surface, state.dataSurface->TotSurfaces);
7216 1 : if (SurfNum == 0) {
7217 0 : ShowWarningError(state, format("{}=\"{}\", invalid specification", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
7218 0 : ShowContinueError(state, format(".. not found {}=\"{}\".", s_ipsc->cAlphaFieldNames(1), s_ipsc->cAlphaArgs(1)));
7219 : // ErrorsFound =.TRUE.
7220 0 : continue;
7221 : }
7222 :
7223 : // Check that associated surface is a shading surface
7224 1 : WrongSurfaceType = false;
7225 1 : auto const &surf = state.dataSurface->Surface(SurfNum);
7226 1 : if (!(surf.Class == SurfaceClass::Shading || surf.Class == SurfaceClass::Detached_F || surf.Class == SurfaceClass::Detached_B ||
7227 0 : surf.Class == SurfaceClass::Overhang || surf.Class == SurfaceClass::Fin)) {
7228 0 : WrongSurfaceType = true;
7229 : }
7230 1 : if (WrongSurfaceType) {
7231 0 : ShowSevereError(
7232 : state,
7233 0 : format("GetShadingSurfReflectanceData: {}=\"{}\", surface is not a shading surface.", s_ipsc->cCurrentModuleObject, surf.Name));
7234 0 : ErrorsFound = true;
7235 0 : continue;
7236 : }
7237 :
7238 : // If associated surface is a shading surface, set reflectance values
7239 1 : state.dataSurface->SurfShadowGlazingFrac(SurfNum) = s_ipsc->rNumericArgs(3);
7240 1 : state.dataSurface->SurfShadowDiffuseSolRefl(SurfNum) = (1.0 - s_ipsc->rNumericArgs(3)) * s_ipsc->rNumericArgs(1);
7241 1 : state.dataSurface->SurfShadowDiffuseVisRefl(SurfNum) = (1.0 - s_ipsc->rNumericArgs(3)) * s_ipsc->rNumericArgs(2);
7242 1 : if (s_ipsc->rNumericArgs(3) > 0.0) {
7243 1 : GlConstrNum = Util::FindItemInList(s_ipsc->cAlphaArgs(2), state.dataConstruction->Construct, state.dataHeatBal->TotConstructs);
7244 1 : if (GlConstrNum == 0) {
7245 0 : ShowSevereError(state,
7246 0 : format("{}=\"{}\", {} not found={}",
7247 0 : s_ipsc->cCurrentModuleObject,
7248 0 : state.dataSurface->Surface(SurfNum).Name,
7249 0 : s_ipsc->cAlphaFieldNames(2),
7250 0 : s_ipsc->cAlphaArgs(2)));
7251 0 : ErrorsFound = true;
7252 : } else {
7253 1 : state.dataConstruction->Construct(GlConstrNum).IsUsed = true;
7254 : }
7255 1 : state.dataSurface->SurfShadowGlazingConstruct(SurfNum) = GlConstrNum;
7256 : }
7257 1 : SurfNum = Util::FindItemInList("Mir-" + s_ipsc->cAlphaArgs(1), state.dataSurface->Surface, state.dataSurface->TotSurfaces);
7258 1 : if (SurfNum == 0) {
7259 0 : continue;
7260 : }
7261 1 : state.dataSurface->SurfShadowGlazingFrac(SurfNum) = s_ipsc->rNumericArgs(3);
7262 1 : state.dataSurface->SurfShadowDiffuseSolRefl(SurfNum) = (1.0 - s_ipsc->rNumericArgs(3)) * s_ipsc->rNumericArgs(1);
7263 1 : state.dataSurface->SurfShadowDiffuseVisRefl(SurfNum) = (1.0 - s_ipsc->rNumericArgs(3)) * s_ipsc->rNumericArgs(2);
7264 1 : if (s_ipsc->rNumericArgs(3) > 0.0) {
7265 1 : GlConstrNum = Util::FindItemInList(s_ipsc->cAlphaArgs(2), state.dataConstruction->Construct, state.dataHeatBal->TotConstructs);
7266 1 : if (GlConstrNum != 0) {
7267 1 : state.dataConstruction->Construct(GlConstrNum).IsUsed = true;
7268 : }
7269 1 : state.dataSurface->SurfShadowGlazingConstruct(SurfNum) = GlConstrNum;
7270 : }
7271 :
7272 : } // End of loop over Shading Surface Reflectance objects
7273 :
7274 : // Write reflectance values to .eio file.
7275 9 : print(state.files.eio,
7276 : "! <ShadingProperty Reflectance>,Shading Surface Name,Shading Type,Diffuse Solar Reflectance, Diffuse "
7277 : "Visible Reflectance,Surface Glazing Fraction,Surface Glazing Construction\n");
7278 :
7279 101 : for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
7280 92 : auto const &surf = state.dataSurface->Surface(SurfNum);
7281 92 : if (!(surf.Class == SurfaceClass::Shading || surf.Class == SurfaceClass::Detached_F || surf.Class == SurfaceClass::Detached_B ||
7282 86 : surf.Class == SurfaceClass::Overhang || surf.Class == SurfaceClass::Fin)) {
7283 86 : continue;
7284 : }
7285 :
7286 6 : constexpr std::string_view fmt = "ShadingProperty Reflectance,{},{},{:.2R},{:.2R},{:.2R}, {}\n";
7287 6 : if (state.dataSurface->SurfShadowGlazingConstruct(SurfNum) != 0) {
7288 6 : print(state.files.eio,
7289 : fmt,
7290 2 : surf.Name,
7291 4 : cSurfaceClass(surf.Class),
7292 2 : state.dataSurface->SurfShadowDiffuseSolRefl(SurfNum),
7293 2 : state.dataSurface->SurfShadowDiffuseVisRefl(SurfNum),
7294 2 : state.dataSurface->SurfShadowGlazingFrac(SurfNum),
7295 2 : state.dataConstruction->Construct(state.dataSurface->SurfShadowGlazingConstruct(SurfNum)).Name);
7296 : } else {
7297 12 : print(state.files.eio,
7298 : fmt,
7299 4 : surf.Name,
7300 8 : cSurfaceClass(surf.Class),
7301 4 : state.dataSurface->SurfShadowDiffuseSolRefl(SurfNum),
7302 4 : state.dataSurface->SurfShadowDiffuseVisRefl(SurfNum),
7303 4 : state.dataSurface->SurfShadowGlazingFrac(SurfNum),
7304 : "N/A");
7305 : }
7306 : }
7307 9 : }
7308 :
7309 801 : void GetHTSurfExtVentedCavityData(EnergyPlusData &state, bool &ErrorsFound) // Error flag indicator (true if errors found)
7310 : {
7311 :
7312 : // SUBROUTINE INFORMATION:
7313 : // AUTHOR BGriffith
7314 : // DATE WRITTEN January 2005
7315 :
7316 : // PURPOSE OF THIS SUBROUTINE:
7317 : // load input data for Exterior Vented Cavity Special case for heat transfer surfaces
7318 :
7319 : // METHODOLOGY EMPLOYED:
7320 : // usual E+ input processes
7321 :
7322 : // REFERENCES:
7323 : // derived from SUBROUTINE GetTranspiredCollectorInput
7324 :
7325 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
7326 : int Item; // Item to be "gotten"
7327 : int NumAlphas; // Number of Alphas for each GetObjectItem call
7328 : int NumNumbers; // Number of Numbers for each GetObjectItem call
7329 : int MaxNumAlphas; // argument for call to GetObjectDefMaxArgs
7330 : int MaxNumNumbers; // argument for call to GetObjectDefMaxArgs
7331 : int Dummy; // argument for call to GetObjectDefMaxArgs
7332 : int IOStatus; // Used in GetObjectItem
7333 : int Found;
7334 : int AlphaOffset; // local temp var
7335 801 : std::string Roughness;
7336 : int ThisSurf; // do loop counter
7337 : Real64 AvgAzimuth; // temp for error checking
7338 : Real64 AvgTilt; // temp for error checking
7339 801 : constexpr Real64 AZITOL = 15.0; // Degree Azimuth Angle Tolerance
7340 801 : constexpr Real64 TILTOL = 10.0; // Degree Tilt Angle Tolerance
7341 : int SurfID; // local surface "pointer"
7342 :
7343 801 : auto &s_ipsc = state.dataIPShortCut;
7344 801 : s_ipsc->cCurrentModuleObject = "SurfaceProperty:ExteriorNaturalVentedCavity";
7345 801 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, s_ipsc->cCurrentModuleObject, Dummy, MaxNumAlphas, MaxNumNumbers);
7346 :
7347 801 : if (MaxNumNumbers != 8) {
7348 0 : ShowSevereError(
7349 : state,
7350 0 : format("{}: Object Definition indicates not = 8 Number Objects, Number Indicated={}", s_ipsc->cCurrentModuleObject, MaxNumNumbers));
7351 0 : ErrorsFound = true;
7352 : }
7353 :
7354 801 : state.dataSurface->TotExtVentCav = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
7355 :
7356 801 : state.dataHeatBal->ExtVentedCavity.allocate(state.dataSurface->TotExtVentCav);
7357 :
7358 806 : for (Item = 1; Item <= state.dataSurface->TotExtVentCav; ++Item) {
7359 10 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
7360 5 : s_ipsc->cCurrentModuleObject,
7361 : Item,
7362 5 : s_ipsc->cAlphaArgs,
7363 : NumAlphas,
7364 5 : s_ipsc->rNumericArgs,
7365 : NumNumbers,
7366 : IOStatus,
7367 5 : s_ipsc->lNumericFieldBlanks,
7368 5 : s_ipsc->lAlphaFieldBlanks,
7369 5 : s_ipsc->cAlphaFieldNames,
7370 5 : s_ipsc->cNumericFieldNames);
7371 : // first handle cAlphaArgs
7372 5 : bool ErrorInName = false;
7373 5 : bool IsBlank = false;
7374 :
7375 10 : Util::VerifyName(state,
7376 5 : s_ipsc->cAlphaArgs(1),
7377 5 : state.dataHeatBal->ExtVentedCavity,
7378 : Item - 1,
7379 : ErrorInName,
7380 : IsBlank,
7381 10 : s_ipsc->cCurrentModuleObject + " Name");
7382 5 : if (ErrorInName) {
7383 0 : ShowContinueError(state, "...cannot not duplicate other names");
7384 0 : ErrorsFound = true;
7385 0 : continue;
7386 : }
7387 5 : state.dataHeatBal->ExtVentedCavity(Item).Name = s_ipsc->cAlphaArgs(1);
7388 :
7389 5 : state.dataHeatBal->ExtVentedCavity(Item).OSCMName = s_ipsc->cAlphaArgs(2);
7390 5 : if (!s_ipsc->lAlphaFieldBlanks(2)) {
7391 5 : Found = Util::FindItemInList(state.dataHeatBal->ExtVentedCavity(Item).OSCMName, state.dataSurface->OSCM, state.dataSurface->TotOSCM);
7392 5 : if (Found == 0) {
7393 0 : ShowSevereError(state,
7394 0 : format("{}=\"{}\", invalid {}=\"{}\".",
7395 0 : s_ipsc->cCurrentModuleObject,
7396 0 : state.dataHeatBal->ExtVentedCavity(Item).Name,
7397 0 : s_ipsc->cAlphaFieldNames(2),
7398 0 : s_ipsc->cAlphaArgs(2)));
7399 0 : ErrorsFound = true;
7400 : }
7401 : } else {
7402 0 : Found = 0;
7403 0 : ShowSevereError(state,
7404 0 : format("{}=\"{}\", invalid {} cannot be blank.",
7405 0 : s_ipsc->cCurrentModuleObject,
7406 0 : state.dataHeatBal->ExtVentedCavity(Item).Name,
7407 0 : s_ipsc->cAlphaFieldNames(2)));
7408 0 : ErrorsFound = true;
7409 : }
7410 5 : state.dataHeatBal->ExtVentedCavity(Item).OSCMPtr = Found;
7411 :
7412 5 : Roughness = s_ipsc->cAlphaArgs(3);
7413 : // Select the correct Number for the associated ascii name for the roughness type
7414 5 : if (Util::SameString(Roughness, "VerySmooth")) {
7415 0 : state.dataHeatBal->ExtVentedCavity(Item).BaffleRoughness = Material::SurfaceRoughness::VerySmooth;
7416 5 : } else if (Util::SameString(Roughness, "Smooth")) {
7417 5 : state.dataHeatBal->ExtVentedCavity(Item).BaffleRoughness = Material::SurfaceRoughness::Smooth;
7418 0 : } else if (Util::SameString(Roughness, "MediumSmooth")) {
7419 0 : state.dataHeatBal->ExtVentedCavity(Item).BaffleRoughness = Material::SurfaceRoughness::MediumSmooth;
7420 0 : } else if (Util::SameString(Roughness, "MediumRough")) {
7421 0 : state.dataHeatBal->ExtVentedCavity(Item).BaffleRoughness = Material::SurfaceRoughness::MediumRough;
7422 0 : } else if (Util::SameString(Roughness, "Rough")) {
7423 0 : state.dataHeatBal->ExtVentedCavity(Item).BaffleRoughness = Material::SurfaceRoughness::Rough;
7424 0 : } else if (Util::SameString(Roughness, "VeryRough")) {
7425 0 : state.dataHeatBal->ExtVentedCavity(Item).BaffleRoughness = Material::SurfaceRoughness::VeryRough;
7426 : } // TODO: fix this after creating FindEnumeratedValueIndex()
7427 :
7428 : // Was it set?
7429 5 : if (state.dataHeatBal->ExtVentedCavity(Item).BaffleRoughness == Material::SurfaceRoughness::Invalid) {
7430 0 : ShowSevereError(state,
7431 0 : format("{}=\"{}\", invalid {}=\"{}",
7432 0 : s_ipsc->cCurrentModuleObject,
7433 0 : state.dataHeatBal->ExtVentedCavity(Item).Name,
7434 0 : s_ipsc->cAlphaFieldNames(3),
7435 0 : s_ipsc->cAlphaArgs(3)));
7436 0 : ErrorsFound = true;
7437 : }
7438 :
7439 5 : AlphaOffset = 3;
7440 5 : state.dataHeatBal->ExtVentedCavity(Item).NumSurfs = NumAlphas - AlphaOffset;
7441 5 : if (state.dataHeatBal->ExtVentedCavity(Item).NumSurfs == 0) {
7442 0 : ShowSevereError(state,
7443 0 : format("{}=\"{}\", no underlying surfaces specified. Must have at least one.",
7444 0 : s_ipsc->cCurrentModuleObject,
7445 0 : state.dataHeatBal->ExtVentedCavity(Item).Name));
7446 0 : ErrorsFound = true;
7447 0 : continue;
7448 : }
7449 5 : state.dataHeatBal->ExtVentedCavity(Item).SurfPtrs.allocate(state.dataHeatBal->ExtVentedCavity(Item).NumSurfs);
7450 5 : state.dataHeatBal->ExtVentedCavity(Item).SurfPtrs = 0;
7451 10 : for (ThisSurf = 1; ThisSurf <= state.dataHeatBal->ExtVentedCavity(Item).NumSurfs; ++ThisSurf) {
7452 5 : Found = Util::FindItemInList(s_ipsc->cAlphaArgs(ThisSurf + AlphaOffset), state.dataSurface->Surface, state.dataSurface->TotSurfaces);
7453 5 : if (Found == 0) {
7454 0 : ShowSevereError(state,
7455 0 : format("{}=\"{}\", invalid {}=\"{}",
7456 0 : s_ipsc->cCurrentModuleObject,
7457 0 : state.dataHeatBal->ExtVentedCavity(Item).Name,
7458 0 : s_ipsc->cAlphaFieldNames(ThisSurf + AlphaOffset),
7459 0 : s_ipsc->cAlphaArgs(ThisSurf + AlphaOffset)));
7460 0 : ErrorsFound = true;
7461 0 : continue;
7462 : }
7463 : // check that surface is appropriate, Heat transfer, Sun, Wind,
7464 5 : if (!state.dataSurface->Surface(Found).HeatTransSurf) {
7465 0 : ShowSevereError(state,
7466 0 : format("{}=\"{}\", invalid {}=\"{}",
7467 0 : s_ipsc->cCurrentModuleObject,
7468 0 : state.dataHeatBal->ExtVentedCavity(Item).Name,
7469 0 : s_ipsc->cAlphaFieldNames(ThisSurf + AlphaOffset),
7470 0 : s_ipsc->cAlphaArgs(ThisSurf + AlphaOffset)));
7471 0 : ShowContinueError(state, "...because it is not a Heat Transfer Surface.");
7472 0 : ErrorsFound = true;
7473 0 : continue;
7474 : }
7475 5 : if (!state.dataSurface->Surface(Found).ExtSolar) {
7476 0 : ShowSevereError(state,
7477 0 : format("{}=\"{}\", invalid {}=\"{}",
7478 0 : s_ipsc->cCurrentModuleObject,
7479 0 : state.dataHeatBal->ExtVentedCavity(Item).Name,
7480 0 : s_ipsc->cAlphaFieldNames(ThisSurf + AlphaOffset),
7481 0 : s_ipsc->cAlphaArgs(ThisSurf + AlphaOffset)));
7482 0 : ShowContinueError(state, "...because it is not exposed to Sun.");
7483 0 : ErrorsFound = true;
7484 0 : continue;
7485 : }
7486 5 : if (!state.dataSurface->Surface(Found).ExtWind) {
7487 0 : ShowSevereError(state,
7488 0 : format("{}=\"{}\", invalid {}=\"{}",
7489 0 : s_ipsc->cCurrentModuleObject,
7490 0 : state.dataHeatBal->ExtVentedCavity(Item).Name,
7491 0 : s_ipsc->cAlphaFieldNames(ThisSurf + AlphaOffset),
7492 0 : s_ipsc->cAlphaArgs(ThisSurf + AlphaOffset)));
7493 0 : ShowContinueError(state, "...because it is not exposed to Wind.");
7494 0 : ErrorsFound = true;
7495 0 : continue;
7496 : }
7497 5 : if (state.dataSurface->Surface(Found).ExtBoundCond != DataSurfaces::OtherSideCondModeledExt) {
7498 0 : ShowSevereError(state,
7499 0 : format("{}=\"{}\", is invalid", s_ipsc->cCurrentModuleObject, state.dataHeatBal->ExtVentedCavity(Item).Name));
7500 0 : ShowContinueError(state,
7501 0 : format("...because {}=\"{}\".",
7502 0 : s_ipsc->cAlphaFieldNames(ThisSurf + AlphaOffset),
7503 0 : s_ipsc->cAlphaArgs(ThisSurf + AlphaOffset)));
7504 0 : ShowContinueError(state, "...is not an OtherSideConditionedModel surface.");
7505 0 : ErrorsFound = true;
7506 0 : continue;
7507 : }
7508 5 : state.dataHeatBal->ExtVentedCavity(Item).SurfPtrs(ThisSurf) = Found;
7509 :
7510 : // now set info in Surface structure
7511 5 : state.dataSurface->SurfExtCavNum(Found) = Item;
7512 5 : state.dataSurface->SurfExtCavityPresent(Found) = true;
7513 : }
7514 :
7515 5 : if (ErrorsFound) {
7516 0 : continue; // previous inner do loop may have detected problems that need to be cycle'd again to avoid crash
7517 : }
7518 :
7519 : // now that we should have all the surfaces, do some preparations and checks.
7520 :
7521 : // are they all similar tilt and azimuth? Issue warnings so people can do it if they really want
7522 5 : Real64 const surfaceArea(sum_sub(state.dataSurface->Surface, &SurfaceData::Area, state.dataHeatBal->ExtVentedCavity(Item).SurfPtrs));
7523 : // AvgAzimuth = sum( Surface( ExtVentedCavity( Item ).SurfPtrs ).Azimuth * Surface( ExtVentedCavity( Item ).SurfPtrs
7524 : //).Area
7525 : //)
7526 : /// sum( Surface( ExtVentedCavity( Item ).SurfPtrs ).Area ); //Autodesk:F2C++ Array subscript usage: Replaced by below
7527 5 : AvgAzimuth = sum_product_sub(state.dataSurface->Surface,
7528 : &SurfaceData::Azimuth,
7529 : &SurfaceData::Area,
7530 5 : state.dataHeatBal->ExtVentedCavity(Item).SurfPtrs) /
7531 : surfaceArea; // Autodesk:F2C++ Functions handle array subscript usage
7532 : // AvgTilt = sum( Surface( ExtVentedCavity( Item ).SurfPtrs ).Tilt * Surface( ExtVentedCavity( Item ).SurfPtrs ).Area )
7533 : // /
7534 : // sum( Surface( ExtVentedCavity( Item ).SurfPtrs ).Area ); //Autodesk:F2C++ Array subscript usage: Replaced by below
7535 10 : AvgTilt = sum_product_sub(
7536 5 : state.dataSurface->Surface, &SurfaceData::Tilt, &SurfaceData::Area, state.dataHeatBal->ExtVentedCavity(Item).SurfPtrs) /
7537 : surfaceArea; // Autodesk:F2C++ Functions handle array subscript usage
7538 10 : for (ThisSurf = 1; ThisSurf <= state.dataHeatBal->ExtVentedCavity(Item).NumSurfs; ++ThisSurf) {
7539 5 : SurfID = state.dataHeatBal->ExtVentedCavity(Item).SurfPtrs(ThisSurf);
7540 5 : if (General::rotAzmDiffDeg(state.dataSurface->Surface(SurfID).Azimuth, AvgAzimuth) > AZITOL) {
7541 0 : ShowWarningError(state,
7542 0 : format("{}=\"{}, Surface {} has Azimuth different from others in the associated group.",
7543 0 : s_ipsc->cCurrentModuleObject,
7544 0 : state.dataHeatBal->ExtVentedCavity(Item).Name,
7545 0 : state.dataSurface->Surface(SurfID).Name));
7546 : }
7547 5 : if (std::abs(state.dataSurface->Surface(SurfID).Tilt - AvgTilt) > TILTOL) {
7548 0 : ShowWarningError(state,
7549 0 : format("{}=\"{}, Surface {} has Tilt different from others in the associated group.",
7550 0 : s_ipsc->cCurrentModuleObject,
7551 0 : state.dataHeatBal->ExtVentedCavity(Item).Name,
7552 0 : state.dataSurface->Surface(SurfID).Name));
7553 : }
7554 :
7555 : // test that there are no windows. Now allow windows
7556 : // If (Surface(SurfID)%GrossArea > Surface(SurfID)%Area) Then
7557 : // Call ShowWarningError(state, 'Surface '//TRIM(Surface(SurfID)%name)//' has a subsurface whose area is not being ' &
7558 : // //'subtracted in the group of surfaces associated with '//TRIM(ExtVentedCavity(Item)%Name))
7559 : // endif
7560 : }
7561 5 : state.dataHeatBal->ExtVentedCavity(Item).Tilt = AvgTilt;
7562 5 : state.dataHeatBal->ExtVentedCavity(Item).Azimuth = AvgAzimuth;
7563 :
7564 : // find area weighted centroid.
7565 : // ExtVentedCavity( Item ).Centroid.z = sum( Surface( ExtVentedCavity( Item ).SurfPtrs ).Centroid.z * Surface(
7566 : // ExtVentedCavity( Item
7567 : //).SurfPtrs ).Area ) / sum( Surface( ExtVentedCavity( Item ).SurfPtrs ).Area ); //Autodesk:F2C++ Array subscript usage: Replaced
7568 : // by below
7569 10 : state.dataHeatBal->ExtVentedCavity(Item).Centroid.z = sum_product_sub(state.dataSurface->Surface,
7570 : &SurfaceData::Centroid,
7571 : &Vector::z,
7572 5 : state.dataSurface->Surface,
7573 : &SurfaceData::Area,
7574 10 : state.dataHeatBal->ExtVentedCavity(Item).SurfPtrs) /
7575 : surfaceArea; // Autodesk:F2C++ Functions handle array subscript usage
7576 :
7577 : // now handle rNumericArgs from input object
7578 5 : state.dataHeatBal->ExtVentedCavity(Item).Porosity = s_ipsc->rNumericArgs(1);
7579 5 : state.dataHeatBal->ExtVentedCavity(Item).LWEmitt = s_ipsc->rNumericArgs(2);
7580 5 : state.dataHeatBal->ExtVentedCavity(Item).SolAbsorp = s_ipsc->rNumericArgs(3);
7581 5 : state.dataHeatBal->ExtVentedCavity(Item).HdeltaNPL = s_ipsc->rNumericArgs(4);
7582 5 : state.dataHeatBal->ExtVentedCavity(Item).PlenGapThick = s_ipsc->rNumericArgs(5);
7583 5 : if (state.dataHeatBal->ExtVentedCavity(Item).PlenGapThick <= 0.0) {
7584 0 : ShowSevereError(state, format("{}=\"{}\", invalid .", s_ipsc->cCurrentModuleObject, state.dataHeatBal->ExtVentedCavity(Item).Name));
7585 0 : ErrorsFound = true;
7586 0 : ShowContinueError(
7587 : state,
7588 0 : format("...because field \"{}\" must be greater than Zero=[{:.2T}].", s_ipsc->cNumericFieldNames(5), s_ipsc->rNumericArgs(5)));
7589 0 : continue;
7590 : }
7591 5 : state.dataHeatBal->ExtVentedCavity(Item).AreaRatio = s_ipsc->rNumericArgs(6);
7592 5 : state.dataHeatBal->ExtVentedCavity(Item).Cv = s_ipsc->rNumericArgs(7);
7593 5 : state.dataHeatBal->ExtVentedCavity(Item).Cd = s_ipsc->rNumericArgs(8);
7594 :
7595 : // Fill out data we now know
7596 : // sum areas of HT surface areas
7597 : // ExtVentedCavity( Item ).ProjArea = sum( Surface( ExtVentedCavity( Item ).SurfPtrs ).Area ); //Autodesk:F2C++ Array
7598 : // subscript usage: Replaced by below
7599 5 : state.dataHeatBal->ExtVentedCavity(Item).ProjArea = surfaceArea;
7600 5 : if (state.dataHeatBal->ExtVentedCavity(Item).ProjArea <= 0.0) {
7601 0 : ShowSevereError(state, format("{}=\"{}\", invalid .", s_ipsc->cCurrentModuleObject, state.dataHeatBal->ExtVentedCavity(Item).Name));
7602 0 : ErrorsFound = true;
7603 0 : ShowContinueError(state,
7604 0 : format("...because gross area of underlying surfaces must be greater than Zero=[{:.2T}].",
7605 0 : state.dataHeatBal->ExtVentedCavity(Item).ProjArea));
7606 0 : continue;
7607 : }
7608 5 : state.dataHeatBal->ExtVentedCavity(Item).ActualArea =
7609 5 : state.dataHeatBal->ExtVentedCavity(Item).ProjArea * state.dataHeatBal->ExtVentedCavity(Item).AreaRatio;
7610 :
7611 10 : SetupOutputVariable(state,
7612 : "Surface Exterior Cavity Baffle Surface Temperature",
7613 : Constant::Units::C,
7614 5 : state.dataHeatBal->ExtVentedCavity(Item).Tbaffle,
7615 : OutputProcessor::TimeStepType::System,
7616 : OutputProcessor::StoreType::Average,
7617 5 : state.dataHeatBal->ExtVentedCavity(Item).Name);
7618 10 : SetupOutputVariable(state,
7619 : "Surface Exterior Cavity Air Drybulb Temperature",
7620 : Constant::Units::C,
7621 5 : state.dataHeatBal->ExtVentedCavity(Item).TAirCav,
7622 : OutputProcessor::TimeStepType::System,
7623 : OutputProcessor::StoreType::Average,
7624 5 : state.dataHeatBal->ExtVentedCavity(Item).Name);
7625 10 : SetupOutputVariable(state,
7626 : "Surface Exterior Cavity Total Natural Ventilation Air Change Rate",
7627 : Constant::Units::ach,
7628 5 : state.dataHeatBal->ExtVentedCavity(Item).PassiveACH,
7629 : OutputProcessor::TimeStepType::System,
7630 : OutputProcessor::StoreType::Average,
7631 5 : state.dataHeatBal->ExtVentedCavity(Item).Name);
7632 10 : SetupOutputVariable(state,
7633 : "Surface Exterior Cavity Total Natural Ventilation Mass Flow Rate",
7634 : Constant::Units::kg_s,
7635 5 : state.dataHeatBal->ExtVentedCavity(Item).PassiveMdotVent,
7636 : OutputProcessor::TimeStepType::System,
7637 : OutputProcessor::StoreType::Average,
7638 5 : state.dataHeatBal->ExtVentedCavity(Item).Name);
7639 10 : SetupOutputVariable(state,
7640 : "Surface Exterior Cavity Natural Ventilation from Wind Mass Flow Rate",
7641 : Constant::Units::kg_s,
7642 5 : state.dataHeatBal->ExtVentedCavity(Item).PassiveMdotWind,
7643 : OutputProcessor::TimeStepType::System,
7644 : OutputProcessor::StoreType::Average,
7645 5 : state.dataHeatBal->ExtVentedCavity(Item).Name);
7646 10 : SetupOutputVariable(state,
7647 : "Surface Exterior Cavity Natural Ventilation from Buoyancy Mass Flow Rate",
7648 : Constant::Units::kg_s,
7649 5 : state.dataHeatBal->ExtVentedCavity(Item).PassiveMdotTherm,
7650 : OutputProcessor::TimeStepType::System,
7651 : OutputProcessor::StoreType::Average,
7652 5 : state.dataHeatBal->ExtVentedCavity(Item).Name);
7653 : }
7654 801 : }
7655 :
7656 801 : void ExposedFoundationPerimeter::getData(EnergyPlusData &state, bool &ErrorsFound)
7657 : {
7658 :
7659 : static constexpr std::string_view routineName = "ExposedFoundationPerimeter::getData";
7660 : int IOStatus; // Used in GetObjectItem
7661 : int NumAlphas;
7662 : int NumNumbers;
7663 :
7664 801 : Real64 constexpr tolerance = 1e-6;
7665 :
7666 801 : auto &s_ipsc = state.dataIPShortCut;
7667 :
7668 801 : s_ipsc->cCurrentModuleObject = "SurfaceProperty:ExposedFoundationPerimeter";
7669 801 : int numObjects = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
7670 :
7671 825 : for (int obj = 1; obj <= numObjects; ++obj) {
7672 24 : int alpF = 1;
7673 24 : int numF = 1;
7674 48 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
7675 24 : s_ipsc->cCurrentModuleObject,
7676 : obj,
7677 24 : s_ipsc->cAlphaArgs,
7678 : NumAlphas,
7679 24 : s_ipsc->rNumericArgs,
7680 : NumNumbers,
7681 : IOStatus,
7682 24 : s_ipsc->lNumericFieldBlanks,
7683 24 : s_ipsc->lAlphaFieldBlanks,
7684 24 : s_ipsc->cAlphaFieldNames,
7685 24 : s_ipsc->cNumericFieldNames);
7686 :
7687 24 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(alpF)};
7688 :
7689 24 : int Found = Util::FindItemInList(s_ipsc->cAlphaArgs(alpF), state.dataSurface->Surface, state.dataSurface->TotSurfaces);
7690 24 : if (Found == 0) {
7691 0 : ShowSevereError(state, format("{}=\"{}\", did not find matching surface", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
7692 0 : ErrorsFound = true;
7693 : }
7694 24 : alpF++;
7695 24 : if (state.dataSurface->Surface(Found).Class != SurfaceClass::Floor) {
7696 0 : ShowWarningError(
7697 0 : state, format("{}: {}, surface is not a floor surface", s_ipsc->cCurrentModuleObject, state.dataSurface->Surface(Found).Name));
7698 0 : ShowContinueError(state, format("{} will not be used", s_ipsc->cCurrentModuleObject));
7699 0 : continue;
7700 : }
7701 :
7702 : // Choose calculation method
7703 :
7704 : enum class CalculationMethod
7705 : {
7706 : Invalid = -1,
7707 : TotalExposedPerimeter,
7708 : ExposedPerimeterFraction,
7709 : Bysegment,
7710 : Num
7711 : };
7712 :
7713 24 : constexpr std::array<std::string_view, static_cast<int>(CalculationMethod::Num)> CalculationMethodUC = {
7714 : "TOTALEXPOSEDPERIMETER", "EXPOSEDPERIMETERFRACTION", "BYSEGMENT"};
7715 24 : CalculationMethod calculationMethod = static_cast<CalculationMethod>(getEnumValue(CalculationMethodUC, s_ipsc->cAlphaArgs(alpF)));
7716 24 : if (calculationMethod != CalculationMethod::TotalExposedPerimeter && calculationMethod != CalculationMethod::ExposedPerimeterFraction &&
7717 19 : calculationMethod != CalculationMethod::Bysegment) {
7718 0 : ShowSevereError(state,
7719 0 : format("{}=\"{}\", {} is not a valid choice for {}",
7720 0 : s_ipsc->cCurrentModuleObject,
7721 0 : s_ipsc->cAlphaArgs(1),
7722 : calculationMethod,
7723 0 : s_ipsc->cAlphaFieldNames(alpF)));
7724 0 : ErrorsFound = true;
7725 : }
7726 24 : alpF++;
7727 :
7728 24 : Data data;
7729 24 : data.useDetailedExposedPerimeter = true;
7730 :
7731 24 : if (!s_ipsc->lNumericFieldBlanks(numF)) {
7732 2 : if (calculationMethod == CalculationMethod::TotalExposedPerimeter) {
7733 2 : data.exposedFraction = s_ipsc->rNumericArgs(numF) / state.dataSurface->Surface(Found).Perimeter;
7734 2 : if (data.exposedFraction > 1 + tolerance) {
7735 0 : ShowWarningError(state,
7736 0 : format("{}: {}, {} is greater than the perimeter of {}",
7737 0 : s_ipsc->cCurrentModuleObject,
7738 0 : state.dataSurface->Surface(Found).Name,
7739 0 : s_ipsc->cNumericFieldNames(numF),
7740 0 : state.dataSurface->Surface(Found).Name));
7741 0 : ShowContinueError(state,
7742 0 : format("{} perimeter = {}, {} exposed perimeter = {}",
7743 0 : state.dataSurface->Surface(Found).Name,
7744 0 : state.dataSurface->Surface(Found).Perimeter,
7745 0 : s_ipsc->cCurrentModuleObject,
7746 0 : s_ipsc->rNumericArgs(numF)));
7747 0 : ShowContinueError(
7748 : state,
7749 0 : format("{} will be set equal to {} perimeter", s_ipsc->cNumericFieldNames(numF), state.dataSurface->Surface(Found).Name));
7750 0 : data.exposedFraction = 1.0;
7751 : }
7752 :
7753 2 : data.useDetailedExposedPerimeter = false;
7754 : } else {
7755 0 : ShowWarningError(state,
7756 0 : format("{}: {}, {} set as calculation method, but a value has been set for {}. This value will be ignored.",
7757 0 : s_ipsc->cCurrentModuleObject,
7758 0 : state.dataSurface->Surface(Found).Name,
7759 : calculationMethod,
7760 0 : s_ipsc->cNumericFieldNames(numF)));
7761 : }
7762 : } else {
7763 22 : if (calculationMethod == CalculationMethod::TotalExposedPerimeter) {
7764 0 : ShowSevereError(state,
7765 0 : format("{}: {}, {} set as calculation method, but no value has been set for {}",
7766 0 : s_ipsc->cCurrentModuleObject,
7767 0 : state.dataSurface->Surface(Found).Name,
7768 : calculationMethod,
7769 0 : s_ipsc->cNumericFieldNames(numF)));
7770 0 : ErrorsFound = true;
7771 : }
7772 : }
7773 24 : numF++;
7774 :
7775 24 : if (!s_ipsc->lNumericFieldBlanks(numF)) {
7776 3 : if (calculationMethod == CalculationMethod::ExposedPerimeterFraction) {
7777 3 : data.exposedFraction = s_ipsc->rNumericArgs(numF);
7778 3 : data.useDetailedExposedPerimeter = false;
7779 : } else {
7780 0 : ShowWarningError(state,
7781 0 : format("{}: {}, {} set as calculation method, but a value has been set for {}. This value will be ignored.",
7782 0 : s_ipsc->cCurrentModuleObject,
7783 0 : state.dataSurface->Surface(Found).Name,
7784 : calculationMethod,
7785 0 : s_ipsc->cNumericFieldNames(numF)));
7786 : }
7787 : } else {
7788 21 : if (calculationMethod == CalculationMethod::ExposedPerimeterFraction) {
7789 0 : ShowSevereError(state,
7790 0 : format("{}: {}, {} set as calculation method, but no value has been set for {}",
7791 0 : s_ipsc->cCurrentModuleObject,
7792 0 : state.dataSurface->Surface(Found).Name,
7793 : calculationMethod,
7794 0 : s_ipsc->cNumericFieldNames(numF)));
7795 0 : ErrorsFound = true;
7796 : }
7797 : }
7798 24 : numF++;
7799 :
7800 24 : int numRemainingFields = NumAlphas - (alpF - 1) + NumNumbers - (numF - 1);
7801 24 : if (numRemainingFields > 0) {
7802 19 : if (calculationMethod == CalculationMethod::Bysegment) {
7803 19 : if (numRemainingFields != (int)state.dataSurface->Surface(Found).Vertex.size()) {
7804 0 : ShowSevereError(state,
7805 0 : format("{}: {}, must have equal number of segments as the floor has vertices.{}\" and \"{}\"",
7806 0 : s_ipsc->cCurrentModuleObject,
7807 0 : state.dataSurface->Surface(Found).Name,
7808 0 : s_ipsc->cAlphaFieldNames(alpF),
7809 0 : s_ipsc->cNumericFieldNames(numF - 1)));
7810 0 : ShowContinueError(state,
7811 0 : format("{} number of vertices = {}, {} number of segments = {}",
7812 0 : state.dataSurface->Surface(Found).Name,
7813 0 : state.dataSurface->Surface(Found).Vertex.size(),
7814 0 : s_ipsc->cCurrentModuleObject,
7815 : numRemainingFields));
7816 0 : ErrorsFound = true;
7817 : }
7818 95 : for (int segNum = 0; segNum < numRemainingFields; segNum++) {
7819 76 : if (s_ipsc->lAlphaFieldBlanks(alpF)) {
7820 0 : ShowSevereEmptyField(
7821 0 : state, eoh, s_ipsc->cAlphaFieldNames(alpF), "Calculation Method", CalculationMethodUC[(int)calculationMethod]);
7822 0 : ErrorsFound = true;
7823 76 : } else if (BooleanSwitch bs = getYesNoValue(s_ipsc->cAlphaArgs(alpF)); bs != BooleanSwitch::Invalid) {
7824 76 : data.isExposedPerimeter.push_back(static_cast<bool>(bs));
7825 : } else {
7826 0 : ShowSevereInvalidBool(state, eoh, s_ipsc->cAlphaFieldNames(alpF), s_ipsc->cAlphaArgs(alpF));
7827 0 : ErrorsFound = true;
7828 : }
7829 76 : alpF++;
7830 : }
7831 : }
7832 : } else {
7833 5 : if (calculationMethod == CalculationMethod::Bysegment) {
7834 0 : ShowSevereError(state,
7835 0 : format("{}: {}, {} set as calculation method, but no values have been set for Surface Segments Exposed",
7836 0 : s_ipsc->cCurrentModuleObject,
7837 0 : state.dataSurface->Surface(Found).Name,
7838 : calculationMethod));
7839 0 : ErrorsFound = true;
7840 : }
7841 : }
7842 24 : surfaceMap[Found] = data;
7843 24 : }
7844 801 : }
7845 :
7846 801 : void GetSurfaceLocalEnvData(EnergyPlusData &state, bool &ErrorsFound) // Error flag indicator (true if errors found)
7847 : {
7848 : // SUBROUTINE INFORMATION:
7849 : // AUTHOR X LUO
7850 : // DATE WRITTEN July 2017
7851 :
7852 : // PURPOSE OF THIS SUBROUTINE:
7853 : // load input data for Outdoor Air Node for exterior surfaces
7854 :
7855 : // SUBROUTINE PARAMETER DEFINITIONS:
7856 : static constexpr std::string_view RoutineName("GetSurfaceLocalEnvData: ");
7857 : static constexpr std::string_view routineName = "GetSurfaceLocalEnvData";
7858 :
7859 801 : auto &s_ipsc = state.dataIPShortCut;
7860 :
7861 801 : s_ipsc->cCurrentModuleObject = "SurfaceProperty:LocalEnvironment";
7862 801 : state.dataSurface->TotSurfLocalEnv = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
7863 :
7864 801 : if (state.dataSurface->TotSurfLocalEnv > 0) {
7865 : int NumAlpha;
7866 : int NumNumeric;
7867 : int IOStat;
7868 :
7869 4 : state.dataGlobal->AnyLocalEnvironmentsInModel = true;
7870 :
7871 4 : if (!allocated(state.dataSurface->SurfLocalEnvironment)) {
7872 4 : state.dataSurface->SurfLocalEnvironment.allocate(state.dataSurface->TotSurfLocalEnv);
7873 : }
7874 :
7875 126 : for (int Loop = 1; Loop <= state.dataSurface->TotSurfLocalEnv; ++Loop) {
7876 :
7877 122 : auto &SurfLocalEnv = state.dataSurface->SurfLocalEnvironment(Loop);
7878 :
7879 244 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
7880 122 : s_ipsc->cCurrentModuleObject,
7881 : Loop,
7882 122 : s_ipsc->cAlphaArgs,
7883 : NumAlpha,
7884 122 : s_ipsc->rNumericArgs,
7885 : NumNumeric,
7886 : IOStat,
7887 122 : s_ipsc->lNumericFieldBlanks,
7888 122 : s_ipsc->lAlphaFieldBlanks,
7889 122 : s_ipsc->cAlphaFieldNames,
7890 122 : s_ipsc->cNumericFieldNames);
7891 :
7892 122 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
7893 :
7894 122 : Util::IsNameEmpty(state, s_ipsc->cAlphaArgs(1), s_ipsc->cCurrentModuleObject, ErrorsFound);
7895 :
7896 122 : SurfLocalEnv.Name = s_ipsc->cAlphaArgs(1);
7897 :
7898 : // Assign surface number
7899 122 : int SurfNum = Util::FindItemInList(s_ipsc->cAlphaArgs(2), state.dataSurface->Surface);
7900 122 : if (SurfNum == 0) {
7901 0 : ShowSevereError(state,
7902 0 : format("{} {} = \"{}\", object. Illegal value for \"{}\" has been found.",
7903 : RoutineName,
7904 0 : s_ipsc->cCurrentModuleObject,
7905 0 : SurfLocalEnv.Name,
7906 0 : s_ipsc->cAlphaFieldNames(2)));
7907 0 : ShowContinueError(state,
7908 0 : format("{} entered value = \"{}\", no corresponding surface (ref BuildingSurface:Detailed) has been "
7909 : "found in the input file.",
7910 0 : s_ipsc->cAlphaFieldNames(2),
7911 0 : s_ipsc->cAlphaArgs(2)));
7912 0 : ErrorsFound = true;
7913 : } else {
7914 122 : SurfLocalEnv.SurfPtr = SurfNum;
7915 : }
7916 :
7917 : // Assign Sunlit Fraction Schedule number
7918 122 : if (s_ipsc->lAlphaFieldBlanks(3)) {
7919 102 : } else if ((SurfLocalEnv.sunlitFracSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(3))) == nullptr) {
7920 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3));
7921 0 : ErrorsFound = true;
7922 : }
7923 :
7924 : // Assign surrounding surfaces object number;
7925 122 : if (!s_ipsc->lAlphaFieldBlanks(4)) {
7926 6 : int SurroundingSurfsNum = Util::FindItemInList(s_ipsc->cAlphaArgs(4), state.dataSurface->SurroundingSurfsProperty);
7927 6 : if (SurroundingSurfsNum == 0) {
7928 0 : ShowSevereError(state,
7929 0 : format("{} {} = \"{}\", object. Illegal value for \"{}\" has been found.",
7930 : RoutineName,
7931 0 : s_ipsc->cCurrentModuleObject,
7932 0 : SurfLocalEnv.Name,
7933 0 : s_ipsc->cAlphaFieldNames(4)));
7934 0 : ShowContinueError(state,
7935 0 : format("{} entered value = \"{}\", no corresponding surrounding surfaces properties has been found "
7936 : "in the input file.",
7937 0 : s_ipsc->cAlphaFieldNames(4),
7938 0 : s_ipsc->cAlphaArgs(4)));
7939 0 : ErrorsFound = true;
7940 : } else {
7941 6 : SurfLocalEnv.SurroundingSurfsPtr = SurroundingSurfsNum;
7942 : }
7943 : }
7944 :
7945 : // Assign outdoor air node number;
7946 122 : if (!s_ipsc->lAlphaFieldBlanks(5)) {
7947 2 : int NodeNum = GetOnlySingleNode(state,
7948 2 : s_ipsc->cAlphaArgs(5),
7949 : ErrorsFound,
7950 : DataLoopNode::ConnectionObjectType::SurfacePropertyLocalEnvironment,
7951 2 : SurfLocalEnv.Name,
7952 : DataLoopNode::NodeFluidType::Air,
7953 : DataLoopNode::ConnectionType::Inlet,
7954 : NodeInputManager::CompFluidStream::Primary,
7955 : DataLoopNode::ObjectIsParent);
7956 2 : if (NodeNum == 0 && OutAirNodeManager::CheckOutAirNodeNumber(state, NodeNum)) {
7957 0 : ShowSevereError(state,
7958 0 : format("{} {} = \"{}\", object. Illegal value for \"{}\" has been found.",
7959 : RoutineName,
7960 0 : s_ipsc->cCurrentModuleObject,
7961 0 : SurfLocalEnv.Name,
7962 0 : s_ipsc->cAlphaFieldNames(5)));
7963 0 : ShowContinueError(state,
7964 0 : format("{} entered value = \"{}\", no corresponding outdoor air node has been found in the input file.",
7965 0 : s_ipsc->cAlphaFieldNames(5),
7966 0 : s_ipsc->cAlphaArgs(5)));
7967 0 : ErrorsFound = true;
7968 : } else {
7969 2 : SurfLocalEnv.OutdoorAirNodePtr = NodeNum;
7970 : }
7971 : }
7972 :
7973 : // get ground surfaces object number;
7974 122 : if (!s_ipsc->lAlphaFieldBlanks(6)) {
7975 13 : int GndSurfsNum = Util::FindItemInList(s_ipsc->cAlphaArgs(6), state.dataSurface->GroundSurfsProperty);
7976 13 : if (GndSurfsNum == 0) {
7977 0 : ShowSevereError(state,
7978 0 : format("{} {} = \"{}\", object. Illegal value for \"{}\" has been found.",
7979 : RoutineName,
7980 0 : s_ipsc->cCurrentModuleObject,
7981 0 : SurfLocalEnv.Name,
7982 0 : s_ipsc->cAlphaFieldNames(6)));
7983 0 : ShowContinueError(
7984 : state,
7985 0 : format("{} entered value = \"{}\", no corresponding ground surfaces object has been found in the input file.",
7986 0 : s_ipsc->cAlphaFieldNames(6),
7987 0 : s_ipsc->cAlphaArgs(6)));
7988 0 : ErrorsFound = true;
7989 : } else {
7990 13 : SurfLocalEnv.GroundSurfsPtr = GndSurfsNum;
7991 : }
7992 : }
7993 : }
7994 : }
7995 : // Link surface properties to surface object
7996 48091 : for (int SurfLoop = 1; SurfLoop <= state.dataSurface->TotSurfaces; ++SurfLoop) {
7997 60796 : for (int Loop = 1; Loop <= state.dataSurface->TotSurfLocalEnv; ++Loop) {
7998 13506 : auto const &SurfLocalEnv = state.dataSurface->SurfLocalEnvironment(Loop);
7999 13506 : if (SurfLocalEnv.SurfPtr == SurfLoop) {
8000 122 : auto &surface = state.dataSurface->Surface(SurfLoop);
8001 122 : if (SurfLocalEnv.OutdoorAirNodePtr != 0) {
8002 2 : surface.SurfLinkedOutAirNode = SurfLocalEnv.OutdoorAirNodePtr;
8003 : }
8004 122 : if (SurfLocalEnv.sunlitFracSched != nullptr) {
8005 102 : surface.SurfSchedExternalShadingFrac = true;
8006 102 : surface.surfExternalShadingSched = SurfLocalEnv.sunlitFracSched;
8007 : }
8008 122 : if (SurfLocalEnv.SurroundingSurfsPtr != 0) {
8009 6 : surface.SurfHasSurroundingSurfProperty = true;
8010 6 : surface.SurfSurroundingSurfacesNum = SurfLocalEnv.SurroundingSurfsPtr;
8011 6 : surface.ViewFactorSrdSurfs =
8012 6 : state.dataSurface->SurroundingSurfsProperty(surface.SurfSurroundingSurfacesNum).SurfsViewFactorSum;
8013 6 : if (surface.ViewFactorSrdSurfs == 0.0) {
8014 0 : surface.SurfHasSurroundingSurfProperty = false;
8015 : }
8016 : }
8017 122 : if (SurfLocalEnv.GroundSurfsPtr != 0) {
8018 13 : surface.IsSurfPropertyGndSurfacesDefined = true;
8019 13 : surface.UseSurfPropertyGndSurfTemp = true;
8020 13 : surface.UseSurfPropertyGndSurfRefl = true;
8021 13 : surface.SurfPropertyGndSurfIndex = SurfLocalEnv.GroundSurfsPtr;
8022 : }
8023 : }
8024 : }
8025 : }
8026 801 : }
8027 :
8028 801 : void GetSurfaceSrdSurfsData(EnergyPlusData &state, bool &ErrorsFound) // Error flag indicator (true if errors found)
8029 : {
8030 : // SUBROUTINE INFORMATION:
8031 : // AUTHOR X LUO
8032 : // DATE WRITTEN July 2017
8033 :
8034 : // PURPOSE OF THIS SUBROUTINE:
8035 : // load input data for surrounding surfaces properties for exterior surfaces
8036 801 : constexpr std::string_view routineName = "GetSurfaceSrdSurfsData";
8037 :
8038 801 : auto &s_ipsc = state.dataIPShortCut;
8039 :
8040 801 : s_ipsc->cCurrentModuleObject = "SurfaceProperty:SurroundingSurfaces";
8041 801 : int TotSrdSurfProperties = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
8042 :
8043 801 : if (TotSrdSurfProperties > 0) {
8044 : int NumAlpha;
8045 : int NumNumeric;
8046 : int IOStat;
8047 :
8048 2 : if (!allocated(state.dataSurface->SurroundingSurfsProperty)) {
8049 2 : state.dataSurface->SurroundingSurfsProperty.allocate(TotSrdSurfProperties);
8050 : }
8051 :
8052 8 : for (int Loop = 1; Loop <= TotSrdSurfProperties; ++Loop) {
8053 :
8054 6 : auto &SrdSurfsProp = state.dataSurface->SurroundingSurfsProperty(Loop);
8055 :
8056 12 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
8057 6 : s_ipsc->cCurrentModuleObject,
8058 : Loop,
8059 6 : s_ipsc->cAlphaArgs,
8060 : NumAlpha,
8061 6 : s_ipsc->rNumericArgs,
8062 : NumNumeric,
8063 : IOStat,
8064 6 : s_ipsc->lNumericFieldBlanks,
8065 6 : s_ipsc->lAlphaFieldBlanks,
8066 6 : s_ipsc->cAlphaFieldNames,
8067 6 : s_ipsc->cNumericFieldNames);
8068 :
8069 6 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
8070 :
8071 6 : Util::IsNameEmpty(state, s_ipsc->cAlphaArgs(1), s_ipsc->cCurrentModuleObject, ErrorsFound);
8072 :
8073 : // A1: Name
8074 6 : SrdSurfsProp.Name = s_ipsc->cAlphaArgs(1);
8075 :
8076 : // N1: sky view factor
8077 6 : if (!s_ipsc->lNumericFieldBlanks(1)) {
8078 6 : SrdSurfsProp.SkyViewFactor = s_ipsc->rNumericArgs(1);
8079 6 : SrdSurfsProp.IsSkyViewFactorSet = true;
8080 : }
8081 :
8082 : // A2: sky temp sch name
8083 6 : if (s_ipsc->lAlphaFieldBlanks(2)) {
8084 0 : } else if ((SrdSurfsProp.skyTempSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(2))) == nullptr) {
8085 0 : ShowWarningItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2));
8086 : }
8087 :
8088 : // N2: ground view factor
8089 6 : if (!s_ipsc->lNumericFieldBlanks(2)) {
8090 3 : SrdSurfsProp.GroundViewFactor = s_ipsc->rNumericArgs(2);
8091 3 : SrdSurfsProp.IsGroundViewFactorSet = true;
8092 : }
8093 :
8094 : // A3: ground temp sch name
8095 6 : if (s_ipsc->lAlphaFieldBlanks(3)) {
8096 0 : } else if ((SrdSurfsProp.groundTempSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(3))) == nullptr) {
8097 0 : ShowWarningItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3));
8098 : }
8099 :
8100 : // The object requires at least one srd surface input, each surface requires a set of 3 fields (2 Alpha fields Name and Temp
8101 : // Sch Name and 1 Num fields View Factor)
8102 6 : if (NumAlpha < 5) {
8103 0 : ShowSevereError(state, format("{} = \"{}\" is not defined correctly.", s_ipsc->cCurrentModuleObject, SrdSurfsProp.Name));
8104 0 : ShowContinueError(state, "At lease one set of surrounding surface properties should be defined.");
8105 0 : ErrorsFound = true;
8106 0 : continue;
8107 : }
8108 6 : if ((NumAlpha - 3) / 2 != (NumNumeric - 2)) {
8109 0 : ShowSevereError(state, format("{} = \"{}\" is not defined correctly.", s_ipsc->cCurrentModuleObject, SrdSurfsProp.Name));
8110 0 : ShowContinueError(state, "Check number of input fields for each surrounding surface.");
8111 0 : ErrorsFound = true;
8112 0 : continue;
8113 : }
8114 : // Read surrounding surfaces properties
8115 6 : SrdSurfsProp.TotSurroundingSurface = NumNumeric - 2;
8116 6 : SrdSurfsProp.SurroundingSurfs.allocate(SrdSurfsProp.TotSurroundingSurface);
8117 14 : for (int SurfLoop = 1; SurfLoop <= SrdSurfsProp.TotSurroundingSurface; ++SurfLoop) {
8118 8 : auto &surroundSurf = SrdSurfsProp.SurroundingSurfs(SurfLoop);
8119 8 : surroundSurf.Name = s_ipsc->cAlphaArgs(SurfLoop * 2 + 2);
8120 8 : surroundSurf.ViewFactor = s_ipsc->rNumericArgs(SurfLoop + 2);
8121 :
8122 : // Added checking
8123 8 : if (s_ipsc->lAlphaFieldBlanks(SurfLoop * 2 + 3)) {
8124 0 : ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(SurfLoop * 2 + 3));
8125 0 : ErrorsFound = true;
8126 8 : } else if ((surroundSurf.tempSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(SurfLoop * 2 + 3))) == nullptr) {
8127 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(SurfLoop * 2 + 3), s_ipsc->cAlphaArgs(SurfLoop * 2 + 3));
8128 0 : ErrorsFound = true;
8129 : }
8130 8 : SrdSurfsProp.SurfsViewFactorSum += SrdSurfsProp.SurroundingSurfs(SurfLoop).ViewFactor;
8131 : }
8132 : }
8133 : }
8134 801 : }
8135 :
8136 801 : void GetSurfaceGroundSurfsData(EnergyPlusData &state, bool &ErrorsFound)
8137 : {
8138 : static constexpr std::string_view routineName = "GetSurfaceGroundSurfsData";
8139 :
8140 801 : auto &s_ipsc = state.dataIPShortCut;
8141 801 : s_ipsc->cCurrentModuleObject = "SurfaceProperty:GroundSurfaces";
8142 801 : state.dataSurface->TotSurfPropGndSurfs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
8143 801 : auto const instances = state.dataInputProcessing->inputProcessor->epJSON.find(s_ipsc->cCurrentModuleObject);
8144 801 : if (instances == state.dataInputProcessing->inputProcessor->epJSON.end()) {
8145 800 : if (state.dataSurface->TotSurfPropGndSurfs > 0) {
8146 0 : ErrorsFound = true;
8147 : }
8148 800 : return;
8149 : }
8150 :
8151 1 : auto &instancesValue = instances.value();
8152 6 : for (auto instance = instancesValue.begin(); instance != instancesValue.end(); ++instance) {
8153 5 : auto const &fields = instance.value();
8154 5 : std::string const &thisObjectName = instance.key();
8155 :
8156 5 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, thisObjectName};
8157 :
8158 5 : DataSurfaces::GroundSurfacesProperty thisGndSurfsObj;
8159 5 : thisGndSurfsObj.Name = Util::makeUPPER(thisObjectName);
8160 5 : state.dataInputProcessing->inputProcessor->markObjectAsUsed(s_ipsc->cCurrentModuleObject, thisObjectName);
8161 5 : auto groundSurfaces = fields.find("ground_surfaces");
8162 5 : if (groundSurfaces != fields.end()) {
8163 5 : auto &groundSurfacesArray = groundSurfaces.value();
8164 5 : thisGndSurfsObj.NumGndSurfs = groundSurfacesArray.size();
8165 16 : for (auto &groundSurface : groundSurfacesArray) {
8166 11 : DataSurfaces::GroundSurfacesData thisGndSurf;
8167 11 : auto GndSurfName = groundSurface.find("ground_surface_name");
8168 11 : if (GndSurfName != groundSurface.end()) {
8169 11 : std::string ground_surf_name = GndSurfName.value().get<std::string>();
8170 11 : if (!ground_surf_name.empty()) {
8171 11 : thisGndSurf.Name = Util::makeUPPER(ground_surf_name);
8172 : }
8173 11 : }
8174 11 : auto groundSurfViewFactor = groundSurface.find("ground_surface_view_factor");
8175 11 : if (groundSurfViewFactor != groundSurface.end()) {
8176 11 : thisGndSurf.ViewFactor = groundSurfViewFactor.value().get<Real64>();
8177 11 : thisGndSurfsObj.IsGroundViewFactorSet = true;
8178 : }
8179 11 : auto TempSchName = groundSurface.find("ground_surface_temperature_schedule_name");
8180 11 : if (TempSchName != groundSurface.end()) {
8181 10 : std::string schedName = TempSchName.value().get<std::string>();
8182 10 : if (schedName.empty()) {
8183 10 : } else if ((thisGndSurf.tempSched = Sched::GetSchedule(state, Util::makeUPPER(schedName))) == nullptr) {
8184 0 : ShowSevereItemNotFound(state, eoh, "Ground Surface Temperature Schedule Name", schedName);
8185 0 : ErrorsFound = true;
8186 : }
8187 10 : }
8188 :
8189 11 : auto ReflSchName = groundSurface.find("ground_surface_reflectance_schedule_name");
8190 11 : if (ReflSchName != groundSurface.end()) {
8191 10 : std::string schedName = ReflSchName.value().get<std::string>();
8192 10 : if (schedName.empty()) {
8193 10 : } else if ((thisGndSurf.reflSched = Sched::GetSchedule(state, Util::makeUPPER(schedName))) == nullptr) {
8194 0 : ShowSevereItemNotFound(state, eoh, "Ground Surface Reflectance Schedule Name", schedName);
8195 0 : ErrorsFound = true;
8196 : }
8197 10 : }
8198 11 : thisGndSurfsObj.GndSurfs.push_back(thisGndSurf);
8199 16 : }
8200 : }
8201 16 : for (int gSurfNum = 1; gSurfNum <= thisGndSurfsObj.NumGndSurfs; gSurfNum++) {
8202 11 : thisGndSurfsObj.SurfsViewFactorSum += thisGndSurfsObj.GndSurfs(gSurfNum).ViewFactor;
8203 : }
8204 5 : state.dataSurface->GroundSurfsProperty.push_back(thisGndSurfsObj);
8205 6 : } // for (instance)
8206 :
8207 : // set report variables
8208 1 : if (state.dataSurface->TotSurfPropGndSurfs > 0) {
8209 6 : for (int Loop = 1; Loop <= state.dataSurface->TotSurfPropGndSurfs; Loop++) {
8210 5 : bool SetTempSchReportVar = true;
8211 5 : bool SetReflSchReportVar = true;
8212 5 : auto &thisGndSurfsObj = state.dataSurface->GroundSurfsProperty(Loop);
8213 16 : for (int gSurfNum = 1; gSurfNum <= thisGndSurfsObj.NumGndSurfs; gSurfNum++) {
8214 11 : if (thisGndSurfsObj.GndSurfs(gSurfNum).tempSched != nullptr && SetTempSchReportVar) {
8215 8 : SetupOutputVariable(state,
8216 : "Surfaces Property Ground Surfaces Average Temperature",
8217 : Constant::Units::C,
8218 4 : thisGndSurfsObj.SurfsTempAvg,
8219 : OutputProcessor::TimeStepType::Zone,
8220 : OutputProcessor::StoreType::Average,
8221 4 : thisGndSurfsObj.Name);
8222 4 : SetTempSchReportVar = false;
8223 : }
8224 11 : if (thisGndSurfsObj.GndSurfs(gSurfNum).reflSched != nullptr && SetReflSchReportVar) {
8225 8 : SetupOutputVariable(state,
8226 : "Surfaces Property Ground Surfaces Average Reflectance",
8227 : Constant::Units::None,
8228 4 : thisGndSurfsObj.SurfsReflAvg,
8229 : OutputProcessor::TimeStepType::Zone,
8230 : OutputProcessor::StoreType::Average,
8231 4 : thisGndSurfsObj.Name);
8232 4 : SetReflSchReportVar = false;
8233 : }
8234 : }
8235 : }
8236 : }
8237 801 : }
8238 :
8239 801 : void GetSurfaceHeatTransferAlgorithmOverrides(EnergyPlusData &state, bool &ErrorsFound)
8240 : {
8241 :
8242 : // SUBROUTINE INFORMATION:
8243 : // AUTHOR B. Griffith, portions from ApplyConvectionValue by Linda Lawrie
8244 : // DATE WRITTEN July 2012
8245 : static constexpr std::string_view routineName = "GetSurfaceHeatTransferAlgorithmOverrides";
8246 :
8247 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
8248 : int CountHTAlgoObjectsSingleSurf;
8249 : int CountHTAlgoObjectsMultiSurf;
8250 : int CountHTAlgoObjectsSurfList;
8251 : int IOStatus; // Used in GetObjectItem
8252 : DataSurfaces::HeatTransferModel tmpAlgoInput;
8253 : int Item;
8254 : int Item1;
8255 : int NumAlphas;
8256 : int NumNumbers;
8257 : int Found;
8258 : bool SurfacesOfType;
8259 : int SurfNum;
8260 : // INTEGER :: Index
8261 : int NumEMPDMat;
8262 : int NumPCMat;
8263 : int NumVTCMat;
8264 : int NumHAMTMat1;
8265 : int NumHAMTMat2;
8266 : int NumHAMTMat3;
8267 : int NumHAMTMat4;
8268 : int NumHAMTMat5;
8269 : int NumHAMTMat6;
8270 : int SumHAMTMat;
8271 : bool msgneeded;
8272 :
8273 801 : auto &s_ipsc = state.dataIPShortCut;
8274 801 : s_ipsc->cCurrentModuleObject = "SurfaceProperty:HeatBalanceSourceTerm";
8275 801 : int CountAddHeatSourceSurf = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
8276 :
8277 805 : for (Item = 1; Item <= CountAddHeatSourceSurf; ++Item) {
8278 8 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
8279 4 : s_ipsc->cCurrentModuleObject,
8280 : Item,
8281 4 : s_ipsc->cAlphaArgs,
8282 : NumAlphas,
8283 4 : s_ipsc->rNumericArgs,
8284 : NumNumbers,
8285 : IOStatus,
8286 4 : s_ipsc->lNumericFieldBlanks,
8287 4 : s_ipsc->lAlphaFieldBlanks,
8288 4 : s_ipsc->cAlphaFieldNames,
8289 4 : s_ipsc->cNumericFieldNames);
8290 :
8291 4 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
8292 4 : Found = Util::FindItemInList(s_ipsc->cAlphaArgs(1), state.dataSurface->Surface, state.dataSurface->TotSurfaces);
8293 :
8294 4 : if (Found == 0) {
8295 0 : ShowSevereError(state, format("{}=\"{}\", did not find matching surface.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
8296 0 : ErrorsFound = true;
8297 8 : } else if (state.dataSurface->Surface(Found).insideHeatSourceTermSched != nullptr ||
8298 4 : state.dataSurface->Surface(Found).outsideHeatSourceTermSched != nullptr) {
8299 0 : ShowSevereError(state,
8300 0 : format("{}=\"{}\", multiple SurfaceProperty:HeatBalanceSourceTerm objects applied to the same surface.",
8301 0 : s_ipsc->cCurrentModuleObject,
8302 0 : s_ipsc->cAlphaArgs(1)));
8303 0 : ErrorsFound = true;
8304 : }
8305 :
8306 4 : if (s_ipsc->lAlphaFieldBlanks(2)) {
8307 1 : } else if ((state.dataSurface->Surface(Found).insideHeatSourceTermSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(2))) == nullptr) {
8308 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2));
8309 0 : ErrorsFound = true;
8310 : } else {
8311 1 : state.dataSurface->allInsideSourceSurfaceList.emplace_back(Found);
8312 : }
8313 :
8314 4 : if (s_ipsc->lAlphaFieldBlanks(3)) {
8315 3 : } else if ((state.dataSurface->Surface(Found).outsideHeatSourceTermSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(3))) == nullptr) {
8316 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3));
8317 0 : ErrorsFound = true;
8318 3 : } else if (state.dataSurface->Surface(Found).OSCPtr > 0) {
8319 0 : ShowSevereError(state,
8320 0 : format("{}=\"SurfaceProperty:HeatBalanceSourceTerm\", cannot be specified for OtherSideCoefficient Surface={}",
8321 0 : s_ipsc->cCurrentModuleObject,
8322 0 : s_ipsc->cAlphaArgs(1)));
8323 0 : ErrorsFound = true;
8324 : } else {
8325 3 : state.dataSurface->allOutsideSourceSurfaceList.emplace_back(Found);
8326 : }
8327 :
8328 5 : if (state.dataSurface->Surface(Found).outsideHeatSourceTermSched == nullptr &&
8329 1 : state.dataSurface->Surface(Found).insideHeatSourceTermSched == nullptr) {
8330 0 : ShowSevereError(
8331 0 : state, format("{}=\"{}\", no schedule defined for additional heat source.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
8332 0 : ErrorsFound = true;
8333 : }
8334 : }
8335 :
8336 : // first initialize each heat transfer surface with the overall model type, array assignment
8337 48091 : for (auto &e : state.dataSurface->Surface) {
8338 47290 : e.HeatTransferAlgorithm = state.dataHeatBal->OverallHeatTransferSolutionAlgo;
8339 801 : }
8340 :
8341 801 : s_ipsc->cCurrentModuleObject = "SurfaceProperty:HeatTransferAlgorithm";
8342 801 : CountHTAlgoObjectsSingleSurf = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
8343 :
8344 801 : s_ipsc->cCurrentModuleObject = "SurfaceProperty:HeatTransferAlgorithm";
8345 803 : for (Item = 1; Item <= CountHTAlgoObjectsSingleSurf; ++Item) {
8346 4 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
8347 2 : s_ipsc->cCurrentModuleObject,
8348 : Item,
8349 2 : s_ipsc->cAlphaArgs,
8350 : NumAlphas,
8351 2 : s_ipsc->rNumericArgs,
8352 : NumNumbers,
8353 : IOStatus,
8354 2 : s_ipsc->lNumericFieldBlanks,
8355 2 : s_ipsc->lAlphaFieldBlanks,
8356 2 : s_ipsc->cAlphaFieldNames,
8357 2 : s_ipsc->cNumericFieldNames);
8358 2 : bool ErrorsFoundSingleSurf = false;
8359 2 : Found = Util::FindItemInList(s_ipsc->cAlphaArgs(1), state.dataSurface->Surface, state.dataSurface->TotSurfaces);
8360 :
8361 2 : if (Found == 0) {
8362 0 : ShowSevereError(state, format("{}=\"{}\", did not find matching surface.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
8363 0 : ErrorsFoundSingleSurf = true;
8364 : }
8365 :
8366 : {
8367 2 : std::string const &SELECT_CASE_var = s_ipsc->cAlphaArgs(2);
8368 :
8369 2 : if (SELECT_CASE_var == "CONDUCTIONTRANSFERFUNCTION") {
8370 0 : tmpAlgoInput = DataSurfaces::HeatTransferModel::CTF;
8371 0 : state.dataHeatBal->AnyCTF = true;
8372 2 : } else if (SELECT_CASE_var == "MOISTUREPENETRATIONDEPTHCONDUCTIONTRANSFERFUNCTION") {
8373 1 : tmpAlgoInput = DataSurfaces::HeatTransferModel::EMPD;
8374 1 : state.dataHeatBal->AnyEMPD = true;
8375 1 : } else if (SELECT_CASE_var == "COMBINEDHEATANDMOISTUREFINITEELEMENT") {
8376 0 : tmpAlgoInput = DataSurfaces::HeatTransferModel::HAMT;
8377 0 : state.dataHeatBal->AnyHAMT = true;
8378 1 : } else if (SELECT_CASE_var == "CONDUCTIONFINITEDIFFERENCE") {
8379 1 : tmpAlgoInput = DataSurfaces::HeatTransferModel::CondFD;
8380 1 : state.dataHeatBal->AnyCondFD = true;
8381 : } else {
8382 0 : ShowSevereError(state,
8383 0 : format("{}=\"{}\", invalid {}=\"{}",
8384 0 : s_ipsc->cCurrentModuleObject,
8385 0 : s_ipsc->cAlphaArgs(1),
8386 0 : s_ipsc->cAlphaFieldNames(2),
8387 0 : s_ipsc->cAlphaArgs(2)));
8388 0 : ErrorsFoundSingleSurf = true;
8389 : }
8390 : }
8391 :
8392 2 : if (!ErrorsFoundSingleSurf) {
8393 2 : state.dataSurface->Surface(Found).HeatTransferAlgorithm = tmpAlgoInput;
8394 : } else {
8395 0 : ErrorsFound = true;
8396 : }
8397 : } // single surface heat transfer algorithm override
8398 :
8399 801 : s_ipsc->cCurrentModuleObject = "SurfaceProperty:HeatTransferAlgorithm:MultipleSurface";
8400 801 : CountHTAlgoObjectsMultiSurf = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
8401 :
8402 801 : for (Item = 1; Item <= CountHTAlgoObjectsMultiSurf; ++Item) {
8403 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
8404 0 : s_ipsc->cCurrentModuleObject,
8405 : Item,
8406 0 : s_ipsc->cAlphaArgs,
8407 : NumAlphas,
8408 0 : s_ipsc->rNumericArgs,
8409 : NumNumbers,
8410 : IOStatus,
8411 0 : s_ipsc->lNumericFieldBlanks,
8412 0 : s_ipsc->lAlphaFieldBlanks,
8413 0 : s_ipsc->cAlphaFieldNames,
8414 0 : s_ipsc->cNumericFieldNames);
8415 0 : bool ErrorsFoundMultiSurf = false;
8416 : {
8417 0 : std::string const &SELECT_CASE_var = s_ipsc->cAlphaArgs(3);
8418 :
8419 0 : if (SELECT_CASE_var == "CONDUCTIONTRANSFERFUNCTION") {
8420 0 : tmpAlgoInput = DataSurfaces::HeatTransferModel::CTF;
8421 0 : state.dataHeatBal->AnyCTF = true;
8422 0 : } else if (SELECT_CASE_var == "MOISTUREPENETRATIONDEPTHCONDUCTIONTRANSFERFUNCTION") {
8423 0 : tmpAlgoInput = DataSurfaces::HeatTransferModel::EMPD;
8424 0 : state.dataHeatBal->AnyEMPD = true;
8425 0 : } else if (SELECT_CASE_var == "COMBINEDHEATANDMOISTUREFINITEELEMENT") {
8426 0 : tmpAlgoInput = DataSurfaces::HeatTransferModel::HAMT;
8427 0 : state.dataHeatBal->AnyHAMT = true;
8428 0 : } else if (SELECT_CASE_var == "CONDUCTIONFINITEDIFFERENCE") {
8429 0 : tmpAlgoInput = DataSurfaces::HeatTransferModel::CondFD;
8430 0 : state.dataHeatBal->AnyCondFD = true;
8431 : } else {
8432 0 : ShowSevereError(state,
8433 0 : format("{}=\"{}\", invalid {}=\"{}",
8434 0 : s_ipsc->cCurrentModuleObject,
8435 0 : s_ipsc->cAlphaArgs(1),
8436 0 : s_ipsc->cAlphaFieldNames(3),
8437 0 : s_ipsc->cAlphaArgs(3)));
8438 0 : ErrorsFoundMultiSurf = true;
8439 : }
8440 : }
8441 :
8442 : {
8443 0 : std::string const &SELECT_CASE_var = s_ipsc->cAlphaArgs(2);
8444 :
8445 0 : if (SELECT_CASE_var == "ALLEXTERIORSURFACES") {
8446 0 : SurfacesOfType = false;
8447 0 : for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
8448 0 : auto &surf = state.dataSurface->Surface(SurfNum);
8449 0 : if (!surf.HeatTransSurf) {
8450 0 : continue;
8451 : }
8452 0 : if (surf.ExtBoundCond > 0) {
8453 0 : continue; // Interior surfaces
8454 : }
8455 0 : if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) {
8456 0 : continue;
8457 : }
8458 0 : SurfacesOfType = true;
8459 0 : surf.HeatTransferAlgorithm = tmpAlgoInput;
8460 : }
8461 :
8462 0 : } else if (SELECT_CASE_var == "ALLEXTERIORWALLS") {
8463 0 : SurfacesOfType = false;
8464 0 : for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
8465 0 : auto &surf = state.dataSurface->Surface(SurfNum);
8466 0 : if (!surf.HeatTransSurf) {
8467 0 : continue;
8468 : }
8469 0 : if (surf.ExtBoundCond > 0) {
8470 0 : continue; // Interior surfaces
8471 : }
8472 :
8473 0 : if (surf.Class != SurfaceClass::Wall) {
8474 0 : continue;
8475 : }
8476 0 : if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) {
8477 0 : continue;
8478 : }
8479 0 : SurfacesOfType = true;
8480 0 : surf.HeatTransferAlgorithm = tmpAlgoInput;
8481 : }
8482 :
8483 0 : } else if (SELECT_CASE_var == "ALLEXTERIORROOFS") {
8484 0 : SurfacesOfType = false;
8485 0 : for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
8486 0 : auto &surf = state.dataSurface->Surface(SurfNum);
8487 0 : if (!surf.HeatTransSurf) {
8488 0 : continue;
8489 : }
8490 0 : if (surf.ExtBoundCond > 0) {
8491 0 : continue; // Interior surfaces
8492 : }
8493 0 : if (surf.Class != SurfaceClass::Roof) {
8494 0 : continue;
8495 : }
8496 0 : if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) {
8497 0 : continue;
8498 : }
8499 0 : SurfacesOfType = true;
8500 0 : surf.HeatTransferAlgorithm = tmpAlgoInput;
8501 : }
8502 :
8503 0 : } else if (SELECT_CASE_var == "ALLEXTERIORFLOORS") {
8504 0 : SurfacesOfType = false;
8505 0 : for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
8506 0 : auto &surf = state.dataSurface->Surface(SurfNum);
8507 0 : if (!surf.HeatTransSurf) {
8508 0 : continue;
8509 : }
8510 0 : if (surf.ExtBoundCond > 0) {
8511 0 : continue; // Interior surfaces
8512 : }
8513 0 : if (surf.Class != SurfaceClass::Floor) {
8514 0 : continue;
8515 : }
8516 0 : if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) {
8517 0 : continue;
8518 : }
8519 0 : SurfacesOfType = true;
8520 0 : surf.HeatTransferAlgorithm = tmpAlgoInput;
8521 : }
8522 :
8523 0 : } else if (SELECT_CASE_var == "ALLGROUNDCONTACTSURFACES") {
8524 0 : SurfacesOfType = false;
8525 0 : for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
8526 0 : auto &surf = state.dataSurface->Surface(SurfNum);
8527 0 : if (!surf.HeatTransSurf) {
8528 0 : continue;
8529 : }
8530 0 : if (surf.ExtBoundCond != DataSurfaces::Ground) {
8531 0 : continue; // ground BC
8532 : }
8533 0 : if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) {
8534 0 : continue;
8535 : }
8536 0 : SurfacesOfType = true;
8537 0 : surf.HeatTransferAlgorithm = tmpAlgoInput;
8538 : }
8539 0 : } else if (SELECT_CASE_var == "ALLINTERIORSURFACES") {
8540 0 : SurfacesOfType = false;
8541 0 : for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
8542 0 : auto &surf = state.dataSurface->Surface(SurfNum);
8543 0 : if (!surf.HeatTransSurf) {
8544 0 : continue;
8545 : }
8546 0 : if (surf.ExtBoundCond <= 0) {
8547 0 : continue; // Exterior surfaces
8548 : }
8549 0 : if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) {
8550 0 : continue;
8551 : }
8552 0 : SurfacesOfType = true;
8553 0 : surf.HeatTransferAlgorithm = tmpAlgoInput;
8554 : }
8555 :
8556 0 : } else if (SELECT_CASE_var == "ALLINTERIORWALLS") {
8557 0 : SurfacesOfType = false;
8558 0 : for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
8559 0 : auto &surf = state.dataSurface->Surface(SurfNum);
8560 0 : if (!surf.HeatTransSurf) {
8561 0 : continue;
8562 : }
8563 0 : if (surf.ExtBoundCond <= 0) {
8564 0 : continue; // Exterior surfaces
8565 : }
8566 0 : if (surf.Class != SurfaceClass::Wall) {
8567 0 : continue;
8568 : }
8569 0 : if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) {
8570 0 : continue;
8571 : }
8572 0 : SurfacesOfType = true;
8573 0 : surf.HeatTransferAlgorithm = tmpAlgoInput;
8574 : }
8575 :
8576 0 : } else if ((SELECT_CASE_var == "ALLINTERIORROOFS") || (SELECT_CASE_var == "ALLINTERIORCEILINGS")) {
8577 0 : SurfacesOfType = false;
8578 0 : for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
8579 0 : auto &surf = state.dataSurface->Surface(SurfNum);
8580 0 : if (!surf.HeatTransSurf) {
8581 0 : continue;
8582 : }
8583 0 : if (surf.ExtBoundCond <= 0) {
8584 0 : continue; // Exterior surfaces
8585 : }
8586 0 : if (surf.Class != SurfaceClass::Roof) {
8587 0 : continue;
8588 : }
8589 0 : if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) {
8590 0 : continue;
8591 : }
8592 0 : SurfacesOfType = true;
8593 0 : surf.HeatTransferAlgorithm = tmpAlgoInput;
8594 : }
8595 :
8596 0 : } else if (SELECT_CASE_var == "ALLINTERIORFLOORS") {
8597 0 : SurfacesOfType = false;
8598 0 : for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
8599 0 : auto &surf = state.dataSurface->Surface(SurfNum);
8600 0 : if (!surf.HeatTransSurf) {
8601 0 : continue;
8602 : }
8603 0 : if (surf.ExtBoundCond <= 0) {
8604 0 : continue; // Exterior surfaces
8605 : }
8606 0 : if (surf.Class != SurfaceClass::Floor) {
8607 0 : continue;
8608 : }
8609 0 : if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) {
8610 0 : continue;
8611 : }
8612 0 : SurfacesOfType = true;
8613 0 : surf.HeatTransferAlgorithm = tmpAlgoInput;
8614 : }
8615 : } else {
8616 0 : SurfacesOfType = false;
8617 0 : ShowSevereError(state,
8618 0 : format("{}=\"{}\", invalid {}=\"{}",
8619 0 : s_ipsc->cCurrentModuleObject,
8620 0 : s_ipsc->cAlphaArgs(1),
8621 0 : s_ipsc->cAlphaFieldNames(2),
8622 0 : s_ipsc->cAlphaArgs(2)));
8623 0 : ErrorsFoundMultiSurf = true;
8624 : }
8625 : }
8626 :
8627 0 : if (!SurfacesOfType) {
8628 0 : ShowWarningError(
8629 : state,
8630 0 : format("In {}=\"{}\", for Multiple Surface Assignment=\"{}\", there were no surfaces of that type found for assignment.",
8631 0 : s_ipsc->cCurrentModuleObject,
8632 0 : s_ipsc->cAlphaArgs(1),
8633 0 : s_ipsc->cAlphaArgs(2)));
8634 : }
8635 0 : if (ErrorsFoundMultiSurf) {
8636 0 : ErrorsFound = true;
8637 : }
8638 :
8639 : } // multi surface heat transfer algo override
8640 :
8641 801 : s_ipsc->cCurrentModuleObject = "SurfaceProperty:HeatTransferAlgorithm:SurfaceList";
8642 801 : CountHTAlgoObjectsSurfList = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
8643 802 : for (Item = 1; Item <= CountHTAlgoObjectsSurfList; ++Item) {
8644 2 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
8645 1 : s_ipsc->cCurrentModuleObject,
8646 : Item,
8647 1 : s_ipsc->cAlphaArgs,
8648 : NumAlphas,
8649 1 : s_ipsc->rNumericArgs,
8650 : NumNumbers,
8651 : IOStatus,
8652 1 : s_ipsc->lNumericFieldBlanks,
8653 1 : s_ipsc->lAlphaFieldBlanks,
8654 1 : s_ipsc->cAlphaFieldNames,
8655 1 : s_ipsc->cNumericFieldNames);
8656 1 : bool ErrorsFoundSurfList = false;
8657 : {
8658 1 : std::string const &SELECT_CASE_var = s_ipsc->cAlphaArgs(2);
8659 :
8660 1 : if (SELECT_CASE_var == "CONDUCTIONTRANSFERFUNCTION") {
8661 0 : tmpAlgoInput = DataSurfaces::HeatTransferModel::CTF;
8662 0 : state.dataHeatBal->AnyCTF = true;
8663 1 : } else if (SELECT_CASE_var == "MOISTUREPENETRATIONDEPTHCONDUCTIONTRANSFERFUNCTION") {
8664 1 : tmpAlgoInput = DataSurfaces::HeatTransferModel::EMPD;
8665 1 : state.dataHeatBal->AnyEMPD = true;
8666 0 : } else if (SELECT_CASE_var == "COMBINEDHEATANDMOISTUREFINITEELEMENT") {
8667 0 : tmpAlgoInput = DataSurfaces::HeatTransferModel::HAMT;
8668 0 : state.dataHeatBal->AnyHAMT = true;
8669 0 : } else if (SELECT_CASE_var == "CONDUCTIONFINITEDIFFERENCE") {
8670 0 : tmpAlgoInput = DataSurfaces::HeatTransferModel::CondFD;
8671 0 : state.dataHeatBal->AnyCondFD = true;
8672 : } else {
8673 0 : ShowSevereError(state,
8674 0 : format("{}=\"{}\", invalid {}=\"{}",
8675 0 : s_ipsc->cCurrentModuleObject,
8676 0 : s_ipsc->cAlphaArgs(1),
8677 0 : s_ipsc->cAlphaFieldNames(2),
8678 0 : s_ipsc->cAlphaArgs(2)));
8679 0 : ErrorsFoundSurfList = true;
8680 : }
8681 : }
8682 :
8683 3 : for (Item1 = 3; Item1 <= NumAlphas; ++Item1) {
8684 :
8685 2 : Found = Util::FindItemInList(s_ipsc->cAlphaArgs(Item1), state.dataSurface->Surface, state.dataSurface->TotSurfaces);
8686 :
8687 2 : if (Found == 0) {
8688 0 : ShowSevereError(state, format("{}=\"{}\", did not find matching surface.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
8689 0 : ShowContinueError(state, format("Name of surface not found = \"{}\"", s_ipsc->cAlphaArgs(Item1)));
8690 0 : ErrorsFoundSurfList = true;
8691 : }
8692 :
8693 2 : if (!ErrorsFoundSurfList) {
8694 2 : state.dataSurface->Surface(Found).HeatTransferAlgorithm = tmpAlgoInput;
8695 : } else {
8696 0 : ErrorsFound = true;
8697 : }
8698 : }
8699 : }
8700 :
8701 801 : s_ipsc->cCurrentModuleObject = "SurfaceProperty:HeatTransferAlgorithm:Construction";
8702 801 : CountHTAlgoObjectsSurfList = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
8703 802 : for (Item = 1; Item <= CountHTAlgoObjectsSurfList; ++Item) {
8704 2 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
8705 1 : s_ipsc->cCurrentModuleObject,
8706 : Item,
8707 1 : s_ipsc->cAlphaArgs,
8708 : NumAlphas,
8709 1 : s_ipsc->rNumericArgs,
8710 : NumNumbers,
8711 : IOStatus,
8712 1 : s_ipsc->lNumericFieldBlanks,
8713 1 : s_ipsc->lAlphaFieldBlanks,
8714 1 : s_ipsc->cAlphaFieldNames,
8715 1 : s_ipsc->cNumericFieldNames);
8716 1 : bool ErrorsFoundByConstruct = false;
8717 : {
8718 1 : std::string const &SELECT_CASE_var = s_ipsc->cAlphaArgs(2);
8719 :
8720 1 : if (SELECT_CASE_var == "CONDUCTIONTRANSFERFUNCTION") {
8721 0 : tmpAlgoInput = DataSurfaces::HeatTransferModel::CTF;
8722 0 : state.dataHeatBal->AnyCTF = true;
8723 1 : } else if (SELECT_CASE_var == "MOISTUREPENETRATIONDEPTHCONDUCTIONTRANSFERFUNCTION") {
8724 0 : tmpAlgoInput = DataSurfaces::HeatTransferModel::EMPD;
8725 0 : state.dataHeatBal->AnyEMPD = true;
8726 1 : } else if (SELECT_CASE_var == "COMBINEDHEATANDMOISTUREFINITEELEMENT") {
8727 1 : tmpAlgoInput = DataSurfaces::HeatTransferModel::HAMT;
8728 1 : state.dataHeatBal->AnyHAMT = true;
8729 0 : } else if (SELECT_CASE_var == "CONDUCTIONFINITEDIFFERENCE") {
8730 0 : tmpAlgoInput = DataSurfaces::HeatTransferModel::CondFD;
8731 0 : state.dataHeatBal->AnyCondFD = true;
8732 : } else {
8733 0 : ShowSevereError(state,
8734 0 : format("{}=\"{}\", invalid {}=\"{}",
8735 0 : s_ipsc->cCurrentModuleObject,
8736 0 : s_ipsc->cAlphaArgs(1),
8737 0 : s_ipsc->cAlphaFieldNames(2),
8738 0 : s_ipsc->cAlphaArgs(2)));
8739 0 : ErrorsFoundByConstruct = true;
8740 : }
8741 : }
8742 :
8743 1 : Found = Util::FindItemInList(s_ipsc->cAlphaArgs(3), state.dataConstruction->Construct, state.dataHeatBal->TotConstructs);
8744 1 : if (Found == 0) {
8745 0 : ShowSevereError(state,
8746 0 : format("{}=\"{}\", invalid {}=\"{}",
8747 0 : s_ipsc->cCurrentModuleObject,
8748 0 : s_ipsc->cAlphaArgs(1),
8749 0 : s_ipsc->cAlphaFieldNames(3),
8750 0 : s_ipsc->cAlphaArgs(3)));
8751 0 : ErrorsFoundByConstruct = true;
8752 : }
8753 :
8754 1 : if (!ErrorsFoundByConstruct) {
8755 7 : for (Item1 = 1; Item1 <= state.dataSurface->TotSurfaces; ++Item1) {
8756 6 : if (state.dataSurface->Surface(Item1).Construction == Found) {
8757 1 : state.dataSurface->Surface(Item1).HeatTransferAlgorithm = tmpAlgoInput;
8758 : }
8759 : }
8760 : }
8761 : }
8762 :
8763 : // Change algorithm for Kiva and air boundary foundation surfaces
8764 48091 : for (auto &surf : state.dataSurface->Surface) {
8765 47290 : if (surf.ExtBoundCond == DataSurfaces::KivaFoundation) {
8766 40 : surf.HeatTransferAlgorithm = DataSurfaces::HeatTransferModel::Kiva;
8767 40 : state.dataHeatBal->AnyKiva = true;
8768 : }
8769 801 : }
8770 :
8771 : // test for missing materials for algorithms selected
8772 801 : NumEMPDMat = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "MaterialProperty:MoisturePenetrationDepth:Settings");
8773 801 : NumPCMat = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "MaterialProperty:PhaseChange") +
8774 801 : state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "MaterialProperty:PhaseChangeHysteresis");
8775 801 : NumVTCMat = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "MaterialProperty:VariableThermalConductivity");
8776 801 : NumHAMTMat1 = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "MaterialProperty:HeatAndMoistureTransfer:Settings");
8777 : NumHAMTMat2 =
8778 801 : state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "MaterialProperty:HeatAndMoistureTransfer:SorptionIsotherm");
8779 801 : NumHAMTMat3 = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "MaterialProperty:HeatAndMoistureTransfer:Suction");
8780 801 : NumHAMTMat4 = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "MaterialProperty:HeatAndMoistureTransfer:Redistribution");
8781 801 : NumHAMTMat5 = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "MaterialProperty:HeatAndMoistureTransfer:Diffusion");
8782 : NumHAMTMat6 =
8783 801 : state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "MaterialProperty:HeatAndMoistureTransfer:ThermalConductivity");
8784 801 : SumHAMTMat = NumHAMTMat1 + NumHAMTMat2 + NumHAMTMat3 + NumHAMTMat4 + NumHAMTMat5 + NumHAMTMat6;
8785 801 : msgneeded = false;
8786 :
8787 801 : if (NumEMPDMat > 0 && !state.dataHeatBal->AnyEMPD) {
8788 0 : ShowWarningError(state,
8789 0 : format("The input file includes {} MaterialProperty:MoisturePenetrationDepth:Settings objects but the moisture "
8790 : "penetration depth algorithm is not used anywhere.",
8791 : NumEMPDMat));
8792 0 : msgneeded = true;
8793 : }
8794 801 : if (NumPCMat > 0 && !state.dataHeatBal->AnyCondFD) {
8795 0 : ShowWarningError(state,
8796 0 : format("The input file includes {} MaterialProperty:PhaseChange objects but the conduction finite difference algorithm "
8797 : "is not used anywhere.",
8798 : NumPCMat));
8799 0 : msgneeded = true;
8800 : }
8801 801 : if (NumVTCMat > 0 && !state.dataHeatBal->AnyCondFD) {
8802 0 : ShowWarningError(state,
8803 0 : format("The input file includes {} MaterialProperty:VariableThermalConductivity objects but the conduction finite "
8804 : "difference algorithm is not used anywhere.",
8805 : NumVTCMat));
8806 0 : msgneeded = true;
8807 : }
8808 801 : if (SumHAMTMat > 0 && !state.dataHeatBal->AnyHAMT) {
8809 0 : ShowWarningError(state,
8810 0 : format("The input file includes {} MaterialProperty:HeatAndMoistureTransfer:* objects but the combined heat and "
8811 : "moisture finite difference algorithm is not used anywhere.",
8812 : SumHAMTMat));
8813 0 : msgneeded = true;
8814 : }
8815 801 : if (msgneeded) {
8816 0 : ShowContinueError(state, "Previous materials will be ignored due to HeatBalanceAlgorithm choice.");
8817 : }
8818 801 : msgneeded = false;
8819 801 : if (NumEMPDMat == 0 && state.dataHeatBal->AnyEMPD) {
8820 0 : ShowWarningError(state,
8821 : "The moisture penetration depth conduction transfer function algorithm is used but the input file includes no "
8822 : "MaterialProperty:MoisturePenetrationDepth:Settings objects.");
8823 0 : msgneeded = true;
8824 : }
8825 801 : if (SumHAMTMat == 0 && state.dataHeatBal->AnyHAMT) {
8826 0 : ShowWarningError(state,
8827 : "The combined heat and moisture finite element algorithm is used but the input file includes no "
8828 : "MaterialProperty:HeatAndMoistureTransfer:* objects.");
8829 0 : msgneeded = true;
8830 : }
8831 801 : if (msgneeded) {
8832 0 : ShowContinueError(state,
8833 : "Certain materials objects are necessary to achieve proper results with the heat transfer algorithm(s) selected.");
8834 : }
8835 :
8836 : // Write Solution Algorithm to the initialization output file for User Verification
8837 801 : print(state.files.eio,
8838 : "{}\n",
8839 : "! <Surface Heat Transfer Algorithm>, Value {CTF - ConductionTransferFunction | EMPD - "
8840 : "MoisturePenetrationDepthConductionTransferFunction | CondFD - ConductionFiniteDifference | HAMT - "
8841 : "CombinedHeatAndMoistureFiniteElement} - Description,Inside Surface Max Temperature Limit{C}, Surface "
8842 : "Convection Coefficient Lower Limit {W/m2-K}, Surface Convection Coefficient Upper Limit {W/m2-K}");
8843 :
8844 801 : int numberOfHeatTransferAlgosUsed = 0;
8845 : // Formats
8846 : static constexpr std::string_view Format_725("Surface Heat Transfer Algorithm, {},{:.0R},{:.2R},{:.1R}\n");
8847 :
8848 801 : if (state.dataHeatBal->AnyCTF) {
8849 787 : constexpr std::string_view AlgoName = "CTF - ConductionTransferFunction";
8850 787 : ++numberOfHeatTransferAlgosUsed;
8851 787 : print(state.files.eio,
8852 : Format_725,
8853 : AlgoName,
8854 787 : state.dataHeatBalSurf->MaxSurfaceTempLimit,
8855 787 : state.dataHeatBal->LowHConvLimit,
8856 787 : state.dataHeatBal->HighHConvLimit);
8857 : }
8858 801 : if (state.dataHeatBal->AnyEMPD) {
8859 2 : state.dataHeatBal->AllCTF = false;
8860 2 : constexpr std::string_view AlgoName = "EMPD - MoisturePenetrationDepthConductionTransferFunction";
8861 2 : ++numberOfHeatTransferAlgosUsed;
8862 2 : print(state.files.eio,
8863 : Format_725,
8864 : AlgoName,
8865 2 : state.dataHeatBalSurf->MaxSurfaceTempLimit,
8866 2 : state.dataHeatBal->LowHConvLimit,
8867 2 : state.dataHeatBal->HighHConvLimit);
8868 2 : if (state.dataHeatBal->doSpaceHeatBalanceSimulation || state.dataHeatBal->doSpaceHeatBalanceSizing) {
8869 0 : ShowSevereError(
8870 : state,
8871 : "MoisturePenetrationDepthConductionTransferFunction is not supported with ZoneAirHeatBalanceAlgorithm Space Heat Balance.");
8872 0 : ErrorsFound = true;
8873 : }
8874 : }
8875 801 : if (state.dataHeatBal->AnyCondFD) {
8876 12 : state.dataHeatBal->AllCTF = false;
8877 12 : constexpr std::string_view AlgoName = "CondFD - ConductionFiniteDifference";
8878 12 : ++numberOfHeatTransferAlgosUsed;
8879 12 : print(state.files.eio,
8880 : Format_725,
8881 : AlgoName,
8882 12 : state.dataHeatBalSurf->MaxSurfaceTempLimit,
8883 12 : state.dataHeatBal->LowHConvLimit,
8884 12 : state.dataHeatBal->HighHConvLimit);
8885 : }
8886 801 : if (state.dataHeatBal->AnyHAMT) {
8887 3 : state.dataHeatBal->AllCTF = false;
8888 3 : constexpr std::string_view AlgoName = "HAMT - CombinedHeatAndMoistureFiniteElement";
8889 3 : ++numberOfHeatTransferAlgosUsed;
8890 3 : print(state.files.eio,
8891 : Format_725,
8892 : AlgoName,
8893 3 : state.dataHeatBalSurf->MaxSurfaceTempLimit,
8894 3 : state.dataHeatBal->LowHConvLimit,
8895 3 : state.dataHeatBal->HighHConvLimit);
8896 3 : if (state.dataHeatBal->doSpaceHeatBalanceSimulation || state.dataHeatBal->doSpaceHeatBalanceSizing) {
8897 0 : ShowSevereError(state, "CombinedHeatAndMoistureFiniteElement is not supported with ZoneAirHeatBalanceAlgorithm Space Heat Balance.");
8898 0 : ErrorsFound = true;
8899 : }
8900 : }
8901 801 : if (state.dataHeatBal->AnyKiva) {
8902 10 : state.dataHeatBal->AllCTF = false;
8903 10 : constexpr std::string_view AlgoName = "KivaFoundation - TwoDimensionalFiniteDifference";
8904 10 : ++numberOfHeatTransferAlgosUsed;
8905 10 : print(state.files.eio,
8906 : Format_725,
8907 : AlgoName,
8908 10 : state.dataHeatBalSurf->MaxSurfaceTempLimit,
8909 10 : state.dataHeatBal->LowHConvLimit,
8910 10 : state.dataHeatBal->HighHConvLimit);
8911 : }
8912 :
8913 : // Check HeatTransferAlgorithm for interior surfaces
8914 801 : if (numberOfHeatTransferAlgosUsed > 1) {
8915 : int ExtSurfNum;
8916 547 : for (Item = 1; Item <= state.dataSurface->TotSurfaces; ++Item) {
8917 536 : auto &surf = state.dataSurface->Surface(Item);
8918 536 : if (surf.ExtBoundCond > 0) {
8919 292 : if ((surf.HeatTransferAlgorithm == DataSurfaces::HeatTransferModel::Invalid) ||
8920 292 : (surf.HeatTransferAlgorithm == DataSurfaces::HeatTransferModel::None)) {
8921 0 : continue;
8922 : }
8923 292 : ExtSurfNum = surf.ExtBoundCond;
8924 292 : auto &extSurf = state.dataSurface->Surface(ExtSurfNum);
8925 292 : if (surf.HeatTransferAlgorithm != extSurf.HeatTransferAlgorithm) {
8926 0 : ShowWarningError(state,
8927 : "An interior surface is defined as two surfaces with reverse constructions. The HeatTransferAlgorithm in "
8928 : "both constructions should be same.");
8929 0 : ShowContinueError(state,
8930 0 : format("The HeatTransferAlgorithm of Surface: {}, is {}",
8931 0 : surf.Name,
8932 0 : DataSurfaces::HeatTransAlgoStrs[static_cast<int>(surf.HeatTransferAlgorithm)]));
8933 0 : ShowContinueError(state,
8934 0 : format("The HeatTransferAlgorithm of Surface: {}, is {}",
8935 0 : extSurf.Name,
8936 0 : DataSurfaces::HeatTransAlgoStrs[static_cast<int>(extSurf.HeatTransferAlgorithm)]));
8937 0 : if (surf.HeatTransferAlgorithm > extSurf.HeatTransferAlgorithm) {
8938 0 : ShowContinueError(state,
8939 0 : format("The HeatTransferAlgorithm of Surface: {}, is assigned to {}. Simulation continues.",
8940 0 : extSurf.Name,
8941 0 : DataSurfaces::HeatTransAlgoStrs[static_cast<int>(surf.HeatTransferAlgorithm)]));
8942 0 : extSurf.HeatTransferAlgorithm = surf.HeatTransferAlgorithm;
8943 : } else {
8944 0 : ShowContinueError(state,
8945 0 : format("The HeatTransferAlgorithm of Surface: {}, is assigned to {}. Simulation continues.",
8946 0 : surf.Name,
8947 0 : DataSurfaces::HeatTransAlgoStrs[static_cast<int>(extSurf.HeatTransferAlgorithm)]));
8948 0 : surf.HeatTransferAlgorithm = extSurf.HeatTransferAlgorithm;
8949 : }
8950 : }
8951 : }
8952 : }
8953 : }
8954 :
8955 : // Assign model type to windows, shading surfaces, and TDDs
8956 48091 : for (Item = 1; Item <= state.dataSurface->TotSurfaces; ++Item) {
8957 47290 : if (state.dataSurface->Surface(Item).Class == SurfaceClass::Window || state.dataSurface->Surface(Item).Class == SurfaceClass::GlassDoor) {
8958 : // todo, add complex fenestration switch HeatTransferModel_ComplexFenestration
8959 6359 : if (state.dataSurface->SurfWinWindowModelType(Item) == DataSurfaces::WindowModel::BSDF) {
8960 0 : state.dataSurface->Surface(Item).HeatTransferAlgorithm = DataSurfaces::HeatTransferModel::ComplexFenestration;
8961 : } else {
8962 6359 : state.dataSurface->Surface(Item).HeatTransferAlgorithm = DataSurfaces::HeatTransferModel::Window5;
8963 : }
8964 : }
8965 47290 : if (state.dataSurface->Surface(Item).Class == SurfaceClass::Detached_B ||
8966 47248 : state.dataSurface->Surface(Item).Class == SurfaceClass::Detached_F ||
8967 140138 : state.dataSurface->Surface(Item).Class == SurfaceClass::Shading || state.dataSurface->Surface(Item).Class == SurfaceClass::Overhang ||
8968 45600 : state.dataSurface->Surface(Item).Class == SurfaceClass::Fin) {
8969 1690 : state.dataSurface->Surface(Item).HeatTransferAlgorithm = DataSurfaces::HeatTransferModel::None;
8970 : }
8971 94580 : if (state.dataSurface->Surface(Item).Class == SurfaceClass::TDD_Diffuser ||
8972 47290 : state.dataSurface->Surface(Item).Class == SurfaceClass::TDD_Dome) {
8973 2 : state.dataSurface->Surface(Item).HeatTransferAlgorithm = DataSurfaces::HeatTransferModel::TDD;
8974 : }
8975 :
8976 55574 : if (state.dataSurface->Surface(Item).HeatTransferAlgorithm == DataSurfaces::HeatTransferModel::CTF ||
8977 8284 : state.dataSurface->Surface(Item).HeatTransferAlgorithm == DataSurfaces::HeatTransferModel::EMPD) {
8978 39049 : state.dataConstruction->Construct(state.dataSurface->Surface(Item).Construction).IsUsedCTF = true;
8979 : }
8980 : }
8981 801 : }
8982 :
8983 : struct PopCoincidentVertexReturn
8984 : {
8985 : double perimeter;
8986 : int poppedVertexPos = -1; // This is a STL vector position, 0-indexed
8987 : int keptVertexPos = -1;
8988 : };
8989 :
8990 43281 : PopCoincidentVertexReturn checkPopCoincidentVertex(const Array1D<Vector> &vertices)
8991 : {
8992 :
8993 43281 : size_t const nSides = vertices.size();
8994 :
8995 : // Pass one: Vector of distance from this vertex to the next one
8996 43281 : std::vector<Real64> distances(nSides);
8997 43281 : size_t index = 0;
8998 43281 : double min_distance = std::numeric_limits<Real64>::max();
8999 43281 : double perimeter = 0.0;
9000 217268 : for (auto it = vertices.begin(); it != vertices.end(); ++it) {
9001 173987 : auto itnext = std::next(it);
9002 173987 : if (itnext == std::end(vertices)) {
9003 43281 : itnext = std::begin(vertices);
9004 : }
9005 173987 : const auto dist = distance(*it, *itnext);
9006 173987 : distances[index++] = dist;
9007 173987 : min_distance = std::min(min_distance, dist);
9008 173987 : perimeter += dist;
9009 : }
9010 : // Return early if nothing to be popped
9011 43281 : if (min_distance >= Constant::OneCentimeter) {
9012 43281 : return {perimeter};
9013 : }
9014 :
9015 : // Pass two: figure out the vertex that is coincident with its previous and/or next vertex and
9016 : // that minimizes the (distanceThisToNext + distanceThisToPrev).
9017 0 : Real64 min_weight = std::numeric_limits<Real64>::max();
9018 0 : int poppedVertexPos = -1;
9019 0 : int keptVertexPos = -1;
9020 :
9021 0 : for (index = 0; index < nSides; ++index) {
9022 0 : size_t const prevIndex = (index == 0) ? nSides - 1 : index - 1;
9023 0 : Real64 const &distanceThisToNext = distances[index];
9024 0 : Real64 const &distanceThisToPrev = distances[prevIndex];
9025 0 : if ((distanceThisToNext >= Constant::OneCentimeter) && (distanceThisToPrev >= Constant::OneCentimeter)) {
9026 0 : continue;
9027 : }
9028 0 : Real64 const weight = distanceThisToNext + distanceThisToPrev;
9029 0 : if (weight < min_weight) {
9030 0 : min_weight = weight;
9031 0 : poppedVertexPos = static_cast<int>(index);
9032 0 : if (distanceThisToPrev < distanceThisToNext) {
9033 0 : keptVertexPos = prevIndex;
9034 : } else {
9035 0 : keptVertexPos = static_cast<int>((index == nSides - 1) ? 0 : index + 1);
9036 : }
9037 : }
9038 : }
9039 :
9040 : // Return the keptVertexPos (which can be the previous or the next), so we can print the displayExtraWarning correctly
9041 0 : return {perimeter, poppedVertexPos, keptVertexPos};
9042 43281 : }
9043 :
9044 43281 : void GetVertices(EnergyPlusData &state,
9045 : int const SurfNum, // Current surface number
9046 : int const NSides, // Number of sides to figure
9047 : Array1S<Real64> const Vertices // Vertices, in specified order
9048 : )
9049 : {
9050 :
9051 : // SUBROUTINE INFORMATION:
9052 : // AUTHOR Linda Lawrie
9053 : // DATE WRITTEN May 2000
9054 :
9055 : // PURPOSE OF THIS SUBROUTINE:
9056 : // This subroutine gets the surface vertices from the arrays
9057 : // passed by the calling routine. These had previously been obtained
9058 : // from the InputProcessor (GetObjectItem). This routine will provide
9059 : // a standard place for determining various properties of the surface
9060 : // from the vertices.
9061 :
9062 : // SUBROUTINE PARAMETER DEFINITIONS:
9063 : static constexpr std::string_view RoutineName("GetVertices: ");
9064 :
9065 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
9066 : int n; // Loop counter
9067 : int NSrc; // Used for CW -> CCW transformation
9068 : int NTar; // Used for CW -> CCW transformation
9069 : Real64 SurfWorldAz;
9070 : Real64 SurfTilt;
9071 : Real64 Perimeter; // Perimeter length of the surface
9072 : Real64 Xb; // Intermediate calculation
9073 : Real64 Yb; // Intermediate calculation
9074 : int ZoneNum;
9075 : int ThisCorner;
9076 : Real64 ThisWidth;
9077 : Real64 ThisHeight;
9078 : // unused REAL(r64) :: ccwtest
9079 : // unused LOGICAL :: SurfaceCCW
9080 : Real64 dotp;
9081 :
9082 : // Object Data
9083 43281 : Vector const TestVector(0.0, 0.0, 1.0);
9084 43281 : Vector temp;
9085 :
9086 43281 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
9087 :
9088 43281 : if (NSides > state.dataSurface->MaxVerticesPerSurface) {
9089 35 : state.dataSurface->MaxVerticesPerSurface = NSides;
9090 : }
9091 43281 : int Ptr = 1;
9092 217268 : for (n = 1; n <= NSides; ++n) {
9093 173987 : surfTemp.Vertex(n).x = Vertices(Ptr);
9094 173987 : ++Ptr;
9095 173987 : surfTemp.Vertex(n).y = Vertices(Ptr);
9096 173987 : ++Ptr;
9097 173987 : surfTemp.Vertex(n).z = Vertices(Ptr);
9098 173987 : ++Ptr;
9099 : }
9100 :
9101 : // Address changing vertices if they were put in in CW order rather than CCW
9102 43281 : if (!state.dataSurface->CCW) {
9103 : // If even number of sides, this will transfer appropriately
9104 : // If odd number, will leave the "odd" one, which is what you want.
9105 195 : NSrc = NSides;
9106 195 : NTar = 2;
9107 390 : for (n = 1; n <= (NSides - 1) / 2; ++n) {
9108 195 : temp = surfTemp.Vertex(NSrc);
9109 195 : surfTemp.Vertex(NSrc) = surfTemp.Vertex(NTar);
9110 195 : surfTemp.Vertex(NTar) = temp;
9111 195 : --NSrc;
9112 195 : ++NTar;
9113 : }
9114 : }
9115 : // Now address which "Corner" has been put in first. Note: the azimuth and tilt and area
9116 : // calculations do not care which corner is put in first.
9117 : // 2/2011 - don't think the shading calculations have a corner preference. Will keep this for
9118 : // consistency (for now)
9119 43281 : ThisCorner = state.dataSurface->Corner;
9120 46428 : while (ThisCorner != DataSurfaces::UpperLeftCorner) {
9121 3147 : if (NSides < 4) {
9122 12 : if (ThisCorner == DataSurfaces::UpperRightCorner) {
9123 0 : break;
9124 : }
9125 : }
9126 3147 : NTar = ThisCorner;
9127 3147 : NSrc = ThisCorner + 1;
9128 3147 : if (NSrc > NSides) {
9129 1039 : NSrc = 1;
9130 : }
9131 12860 : for (n = 1; n <= NSides - 1; ++n) {
9132 9713 : temp = surfTemp.Vertex(NTar);
9133 9713 : surfTemp.Vertex(NTar) = surfTemp.Vertex(NSrc);
9134 9713 : surfTemp.Vertex(NSrc) = temp;
9135 9713 : ++NTar;
9136 9713 : ++NSrc;
9137 9713 : if (NTar > NSides) {
9138 3147 : NTar = 1;
9139 : }
9140 9713 : if (NSrc > NSides) {
9141 2108 : NSrc = 1;
9142 : }
9143 : }
9144 3147 : ++ThisCorner;
9145 3147 : if (ThisCorner > NSides) {
9146 1039 : ThisCorner = 1;
9147 : }
9148 : } // Corners
9149 43281 : if (!state.dataSurface->WorldCoordSystem) {
9150 : // Input in "relative" coordinates, use Building and Zone North Axes and Origins
9151 : // to translate each point (including rotation for Appendix G)
9152 34682 : ZoneNum = surfTemp.Zone;
9153 34682 : if (ZoneNum > 0) {
9154 173843 : for (n = 1; n <= NSides; ++n) {
9155 139195 : Xb = surfTemp.Vertex(n).x * state.dataSurfaceGeometry->CosZoneRelNorth(ZoneNum) -
9156 139195 : surfTemp.Vertex(n).y * state.dataSurfaceGeometry->SinZoneRelNorth(ZoneNum) + state.dataHeatBal->Zone(ZoneNum).OriginX;
9157 139195 : Yb = surfTemp.Vertex(n).x * state.dataSurfaceGeometry->SinZoneRelNorth(ZoneNum) +
9158 139195 : surfTemp.Vertex(n).y * state.dataSurfaceGeometry->CosZoneRelNorth(ZoneNum) + state.dataHeatBal->Zone(ZoneNum).OriginY;
9159 139195 : surfTemp.Vertex(n).x = Xb * state.dataSurfaceGeometry->CosBldgRelNorth - Yb * state.dataSurfaceGeometry->SinBldgRelNorth;
9160 139195 : surfTemp.Vertex(n).y = Xb * state.dataSurfaceGeometry->SinBldgRelNorth + Yb * state.dataSurfaceGeometry->CosBldgRelNorth;
9161 139195 : surfTemp.Vertex(n).z += state.dataHeatBal->Zone(ZoneNum).OriginZ;
9162 : }
9163 34 : } else if (surfTemp.Class == SurfaceClass::Detached_B) {
9164 67 : for (n = 1; n <= NSides; ++n) {
9165 52 : Xb = surfTemp.Vertex(n).x;
9166 52 : Yb = surfTemp.Vertex(n).y;
9167 52 : surfTemp.Vertex(n).x = Xb * state.dataSurfaceGeometry->CosBldgRelNorth - Yb * state.dataSurfaceGeometry->SinBldgRelNorth;
9168 52 : surfTemp.Vertex(n).y = Xb * state.dataSurfaceGeometry->SinBldgRelNorth + Yb * state.dataSurfaceGeometry->CosBldgRelNorth;
9169 : }
9170 : }
9171 : } else {
9172 : // if world coordinate only need to rotate for Appendix G
9173 8599 : ZoneNum = surfTemp.Zone;
9174 8599 : if (ZoneNum > 0) {
9175 43167 : for (n = 1; n <= NSides; ++n) {
9176 34590 : Xb = surfTemp.Vertex(n).x;
9177 34590 : Yb = surfTemp.Vertex(n).y;
9178 34590 : surfTemp.Vertex(n).x = Xb * state.dataSurfaceGeometry->CosBldgRotAppGonly - Yb * state.dataSurfaceGeometry->SinBldgRotAppGonly;
9179 34590 : surfTemp.Vertex(n).y = Xb * state.dataSurfaceGeometry->SinBldgRotAppGonly + Yb * state.dataSurfaceGeometry->CosBldgRotAppGonly;
9180 : }
9181 22 : } else if (surfTemp.Class == SurfaceClass::Detached_B) {
9182 0 : for (n = 1; n <= NSides; ++n) {
9183 0 : Xb = surfTemp.Vertex(n).x;
9184 0 : Yb = surfTemp.Vertex(n).y;
9185 0 : surfTemp.Vertex(n).x = Xb * state.dataSurfaceGeometry->CosBldgRotAppGonly - Yb * state.dataSurfaceGeometry->SinBldgRotAppGonly;
9186 0 : surfTemp.Vertex(n).y = Xb * state.dataSurfaceGeometry->SinBldgRotAppGonly + Yb * state.dataSurfaceGeometry->CosBldgRotAppGonly;
9187 : }
9188 : }
9189 : }
9190 :
9191 43281 : if (NSides > 2) {
9192 43281 : auto &surface = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
9193 43281 : auto &vertices = surface.Vertex;
9194 43281 : auto &nSides = surface.Sides;
9195 43281 : std::string TiltString;
9196 :
9197 : while (true) {
9198 43281 : PopCoincidentVertexReturn const popResult = checkPopCoincidentVertex(vertices);
9199 43281 : Perimeter = popResult.perimeter;
9200 43281 : if (popResult.poppedVertexPos < 0) {
9201 : // No pop needed, we're done
9202 43281 : break;
9203 : }
9204 :
9205 : // Grab the popped one, and the kept one (regardless of whether it's previous or next)
9206 0 : auto it = vertices.begin();
9207 0 : std::advance(it, popResult.poppedVertexPos);
9208 0 : int const poppedVertexIndex = popResult.poppedVertexPos + 1;
9209 :
9210 0 : auto itKept = vertices.begin();
9211 0 : std::advance(itKept, popResult.keptVertexPos);
9212 0 : int const keptVertexIndex = popResult.keptVertexPos + 1;
9213 :
9214 0 : if (state.dataGlobal->DisplayExtraWarnings) {
9215 0 : ShowWarningError(state,
9216 0 : format("{}Distance between two vertices < .01, possibly coincident. for Surface={}, in Zone={}",
9217 : RoutineName,
9218 0 : surfTemp.Name,
9219 0 : surfTemp.ZoneName));
9220 :
9221 0 : bool const printPoppedFirst = (poppedVertexIndex < keptVertexIndex) ? !(poppedVertexIndex == 1 && keptVertexIndex == nSides)
9222 0 : : (poppedVertexIndex == nSides && keptVertexIndex == 1);
9223 :
9224 0 : if (printPoppedFirst) {
9225 0 : ShowContinueError(state, format("Vertex [{}]=({:.2R},{:.2R},{:.2R})", poppedVertexIndex, it->x, it->y, it->z));
9226 0 : ShowContinueError(state, format("Vertex [{}]=({:.2R},{:.2R},{:.2R})", keptVertexIndex, itKept->x, itKept->y, itKept->z));
9227 : } else {
9228 0 : ShowContinueError(state, format("Vertex [{}]=({:.2R},{:.2R},{:.2R})", keptVertexIndex, itKept->x, itKept->y, itKept->z));
9229 0 : ShowContinueError(state, format("Vertex [{}]=({:.2R},{:.2R},{:.2R})", poppedVertexIndex, it->x, it->y, it->z));
9230 : }
9231 : }
9232 0 : ++state.dataErrTracking->TotalCoincidentVertices;
9233 0 : if (nSides <= 3) {
9234 0 : if (state.dataGlobal->DisplayExtraWarnings) {
9235 0 : ShowContinueError(state,
9236 0 : format("Cannot Drop Vertex [{}]; Number of Surface Sides at minimum. This surface is now a "
9237 : "degenerate surface.",
9238 : poppedVertexIndex));
9239 : }
9240 0 : ++state.dataErrTracking->TotalDegenerateSurfaces;
9241 : // If degenerate, we won't be able to pop now nor later, so exit
9242 : // mark degenerate surface?
9243 0 : break;
9244 : }
9245 :
9246 0 : if (state.dataGlobal->DisplayExtraWarnings) {
9247 0 : ShowContinueError(state, format("Dropping Vertex [{}].", poppedVertexIndex));
9248 : }
9249 0 : --nSides;
9250 0 : vertices.erase(it);
9251 : // No need to recompute perimeter, because it'll be done in the next iteration, until no popping or degenerate happens
9252 0 : }
9253 :
9254 43281 : surfTemp.Perimeter = Perimeter;
9255 :
9256 43281 : Vectors::CreateNewellSurfaceNormalVector(surfTemp.Vertex, surfTemp.Sides, surfTemp.NewellSurfaceNormalVector);
9257 43281 : Vectors::CreateNewellAreaVector(surfTemp.Vertex, surfTemp.Sides, surfTemp.NewellAreaVector);
9258 : // For surfaces with subsurfaces, the following two areas are turned into net areas later by
9259 : // subtracting subsurface areas
9260 43281 : surfTemp.GrossArea = Vectors::VecLength(surfTemp.NewellAreaVector);
9261 43281 : surfTemp.Area = surfTemp.GrossArea;
9262 43281 : surfTemp.NetAreaShadowCalc = surfTemp.Area;
9263 43281 : Vectors::DetermineAzimuthAndTilt(
9264 43281 : surfTemp.Vertex, SurfWorldAz, SurfTilt, surfTemp.lcsx, surfTemp.lcsy, surfTemp.lcsz, surfTemp.NewellSurfaceNormalVector);
9265 43281 : dotp = dot(surfTemp.NewellSurfaceNormalVector, TestVector);
9266 43281 : if (surfTemp.Class == SurfaceClass::Roof && dotp < -0.000001) {
9267 0 : TiltString = format("{:.1R}", SurfTilt);
9268 0 : ShowWarningError(state,
9269 0 : format("{}Roof/Ceiling is upside down! Tilt angle=[{}], should be near 0, Surface=\"{}\", in Zone=\"{}\".",
9270 : RoutineName,
9271 : TiltString,
9272 0 : surfTemp.Name,
9273 0 : surfTemp.ZoneName));
9274 0 : ShowContinueError(state, "Automatic fix is attempted.");
9275 0 : ReverseAndRecalculate(state, SurfNum, surfTemp.Sides, SurfWorldAz, SurfTilt);
9276 43281 : } else if (surfTemp.Class == SurfaceClass::Roof && SurfTilt > 80.0) {
9277 0 : TiltString = format("{:.1R}", SurfTilt);
9278 0 : ShowWarningError(
9279 : state,
9280 0 : format("{}Roof/Ceiling is not oriented correctly! Tilt angle=[{}], should be near 0, Surface=\"{}\", in Zone=\"{}\".",
9281 : RoutineName,
9282 : TiltString,
9283 0 : surfTemp.Name,
9284 0 : surfTemp.ZoneName));
9285 : }
9286 43281 : if (surfTemp.Class == SurfaceClass::Floor && dotp > 0.000001) {
9287 0 : TiltString = format("{:.1R}", SurfTilt);
9288 0 : ShowWarningError(state,
9289 0 : format("{}Floor is upside down! Tilt angle=[{}], should be near 180, Surface=\"{}\", in Zone=\"{}\".",
9290 : RoutineName,
9291 : TiltString,
9292 0 : surfTemp.Name,
9293 0 : surfTemp.ZoneName));
9294 0 : ShowContinueError(state, "Automatic fix is attempted.");
9295 0 : ReverseAndRecalculate(state, SurfNum, surfTemp.Sides, SurfWorldAz, SurfTilt);
9296 43281 : } else if (surfTemp.Class == SurfaceClass::Floor && SurfTilt < 158.2) { // slope/grade = 40%!
9297 0 : TiltString = format("{:.1R}", SurfTilt);
9298 0 : ShowWarningError(state,
9299 0 : format("{}Floor is not oriented correctly! Tilt angle=[{}], should be near 180, Surface=\"{}\", in Zone=\"{}\".",
9300 : RoutineName,
9301 : TiltString,
9302 0 : surfTemp.Name,
9303 0 : surfTemp.ZoneName));
9304 : }
9305 43281 : surfTemp.Azimuth = SurfWorldAz;
9306 43281 : surfTemp.Tilt = SurfTilt;
9307 43281 : surfTemp.convOrientation = Convect::GetSurfConvOrientation(surfTemp.Tilt);
9308 :
9309 : // Sine and cosine of azimuth and tilt
9310 43281 : surfTemp.SinAzim = std::sin(SurfWorldAz * Constant::DegToRad);
9311 43281 : surfTemp.CosAzim = std::cos(SurfWorldAz * Constant::DegToRad);
9312 43281 : surfTemp.SinTilt = std::sin(SurfTilt * Constant::DegToRad);
9313 43281 : surfTemp.CosTilt = std::cos(SurfTilt * Constant::DegToRad);
9314 43281 : if (surfTemp.ViewFactorGround == Constant::AutoCalculate) {
9315 20915 : surfTemp.ViewFactorGround = 0.5 * (1.0 - surfTemp.CosTilt);
9316 : }
9317 : // Outward normal unit vector (pointing away from room)
9318 43281 : surfTemp.OutNormVec = surfTemp.NewellSurfaceNormalVector;
9319 173124 : for (n = 1; n <= 3; ++n) {
9320 129843 : if (std::abs(surfTemp.OutNormVec(n) - 1.0) < 1.e-06) {
9321 16340 : surfTemp.OutNormVec(n) = +1.0;
9322 : }
9323 129843 : if (std::abs(surfTemp.OutNormVec(n) + 1.0) < 1.e-06) {
9324 18559 : surfTemp.OutNormVec(n) = -1.0;
9325 : }
9326 129843 : if (std::abs(surfTemp.OutNormVec(n)) < 1.e-06) {
9327 78146 : surfTemp.OutNormVec(n) = 0.0;
9328 : }
9329 : }
9330 :
9331 43281 : if (surfTemp.Class == SurfaceClass::Window || surfTemp.Class == SurfaceClass::GlassDoor || surfTemp.Class == SurfaceClass::Door) {
9332 6760 : surfTemp.Area *= surfTemp.Multiplier;
9333 : }
9334 : // Can perform tests on this surface here
9335 43281 : surfTemp.ViewFactorSky = 0.5 * (1.0 + surfTemp.CosTilt);
9336 : // The following IR view factors are modified in subr. SkyDifSolarShading if there are shadowing
9337 : // surfaces
9338 43281 : surfTemp.ViewFactorSkyIR = surfTemp.ViewFactorSky;
9339 43281 : surfTemp.ViewFactorGroundIR = 0.5 * (1.0 - surfTemp.CosTilt);
9340 :
9341 : // Call to transform vertices
9342 :
9343 43281 : TransformVertsByAspect(state, SurfNum, surfTemp.Sides);
9344 :
9345 43281 : } else {
9346 0 : ShowFatalError(state, format("{}Called with less than 2 sides, Surface={}", RoutineName, surfTemp.Name));
9347 : }
9348 :
9349 : // Preliminary Height/Width
9350 43281 : temp = surfTemp.Vertex(3) - surfTemp.Vertex(2);
9351 43281 : ThisWidth = Vectors::VecLength(temp);
9352 43281 : temp = surfTemp.Vertex(2) - surfTemp.Vertex(1);
9353 43281 : ThisHeight = Vectors::VecLength(temp);
9354 43281 : surfTemp.Height = ThisHeight;
9355 43281 : surfTemp.Width = ThisWidth;
9356 43281 : }
9357 :
9358 0 : void ReverseAndRecalculate(EnergyPlusData &state,
9359 : int const SurfNum, // Surface number for the surface
9360 : int const NSides, // number of sides to surface
9361 : Real64 &SurfAzimuth, // Surface Facing angle (will be 0 for roofs/floors)
9362 : Real64 &SurfTilt // Surface tilt (
9363 : )
9364 : {
9365 :
9366 : // SUBROUTINE INFORMATION:
9367 : // AUTHOR Linda Lawrie
9368 : // DATE WRITTEN February 2011
9369 :
9370 : // PURPOSE OF THIS SUBROUTINE:
9371 : // This routine reverses the vertices for a surface (needed when roof/floor is upside down)
9372 : // and recalculates the azimuth, etc for the surface.
9373 :
9374 : // SUBROUTINE PARAMETER DEFINITIONS:
9375 : static constexpr std::string_view RoutineName("ReverseAndRecalculate: ");
9376 :
9377 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
9378 : int n; // Loop Control
9379 : int RevPtr; // pointer for reversing vertices
9380 0 : std::string TiltString;
9381 :
9382 : // Object Data
9383 0 : Array1D<Vector> Vertices(NSides); // Vertices, in specified order
9384 :
9385 0 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
9386 :
9387 0 : for (n = 1; n <= NSides; ++n) {
9388 0 : Vertices(n) = surfTemp.Vertex(n);
9389 : }
9390 0 : RevPtr = NSides;
9391 0 : for (n = 1; n <= NSides; ++n) {
9392 0 : surfTemp.Vertex(n) = Vertices(RevPtr);
9393 0 : --RevPtr;
9394 : }
9395 :
9396 0 : print(state.files.debug, "Reversing Surface Name={}\n", surfTemp.Name);
9397 0 : for (n = 1; n <= NSides; ++n) {
9398 0 : print(state.files.debug,
9399 : "side={:5} abs coord vertex= {:18.13F} {:18.13F} {:18.13F}\n",
9400 : n,
9401 0 : surfTemp.Vertex(n).x,
9402 0 : surfTemp.Vertex(n).y,
9403 0 : surfTemp.Vertex(n).z);
9404 : }
9405 :
9406 0 : Vectors::CreateNewellSurfaceNormalVector(surfTemp.Vertex, surfTemp.Sides, surfTemp.NewellSurfaceNormalVector);
9407 0 : Vectors::DetermineAzimuthAndTilt(
9408 0 : surfTemp.Vertex, SurfAzimuth, SurfTilt, surfTemp.lcsx, surfTemp.lcsy, surfTemp.lcsz, surfTemp.NewellSurfaceNormalVector);
9409 0 : if (surfTemp.Class == SurfaceClass::Roof && SurfTilt > 80.0) {
9410 0 : TiltString = format("{:.1R}", SurfTilt);
9411 0 : ShowWarningError(
9412 : state,
9413 0 : format("{}Roof/Ceiling is still upside down! Tilt angle=[{}], should be near 0, please fix manually.", RoutineName, TiltString));
9414 : }
9415 0 : if (surfTemp.Class == SurfaceClass::Floor && SurfTilt < 158.2) { // 40% grade!
9416 0 : ShowWarningError(
9417 0 : state, format("{}Floor is still upside down! Tilt angle=[{}], should be near 180, please fix manually.", RoutineName, TiltString));
9418 : }
9419 0 : }
9420 :
9421 845 : void MakeMirrorSurface(EnergyPlusData &state, int &SurfNum) // In=>Surface to Mirror, Out=>new Surface index // This is not good
9422 : {
9423 :
9424 : // SUBROUTINE INFORMATION:
9425 : // AUTHOR Linda Lawrie
9426 : // DATE WRITTEN June 2002
9427 :
9428 : // PURPOSE OF THIS SUBROUTINE:
9429 : // This subroutine creates a "mirror" surface using the indicated surface.
9430 : // This is the simple approach for bi-directional shading devices. If, perchance,
9431 : // the user has already taken care of this (e.g. fins in middle of wall), there will
9432 : // be extra shading devices shown.
9433 :
9434 845 : auto &origSurface = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
9435 845 : auto &newSurface = state.dataSurfaceGeometry->SurfaceTmp(SurfNum + 1);
9436 845 : newSurface = origSurface;
9437 :
9438 845 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
9439 :
9440 845 : int nVert = origSurface.Sides;
9441 : // Reverse the vertices in the original surface. Add "MIR-" to name.
9442 4203 : for (int Vert = 1; Vert <= surfTemp.Sides; ++Vert) {
9443 3358 : newSurface.Vertex(Vert) = origSurface.Vertex(nVert);
9444 3358 : --nVert;
9445 : }
9446 845 : newSurface.Name = "Mir-" + origSurface.Name;
9447 845 : newSurface.MirroredSurf = true;
9448 :
9449 845 : if (newSurface.Sides > 2) {
9450 845 : Vectors::CreateNewellAreaVector(newSurface.Vertex, newSurface.Sides, newSurface.NewellAreaVector);
9451 845 : newSurface.GrossArea = Vectors::VecLength(newSurface.NewellAreaVector);
9452 845 : newSurface.Area = newSurface.GrossArea;
9453 845 : newSurface.NetAreaShadowCalc = newSurface.Area;
9454 845 : Vectors::CreateNewellSurfaceNormalVector(newSurface.Vertex, newSurface.Sides, newSurface.NewellSurfaceNormalVector);
9455 845 : Real64 SurfWorldAz = 0.0;
9456 845 : Real64 SurfTilt = 0.0;
9457 845 : Vectors::DetermineAzimuthAndTilt(
9458 845 : newSurface.Vertex, SurfWorldAz, SurfTilt, newSurface.lcsx, newSurface.lcsy, newSurface.lcsz, newSurface.NewellSurfaceNormalVector);
9459 845 : newSurface.Azimuth = SurfWorldAz;
9460 845 : newSurface.Tilt = SurfTilt;
9461 845 : newSurface.convOrientation = Convect::GetSurfConvOrientation(newSurface.Tilt);
9462 :
9463 : // Sine and cosine of azimuth and tilt
9464 845 : newSurface.SinAzim = std::sin(SurfWorldAz * Constant::DegToRad);
9465 845 : newSurface.CosAzim = std::cos(SurfWorldAz * Constant::DegToRad);
9466 845 : newSurface.SinTilt = std::sin(SurfTilt * Constant::DegToRad);
9467 845 : newSurface.CosTilt = std::cos(SurfTilt * Constant::DegToRad);
9468 : // Outward normal unit vector (pointing away from room)
9469 845 : newSurface.OutNormVec = newSurface.NewellSurfaceNormalVector;
9470 3380 : for (int n = 1; n <= 3; ++n) {
9471 2535 : if (std::abs(newSurface.OutNormVec(n) - 1.0) < 1.e-06) {
9472 773 : newSurface.OutNormVec(n) = +1.0;
9473 : }
9474 2535 : if (std::abs(newSurface.OutNormVec(n) + 1.0) < 1.e-06) {
9475 55 : newSurface.OutNormVec(n) = -1.0;
9476 : }
9477 2535 : if (std::abs(newSurface.OutNormVec(n)) < 1.e-06) {
9478 1673 : newSurface.OutNormVec(n) = 0.0;
9479 : }
9480 : }
9481 :
9482 : // Can perform tests on this surface here
9483 845 : newSurface.ViewFactorSky = 0.5 * (1.0 + newSurface.CosTilt);
9484 : // The following IR view factors are modified in subr. SkyDifSolarShading if there are shadowing surfaces
9485 845 : newSurface.ViewFactorSkyIR = newSurface.ViewFactorSky;
9486 845 : newSurface.ViewFactorGroundIR = 0.5 * (1.0 - newSurface.CosTilt);
9487 845 : ++SurfNum; // Calling function expects incremented argument on return
9488 : }
9489 845 : }
9490 :
9491 801 : void GetWindowShadingControlData(EnergyPlusData &state, bool &ErrorsFound) // If errors found in input
9492 : {
9493 :
9494 : // SUBROUTINE INFORMATION:
9495 : // AUTHOR Fred Winkelmann
9496 : // DATE WRITTEN November 1998
9497 : // MODIFIED Aug 2001 (FW): add handling of new ShadingControlIsScheduled
9498 : // and GlareControlIsActive fields
9499 : // Nov 2001 (FW): add ShadingDevice as alternative to ShadedConstruction
9500 : // Dec 2001 (FW): add slat angle controls for blinds
9501 : // Aug 2002 (FW): add Setpoint2; check that specified control type is legal
9502 : // Feb 2003 (FW): add error if Material Name of Shading Device is used with
9503 : // Shading Type = BetweenGlassShade or BetweenGlassBlind
9504 : // Dec 2003 (FW): improve BetweenGlassBlind error messages
9505 : // Feb 2009 (BG): improve error checking for OnIfScheduleAllows
9506 :
9507 : // PURPOSE OF THIS SUBROUTINE:
9508 : // Reads in the window shading control information
9509 : // from the input data file, interprets it and puts it in the derived type
9510 :
9511 : // SUBROUTINE PARAMETER DEFINITIONS:
9512 : static constexpr std::string_view routineName = "GetWindowShadingControlData";
9513 :
9514 801 : int constexpr NumValidShadingTypes(9);
9515 : static Array1D_string const cValidShadingTypes(NumValidShadingTypes,
9516 : {
9517 : "SHADEOFF", // 1
9518 : "INTERIORSHADE", // 2
9519 : "SWITCHABLEGLAZING", // 3
9520 : "EXTERIORSHADE", // 4
9521 : "EXTERIORSCREEN", // 5
9522 : "INTERIORBLIND", // 6
9523 : "EXTERIORBLIND", // 7
9524 : "BETWEENGLASSSHADE", // 8
9525 : "BETWEENGLASSBLIND" // 9
9526 801 : });
9527 :
9528 801 : constexpr std::array<std::string_view, static_cast<int>(DataSurfaces::WindowShadingControlType::Num)> WindowShadingControlTypeNamesUC{
9529 : "ALWAYSON",
9530 : "ALWAYSOFF",
9531 : "ONIFSCHEDULEALLOWS",
9532 : "ONIFHIGHSOLARONWINDOW",
9533 : "ONIFHIGHHORIZONTALSOLAR",
9534 : "ONIFHIGHOUTDOORAIRTEMPERATURE",
9535 : "ONIFHIGHZONEAIRTEMPERATURE",
9536 : "ONIFHIGHZONECOOLING",
9537 : "ONIFHIGHGLARE",
9538 : "MEETDAYLIGHTILLUMINANCESETPOINT",
9539 : "ONNIGHTIFLOWOUTDOORTEMPANDOFFDAY",
9540 : "ONNIGHTIFLOWINSIDETEMPANDOFFDAY",
9541 : "ONNIGHTIFHEATINGANDOFFDAY",
9542 : "ONNIGHTIFLOWOUTDOORTEMPANDONDAYIFCOOLING",
9543 : "ONNIGHTIFHEATINGANDONDAYIFCOOLING",
9544 : "OFFNIGHTANDONDAYIFCOOLINGANDHIGHSOLARONWINDOW",
9545 : "ONNIGHTANDONDAYIFCOOLINGANDHIGHSOLARONWINDOW",
9546 : "ONIFHIGHOUTDOORAIRTEMPANDHIGHSOLARONWINDOW",
9547 : "ONIFHIGHOUTDOORAIRTEMPANDHIGHHORIZONTALSOLAR",
9548 : "ONIFHIGHZONEAIRTEMPANDHIGHSOLARONWINDOW",
9549 : "ONIFHIGHZONEAIRTEMPANDHIGHHORIZONTALSOLAR",
9550 : "ONIFHIGHSOLARORHIGHLUMINANCETILLMIDNIGHT",
9551 : "ONIFHIGHSOLARORHIGHLUMINANCETILLSUNSET",
9552 : "ONIFHIGHSOLARORHIGHLUMINANCETILLNEXTMORNING"};
9553 :
9554 801 : constexpr std::array<std::string_view, static_cast<int>(DataSurfaces::SlatAngleControl::Num)> SlatAngleNamesUC{
9555 : "FIXEDSLATANGLE", "SCHEDULEDSLATANGLE", "BLOCKBEAMSOLAR"};
9556 :
9557 801 : constexpr std::array<std::string_view, static_cast<int>(DataSurfaces::MultiSurfaceControl::Num)> MultiSurfaceControlNamesUC = {"SEQUENTIAL",
9558 : "GROUP"};
9559 :
9560 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
9561 : int IOStat; // IO Status when calling get input subroutine
9562 : int ControlNumAlpha; // Number of control alpha names being passed
9563 : int ControlNumProp; // Number of control properties being passed
9564 : int ControlNum; // DO loop counter/index for window shading control number
9565 : int IShadedConst; // Construction number of shaded construction
9566 : int IShadingDevice; // Material number of shading device
9567 : int NLayers; // Layers in shaded construction
9568 : int Loop;
9569 : bool BGShadeBlindError; // True if problem with construction that is supposed to have between-glass
9570 : // shade or blind
9571 : int Found;
9572 :
9573 801 : auto &s_mat = state.dataMaterial;
9574 801 : auto &s_ipsc = state.dataIPShortCut;
9575 : // Get the total number of window shading control blocks
9576 801 : s_ipsc->cCurrentModuleObject = "WindowShadingControl";
9577 801 : state.dataSurface->TotWinShadingControl = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
9578 801 : if (state.dataSurface->TotWinShadingControl == 0) {
9579 758 : return;
9580 : }
9581 :
9582 43 : state.dataSurface->WindowShadingControl.allocate(state.dataSurface->TotWinShadingControl);
9583 :
9584 43 : ControlNum = 0;
9585 116 : for (Loop = 1; Loop <= state.dataSurface->TotWinShadingControl; ++Loop) {
9586 :
9587 146 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
9588 73 : s_ipsc->cCurrentModuleObject,
9589 : Loop,
9590 73 : s_ipsc->cAlphaArgs,
9591 : ControlNumAlpha,
9592 73 : s_ipsc->rNumericArgs,
9593 : ControlNumProp,
9594 : IOStat,
9595 73 : s_ipsc->lNumericFieldBlanks,
9596 73 : s_ipsc->lAlphaFieldBlanks,
9597 73 : s_ipsc->cAlphaFieldNames,
9598 73 : s_ipsc->cNumericFieldNames);
9599 :
9600 73 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
9601 :
9602 73 : bool ErrorInName = false;
9603 73 : bool IsBlank = false;
9604 :
9605 73 : Util::VerifyName(state,
9606 73 : s_ipsc->cAlphaArgs(1),
9607 73 : state.dataSurface->WindowShadingControl,
9608 : ControlNum,
9609 : ErrorInName,
9610 : IsBlank,
9611 146 : s_ipsc->cCurrentModuleObject + " Name");
9612 73 : if (ErrorInName) {
9613 0 : ErrorsFound = true;
9614 0 : continue;
9615 : }
9616 :
9617 73 : ++ControlNum;
9618 :
9619 73 : auto &windowShadingControl = state.dataSurface->WindowShadingControl(ControlNum);
9620 :
9621 73 : windowShadingControl.Name = s_ipsc->cAlphaArgs(1); // Set the Control Name in the Derived Type
9622 :
9623 73 : windowShadingControl.ZoneIndex = Util::FindItemInList(s_ipsc->cAlphaArgs(2), state.dataHeatBal->Zone);
9624 73 : if (windowShadingControl.ZoneIndex == 0) {
9625 0 : ShowSevereError(state,
9626 0 : format("{}=\"{}\" invalid {}=\"{}\" not found.",
9627 0 : s_ipsc->cCurrentModuleObject,
9628 0 : s_ipsc->cAlphaArgs(1),
9629 0 : s_ipsc->cAlphaFieldNames(2),
9630 0 : s_ipsc->cAlphaArgs(2)));
9631 0 : ErrorsFound = true;
9632 : }
9633 :
9634 73 : windowShadingControl.SequenceNumber = int(s_ipsc->rNumericArgs(1));
9635 :
9636 : // For upward compatibility change old "noninsulating" and "insulating" shade types to
9637 : // INTERIORSHADE or EXTERIORSHADE
9638 73 : if (s_ipsc->cAlphaArgs(3) == "INTERIORNONINSULATINGSHADE" || s_ipsc->cAlphaArgs(3) == "INTERIORINSULATINGSHADE") {
9639 0 : ShowWarningError(state,
9640 0 : format("{}=\"{}\" is using obsolete {}=\"{}\", changing to \"InteriorShade\"",
9641 0 : s_ipsc->cCurrentModuleObject,
9642 0 : windowShadingControl.Name,
9643 0 : s_ipsc->cAlphaFieldNames(3),
9644 0 : s_ipsc->cAlphaArgs(3)));
9645 0 : windowShadingControl.ShadingType = DataSurfaces::WinShadingType::IntShade;
9646 0 : s_ipsc->cAlphaArgs(3) = "INTERIORSHADE";
9647 : }
9648 73 : if (s_ipsc->cAlphaArgs(3) == "EXTERIORNONINSULATINGSHADE" || s_ipsc->cAlphaArgs(3) == "EXTERIORINSULATINGSHADE") {
9649 0 : ShowWarningError(state,
9650 0 : format("{}=\"{}\" is using obsolete {}=\"{}\", changing to \"ExteriorShade\"",
9651 0 : s_ipsc->cCurrentModuleObject,
9652 0 : windowShadingControl.Name,
9653 0 : s_ipsc->cAlphaFieldNames(3),
9654 0 : s_ipsc->cAlphaArgs(3)));
9655 0 : windowShadingControl.ShadingType = DataSurfaces::WinShadingType::ExtShade;
9656 0 : s_ipsc->cAlphaArgs(3) = "EXTERIORSHADE";
9657 : }
9658 :
9659 : // Check for illegal shading type name
9660 73 : Found = Util::FindItemInList(s_ipsc->cAlphaArgs(3), cValidShadingTypes, NumValidShadingTypes);
9661 73 : if (Found <= 1) {
9662 0 : ErrorsFound = true;
9663 0 : ShowSevereError(state,
9664 0 : format("{}=\"{}\" invalid {}=\"{}\".",
9665 0 : s_ipsc->cCurrentModuleObject,
9666 0 : windowShadingControl.Name,
9667 0 : s_ipsc->cAlphaFieldNames(3),
9668 0 : s_ipsc->cAlphaArgs(3)));
9669 : } else {
9670 73 : windowShadingControl.ShadingType = DataSurfaces::WinShadingType(Found);
9671 : }
9672 :
9673 : // WindowShadingControl().getInputShadedConstruction is only used during GetInput process and is ultimately stored in
9674 : // Surface().shadedConstructionList
9675 73 : windowShadingControl.getInputShadedConstruction =
9676 73 : Util::FindItemInList(s_ipsc->cAlphaArgs(4), state.dataConstruction->Construct, state.dataHeatBal->TotConstructs);
9677 73 : windowShadingControl.ShadingDevice = Material::GetMaterialNum(state, s_ipsc->cAlphaArgs(9));
9678 :
9679 73 : if (s_ipsc->lAlphaFieldBlanks(6)) {
9680 59 : windowShadingControl.sched = Sched::GetScheduleAlwaysOn(state); // Not an availability schedule, but the default is constant-1.0
9681 14 : } else if ((windowShadingControl.sched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(6))) == nullptr) {
9682 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(6), s_ipsc->cAlphaArgs(6));
9683 0 : ErrorsFound = true;
9684 : }
9685 :
9686 73 : windowShadingControl.SetPoint = s_ipsc->rNumericArgs(2);
9687 73 : windowShadingControl.SetPoint2 = s_ipsc->rNumericArgs(3);
9688 73 : windowShadingControl.ShadingControlIsScheduled = getYesNoValue(s_ipsc->cAlphaArgs(7)) == BooleanSwitch::Yes;
9689 73 : windowShadingControl.GlareControlIsActive = getYesNoValue(s_ipsc->cAlphaArgs(8)) == BooleanSwitch::Yes;
9690 :
9691 73 : if (windowShadingControl.ShadingType != DataSurfaces::WinShadingType::IntBlind &&
9692 60 : windowShadingControl.ShadingType != DataSurfaces::WinShadingType::ExtBlind &&
9693 58 : windowShadingControl.ShadingType != DataSurfaces::WinShadingType::BGBlind) {
9694 18 : } else if (s_ipsc->cAlphaArgs(10).empty()) {
9695 0 : ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(10), s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3));
9696 0 : ErrorsFound = true;
9697 18 : } else if ((windowShadingControl.slatAngleControl = static_cast<DataSurfaces::SlatAngleControl>(
9698 18 : getEnumValue(SlatAngleNamesUC, s_ipsc->cAlphaArgs(10)))) == DataSurfaces::SlatAngleControl::Invalid) {
9699 0 : ShowSevereInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(10), s_ipsc->cAlphaArgs(10));
9700 0 : ErrorsFound = true;
9701 18 : } else if (windowShadingControl.slatAngleControl != DataSurfaces::SlatAngleControl::Scheduled) {
9702 0 : } else if (s_ipsc->lAlphaFieldBlanks(11)) {
9703 0 : ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(11), s_ipsc->cAlphaFieldNames(10), s_ipsc->cAlphaArgs(10));
9704 0 : ErrorsFound = true;
9705 0 : } else if ((windowShadingControl.slatAngleSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(11))) == nullptr) {
9706 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(11), s_ipsc->cAlphaArgs(11));
9707 0 : ErrorsFound = true;
9708 : }
9709 :
9710 : // store the string for now and associate it after daylighting control objects are read
9711 73 : windowShadingControl.DaylightingControlName = s_ipsc->cAlphaArgs(12);
9712 :
9713 73 : windowShadingControl.multiSurfaceControl =
9714 73 : static_cast<DataSurfaces::MultiSurfaceControl>(getEnumValue(MultiSurfaceControlNamesUC, s_ipsc->cAlphaArgs(13)));
9715 :
9716 73 : if (windowShadingControl.multiSurfaceControl == DataSurfaces::MultiSurfaceControl::Invalid) {
9717 0 : windowShadingControl.multiSurfaceControl = DataSurfaces::MultiSurfaceControl::Sequential;
9718 0 : ShowWarningError(state,
9719 0 : format("{}=\"{}\" should be either SEQUENTIAL or GROUP {}=\"{}\", defaulting to \"SEQUENTIAL\"",
9720 0 : s_ipsc->cCurrentModuleObject,
9721 0 : windowShadingControl.Name,
9722 0 : s_ipsc->cAlphaFieldNames(13),
9723 0 : s_ipsc->cAlphaArgs(13)));
9724 : }
9725 :
9726 73 : if (ControlNumAlpha >= 14) {
9727 73 : windowShadingControl.FenestrationCount = ControlNumAlpha - 13;
9728 73 : windowShadingControl.FenestrationName.allocate(windowShadingControl.FenestrationCount);
9729 73 : windowShadingControl.FenestrationIndex.allocate(windowShadingControl.FenestrationCount);
9730 228 : for (int i = 1; i <= windowShadingControl.FenestrationCount; i++) {
9731 155 : windowShadingControl.FenestrationName(i) = s_ipsc->cAlphaArgs(i + 13);
9732 : }
9733 : } else {
9734 0 : ShowSevereError(state,
9735 0 : format("{}=\"{}\" invalid. Must reference at least one Fenestration Surface object name.",
9736 0 : s_ipsc->cCurrentModuleObject,
9737 0 : s_ipsc->cAlphaArgs(1)));
9738 : }
9739 :
9740 73 : windowShadingControl.shadingControlType = static_cast<DataSurfaces::WindowShadingControlType>(
9741 73 : getEnumValue(WindowShadingControlTypeNamesUC, Util::makeUPPER(s_ipsc->cAlphaArgs(5))));
9742 :
9743 73 : if (windowShadingControl.ShadingDevice > 0) {
9744 13 : if (s_mat->materials(windowShadingControl.ShadingDevice)->group == Material::Group::Screen &&
9745 0 : !(windowShadingControl.shadingControlType == DataSurfaces::WindowShadingControlType::AlwaysOn ||
9746 0 : windowShadingControl.shadingControlType == DataSurfaces::WindowShadingControlType::AlwaysOff ||
9747 0 : windowShadingControl.shadingControlType == DataSurfaces::WindowShadingControlType::OnIfScheduled)) {
9748 0 : ErrorsFound = true;
9749 0 : ShowSevereError(state,
9750 0 : format("{}=\"{}\" invalid {}=\"{}\" for exterior screens.",
9751 0 : s_ipsc->cCurrentModuleObject,
9752 0 : windowShadingControl.Name,
9753 0 : s_ipsc->cAlphaFieldNames(5),
9754 0 : s_ipsc->cAlphaArgs(5)));
9755 0 : ShowContinueError(state,
9756 : "Valid shading control types for exterior window screens are ALWAYSON, ALWAYSOFF, or ONIFSCHEDULEALLOWS.");
9757 : }
9758 : } else {
9759 60 : if (windowShadingControl.getInputShadedConstruction > 0) {
9760 60 : state.dataConstruction->Construct(windowShadingControl.getInputShadedConstruction).IsUsed = true;
9761 60 : if (s_mat->materials(state.dataConstruction->Construct(windowShadingControl.getInputShadedConstruction).LayerPoint(1))->group ==
9762 62 : Material::Group::Screen &&
9763 2 : !(windowShadingControl.shadingControlType == DataSurfaces::WindowShadingControlType::AlwaysOn ||
9764 2 : windowShadingControl.shadingControlType == DataSurfaces::WindowShadingControlType::AlwaysOff ||
9765 2 : windowShadingControl.shadingControlType == DataSurfaces::WindowShadingControlType::OnIfScheduled)) {
9766 0 : ErrorsFound = true;
9767 0 : ShowSevereError(state,
9768 0 : format("{}=\"{}\" invalid {}=\"{}\" for exterior screens.",
9769 0 : s_ipsc->cCurrentModuleObject,
9770 0 : windowShadingControl.Name,
9771 0 : s_ipsc->cAlphaFieldNames(5),
9772 0 : s_ipsc->cAlphaArgs(5)));
9773 0 : ShowContinueError(state,
9774 : "Valid shading control types for exterior window screens are ALWAYSON, ALWAYSOFF, or ONIFSCHEDULEALLOWS.");
9775 : }
9776 0 : } else if (s_ipsc->lAlphaFieldBlanks(4)) {
9777 0 : ShowSevereError(
9778 : state,
9779 0 : format("{}=\"{}\", {} is blank.", s_ipsc->cCurrentModuleObject, windowShadingControl.Name, s_ipsc->cAlphaFieldNames(4)));
9780 0 : ShowContinueError(state, "A valid construction is required.");
9781 0 : ErrorsFound = true;
9782 : } else {
9783 0 : ShowSevereError(
9784 : state,
9785 0 : format("{}=\"{}\", {} is invalid.", s_ipsc->cCurrentModuleObject, windowShadingControl.Name, s_ipsc->cAlphaFieldNames(4)));
9786 0 : ShowContinueError(state, format("Construction=\"{}\" was used. A valid construction is required.", s_ipsc->cAlphaArgs(4)));
9787 0 : ErrorsFound = true;
9788 : }
9789 : }
9790 :
9791 : // Warning if setpoint is unintentionally zero
9792 73 : if (windowShadingControl.SetPoint == 0 && windowShadingControl.shadingControlType != DataSurfaces::WindowShadingControlType::AlwaysOn &&
9793 33 : windowShadingControl.shadingControlType != DataSurfaces::WindowShadingControlType::AlwaysOff &&
9794 33 : windowShadingControl.shadingControlType != DataSurfaces::WindowShadingControlType::OnIfScheduled &&
9795 22 : windowShadingControl.shadingControlType != DataSurfaces::WindowShadingControlType::HiGlare) {
9796 0 : ShowWarningError(state, format("{}=\"{}\", The first SetPoint is zero.", s_ipsc->cCurrentModuleObject, windowShadingControl.Name));
9797 0 : ShowContinueError(state, "..You may have forgotten to specify that setpoint.");
9798 : }
9799 :
9800 : // Error checks
9801 73 : if (BooleanSwitch bs = getYesNoValue(s_ipsc->cAlphaArgs(7)); bs == BooleanSwitch::Invalid) { // Shading Control is Schedule field
9802 0 : ShowSevereInvalidBool(state, eoh, s_ipsc->cAlphaFieldNames(7), s_ipsc->cAlphaArgs(7));
9803 0 : ErrorsFound = true;
9804 : }
9805 :
9806 73 : if (BooleanSwitch bs = getYesNoValue(s_ipsc->cAlphaArgs(8)); bs == BooleanSwitch::Invalid) { // Shading Control is Schedule field
9807 0 : ShowSevereInvalidBool(state, eoh, s_ipsc->cAlphaFieldNames(8), s_ipsc->cAlphaArgs(8));
9808 0 : ErrorsFound = true;
9809 : }
9810 :
9811 73 : if ((windowShadingControl.shadingControlType == DataSurfaces::WindowShadingControlType::OnIfScheduled) &&
9812 13 : (!windowShadingControl.ShadingControlIsScheduled)) { // CR 7709 BG
9813 0 : ErrorsFound = true;
9814 0 : ShowSevereError(state,
9815 0 : format("{} = \"{}\" invalid, {} must be set to \"Yes\" for {} = OnIfScheduleAllows",
9816 0 : s_ipsc->cCurrentModuleObject,
9817 0 : windowShadingControl.Name,
9818 0 : s_ipsc->cAlphaFieldNames(7),
9819 0 : s_ipsc->cAlphaFieldNames(5)));
9820 : }
9821 :
9822 73 : if (windowShadingControl.shadingControlType == DataSurfaces::WindowShadingControlType::MeetDaylIlumSetp &&
9823 1 : windowShadingControl.ShadingType != DataSurfaces::WinShadingType::SwitchableGlazing) {
9824 0 : ErrorsFound = true;
9825 0 : ShowSevereError(state,
9826 0 : format("{}=\"{}\" invalid {}=\"{}\".",
9827 0 : s_ipsc->cCurrentModuleObject,
9828 0 : windowShadingControl.Name,
9829 0 : s_ipsc->cAlphaFieldNames(3),
9830 0 : s_ipsc->cAlphaArgs(3)));
9831 0 : ShowContinueError(state,
9832 0 : format("...{} must be SwitchableGlazing for this control, but entered type=\"{}\".",
9833 0 : s_ipsc->cAlphaFieldNames(3),
9834 0 : s_ipsc->cAlphaArgs(3)));
9835 : }
9836 :
9837 73 : DataSurfaces::WinShadingType ShTyp = windowShadingControl.ShadingType;
9838 73 : IShadedConst = windowShadingControl.getInputShadedConstruction;
9839 73 : IShadingDevice = windowShadingControl.ShadingDevice;
9840 :
9841 73 : if (IShadedConst == 0 && IShadingDevice == 0) {
9842 0 : ShowSevereError(state,
9843 0 : format("{}=\"{}\" has no matching shaded construction or shading device.",
9844 0 : s_ipsc->cCurrentModuleObject,
9845 0 : windowShadingControl.Name));
9846 0 : ErrorsFound = true;
9847 73 : } else if (IShadedConst == 0 && IShadingDevice > 0) {
9848 13 : if (ShTyp == DataSurfaces::WinShadingType::SwitchableGlazing) {
9849 0 : ShowSevereError(state,
9850 0 : format("{}=\"{}\" has {}= SwitchableGlazing but no matching shaded construction",
9851 0 : s_ipsc->cCurrentModuleObject,
9852 0 : windowShadingControl.Name,
9853 0 : s_ipsc->cAlphaArgs(3)));
9854 0 : ErrorsFound = true;
9855 : }
9856 26 : if ((ShTyp == DataSurfaces::WinShadingType::IntShade || ShTyp == DataSurfaces::WinShadingType::ExtShade) &&
9857 13 : s_mat->materials(IShadingDevice)->group != Material::Group::Shade) {
9858 0 : ShowSevereError(state,
9859 0 : format("{}=\"{}\" has {}= InteriorShade or ExteriorShade but matching shading device is not a window shade",
9860 0 : s_ipsc->cCurrentModuleObject,
9861 0 : windowShadingControl.Name,
9862 0 : s_ipsc->cAlphaArgs(3)));
9863 0 : ShowContinueError(state, format("{} in error=\"{}\".", s_ipsc->cAlphaFieldNames(8), s_mat->materials(IShadingDevice)->Name));
9864 0 : ErrorsFound = true;
9865 : }
9866 13 : if ((ShTyp == DataSurfaces::WinShadingType::ExtScreen) && s_mat->materials(IShadingDevice)->group != Material::Group::Screen) {
9867 0 : ShowSevereError(state,
9868 0 : format("{}=\"{}\" has {}= ExteriorScreen but matching shading device is not a window screen",
9869 0 : s_ipsc->cCurrentModuleObject,
9870 0 : windowShadingControl.Name,
9871 0 : s_ipsc->cAlphaArgs(3)));
9872 0 : ShowContinueError(state, format("{} in error=\"{}\".", s_ipsc->cAlphaFieldNames(8), s_mat->materials(IShadingDevice)->Name));
9873 0 : ErrorsFound = true;
9874 : }
9875 13 : if ((ShTyp == DataSurfaces::WinShadingType::IntBlind || ShTyp == DataSurfaces::WinShadingType::ExtBlind) &&
9876 0 : s_mat->materials(IShadingDevice)->group != Material::Group::Blind) {
9877 0 : ShowSevereError(state,
9878 0 : format("{}=\"{}\" has {}= InteriorBlind or ExteriorBlind but matching shading device is not a window blind",
9879 0 : s_ipsc->cCurrentModuleObject,
9880 0 : windowShadingControl.Name,
9881 0 : s_ipsc->cAlphaArgs(3)));
9882 0 : ShowContinueError(state, format("{} in error=\"{}\".", s_ipsc->cAlphaFieldNames(8), s_mat->materials(IShadingDevice)->Name));
9883 0 : ErrorsFound = true;
9884 : }
9885 13 : if (ShTyp == DataSurfaces::WinShadingType::BGShade || ShTyp == DataSurfaces::WinShadingType::BGBlind) {
9886 0 : ShowSevereError(state,
9887 0 : format("{}=\"{}\" has {}= BetweenGlassShade or BetweenGlassBlind and",
9888 0 : s_ipsc->cCurrentModuleObject,
9889 0 : windowShadingControl.Name,
9890 0 : s_ipsc->cAlphaArgs(3)));
9891 0 : ShowContinueError(state,
9892 0 : format("{} is specified. This is illegal. Specify shaded construction instead.", s_ipsc->cAlphaFieldNames(8)));
9893 0 : ErrorsFound = true;
9894 : }
9895 60 : } else if (IShadedConst > 0 && IShadingDevice > 0) {
9896 0 : IShadingDevice = 0;
9897 0 : ShowWarningError(state,
9898 0 : format("{}=\"{}\" Both {} and {} are specified.",
9899 0 : s_ipsc->cCurrentModuleObject,
9900 0 : windowShadingControl.Name,
9901 0 : s_ipsc->cAlphaFieldNames(4),
9902 0 : s_ipsc->cAlphaFieldNames(9)));
9903 0 : ShowContinueError(
9904 0 : state, format("The {}=\"{}\" will be used.", s_ipsc->cAlphaFieldNames(4), state.dataConstruction->Construct(IShadedConst).Name));
9905 : }
9906 :
9907 : // If type = interior or exterior shade or blind require that the shaded construction
9908 : // have a shade layer in the correct position
9909 73 : if (IShadedConst != 0) {
9910 :
9911 60 : NLayers = state.dataConstruction->Construct(IShadedConst).TotLayers;
9912 60 : BGShadeBlindError = false;
9913 60 : IShadingDevice = 0;
9914 60 : if (state.dataConstruction->Construct(IShadedConst).LayerPoint(NLayers) != 0) {
9915 60 : if (windowShadingControl.ShadingType == DataSurfaces::WinShadingType::IntShade) {
9916 10 : IShadingDevice = state.dataConstruction->Construct(IShadedConst).LayerPoint(NLayers);
9917 10 : if (s_mat->materials(state.dataConstruction->Construct(IShadedConst).LayerPoint(NLayers))->group != Material::Group::Shade) {
9918 0 : ErrorsFound = true;
9919 0 : ShowSevereError(state,
9920 0 : format("{}=\"{}\" the {}=\"{}\"",
9921 0 : s_ipsc->cCurrentModuleObject,
9922 0 : windowShadingControl.Name,
9923 0 : s_ipsc->cAlphaFieldNames(4),
9924 0 : s_ipsc->cAlphaArgs(4)));
9925 0 : ShowContinueError(state,
9926 0 : format("of {}=\"{}\" should have a shade layer on the inside of the window.",
9927 0 : s_ipsc->cAlphaFieldNames(3),
9928 0 : s_ipsc->cAlphaArgs(3)));
9929 : }
9930 50 : } else if (windowShadingControl.ShadingType == DataSurfaces::WinShadingType::ExtShade) {
9931 5 : IShadingDevice = state.dataConstruction->Construct(IShadedConst).LayerPoint(1);
9932 5 : if (s_mat->materials(state.dataConstruction->Construct(IShadedConst).LayerPoint(1))->group != Material::Group::Shade) {
9933 0 : ErrorsFound = true;
9934 0 : ShowSevereError(state,
9935 0 : format("{}=\"{}\" the {}=\"{}\"",
9936 0 : s_ipsc->cCurrentModuleObject,
9937 0 : windowShadingControl.Name,
9938 0 : s_ipsc->cAlphaFieldNames(43),
9939 0 : s_ipsc->cAlphaArgs(4)));
9940 0 : ShowContinueError(state,
9941 0 : format("of {}=\"{}\" should have a shade layer on the outside of the window.",
9942 0 : s_ipsc->cAlphaFieldNames(3),
9943 0 : s_ipsc->cAlphaArgs(3)));
9944 : }
9945 45 : } else if (windowShadingControl.ShadingType == DataSurfaces::WinShadingType::ExtScreen) {
9946 2 : IShadingDevice = state.dataConstruction->Construct(IShadedConst).LayerPoint(1);
9947 2 : if (s_mat->materials(state.dataConstruction->Construct(IShadedConst).LayerPoint(1))->group != Material::Group::Screen) {
9948 0 : ErrorsFound = true;
9949 0 : ShowSevereError(state,
9950 0 : format("{}=\"{}\" the {}=\"{}\"",
9951 0 : s_ipsc->cCurrentModuleObject,
9952 0 : windowShadingControl.Name,
9953 0 : s_ipsc->cAlphaFieldNames(4),
9954 0 : s_ipsc->cAlphaArgs(4)));
9955 0 : ShowContinueError(state,
9956 0 : format("of {}=\"{}\" should have a screen layer on the outside of the window.",
9957 0 : s_ipsc->cAlphaFieldNames(3),
9958 0 : s_ipsc->cAlphaArgs(3)));
9959 : }
9960 43 : } else if (windowShadingControl.ShadingType == DataSurfaces::WinShadingType::IntBlind) {
9961 13 : IShadingDevice = state.dataConstruction->Construct(IShadedConst).LayerPoint(NLayers);
9962 13 : if (s_mat->materials(state.dataConstruction->Construct(IShadedConst).LayerPoint(NLayers))->group != Material::Group::Blind) {
9963 0 : ErrorsFound = true;
9964 0 : ShowSevereError(state,
9965 0 : format("{}=\"{}\" the {}=\"{}\"",
9966 0 : s_ipsc->cCurrentModuleObject,
9967 0 : windowShadingControl.Name,
9968 0 : s_ipsc->cAlphaFieldNames(4),
9969 0 : s_ipsc->cAlphaArgs(4)));
9970 0 : ShowContinueError(state,
9971 0 : format("of {}=\"{}\" should have a blind layer on the inside of the window.",
9972 0 : s_ipsc->cAlphaFieldNames(3),
9973 0 : s_ipsc->cAlphaArgs(3)));
9974 : }
9975 30 : } else if (windowShadingControl.ShadingType == DataSurfaces::WinShadingType::ExtBlind) {
9976 2 : IShadingDevice = state.dataConstruction->Construct(IShadedConst).LayerPoint(1);
9977 2 : if (s_mat->materials(state.dataConstruction->Construct(IShadedConst).LayerPoint(1))->group != Material::Group::Blind) {
9978 0 : ErrorsFound = true;
9979 0 : ShowSevereError(state,
9980 0 : format("{}=\"{}\" the {}=\"{}\"",
9981 0 : s_ipsc->cCurrentModuleObject,
9982 0 : windowShadingControl.Name,
9983 0 : s_ipsc->cAlphaFieldNames(4),
9984 0 : s_ipsc->cAlphaArgs(4)));
9985 0 : ShowContinueError(state,
9986 0 : format("of {}=\"{}\" should have a blind layer on the outside of the window.",
9987 0 : s_ipsc->cAlphaFieldNames(3),
9988 0 : s_ipsc->cAlphaArgs(3)));
9989 : }
9990 28 : } else if (windowShadingControl.ShadingType == DataSurfaces::WinShadingType::BGShade) {
9991 2 : if (NLayers != 5 && NLayers != 7) {
9992 0 : BGShadeBlindError = true;
9993 : }
9994 2 : if (NLayers == 5) {
9995 1 : if (s_mat->materials(state.dataConstruction->Construct(IShadedConst).LayerPoint(3))->group != Material::Group::Shade) {
9996 0 : BGShadeBlindError = true;
9997 : }
9998 : }
9999 2 : if (NLayers == 7) {
10000 1 : if (s_mat->materials(state.dataConstruction->Construct(IShadedConst).LayerPoint(5))->group != Material::Group::Shade) {
10001 0 : BGShadeBlindError = true;
10002 : }
10003 : }
10004 2 : if (BGShadeBlindError) {
10005 0 : ErrorsFound = true;
10006 0 : ShowSevereError(state,
10007 0 : format("{}=\"{}\" the {}=\"{}\"",
10008 0 : s_ipsc->cCurrentModuleObject,
10009 0 : windowShadingControl.Name,
10010 0 : s_ipsc->cAlphaFieldNames(4),
10011 0 : s_ipsc->cAlphaArgs(4)));
10012 0 : ShowContinueError(state,
10013 0 : format("of {}=\"{}\" should have two or three glass layers and a",
10014 0 : s_ipsc->cAlphaFieldNames(3),
10015 0 : s_ipsc->cAlphaArgs(3)));
10016 0 : ShowContinueError(state, "between-glass shade layer with a gas layer on each side.");
10017 : }
10018 26 : } else if (windowShadingControl.ShadingType == DataSurfaces::WinShadingType::BGBlind) {
10019 3 : if (NLayers != 5 && NLayers != 7) {
10020 0 : BGShadeBlindError = true;
10021 : }
10022 3 : if (NLayers == 5) {
10023 2 : if (s_mat->materials(state.dataConstruction->Construct(IShadedConst).LayerPoint(3))->group != Material::Group::Blind) {
10024 0 : BGShadeBlindError = true;
10025 : }
10026 : }
10027 3 : if (NLayers == 7) {
10028 1 : if (s_mat->materials(state.dataConstruction->Construct(IShadedConst).LayerPoint(5))->group != Material::Group::Blind) {
10029 0 : BGShadeBlindError = true;
10030 : }
10031 : }
10032 3 : if (BGShadeBlindError) {
10033 0 : ErrorsFound = true;
10034 0 : ShowSevereError(state,
10035 0 : format("{}=\"{}\" the {}=\"{}\"",
10036 0 : s_ipsc->cCurrentModuleObject,
10037 0 : windowShadingControl.Name,
10038 0 : s_ipsc->cAlphaFieldNames(4),
10039 0 : s_ipsc->cAlphaArgs(4)));
10040 0 : ShowContinueError(state,
10041 0 : format("of {}=\"{}\" should have two or three glass layers and a",
10042 0 : s_ipsc->cAlphaFieldNames(3),
10043 0 : s_ipsc->cAlphaArgs(3)));
10044 0 : ShowContinueError(state, "between-glass blind layer with a gas layer on each side.");
10045 : }
10046 : }
10047 : }
10048 60 : if (IShadingDevice > 0) {
10049 47 : if ((ShTyp == DataSurfaces::WinShadingType::IntShade || ShTyp == DataSurfaces::WinShadingType::ExtShade) &&
10050 15 : s_mat->materials(IShadingDevice)->group != Material::Group::Shade) {
10051 0 : ShowSevereError(state,
10052 0 : format("{}=\"{}\" has {}= InteriorShade or ExteriorShade but matching shading device is not a window shade",
10053 0 : s_ipsc->cCurrentModuleObject,
10054 0 : windowShadingControl.Name,
10055 0 : s_ipsc->cAlphaFieldNames(3)));
10056 0 : ShowContinueError(state, format("Shading Device in error=\"{}\".", s_mat->materials(IShadingDevice)->Name));
10057 0 : ErrorsFound = true;
10058 : }
10059 32 : if ((ShTyp == DataSurfaces::WinShadingType::ExtScreen) && s_mat->materials(IShadingDevice)->group != Material::Group::Screen) {
10060 0 : ShowSevereError(state,
10061 0 : format("{}=\"{}\" has {}= ExteriorScreen but matching shading device is not an exterior window screen.",
10062 0 : s_ipsc->cCurrentModuleObject,
10063 0 : windowShadingControl.Name,
10064 0 : s_ipsc->cAlphaFieldNames(3)));
10065 0 : ShowContinueError(state, format("Shading Device in error=\"{}\".", s_mat->materials(IShadingDevice)->Name));
10066 0 : ErrorsFound = true;
10067 : }
10068 47 : if ((ShTyp == DataSurfaces::WinShadingType::IntBlind || ShTyp == DataSurfaces::WinShadingType::ExtBlind) &&
10069 15 : s_mat->materials(IShadingDevice)->group != Material::Group::Blind) {
10070 0 : ShowSevereError(state,
10071 0 : format("{}=\"{}\" has {}= InteriorBlind or ExteriorBlind but matching shading device is not a window blind.",
10072 0 : s_ipsc->cCurrentModuleObject,
10073 0 : windowShadingControl.Name,
10074 0 : s_ipsc->cAlphaFieldNames(3)));
10075 0 : ShowContinueError(state, format("Shading Device in error=\"{}\".", s_mat->materials(IShadingDevice)->Name));
10076 0 : ErrorsFound = true;
10077 : }
10078 : }
10079 : }
10080 : } // End of loop over window shading controls
10081 : }
10082 :
10083 6368 : void InitialAssociateWindowShadingControlFenestration(EnergyPlusData &state, bool &ErrorsFound, int SurfNum)
10084 : {
10085 6368 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
10086 : // J.Glazer 2018 - operates on SurfaceTmp array before final indices are known for windows and sets the activeWindowShadingControl
10087 8058 : for (int iShadeCtrl = 1; iShadeCtrl <= state.dataSurface->TotWinShadingControl; ++iShadeCtrl) {
10088 1690 : int curShadedConstruction = state.dataSurface->WindowShadingControl(iShadeCtrl).getInputShadedConstruction;
10089 6672 : for (int jFeneRef = 1; jFeneRef <= state.dataSurface->WindowShadingControl(iShadeCtrl).FenestrationCount; ++jFeneRef) {
10090 4982 : if (Util::SameString(state.dataSurface->WindowShadingControl(iShadeCtrl).FenestrationName(jFeneRef), surfTemp.Name)) {
10091 155 : state.dataGlobal->AndShadingControlInModel = true;
10092 155 : surfTemp.HasShadeControl = true;
10093 155 : surfTemp.windowShadingControlList.push_back(iShadeCtrl);
10094 155 : surfTemp.activeWindowShadingControl = iShadeCtrl;
10095 155 : surfTemp.shadedConstructionList.push_back(curShadedConstruction);
10096 155 : surfTemp.activeShadedConstruction = curShadedConstruction;
10097 :
10098 : // check to make the window refenced is an exterior window
10099 155 : if (surfTemp.ExtBoundCond != DataSurfaces::ExternalEnvironment) {
10100 0 : ErrorsFound = true;
10101 0 : ShowSevereError(
10102 : state,
10103 0 : format("InitialAssociateWindowShadingControlFenestration: \"{}\", invalid because it is not an exterior window.",
10104 0 : surfTemp.Name));
10105 0 : ShowContinueError(
10106 : state,
10107 0 : format(".. It appears on WindowShadingControl object: \"{}", state.dataSurface->WindowShadingControl(iShadeCtrl).Name));
10108 : }
10109 : // check to make sure the window is not using equivalent layer window construction
10110 155 : if (state.dataConstruction->Construct(surfTemp.Construction).WindowTypeEQL) {
10111 0 : ErrorsFound = true;
10112 0 : ShowSevereError(state, format("InitialAssociateWindowShadingControlFenestration: =\"{}\", invalid \".", surfTemp.Name));
10113 0 : ShowContinueError(state, ".. equivalent layer window model does not use shading control object.");
10114 0 : ShowContinueError(state, ".. Shading control is set to none or zero, and simulation continues.");
10115 0 : ShowContinueError(
10116 : state,
10117 0 : format(".. It appears on WindowShadingControl object: \"{}", state.dataSurface->WindowShadingControl(iShadeCtrl).Name));
10118 0 : surfTemp.activeWindowShadingControl = 0;
10119 : }
10120 : }
10121 : }
10122 : }
10123 6368 : }
10124 :
10125 801 : void FinalAssociateWindowShadingControlFenestration(EnergyPlusData &state, bool &ErrorsFound)
10126 : {
10127 : // J.Glazer 2018 - operates on Surface array after final indices are known for windows and checks to make sure it is correct
10128 874 : for (int iShadeCtrl = 1; iShadeCtrl <= state.dataSurface->TotWinShadingControl; ++iShadeCtrl) {
10129 228 : for (int jFeneRef = 1; jFeneRef <= state.dataSurface->WindowShadingControl(iShadeCtrl).FenestrationCount; ++jFeneRef) {
10130 155 : int fenestrationIndex = Util::FindItemInList(state.dataSurface->WindowShadingControl(iShadeCtrl).FenestrationName(jFeneRef),
10131 155 : state.dataSurface->Surface,
10132 155 : state.dataSurface->TotSurfaces);
10133 310 : if (std::find(state.dataSurface->Surface(fenestrationIndex).windowShadingControlList.begin(),
10134 310 : state.dataSurface->Surface(fenestrationIndex).windowShadingControlList.end(),
10135 465 : iShadeCtrl) != state.dataSurface->Surface(fenestrationIndex).windowShadingControlList.end()) {
10136 155 : state.dataSurface->WindowShadingControl(iShadeCtrl).FenestrationIndex(jFeneRef) = fenestrationIndex;
10137 : } else {
10138 : // this error condition should not occur since the rearrangement of Surface() from SurfureTmp() is reliable.
10139 0 : ErrorsFound = true;
10140 0 : ShowSevereError(state,
10141 0 : format("FinalAssociateWindowShadingControlFenestration: Fenestration surface named \"{}\" has "
10142 : "WindowShadingContol index that does not match the initial index assigned.",
10143 0 : state.dataSurface->Surface(fenestrationIndex).Name));
10144 0 : ShowContinueError(state,
10145 0 : format("This occurs while WindowShadingControl object: \"{}\" is being evaluated. ",
10146 0 : state.dataSurface->WindowShadingControl(iShadeCtrl).Name));
10147 : }
10148 : }
10149 : }
10150 801 : }
10151 :
10152 801 : void CheckWindowShadingControlSimilarForWindow(EnergyPlusData &state, bool &ErrorsFound)
10153 : {
10154 : // For each window check if all window shading controls on list are the same except for name, schedule name, construction, and
10155 : // material
10156 48091 : for (auto &theSurf : state.dataSurface->Surface) {
10157 47290 : if (theSurf.HasShadeControl) {
10158 151 : if (theSurf.windowShadingControlList.size() > 1) {
10159 4 : int firstWindowShadingControl = theSurf.windowShadingControlList.front();
10160 12 : for (auto wsc = std::next(theSurf.windowShadingControlList.begin()); wsc != theSurf.windowShadingControlList.end(); ++wsc) {
10161 4 : if (!isWindowShadingControlSimilar(state, firstWindowShadingControl, *wsc)) {
10162 0 : ErrorsFound = true;
10163 0 : ShowSevereError(state,
10164 0 : format("CheckWindowShadingControlSimilarForWindow: Fenestration surface named \"{}\" has multiple "
10165 : "WindowShadingContols that are not similar.",
10166 0 : theSurf.Name));
10167 0 : ShowContinueError(state,
10168 0 : format("for: \"{} and: {}",
10169 0 : state.dataSurface->WindowShadingControl(firstWindowShadingControl).Name,
10170 0 : state.dataSurface->WindowShadingControl(*wsc).Name));
10171 : }
10172 4 : }
10173 : }
10174 : }
10175 801 : }
10176 801 : }
10177 :
10178 4 : bool isWindowShadingControlSimilar(EnergyPlusData &state, int a, int b)
10179 : {
10180 : // Compares two window shading controls are the same except for the name, schedule name, construction, and material
10181 4 : auto const &WindowShadingControlA = state.dataSurface->WindowShadingControl(a);
10182 4 : auto const &WindowShadingControlB = state.dataSurface->WindowShadingControl(b);
10183 8 : return (WindowShadingControlA.ZoneIndex == WindowShadingControlB.ZoneIndex &&
10184 4 : WindowShadingControlA.ShadingType == WindowShadingControlB.ShadingType &&
10185 4 : WindowShadingControlA.shadingControlType == WindowShadingControlB.shadingControlType &&
10186 4 : WindowShadingControlA.SetPoint == WindowShadingControlB.SetPoint &&
10187 4 : WindowShadingControlA.ShadingControlIsScheduled == WindowShadingControlB.ShadingControlIsScheduled &&
10188 4 : WindowShadingControlA.GlareControlIsActive == WindowShadingControlB.GlareControlIsActive &&
10189 4 : WindowShadingControlA.slatAngleControl == WindowShadingControlB.slatAngleControl &&
10190 8 : WindowShadingControlA.SetPoint2 == WindowShadingControlB.SetPoint2 &&
10191 4 : WindowShadingControlA.DaylightingControlName == WindowShadingControlB.DaylightingControlName &&
10192 12 : WindowShadingControlA.DaylightControlIndex == WindowShadingControlB.DaylightControlIndex &&
10193 8 : WindowShadingControlA.multiSurfaceControl == WindowShadingControlB.multiSurfaceControl);
10194 : }
10195 :
10196 801 : void GetStormWindowData(EnergyPlusData &state, bool &ErrorsFound) // If errors found in input
10197 : {
10198 :
10199 : // SUBROUTINE INFORMATION:
10200 : // AUTHOR Fred Winkelmann
10201 : // DATE WRITTEN December 2003
10202 :
10203 : // PURPOSE OF THIS SUBROUTINE:
10204 : // Reads in the storm window data from the input file, interprets it and puts it in the derived type
10205 :
10206 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
10207 : int IOStat; // IO Status when calling get input subroutine
10208 : int StormWinNumAlpha; // Number of alpha names being passed
10209 : int StormWinNumProp; // Number of properties being passed
10210 : int loop; // Do loop counter
10211 :
10212 801 : auto &s_ipsc = state.dataIPShortCut;
10213 801 : auto &s_mat = state.dataMaterial;
10214 :
10215 : // Get the total number of storm window input objects
10216 801 : s_ipsc->cCurrentModuleObject = "WindowProperty:StormWindow";
10217 801 : state.dataSurface->TotStormWin = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
10218 801 : if (state.dataSurface->TotStormWin == 0) {
10219 800 : return;
10220 : }
10221 :
10222 1 : state.dataSurface->StormWindow.allocate(state.dataSurface->TotStormWin);
10223 :
10224 1 : int StormWinNum = 0;
10225 1 : for (loop = 1; loop <= state.dataSurface->TotStormWin; ++loop) {
10226 :
10227 2 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
10228 1 : s_ipsc->cCurrentModuleObject,
10229 : loop,
10230 1 : s_ipsc->cAlphaArgs,
10231 : StormWinNumAlpha,
10232 1 : s_ipsc->rNumericArgs,
10233 : StormWinNumProp,
10234 : IOStat,
10235 1 : s_ipsc->lNumericFieldBlanks,
10236 1 : s_ipsc->lAlphaFieldBlanks,
10237 1 : s_ipsc->cAlphaFieldNames,
10238 1 : s_ipsc->cNumericFieldNames);
10239 1 : ++StormWinNum;
10240 1 : state.dataSurface->StormWindow(StormWinNum).BaseWindowNum =
10241 1 : Util::FindItemInList(s_ipsc->cAlphaArgs(1), state.dataSurface->Surface, state.dataSurface->TotSurfaces);
10242 1 : state.dataSurface->StormWindow(StormWinNum).StormWinMaterialNum = Material::GetMaterialNum(state, s_ipsc->cAlphaArgs(2));
10243 1 : state.dataSurface->StormWindow(StormWinNum).StormWinDistance = s_ipsc->rNumericArgs(1);
10244 1 : state.dataSurface->StormWindow(StormWinNum).MonthOn = s_ipsc->rNumericArgs(2);
10245 1 : state.dataSurface->StormWindow(StormWinNum).DayOfMonthOn = s_ipsc->rNumericArgs(3);
10246 1 : state.dataSurface->StormWindow(StormWinNum).DateOn =
10247 1 : General::OrdinalDay(state.dataSurface->StormWindow(StormWinNum).MonthOn, state.dataSurface->StormWindow(StormWinNum).DayOfMonthOn, 1);
10248 1 : state.dataSurface->StormWindow(StormWinNum).MonthOff = s_ipsc->rNumericArgs(4);
10249 1 : state.dataSurface->StormWindow(StormWinNum).DayOfMonthOff = s_ipsc->rNumericArgs(5);
10250 1 : state.dataSurface->StormWindow(StormWinNum).DateOff = General::OrdinalDay(
10251 1 : state.dataSurface->StormWindow(StormWinNum).MonthOff, state.dataSurface->StormWindow(StormWinNum).DayOfMonthOff, 1);
10252 :
10253 1 : if (state.dataSurface->StormWindow(StormWinNum).DateOn == state.dataSurface->StormWindow(StormWinNum).DateOff) {
10254 0 : ShowSevereError(state,
10255 0 : format("{}: Date On = Date Off -- not allowed, occurred in WindowProperty:StormWindow Input #{}",
10256 0 : s_ipsc->cCurrentModuleObject,
10257 : StormWinNum));
10258 0 : ErrorsFound = true;
10259 : }
10260 :
10261 : enum Month
10262 : {
10263 : January = 1,
10264 : February,
10265 : March,
10266 : April,
10267 : May,
10268 : June,
10269 : July,
10270 : August,
10271 : September,
10272 : October,
10273 : November,
10274 : December
10275 : };
10276 1 : constexpr std::array<int, 13> oneBasedDaysInMonth = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
10277 :
10278 1 : int const monthOn = state.dataSurface->StormWindow(StormWinNum).MonthOn;
10279 1 : if (monthOn >= January && monthOn <= December) {
10280 2 : if (state.dataSurface->StormWindow(StormWinNum).DayOfMonthOn >
10281 1 : oneBasedDaysInMonth[state.dataSurface->StormWindow(StormWinNum).MonthOn]) {
10282 0 : ShowSevereError(state,
10283 0 : format("{}: Date On (Day of Month) [{}], invalid for WindowProperty:StormWindow Input #{}",
10284 0 : s_ipsc->cCurrentModuleObject,
10285 0 : state.dataSurface->StormWindow(StormWinNum).DayOfMonthOn,
10286 : StormWinNum));
10287 0 : ErrorsFound = true;
10288 : }
10289 1 : break;
10290 : } else {
10291 0 : ShowSevereError(state,
10292 0 : format("{}: Date On Month [{}], invalid for WindowProperty:StormWindow Input #{}",
10293 0 : s_ipsc->cCurrentModuleObject,
10294 0 : state.dataSurface->StormWindow(StormWinNum).MonthOn,
10295 : StormWinNum));
10296 0 : ErrorsFound = true;
10297 : }
10298 :
10299 0 : int const monthOff = state.dataSurface->StormWindow(StormWinNum).MonthOff;
10300 0 : if (monthOff >= January && monthOff <= December) {
10301 0 : if (state.dataSurface->StormWindow(StormWinNum).DayOfMonthOff >
10302 0 : oneBasedDaysInMonth[state.dataSurface->StormWindow(StormWinNum).MonthOff]) {
10303 0 : ShowSevereError(state,
10304 0 : format("{}: Date Off (Day of Month) [{}], invalid for WindowProperty:StormWindow Input #{}",
10305 0 : s_ipsc->cCurrentModuleObject,
10306 0 : state.dataSurface->StormWindow(StormWinNum).DayOfMonthOff,
10307 : StormWinNum));
10308 0 : ErrorsFound = true;
10309 : }
10310 0 : break;
10311 : } else {
10312 0 : ShowSevereError(state,
10313 0 : format("{}: Date Off Month [{}], invalid for WindowProperty:StormWindow Input #{}",
10314 0 : s_ipsc->cCurrentModuleObject,
10315 0 : state.dataSurface->StormWindow(StormWinNum).MonthOff,
10316 : StormWinNum));
10317 0 : ErrorsFound = true;
10318 : }
10319 : }
10320 :
10321 : // Error checks
10322 :
10323 2 : for (StormWinNum = 1; StormWinNum <= state.dataSurface->TotStormWin; ++StormWinNum) {
10324 : // Require BaseWindowNum be that of an exterior window
10325 1 : int SurfNum = state.dataSurface->StormWindow(StormWinNum).BaseWindowNum;
10326 1 : if (SurfNum == 0) {
10327 0 : ShowSevereError(state, format("{}=\"{}\" invalid.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
10328 0 : ErrorsFound = true;
10329 : } else {
10330 1 : auto const &surf = state.dataSurface->Surface(SurfNum);
10331 1 : if (surf.Class != SurfaceClass::Window || surf.ExtBoundCond != 0) {
10332 0 : ShowSevereError(state, format("{}=\"{}\"", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
10333 0 : ShowSevereError(state, format("cannot be used with surface={}", surf.Name));
10334 0 : ShowContinueError(state, "because that surface is not an exterior window.");
10335 0 : ErrorsFound = true;
10336 : }
10337 : }
10338 :
10339 : // Require that storm window material be glass
10340 1 : int MatNum = state.dataSurface->StormWindow(StormWinNum).StormWinMaterialNum;
10341 1 : if (SurfNum > 0) {
10342 1 : if (MatNum == 0) {
10343 0 : ShowSevereError(state, format("{}=\"{}\"", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
10344 0 : ShowContinueError(state,
10345 0 : format("{}=\"{}\" not found as storm window layer.", s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2)));
10346 0 : ErrorsFound = true;
10347 : } else {
10348 1 : if (s_mat->materials(MatNum)->group != Material::Group::Glass) {
10349 0 : ShowSevereError(state, format("{}=\"{}\"", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
10350 0 : ShowContinueError(state,
10351 0 : format("{}=\"{}must be a WindowMaterial:Glazing or WindowMaterial:Glazing:RefractionExtinctionMethod",
10352 0 : s_ipsc->cAlphaFieldNames(2),
10353 0 : s_ipsc->cAlphaArgs(2)));
10354 0 : ErrorsFound = true;
10355 : }
10356 : }
10357 : // Error if base window has airflow control
10358 1 : if (state.dataSurface->SurfWinAirflowControlType(SurfNum) != DataSurfaces::WindowAirFlowControlType::Invalid) {
10359 0 : ShowSevereError(
10360 : state,
10361 0 : format("{}=\"{} cannot be used because it is an airflow window (i.e., has WindowProperty:AirflowControl specified)",
10362 0 : s_ipsc->cCurrentModuleObject,
10363 0 : s_ipsc->cAlphaArgs(1)));
10364 0 : ErrorsFound = true;
10365 : }
10366 : }
10367 :
10368 : // Check for reversal of on and off times
10369 1 : if (SurfNum > 0) {
10370 1 : if ((state.dataEnvrn->Latitude > 0.0 &&
10371 2 : (state.dataSurface->StormWindow(StormWinNum).MonthOn < state.dataSurface->StormWindow(StormWinNum).MonthOff)) ||
10372 1 : (state.dataEnvrn->Latitude <= 0.0 &&
10373 0 : (state.dataSurface->StormWindow(StormWinNum).MonthOn > state.dataSurface->StormWindow(StormWinNum).MonthOff))) {
10374 0 : ShowWarningError(state, format("{}=\"{}\" check times that storm window", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
10375 0 : ShowContinueError(state,
10376 0 : format("is put on (month={}, day={}) and taken off (month={}, day={});",
10377 0 : state.dataSurface->StormWindow(StormWinNum).MonthOn,
10378 0 : state.dataSurface->StormWindow(StormWinNum).DayOfMonthOn,
10379 0 : state.dataSurface->StormWindow(StormWinNum).MonthOff,
10380 0 : state.dataSurface->StormWindow(StormWinNum).DayOfMonthOff));
10381 0 : ShowContinueError(state, format("these times may be reversed for your building latitude={:.2R} deg.", state.dataEnvrn->Latitude));
10382 : }
10383 : }
10384 : }
10385 : }
10386 :
10387 801 : void GetWindowGapAirflowControlData(EnergyPlusData &state, bool &ErrorsFound) // If errors found in input
10388 : {
10389 :
10390 : // SUBROUTINE INFORMATION:
10391 : // AUTHOR Fred Winkelmann
10392 : // DATE WRITTEN Feb 2003
10393 : // MODIFIED June 2003, FCW: add destination = return air;
10394 : // more error messages
10395 :
10396 : // PURPOSE OF THIS SUBROUTINE:
10397 : // Reads in the window airflow control information from the input data file,
10398 : // interprets it and puts it in the SurfaceWindow derived type
10399 :
10400 : static constexpr std::string_view routineName = "GetWindowGapAirflowControlData";
10401 :
10402 : int IOStat; // IO Status when calling get input subroutine
10403 : int ControlNumAlpha; // Number of control alpha names being passed
10404 : int ControlNumProp; // Number of control properties being passed
10405 : int TotWinAirflowControl; // Total window airflow control statements
10406 : int Loop;
10407 801 : int ConstrNum(0); // Construction number
10408 : int ConstrNumSh; // Shaded Construction number
10409 : int MatGapFlow; // Material number of gas in airflow gap of window's construction
10410 : int MatGapFlow1; // Material number of gas on either side of a between-glass shade/blind
10411 : int MatGapFlow2;
10412 :
10413 801 : constexpr std::array<std::string_view, static_cast<int>(DataSurfaces::WindowAirFlowSource::Num)> WindowAirFlowSourceNamesUC{"INDOORAIR",
10414 : "OUTDOORAIR"};
10415 801 : constexpr std::array<std::string_view, static_cast<int>(DataSurfaces::WindowAirFlowDestination::Num)> WindowAirFlowDestinationNamesUC{
10416 : "INDOORAIR", "OUTDOORAIR", "RETURNAIR"};
10417 :
10418 : // of the shaded construction of airflow window
10419 801 : auto &s_ipsc = state.dataIPShortCut;
10420 801 : auto &s_mat = state.dataMaterial;
10421 :
10422 : // Get the total number of window airflow control statements
10423 801 : s_ipsc->cCurrentModuleObject = "WindowProperty:AirflowControl";
10424 801 : TotWinAirflowControl = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
10425 801 : if (TotWinAirflowControl == 0) {
10426 799 : return;
10427 : }
10428 :
10429 10 : for (Loop = 1; Loop <= TotWinAirflowControl; ++Loop) { // Loop through all surfaces in the input...
10430 :
10431 16 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
10432 8 : s_ipsc->cCurrentModuleObject,
10433 : Loop,
10434 8 : s_ipsc->cAlphaArgs,
10435 : ControlNumAlpha,
10436 8 : s_ipsc->rNumericArgs,
10437 : ControlNumProp,
10438 : IOStat,
10439 8 : s_ipsc->lNumericFieldBlanks,
10440 8 : s_ipsc->lAlphaFieldBlanks,
10441 8 : s_ipsc->cAlphaFieldNames,
10442 8 : s_ipsc->cNumericFieldNames);
10443 :
10444 8 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
10445 :
10446 8 : int SurfNum = Util::FindItemInList(s_ipsc->cAlphaArgs(1), state.dataSurface->Surface, state.dataSurface->TotSurfaces);
10447 8 : if (SurfNum == 0) {
10448 0 : ShowSevereError(state, format("{}=\"{}\" not found.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
10449 0 : ErrorsFound = true;
10450 : }
10451 : // Check that associated surface is a 2- or 3-pane exterior window
10452 8 : if (SurfNum != 0) {
10453 8 : bool WrongSurfaceType = false;
10454 8 : auto const &surf = state.dataSurface->Surface(SurfNum);
10455 8 : if (surf.Class != SurfaceClass::Window) {
10456 0 : WrongSurfaceType = true;
10457 : }
10458 8 : if (surf.Class == SurfaceClass::Window) {
10459 8 : ConstrNum = surf.Construction;
10460 12 : if (state.dataConstruction->Construct(ConstrNum).TotGlassLayers != 2 &&
10461 4 : state.dataConstruction->Construct(ConstrNum).TotGlassLayers != 3) {
10462 0 : WrongSurfaceType = true;
10463 : }
10464 8 : if (surf.ExtBoundCond != DataSurfaces::ExternalEnvironment) {
10465 0 : WrongSurfaceType = true;
10466 : }
10467 : }
10468 8 : if (WrongSurfaceType) {
10469 0 : ShowSevereError(
10470 : state,
10471 0 : format("{}=\"{}\" is not an exterior window with 2 or 3 glass layers.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
10472 0 : ErrorsFound = true;
10473 : }
10474 : }
10475 :
10476 : // Error if illegal airflow source
10477 8 : if (s_ipsc->cAlphaArgs(2) != "INDOORAIR" && s_ipsc->cAlphaArgs(2) != "OUTDOORAIR") {
10478 0 : ErrorsFound = true;
10479 0 : ShowSevereError(state,
10480 0 : format("{}=\"{}\" invalid {}=\"{}\"",
10481 0 : s_ipsc->cCurrentModuleObject,
10482 0 : s_ipsc->cAlphaArgs(1),
10483 0 : s_ipsc->cAlphaFieldNames(2),
10484 0 : s_ipsc->cAlphaArgs(2)));
10485 : }
10486 :
10487 : // Error if illegal airflow destination
10488 8 : if (s_ipsc->cAlphaArgs(3) != "INDOORAIR" && s_ipsc->cAlphaArgs(3) != "OUTDOORAIR" && s_ipsc->cAlphaArgs(3) != "RETURNAIR") {
10489 0 : ErrorsFound = true;
10490 0 : ShowSevereError(state,
10491 0 : format("{}=\"{}\" invalid {}=\"{}\"",
10492 0 : s_ipsc->cCurrentModuleObject,
10493 0 : s_ipsc->cAlphaArgs(1),
10494 0 : s_ipsc->cAlphaFieldNames(3),
10495 0 : s_ipsc->cAlphaArgs(3)));
10496 : }
10497 :
10498 : // Error if source = OutsideAir and destination = ReturnAir
10499 8 : if (s_ipsc->cAlphaArgs(2) == "OUTDOORAIR" && s_ipsc->cAlphaArgs(3) == "RETURNAIR") {
10500 0 : ErrorsFound = true;
10501 0 : ShowSevereError(state,
10502 0 : format("{}=\"{}\" invalid {}=\"{}\"",
10503 0 : s_ipsc->cCurrentModuleObject,
10504 0 : s_ipsc->cAlphaArgs(1),
10505 0 : s_ipsc->cAlphaFieldNames(2),
10506 0 : s_ipsc->cAlphaArgs(2)));
10507 0 : ShowContinueError(state, format("..when {}=\"{}\"", s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3)));
10508 : }
10509 :
10510 : // Error if illegal airflow control type
10511 8 : if (s_ipsc->cAlphaArgs(4) != "ALWAYSONATMAXIMUMFLOW" && s_ipsc->cAlphaArgs(4) != "ALWAYSOFF" &&
10512 0 : s_ipsc->cAlphaArgs(4) != "SCHEDULEDONLY") {
10513 0 : ErrorsFound = true;
10514 0 : ShowSevereError(state,
10515 0 : format("{}=\"{}\" invalid {}=\"{}\"",
10516 0 : s_ipsc->cCurrentModuleObject,
10517 0 : s_ipsc->cAlphaArgs(1),
10518 0 : s_ipsc->cAlphaFieldNames(4),
10519 0 : s_ipsc->cAlphaArgs(4)));
10520 : }
10521 :
10522 : // Error if illegal value for Airflow Has Multiplier Schedule
10523 8 : if (s_ipsc->cAlphaArgs(5) != "YES" && s_ipsc->cAlphaArgs(5) != "NO") {
10524 0 : ErrorsFound = true;
10525 0 : ShowSevereError(state,
10526 0 : format("{}=\"{}\" invalid {}=\"{}\"",
10527 0 : s_ipsc->cCurrentModuleObject,
10528 0 : s_ipsc->cAlphaArgs(1),
10529 0 : s_ipsc->cAlphaFieldNames(5),
10530 0 : s_ipsc->cAlphaArgs(5)));
10531 : }
10532 :
10533 : // Error if Airflow Control Type = ScheduledOnly and Airflow Has Multiplier Schedule = No
10534 8 : if (s_ipsc->cAlphaArgs(4) == "SCHEDULEDONLY" && s_ipsc->cAlphaArgs(5) == "NO") {
10535 0 : ErrorsFound = true;
10536 0 : ShowSevereError(state,
10537 0 : format("{}=\"{}\" invalid {}=\"{}\"",
10538 0 : s_ipsc->cCurrentModuleObject,
10539 0 : s_ipsc->cAlphaArgs(1),
10540 0 : s_ipsc->cAlphaFieldNames(4),
10541 0 : s_ipsc->cAlphaArgs(4)));
10542 0 : ShowContinueError(state, format("..when {}=\"{}\"", s_ipsc->cAlphaFieldNames(5), s_ipsc->cAlphaArgs(5)));
10543 : }
10544 :
10545 : // Warning if Airflow Control Type = AlwaysOnAtMaxFlow and Airflow Has Multiplier Schedule = Yes
10546 8 : if (s_ipsc->cAlphaArgs(4) == "ALWAYSONATMAXIMUMFLOW" && s_ipsc->cAlphaArgs(5) == "YES") {
10547 0 : ShowWarningError(state,
10548 0 : format("{}=\"{}has {}=\"{}\"",
10549 0 : s_ipsc->cCurrentModuleObject,
10550 0 : s_ipsc->cAlphaArgs(1),
10551 0 : s_ipsc->cAlphaFieldNames(4),
10552 0 : s_ipsc->cAlphaArgs(4)));
10553 0 : ShowContinueError(state,
10554 0 : format("..but {}=\"{}If specified, the {} will be ignored.",
10555 0 : s_ipsc->cAlphaFieldNames(5),
10556 0 : s_ipsc->cAlphaArgs(5),
10557 0 : s_ipsc->cAlphaFieldNames(5)));
10558 : }
10559 :
10560 : // Warning if Airflow Control Type = AlwaysOff and Airflow Has Multiplier Schedule = Yes
10561 8 : if (s_ipsc->cAlphaArgs(4) == "ALWAYSOFF" && s_ipsc->cAlphaArgs(5) == "YES") {
10562 0 : ShowWarningError(state,
10563 0 : format("{}=\"{}has {}=\"{}\"",
10564 0 : s_ipsc->cCurrentModuleObject,
10565 0 : s_ipsc->cAlphaArgs(1),
10566 0 : s_ipsc->cAlphaFieldNames(4),
10567 0 : s_ipsc->cAlphaArgs(4)));
10568 0 : ShowContinueError(state,
10569 0 : format("..but {}=\"{}\". If specified, the {} will be ignored.",
10570 0 : s_ipsc->cAlphaFieldNames(5),
10571 0 : s_ipsc->cAlphaArgs(5),
10572 0 : s_ipsc->cAlphaFieldNames(5)));
10573 : }
10574 :
10575 8 : if (SurfNum > 0) {
10576 8 : auto const &surf = state.dataSurface->Surface(SurfNum);
10577 8 : state.dataSurface->AirflowWindows = true;
10578 8 : state.dataSurface->SurfWinAirflowSource(SurfNum) =
10579 8 : static_cast<DataSurfaces::WindowAirFlowSource>(getEnumValue(WindowAirFlowSourceNamesUC, s_ipsc->cAlphaArgs(2)));
10580 :
10581 8 : state.dataSurface->SurfWinAirflowDestination(SurfNum) =
10582 8 : static_cast<DataSurfaces::WindowAirFlowDestination>(getEnumValue(WindowAirFlowDestinationNamesUC, s_ipsc->cAlphaArgs(3)));
10583 :
10584 8 : if (state.dataSurface->SurfWinAirflowDestination(SurfNum) == DataSurfaces::WindowAirFlowDestination::Return) {
10585 0 : int controlledZoneNum = DataZoneEquipment::GetControlledZoneIndex(state, surf.ZoneName);
10586 0 : if (controlledZoneNum > 0) {
10587 0 : state.dataHeatBal->Zone(surf.Zone).HasAirFlowWindowReturn = true;
10588 : }
10589 :
10590 : // Set return air node number
10591 0 : state.dataSurface->SurfWinAirflowReturnNodePtr(SurfNum) = 0;
10592 0 : std::string retNodeName = "";
10593 0 : if (!s_ipsc->lAlphaFieldBlanks(7)) {
10594 0 : retNodeName = s_ipsc->cAlphaArgs(7);
10595 : }
10596 0 : std::string callDescription = s_ipsc->cCurrentModuleObject + "=" + surf.Name;
10597 0 : state.dataSurface->SurfWinAirflowReturnNodePtr(SurfNum) =
10598 0 : DataZoneEquipment::GetReturnAirNodeForZone(state, surf.Zone, retNodeName, callDescription);
10599 0 : if (state.dataSurface->SurfWinAirflowReturnNodePtr(SurfNum) == 0) {
10600 0 : ShowSevereError(state,
10601 0 : format("{}{}=\"{}\", airflow window return air node not found for {} = {}",
10602 : routineName,
10603 0 : s_ipsc->cCurrentModuleObject,
10604 0 : surf.Name,
10605 0 : s_ipsc->cAlphaFieldNames(3),
10606 0 : s_ipsc->cAlphaArgs(3)));
10607 0 : if (!s_ipsc->lAlphaFieldBlanks(7)) {
10608 0 : ShowContinueError(
10609 : state,
10610 0 : format("{}=\"{}\" did not find a matching return air node.", s_ipsc->cAlphaFieldNames(7), s_ipsc->cAlphaArgs(7)));
10611 : }
10612 0 : ShowContinueError(state,
10613 : "..Airflow windows with Airflow Destination = ReturnAir must reference a controlled Zone (appear in a "
10614 : "ZoneHVAC:EquipmentConnections object) with at least one return air node.");
10615 0 : ErrorsFound = true;
10616 : }
10617 0 : }
10618 8 : if (Util::SameString(s_ipsc->cAlphaArgs(4), "AlwaysOnAtMaximumFlow")) {
10619 8 : state.dataSurface->SurfWinAirflowControlType(SurfNum) = DataSurfaces::WindowAirFlowControlType::MaxFlow;
10620 0 : } else if (Util::SameString(s_ipsc->cAlphaArgs(4), "AlwaysOff")) {
10621 0 : state.dataSurface->SurfWinAirflowControlType(SurfNum) = DataSurfaces::WindowAirFlowControlType::AlwaysOff;
10622 0 : } else if (Util::SameString(s_ipsc->cAlphaArgs(4), "ScheduledOnly")) {
10623 0 : state.dataSurface->SurfWinAirflowControlType(SurfNum) = DataSurfaces::WindowAirFlowControlType::Schedule;
10624 : }
10625 8 : state.dataSurface->SurfWinMaxAirflow(SurfNum) = s_ipsc->rNumericArgs(1);
10626 8 : if (s_ipsc->cAlphaArgs(4) == "SCHEDULEDONLY" && s_ipsc->cAlphaArgs(5) == "YES") {
10627 0 : if (s_ipsc->lAlphaFieldBlanks(6)) {
10628 0 : ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(6), s_ipsc->cAlphaFieldNames(4), s_ipsc->cAlphaArgs(4));
10629 0 : ErrorsFound = true;
10630 0 : } else if ((state.dataSurface->SurfWinAirflowScheds(SurfNum) = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(6))) == nullptr) {
10631 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(6), s_ipsc->cAlphaArgs(6));
10632 0 : ErrorsFound = true;
10633 0 : ShowSevereError(state,
10634 0 : format("{}=\"{}\", has {}=\"{}\"",
10635 0 : s_ipsc->cCurrentModuleObject,
10636 0 : s_ipsc->cAlphaArgs(1),
10637 0 : s_ipsc->cAlphaFieldNames(4),
10638 0 : s_ipsc->cAlphaArgs(4)));
10639 0 : ShowContinueError(state,
10640 0 : format("..and {}=\"{}\", but no {} specified.",
10641 0 : s_ipsc->cAlphaFieldNames(5),
10642 0 : s_ipsc->cAlphaArgs(5),
10643 0 : s_ipsc->cAlphaFieldNames(6)));
10644 : } else {
10645 0 : state.dataSurface->SurfWinAirflowHasSchedule(SurfNum) = true;
10646 0 : if ((state.dataSurface->SurfWinAirflowScheds(SurfNum) = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(6))) == nullptr) {
10647 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(6), s_ipsc->cAlphaArgs(6));
10648 0 : ErrorsFound = true;
10649 : }
10650 : }
10651 : }
10652 : // Warning if associated window is an interior window
10653 8 : if (surf.ExtBoundCond != DataSurfaces::ExternalEnvironment && !ErrorsFound) {
10654 0 : ShowWarningError(state,
10655 0 : format("{}=\"{}\", is an Interior window; cannot be an airflow window.",
10656 0 : s_ipsc->cCurrentModuleObject,
10657 0 : s_ipsc->cAlphaArgs(1)));
10658 : }
10659 8 : if (!ErrorsFound) {
10660 : // Require that gas in airflow gap has type = air
10661 8 : MatGapFlow = state.dataConstruction->Construct(ConstrNum).LayerPoint(2);
10662 8 : if (state.dataConstruction->Construct(ConstrNum).TotGlassLayers == 3) {
10663 4 : MatGapFlow = state.dataConstruction->Construct(ConstrNum).LayerPoint(4);
10664 : }
10665 8 : if (dynamic_cast<Material::MaterialGasMix const *>(s_mat->materials(MatGapFlow))->gases[0].type != Material::GasType::Air) {
10666 0 : ErrorsFound = true;
10667 0 : ShowSevereError(state,
10668 0 : format("{}=\"{}\", Gas type not air in airflow gap of construction {}",
10669 0 : s_ipsc->cCurrentModuleObject,
10670 0 : s_ipsc->cAlphaArgs(1),
10671 0 : state.dataConstruction->Construct(ConstrNum).Name));
10672 : }
10673 : // Require that gas be air in airflow gaps on either side of a between glass shade/blind
10674 8 : if (surf.HasShadeControl) {
10675 4 : for (std::size_t listIndex = 0; listIndex < surf.windowShadingControlList.size(); ++listIndex) {
10676 4 : int WSCPtr = surf.windowShadingControlList[listIndex];
10677 4 : if (ANY_BETWEENGLASS_SHADE_BLIND(state.dataSurface->WindowShadingControl(WSCPtr).ShadingType)) {
10678 4 : ConstrNumSh = surf.shadedConstructionList[listIndex];
10679 4 : if (state.dataConstruction->Construct(ConstrNum).TotGlassLayers == 2) {
10680 2 : MatGapFlow1 = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(2);
10681 2 : MatGapFlow2 = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(4);
10682 : } else {
10683 2 : MatGapFlow1 = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(4);
10684 2 : MatGapFlow2 = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(6);
10685 : }
10686 4 : if (dynamic_cast<Material::MaterialGasMix const *>(s_mat->materials(MatGapFlow1))->gases[0].type !=
10687 8 : Material::GasType::Air ||
10688 4 : dynamic_cast<Material::MaterialGasMix const *>(s_mat->materials(MatGapFlow2))->gases[0].type !=
10689 : Material::GasType::Air) {
10690 0 : ErrorsFound = true;
10691 0 : ShowSevereError(state,
10692 0 : format("{}=\"{}\", gas type must be air on either side of the shade/blind",
10693 0 : s_ipsc->cCurrentModuleObject,
10694 0 : s_ipsc->cAlphaArgs(1)));
10695 : }
10696 4 : break; // only need the first window shading control since they should be the same
10697 : }
10698 : }
10699 : }
10700 : }
10701 : }
10702 :
10703 : } // End of loop over window airflow controls
10704 : }
10705 :
10706 801 : void GetFoundationData(EnergyPlusData &state, bool &ErrorsFound)
10707 : {
10708 :
10709 : int NumAlphas;
10710 : int NumProps;
10711 : int IOStat;
10712 :
10713 : static constexpr std::string_view routineName = "GetFoundationData";
10714 :
10715 801 : auto &s_ipsc = state.dataIPShortCut;
10716 :
10717 : // Read Kiva Settings
10718 801 : s_ipsc->cCurrentModuleObject = "Foundation:Kiva:Settings";
10719 801 : int TotKivaStgs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
10720 :
10721 801 : if (TotKivaStgs > 1) {
10722 0 : ErrorsFound = true;
10723 0 : ShowSevereError(state, format("Multiple {} objects found. Only one is allowed.", s_ipsc->cCurrentModuleObject));
10724 : }
10725 :
10726 801 : if (TotKivaStgs == 1) {
10727 12 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
10728 6 : s_ipsc->cCurrentModuleObject,
10729 : 1,
10730 6 : s_ipsc->cAlphaArgs,
10731 : NumAlphas,
10732 6 : s_ipsc->rNumericArgs,
10733 : NumProps,
10734 : IOStat,
10735 6 : s_ipsc->lNumericFieldBlanks,
10736 6 : s_ipsc->lAlphaFieldBlanks,
10737 6 : s_ipsc->cAlphaFieldNames,
10738 6 : s_ipsc->cNumericFieldNames);
10739 :
10740 6 : int numF = 1;
10741 6 : int alpF = 1;
10742 :
10743 6 : if (!s_ipsc->lNumericFieldBlanks(numF)) {
10744 6 : state.dataSurfaceGeometry->kivaManager.settings.soilK = s_ipsc->rNumericArgs(numF);
10745 : }
10746 6 : numF++;
10747 6 : if (!s_ipsc->lNumericFieldBlanks(numF)) {
10748 6 : state.dataSurfaceGeometry->kivaManager.settings.soilRho = s_ipsc->rNumericArgs(numF);
10749 : }
10750 6 : numF++;
10751 6 : if (!s_ipsc->lNumericFieldBlanks(numF)) {
10752 6 : state.dataSurfaceGeometry->kivaManager.settings.soilCp = s_ipsc->rNumericArgs(numF);
10753 : }
10754 6 : numF++;
10755 6 : if (!s_ipsc->lNumericFieldBlanks(numF)) {
10756 6 : state.dataSurfaceGeometry->kivaManager.settings.groundSolarAbs = s_ipsc->rNumericArgs(numF);
10757 : }
10758 6 : numF++;
10759 6 : if (!s_ipsc->lNumericFieldBlanks(numF)) {
10760 6 : state.dataSurfaceGeometry->kivaManager.settings.groundThermalAbs = s_ipsc->rNumericArgs(numF);
10761 : }
10762 6 : numF++;
10763 6 : if (!s_ipsc->lNumericFieldBlanks(numF)) {
10764 6 : state.dataSurfaceGeometry->kivaManager.settings.groundRoughness = s_ipsc->rNumericArgs(numF);
10765 : }
10766 6 : numF++;
10767 6 : if (!s_ipsc->lNumericFieldBlanks(numF)) {
10768 6 : state.dataSurfaceGeometry->kivaManager.settings.farFieldWidth = s_ipsc->rNumericArgs(numF);
10769 : }
10770 6 : numF++;
10771 :
10772 6 : if (!s_ipsc->lAlphaFieldBlanks(alpF)) {
10773 6 : if (Util::SameString(s_ipsc->cAlphaArgs(alpF), "ZeroFlux")) {
10774 2 : state.dataSurfaceGeometry->kivaManager.settings.deepGroundBoundary = HeatBalanceKivaManager::KivaManager::Settings::ZERO_FLUX;
10775 4 : } else if (Util::SameString(s_ipsc->cAlphaArgs(alpF), "GroundWater")) {
10776 0 : state.dataSurfaceGeometry->kivaManager.settings.deepGroundBoundary = HeatBalanceKivaManager::KivaManager::Settings::GROUNDWATER;
10777 4 : } else if (Util::SameString(s_ipsc->cAlphaArgs(alpF), "Autoselect")) {
10778 4 : state.dataSurfaceGeometry->kivaManager.settings.deepGroundBoundary = HeatBalanceKivaManager::KivaManager::Settings::AUTO;
10779 : } else {
10780 0 : ErrorsFound = true;
10781 0 : ShowSevereError(state,
10782 0 : format("{}, {} is not a valid choice for {}",
10783 0 : s_ipsc->cCurrentModuleObject,
10784 0 : s_ipsc->cAlphaArgs(alpF),
10785 0 : s_ipsc->cAlphaFieldNames(alpF)));
10786 : }
10787 : }
10788 6 : alpF++;
10789 :
10790 6 : if (s_ipsc->lNumericFieldBlanks(numF) || s_ipsc->rNumericArgs(numF) == Constant::AutoCalculate) {
10791 : // Autocalculate deep-ground depth (see KivaManager::defineDefaultFoundation() for actual calculation)
10792 4 : state.dataSurfaceGeometry->kivaManager.settings.deepGroundDepth = 40.0;
10793 4 : state.dataSurfaceGeometry->kivaManager.settings.autocalculateDeepGroundDepth = true;
10794 4 : if (state.dataSurfaceGeometry->kivaManager.settings.deepGroundBoundary != HeatBalanceKivaManager::KivaManager::Settings::AUTO) {
10795 0 : ErrorsFound = true;
10796 0 : ShowSevereError(state,
10797 0 : format("{}, {} should not be set to Autocalculate unless {} is set to Autoselect",
10798 0 : s_ipsc->cCurrentModuleObject,
10799 0 : s_ipsc->cNumericFieldNames(numF),
10800 0 : s_ipsc->cAlphaFieldNames(alpF - 1)));
10801 : }
10802 : } else {
10803 2 : state.dataSurfaceGeometry->kivaManager.settings.deepGroundDepth = s_ipsc->rNumericArgs(numF);
10804 2 : state.dataSurfaceGeometry->kivaManager.settings.autocalculateDeepGroundDepth = false;
10805 : }
10806 6 : numF++;
10807 6 : if (!s_ipsc->lNumericFieldBlanks(numF)) {
10808 2 : state.dataSurfaceGeometry->kivaManager.settings.minCellDim = s_ipsc->rNumericArgs(numF);
10809 : }
10810 6 : numF++;
10811 6 : if (!s_ipsc->lNumericFieldBlanks(numF)) {
10812 2 : state.dataSurfaceGeometry->kivaManager.settings.maxGrowthCoeff = s_ipsc->rNumericArgs(numF);
10813 : }
10814 6 : numF++;
10815 :
10816 6 : if (!s_ipsc->lAlphaFieldBlanks(alpF)) {
10817 2 : if (Util::SameString(s_ipsc->cAlphaArgs(alpF), "Hourly")) {
10818 1 : state.dataSurfaceGeometry->kivaManager.settings.timestepType = HeatBalanceKivaManager::KivaManager::Settings::HOURLY;
10819 1 : state.dataSurfaceGeometry->kivaManager.timestep = 3600.; // seconds
10820 : } else { // if (Util::SameString(s_ipsc->cAlphaArgs( alpF ), "Timestep"))
10821 1 : state.dataSurfaceGeometry->kivaManager.settings.timestepType = HeatBalanceKivaManager::KivaManager::Settings::TIMESTEP;
10822 1 : state.dataSurfaceGeometry->kivaManager.timestep = state.dataGlobal->MinutesInTimeStep * 60.;
10823 : }
10824 : }
10825 6 : alpF++;
10826 : }
10827 :
10828 : // Set default foundation (probably doesn't need to be called if there are no Kiva
10829 : // surfaces, but we don't know that yet). We call this here so that the default
10830 : // foundation is available for 1) the starting copy for user-defined Foundation:Kiva
10831 : // object default inputs, and 2) the actual default Foundation object if a
10832 : // user-defined Foundation:Kiva name is not referenced by a surface.
10833 801 : state.dataSurfaceGeometry->kivaManager.defineDefaultFoundation(state);
10834 :
10835 : // Read Foundation objects
10836 801 : s_ipsc->cCurrentModuleObject = "Foundation:Kiva";
10837 801 : int TotKivaFnds = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
10838 :
10839 801 : if (TotKivaFnds > 0) {
10840 8 : auto &s_mat = state.dataMaterial;
10841 16 : for (int Loop = 1; Loop <= TotKivaFnds; ++Loop) {
10842 16 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
10843 8 : s_ipsc->cCurrentModuleObject,
10844 : Loop,
10845 8 : s_ipsc->cAlphaArgs,
10846 : NumAlphas,
10847 8 : s_ipsc->rNumericArgs,
10848 : NumProps,
10849 : IOStat,
10850 8 : s_ipsc->lNumericFieldBlanks,
10851 8 : s_ipsc->lAlphaFieldBlanks,
10852 8 : s_ipsc->cAlphaFieldNames,
10853 8 : s_ipsc->cNumericFieldNames);
10854 :
10855 8 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
10856 :
10857 8 : int numF = 1;
10858 8 : int alpF = 1;
10859 :
10860 8 : bool ErrorInName = false;
10861 :
10862 8 : HeatBalanceKivaManager::FoundationKiva fndInput;
10863 :
10864 8 : fndInput.name = s_ipsc->cAlphaArgs(alpF);
10865 8 : alpF++;
10866 8 : Util::IsNameEmpty(state, fndInput.name, s_ipsc->cCurrentModuleObject, ErrorInName);
10867 8 : if (ErrorInName) {
10868 0 : ErrorsFound = true;
10869 0 : continue;
10870 : }
10871 :
10872 : // Start with copy of default
10873 8 : auto &fnd = fndInput.foundation;
10874 8 : fnd = state.dataSurfaceGeometry->kivaManager.defaultFoundation.foundation;
10875 :
10876 : // Indoor temperature
10877 8 : if (!s_ipsc->lNumericFieldBlanks(numF)) {
10878 2 : fndInput.assumedIndoorTemperature = s_ipsc->rNumericArgs(numF);
10879 : } else {
10880 6 : fndInput.assumedIndoorTemperature = -9999;
10881 : }
10882 8 : numF++;
10883 :
10884 : // Interior horizontal insulation
10885 8 : if (!s_ipsc->lAlphaFieldBlanks(alpF)) {
10886 3 : int index = Material::GetMaterialNum(state, s_ipsc->cAlphaArgs(alpF));
10887 3 : if (index == 0) {
10888 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(alpF), s_ipsc->cAlphaArgs(alpF));
10889 0 : ErrorsFound = true;
10890 0 : continue;
10891 : }
10892 3 : auto *m = s_mat->materials(index);
10893 3 : if (m->group != Material::Group::Regular || m->ROnly) {
10894 0 : ErrorsFound = true;
10895 0 : ShowSevereError(state,
10896 0 : format("{}=\"{}\", invalid {}=\"{}",
10897 0 : s_ipsc->cCurrentModuleObject,
10898 : fndInput.name,
10899 0 : s_ipsc->cAlphaFieldNames(alpF),
10900 0 : s_ipsc->cAlphaArgs(alpF)));
10901 0 : ShowContinueError(state, "Must be of type \"Material\"");
10902 0 : continue;
10903 : }
10904 3 : fndInput.intHIns.x = 0.0;
10905 3 : fndInput.intHIns.material = Kiva::Material(m->Conductivity, m->Density, m->SpecHeat);
10906 3 : fndInput.intHIns.depth = m->Thickness;
10907 : }
10908 8 : alpF++;
10909 :
10910 8 : if (!s_ipsc->lAlphaFieldBlanks(alpF - 1)) {
10911 3 : if (s_ipsc->lNumericFieldBlanks(numF)) {
10912 3 : fndInput.intHIns.z = 0.0;
10913 : } else {
10914 0 : fndInput.intHIns.z = s_ipsc->rNumericArgs(numF);
10915 : }
10916 3 : numF++;
10917 3 : if (s_ipsc->lNumericFieldBlanks(numF)) {
10918 0 : ErrorsFound = true;
10919 0 : ShowSevereError(state,
10920 0 : format("{}=\"{}\", {} defined, but no {}provided",
10921 0 : s_ipsc->cCurrentModuleObject,
10922 : fndInput.name,
10923 0 : s_ipsc->cAlphaFieldNames(alpF - 1),
10924 0 : s_ipsc->cNumericFieldNames(numF)));
10925 0 : continue;
10926 : } else {
10927 3 : fndInput.intHIns.width = -s_ipsc->rNumericArgs(numF);
10928 : }
10929 3 : numF++;
10930 : } else {
10931 5 : if (!s_ipsc->lNumericFieldBlanks(numF)) {
10932 0 : ShowWarningError(
10933 : state,
10934 0 : format("{}=\"{}\", no {} defined", s_ipsc->cCurrentModuleObject, fndInput.name, s_ipsc->cAlphaFieldNames(alpF - 1)));
10935 0 : ShowContinueError(state, format("{} will not be used.", s_ipsc->cNumericFieldNames(numF)));
10936 : }
10937 5 : numF++;
10938 5 : if (!s_ipsc->lNumericFieldBlanks(numF)) {
10939 0 : ShowWarningError(
10940 : state,
10941 0 : format("{}=\"{}\", no {} defined", s_ipsc->cCurrentModuleObject, fndInput.name, s_ipsc->cAlphaFieldNames(alpF - 1)));
10942 0 : ShowContinueError(state, format("{} will not be used.", s_ipsc->cNumericFieldNames(numF)));
10943 : }
10944 5 : numF++;
10945 : }
10946 :
10947 : // Interior vertical insulation
10948 8 : if (!s_ipsc->lAlphaFieldBlanks(alpF)) {
10949 0 : int index = Material::GetMaterialNum(state, s_ipsc->cAlphaArgs(alpF));
10950 0 : if (index == 0) {
10951 0 : ErrorsFound = true;
10952 0 : ShowSevereError(state,
10953 0 : format("Did not find matching material for {}=\"{}\", {}, missing material = {}",
10954 0 : s_ipsc->cCurrentModuleObject,
10955 : fndInput.name,
10956 0 : s_ipsc->cAlphaFieldNames(alpF),
10957 0 : s_ipsc->cAlphaArgs(alpF)));
10958 0 : continue;
10959 : }
10960 0 : auto *m = s_mat->materials(index);
10961 0 : if (m->group != Material::Group::Regular || m->ROnly) {
10962 0 : ErrorsFound = true;
10963 0 : ShowSevereError(state,
10964 0 : format("{}=\"{}\", invalid {}=\"{}",
10965 0 : s_ipsc->cCurrentModuleObject,
10966 : fndInput.name,
10967 0 : s_ipsc->cAlphaFieldNames(alpF),
10968 0 : s_ipsc->cAlphaArgs(alpF)));
10969 0 : ShowContinueError(state, "Must be of type \"Material\"");
10970 0 : continue;
10971 : }
10972 0 : fndInput.intVIns.material = Kiva::Material(m->Conductivity, m->Density, m->SpecHeat);
10973 0 : fndInput.intVIns.width = -m->Thickness;
10974 0 : fndInput.intVIns.x = 0.0;
10975 0 : fndInput.intVIns.z = 0.0;
10976 : }
10977 8 : alpF++;
10978 :
10979 8 : if (!s_ipsc->lAlphaFieldBlanks(alpF - 1)) {
10980 0 : if (s_ipsc->lNumericFieldBlanks(numF)) {
10981 0 : ErrorsFound = true;
10982 0 : ShowSevereError(state,
10983 0 : format("{}=\"{}\", {} defined, but no {}provided",
10984 0 : s_ipsc->cCurrentModuleObject,
10985 : fndInput.name,
10986 0 : s_ipsc->cAlphaFieldNames(alpF - 1),
10987 0 : s_ipsc->cNumericFieldNames(numF)));
10988 0 : continue;
10989 : } else {
10990 0 : fndInput.intVIns.depth = s_ipsc->rNumericArgs(numF);
10991 : }
10992 0 : numF++;
10993 : } else {
10994 8 : if (!s_ipsc->lNumericFieldBlanks(numF)) {
10995 0 : ShowWarningError(
10996 : state,
10997 0 : format("{}=\"{}\", no {} defined", s_ipsc->cCurrentModuleObject, fndInput.name, s_ipsc->cAlphaFieldNames(alpF - 1)));
10998 0 : ShowContinueError(state, format("{} will not be used.", s_ipsc->cNumericFieldNames(numF)));
10999 : }
11000 8 : numF++;
11001 : }
11002 :
11003 : // Exterior horizontal insulation
11004 8 : if (!s_ipsc->lAlphaFieldBlanks(alpF)) {
11005 0 : int index = Material::GetMaterialNum(state, s_ipsc->cAlphaArgs(alpF));
11006 0 : if (index == 0) {
11007 0 : ErrorsFound = true;
11008 0 : ShowSevereError(state,
11009 0 : format("Did not find matching material for {}=\"{}\", {}, missing material = {}",
11010 0 : s_ipsc->cCurrentModuleObject,
11011 : fndInput.name,
11012 0 : s_ipsc->cAlphaFieldNames(alpF),
11013 0 : s_ipsc->cAlphaArgs(alpF)));
11014 0 : continue;
11015 : }
11016 0 : auto *m = s_mat->materials(index);
11017 0 : if (m->group != Material::Group::Regular || m->ROnly) {
11018 0 : ErrorsFound = true;
11019 0 : ShowSevereError(state,
11020 0 : format("{}=\"{}\", invalid {}=\"{}",
11021 0 : s_ipsc->cCurrentModuleObject,
11022 : fndInput.name,
11023 0 : s_ipsc->cAlphaFieldNames(alpF),
11024 0 : s_ipsc->cAlphaArgs(alpF)));
11025 0 : ShowContinueError(state, "Must be of type \"Material\"");
11026 0 : continue;
11027 : }
11028 0 : fndInput.extHIns.x = 0.0;
11029 0 : fndInput.extHIns.material = Kiva::Material(m->Conductivity, m->Density, m->SpecHeat);
11030 0 : fndInput.extHIns.depth = m->Thickness;
11031 : }
11032 8 : alpF++;
11033 :
11034 8 : if (!s_ipsc->lAlphaFieldBlanks(alpF - 1)) {
11035 0 : if (s_ipsc->lNumericFieldBlanks(numF)) {
11036 0 : fndInput.extHIns.z = 0.0;
11037 : } else {
11038 0 : fndInput.extHIns.z = s_ipsc->rNumericArgs(numF);
11039 : }
11040 0 : numF++;
11041 0 : if (s_ipsc->lNumericFieldBlanks(numF)) {
11042 0 : ErrorsFound = true;
11043 0 : ShowSevereError(state,
11044 0 : format("{}=\"{}\", {} defined, but no {}provided",
11045 0 : s_ipsc->cCurrentModuleObject,
11046 : fndInput.name,
11047 0 : s_ipsc->cAlphaFieldNames(alpF - 1),
11048 0 : s_ipsc->cNumericFieldNames(numF)));
11049 0 : continue;
11050 : } else {
11051 0 : fndInput.extHIns.width = s_ipsc->rNumericArgs(numF);
11052 : }
11053 0 : numF++;
11054 : } else {
11055 8 : if (!s_ipsc->lNumericFieldBlanks(numF)) {
11056 0 : ShowWarningError(
11057 : state,
11058 0 : format("{}=\"{}\", no {} defined", s_ipsc->cCurrentModuleObject, fndInput.name, s_ipsc->cAlphaFieldNames(alpF - 1)));
11059 0 : ShowContinueError(state, format("{} will not be used.", s_ipsc->cNumericFieldNames(numF)));
11060 : }
11061 8 : numF++;
11062 8 : if (!s_ipsc->lNumericFieldBlanks(numF)) {
11063 0 : ShowWarningError(
11064 : state,
11065 0 : format("{}=\"{}\", no {} defined", s_ipsc->cCurrentModuleObject, fndInput.name, s_ipsc->cAlphaFieldNames(alpF - 1)));
11066 0 : ShowContinueError(state, format("{} will not be used.", s_ipsc->cNumericFieldNames(numF)));
11067 : }
11068 8 : numF++;
11069 : }
11070 :
11071 : // Exterior vertical insulation
11072 8 : if (!s_ipsc->lAlphaFieldBlanks(alpF)) {
11073 4 : int index = Material::GetMaterialNum(state, s_ipsc->cAlphaArgs(alpF));
11074 4 : if (index == 0) {
11075 0 : ErrorsFound = true;
11076 0 : ShowSevereError(state,
11077 0 : format("Did not find matching material for {}=\"{}\", {}, missing material = {}",
11078 0 : s_ipsc->cCurrentModuleObject,
11079 : fndInput.name,
11080 0 : s_ipsc->cAlphaFieldNames(alpF),
11081 0 : s_ipsc->cAlphaArgs(alpF)));
11082 0 : continue;
11083 : }
11084 4 : auto *m = s_mat->materials(index);
11085 4 : if (m->group != Material::Group::Regular || m->ROnly) {
11086 0 : ErrorsFound = true;
11087 0 : ShowSevereError(state,
11088 0 : format("{}=\"{}\", invalid {}=\"{}",
11089 0 : s_ipsc->cCurrentModuleObject,
11090 : fndInput.name,
11091 0 : s_ipsc->cAlphaFieldNames(alpF),
11092 0 : s_ipsc->cAlphaArgs(alpF)));
11093 0 : ShowContinueError(state, "Must be of type \"Material\"");
11094 0 : continue;
11095 : }
11096 4 : fndInput.extVIns.material = Kiva::Material(m->Conductivity, m->Density, m->SpecHeat);
11097 4 : fndInput.extVIns.width = m->Thickness;
11098 4 : fndInput.extVIns.x = 0.0;
11099 4 : fndInput.extVIns.z = 0.0;
11100 : }
11101 8 : alpF++;
11102 :
11103 8 : if (!s_ipsc->lAlphaFieldBlanks(alpF - 1)) {
11104 4 : if (s_ipsc->lNumericFieldBlanks(numF)) {
11105 0 : ErrorsFound = true;
11106 0 : ShowSevereError(state,
11107 0 : format("{}=\"{}\", {} defined, but no {}provided",
11108 0 : s_ipsc->cCurrentModuleObject,
11109 : fndInput.name,
11110 0 : s_ipsc->cAlphaFieldNames(alpF - 1),
11111 0 : s_ipsc->cNumericFieldNames(numF)));
11112 0 : continue;
11113 : } else {
11114 4 : fndInput.extVIns.depth = s_ipsc->rNumericArgs(numF);
11115 : }
11116 4 : numF++;
11117 : } else {
11118 4 : if (!s_ipsc->lNumericFieldBlanks(numF)) {
11119 0 : ShowWarningError(
11120 : state,
11121 0 : format("{}=\"{}\", no {} defined", s_ipsc->cCurrentModuleObject, fndInput.name, s_ipsc->cAlphaFieldNames(alpF - 1)));
11122 0 : ShowContinueError(state, format("{} will not be used.", s_ipsc->cNumericFieldNames(numF)));
11123 : }
11124 4 : numF++;
11125 : }
11126 :
11127 : // Foundation wall
11128 8 : if (!s_ipsc->lNumericFieldBlanks(numF)) {
11129 8 : fnd.wall.heightAboveGrade = s_ipsc->rNumericArgs(numF);
11130 : }
11131 8 : numF++;
11132 :
11133 8 : if (!s_ipsc->lNumericFieldBlanks(numF)) {
11134 8 : fnd.wall.depthBelowSlab = s_ipsc->rNumericArgs(numF);
11135 : }
11136 8 : numF++;
11137 :
11138 8 : if (!s_ipsc->lAlphaFieldBlanks(alpF)) {
11139 0 : fndInput.wallConstructionIndex = Util::FindItemInList(s_ipsc->cAlphaArgs(alpF), state.dataConstruction->Construct);
11140 0 : if (fndInput.wallConstructionIndex == 0) {
11141 0 : ErrorsFound = true;
11142 0 : ShowSevereError(state,
11143 0 : format("Did not find matching construction for {}=\"{}\", {}, missing construction = {}",
11144 0 : s_ipsc->cCurrentModuleObject,
11145 : fndInput.name,
11146 0 : s_ipsc->cAlphaFieldNames(alpF),
11147 0 : s_ipsc->cAlphaArgs(alpF)));
11148 0 : continue;
11149 : }
11150 0 : auto &c = state.dataConstruction->Construct(fndInput.wallConstructionIndex);
11151 0 : c.IsUsed = true;
11152 0 : if (c.TypeIsWindow) {
11153 0 : ErrorsFound = true;
11154 0 : ShowSevereError(state,
11155 0 : format("{}=\"{}\", invalid {}=\"{}",
11156 0 : s_ipsc->cCurrentModuleObject,
11157 : fndInput.name,
11158 0 : s_ipsc->cAlphaFieldNames(alpF),
11159 0 : s_ipsc->cAlphaArgs(alpF)));
11160 0 : ShowContinueError(state, "Cannot be a window construction");
11161 0 : continue;
11162 : }
11163 : } else {
11164 8 : fndInput.wallConstructionIndex = 0; // Use default wall construction
11165 : }
11166 8 : alpF++;
11167 :
11168 : // Footing
11169 8 : if (!s_ipsc->lAlphaFieldBlanks(alpF)) {
11170 0 : int index = Material::GetMaterialNum(state, s_ipsc->cAlphaArgs(alpF));
11171 0 : if (index == 0) {
11172 0 : ErrorsFound = true;
11173 0 : ShowSevereError(state,
11174 0 : format("Did not find matching material for {}=\"{}\", {}, missing material = {}",
11175 0 : s_ipsc->cCurrentModuleObject,
11176 : fndInput.name,
11177 0 : s_ipsc->cAlphaFieldNames(alpF),
11178 0 : s_ipsc->cAlphaArgs(alpF)));
11179 0 : continue;
11180 : }
11181 0 : auto *m = s_mat->materials(index);
11182 0 : if (m->group != Material::Group::Regular || m->ROnly) {
11183 0 : ErrorsFound = true;
11184 0 : ShowSevereError(state,
11185 0 : format("{}=\"{}\", invalid {}=\"{}",
11186 0 : s_ipsc->cCurrentModuleObject,
11187 : fndInput.name,
11188 0 : s_ipsc->cAlphaFieldNames(alpF),
11189 0 : s_ipsc->cAlphaArgs(alpF)));
11190 0 : ShowContinueError(state, "Must be of type \"Material\"");
11191 0 : continue;
11192 : }
11193 0 : fndInput.footing.material = Kiva::Material(m->Conductivity, m->Density, m->SpecHeat);
11194 0 : fndInput.footing.width = m->Thickness;
11195 0 : fndInput.footing.x = 0.0;
11196 0 : fndInput.footing.z = 0.0;
11197 : }
11198 8 : alpF++;
11199 :
11200 8 : if (!s_ipsc->lAlphaFieldBlanks(alpF - 1)) {
11201 0 : if (s_ipsc->lNumericFieldBlanks(numF)) {
11202 0 : ErrorsFound = true;
11203 0 : ShowSevereError(state,
11204 0 : format("{}=\"{}\", {} defined, but no {}provided",
11205 0 : s_ipsc->cCurrentModuleObject,
11206 : fndInput.name,
11207 0 : s_ipsc->cAlphaFieldNames(alpF - 1),
11208 0 : s_ipsc->cNumericFieldNames(numF)));
11209 0 : continue;
11210 : } else {
11211 0 : fndInput.footing.depth = s_ipsc->rNumericArgs(numF);
11212 : }
11213 0 : numF++;
11214 : } else {
11215 8 : if (!s_ipsc->lNumericFieldBlanks(numF)) {
11216 0 : ShowWarningError(
11217 : state,
11218 0 : format("{}=\"{}\", no {} defined", s_ipsc->cCurrentModuleObject, fndInput.name, s_ipsc->cAlphaFieldNames(alpF - 1)));
11219 0 : ShowContinueError(state, format("{} will not be used.", s_ipsc->cNumericFieldNames(numF)));
11220 : }
11221 8 : numF++;
11222 : }
11223 :
11224 : // General Blocks
11225 8 : int numRemainingFields = NumAlphas - (alpF - 1) + NumProps - (numF - 1);
11226 8 : if (numRemainingFields > 0) {
11227 1 : int numBlocks = numRemainingFields / 4;
11228 1 : if (mod(numRemainingFields, 4) != 0) {
11229 0 : ShowWarningError(state,
11230 0 : format("{}=\"{}\", number of Block fields not even multiple of 4. Will read in {}",
11231 0 : s_ipsc->cCurrentModuleObject,
11232 : fndInput.name,
11233 : numBlocks));
11234 : }
11235 2 : for (int blockNum = 0; blockNum < numBlocks; blockNum++) {
11236 1 : Kiva::InputBlock block;
11237 1 : if (!s_ipsc->lAlphaFieldBlanks(alpF)) {
11238 1 : int index = Material::GetMaterialNum(state, s_ipsc->cAlphaArgs(alpF));
11239 1 : if (index == 0) {
11240 0 : ErrorsFound = true;
11241 0 : ShowSevereError(state,
11242 0 : format("Did not find matching material for {}=\"{}\", {}, missing material = {}",
11243 0 : s_ipsc->cCurrentModuleObject,
11244 : fndInput.name,
11245 0 : s_ipsc->cAlphaFieldNames(alpF),
11246 0 : s_ipsc->cAlphaArgs(alpF)));
11247 0 : continue;
11248 : }
11249 1 : auto *m = s_mat->materials(index);
11250 1 : if (m->group != Material::Group::Regular || m->ROnly) {
11251 0 : ErrorsFound = true;
11252 0 : ShowSevereError(state,
11253 0 : format("{}=\"{}\", invalid {}=\"{}",
11254 0 : s_ipsc->cCurrentModuleObject,
11255 : fndInput.name,
11256 0 : s_ipsc->cAlphaFieldNames(alpF),
11257 0 : s_ipsc->cAlphaArgs(alpF)));
11258 0 : ShowContinueError(state, "Must be of type \"Material\"");
11259 0 : continue;
11260 : }
11261 1 : block.material = Kiva::Material(m->Conductivity, m->Density, m->SpecHeat);
11262 1 : block.width = m->Thickness;
11263 : } else {
11264 0 : ErrorsFound = true;
11265 0 : ShowSevereError(state,
11266 0 : format("{}=\"{}\", {} is required and not given.",
11267 0 : s_ipsc->cCurrentModuleObject,
11268 : fndInput.name,
11269 0 : s_ipsc->cAlphaFieldNames(alpF)));
11270 0 : continue;
11271 : }
11272 1 : alpF++;
11273 :
11274 1 : if (s_ipsc->lNumericFieldBlanks(numF)) {
11275 0 : block.depth = 0.0; // Temporary indicator to default to foundation depth
11276 : } else {
11277 1 : block.depth = s_ipsc->rNumericArgs(numF);
11278 : }
11279 1 : numF++;
11280 :
11281 1 : if (s_ipsc->lNumericFieldBlanks(numF)) {
11282 0 : ErrorsFound = true;
11283 0 : ShowSevereError(state,
11284 0 : format("{}=\"{}\", {} defined, but no {}provided",
11285 0 : s_ipsc->cCurrentModuleObject,
11286 : fndInput.name,
11287 0 : s_ipsc->cAlphaFieldNames(alpF - 1),
11288 0 : s_ipsc->cNumericFieldNames(numF)));
11289 0 : continue;
11290 : } else {
11291 1 : block.x = s_ipsc->rNumericArgs(numF);
11292 : }
11293 1 : numF++;
11294 :
11295 1 : if (s_ipsc->lNumericFieldBlanks(numF)) {
11296 0 : block.z = 0.0;
11297 : } else {
11298 1 : block.z = s_ipsc->rNumericArgs(numF);
11299 : }
11300 1 : numF++;
11301 :
11302 1 : fnd.inputBlocks.push_back(block);
11303 : }
11304 : }
11305 :
11306 8 : state.dataSurfaceGeometry->kivaManager.foundationInputs.push_back(fndInput);
11307 8 : }
11308 : }
11309 801 : }
11310 :
11311 801 : void GetOSCData(EnergyPlusData &state, bool &ErrorsFound)
11312 : {
11313 :
11314 : // SUBROUTINE INFORMATION:
11315 : // AUTHOR Linda Lawrie
11316 : // DATE WRITTEN May 2000
11317 : // MODIFIED Jul 2011, M.J. Witte and C.O. Pedersen, add new fields to OSC for last T, max and min
11318 :
11319 : // PURPOSE OF THIS SUBROUTINE:
11320 : // This subroutine gets the OtherSideCoefficient data.
11321 :
11322 : // REFERENCES:
11323 : // Other Side Coefficient Definition
11324 : // OtherSideCoefficients,
11325 : // \memo This object sets the other side conditions for a surface in a variety of ways.
11326 : // A1, \field OtherSideCoeff Name
11327 : // \required-field
11328 : // \reference OSCNames
11329 : // \reference OutFaceEnvNames
11330 : // N1, \field Combined convective/radiative film coefficient
11331 : // \required-field
11332 : // \type real
11333 : // \note if>0, N1 becomes exterior convective/radiative film coefficient and other fields
11334 : // \note are used to calc outside air temp then exterior surface temp based on outside air
11335 : // \note and specified coefficient
11336 : // \note if<=0, then remaining fields calculate the outside surface temperature(?)
11337 : // \note following fields are used in the equation:
11338 : // \note SurfTemp=N7*TempZone + N4*OutsideDryBulb + N2*N3 + GroundTemp*N5 + WindSpeed*N6*OutsideDryBulb
11339 : // N2, \field User selected Constant Temperature
11340 : // \units C
11341 : // \type real
11342 : // \note This parameter will be overwritten by the values from the schedule(A2 below) if one is present
11343 : // N3, \field Coefficient modifying the user selected constant temperature
11344 : // \note This coefficient is used even with a schedule. It should normally be 1.0 in that case
11345 : // N4, \field Coefficient modifying the external dry bulb temperature
11346 : // \type real
11347 : // N5, \field Coefficient modifying the ground temperature
11348 : // \type real
11349 : // N6, \field Coefficient modifying the wind speed term (s/m)
11350 : // \type real
11351 : // N7, \field Coefficient modifying the zone air temperature part of the equation
11352 : // \type real
11353 : // A2, \field ScheduleName for constant temperature
11354 : // \note Name of Schedule for values of "const" temperature.
11355 : // \note Schedule values replace N2 - User selected constant temperature.
11356 : // \type object-list
11357 : // \object-list ScheduleNames
11358 : // A3, \field Sinusoidal Variation of Constant Temperature Coefficient
11359 : // \note Optionally used to vary Constant Temperature Coefficient with unitary sine wave
11360 : // \type choice
11361 : // \key Yes
11362 : // \key No
11363 : // \default No
11364 : // N8; \field Period of Sinusoidal Variation
11365 : // \note Use with sinusoidal variation to define the time period
11366 : // \type real
11367 : // \units hr
11368 : // \default 24
11369 : // N9, \field Previous Other Side Temperature Coefficient
11370 : // \note This coefficient multiplies the other side temperature result from the
11371 : // \note previous zone timestep
11372 : // \type real
11373 : // \default 0
11374 : // N10, \field Minimum Other Side Temperature
11375 : // \type real
11376 : // \units C
11377 : // \default -100
11378 : // N11; \field Maximum Other Side Temperature
11379 : // \type real
11380 : // \units C
11381 : // \default 200
11382 :
11383 : static constexpr std::string_view routineName = "GetOSCData";
11384 : // Locals
11385 : // SUBROUTINE ARGUMENT DEFINITIONS:
11386 :
11387 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
11388 : int NumAlphas;
11389 : int NumProps;
11390 : int Loop;
11391 : int IOStat;
11392 801 : std::string cOSCLimitsString;
11393 :
11394 801 : auto &s_ipsc = state.dataIPShortCut;
11395 :
11396 801 : s_ipsc->cCurrentModuleObject = "SurfaceProperty:OtherSideCoefficients";
11397 801 : state.dataSurface->TotOSC = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
11398 801 : state.dataSurface->OSC.allocate(state.dataSurface->TotOSC);
11399 :
11400 801 : int OSCNum = 0;
11401 822 : for (Loop = 1; Loop <= state.dataSurface->TotOSC; ++Loop) {
11402 42 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
11403 21 : s_ipsc->cCurrentModuleObject,
11404 : Loop,
11405 21 : s_ipsc->cAlphaArgs,
11406 : NumAlphas,
11407 21 : s_ipsc->rNumericArgs,
11408 : NumProps,
11409 : IOStat,
11410 21 : s_ipsc->lNumericFieldBlanks,
11411 21 : s_ipsc->lAlphaFieldBlanks,
11412 21 : s_ipsc->cAlphaFieldNames,
11413 21 : s_ipsc->cNumericFieldNames);
11414 :
11415 21 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
11416 21 : bool ErrorInName = false;
11417 21 : bool IsBlank = false;
11418 21 : Util::VerifyName(
11419 21 : state, s_ipsc->cAlphaArgs(1), state.dataSurface->OSC, OSCNum, ErrorInName, IsBlank, s_ipsc->cCurrentModuleObject + " Name");
11420 21 : if (ErrorInName) {
11421 0 : ErrorsFound = true;
11422 0 : continue;
11423 : }
11424 :
11425 21 : ++OSCNum;
11426 21 : state.dataSurface->OSC(OSCNum).Name = s_ipsc->cAlphaArgs(1);
11427 21 : state.dataSurface->OSC(OSCNum).SurfFilmCoef = s_ipsc->rNumericArgs(1);
11428 21 : state.dataSurface->OSC(OSCNum).ConstTemp = s_ipsc->rNumericArgs(2); // This will be replaced if schedule is used
11429 21 : state.dataSurface->OSC(OSCNum).ConstTempCoef =
11430 21 : s_ipsc->rNumericArgs(3); // This multiplier is used (even with schedule). It should normally be 1.0
11431 21 : state.dataSurface->OSC(OSCNum).ExtDryBulbCoef = s_ipsc->rNumericArgs(4);
11432 21 : state.dataSurface->OSC(OSCNum).GroundTempCoef = s_ipsc->rNumericArgs(5);
11433 21 : state.dataSurface->OSC(OSCNum).WindSpeedCoef = s_ipsc->rNumericArgs(6);
11434 21 : state.dataSurface->OSC(OSCNum).ZoneAirTempCoef = s_ipsc->rNumericArgs(7);
11435 21 : state.dataSurface->OSC(OSCNum).SinusoidPeriod = s_ipsc->rNumericArgs(8);
11436 :
11437 21 : if ((NumAlphas == 1) || s_ipsc->lAlphaFieldBlanks(2)) { // Const temp will come from schedule specified below.
11438 18 : } else if ((state.dataSurface->OSC(OSCNum).constTempSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(2))) == nullptr) {
11439 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2));
11440 0 : ErrorsFound = true;
11441 : }
11442 :
11443 21 : if (!s_ipsc->lAlphaFieldBlanks(3)) {
11444 18 : if (BooleanSwitch bs = getYesNoValue(s_ipsc->cAlphaArgs(3)); bs != BooleanSwitch::Invalid) {
11445 18 : state.dataSurface->OSC(OSCNum).SinusoidalConstTempCoef = static_cast<bool>(bs);
11446 : } else {
11447 0 : ShowSevereInvalidBool(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3));
11448 0 : ErrorsFound = true;
11449 : }
11450 : }
11451 :
11452 21 : if (s_ipsc->rNumericArgs(1) > 0.0 && !any_ne(s_ipsc->rNumericArgs({3, 7}), 0.0) &&
11453 0 : (!state.dataSurface->OSC(OSCNum).SinusoidalConstTempCoef)) {
11454 0 : ShowSevereError(state, format("{}=\"{}\" has zeros for all coefficients.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
11455 0 : ShowContinueError(state, "...The outdoor air temperature for surfaces using this OtherSideCoefficients object will always be 0C.");
11456 : }
11457 :
11458 22 : if (s_ipsc->rNumericArgs(1) <= 0.0 && !any_ne(s_ipsc->rNumericArgs({3, 7}), 0.0) &&
11459 1 : (!state.dataSurface->OSC(OSCNum).SinusoidalConstTempCoef)) {
11460 0 : ShowSevereError(state, format("{}=\"{}\" has zeros for all coefficients.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
11461 0 : ShowContinueError(state,
11462 : "...The outside surface temperature for surfaces using this OtherSideCoefficients object will always be 0C.");
11463 : }
11464 :
11465 21 : state.dataSurface->OSC(OSCNum).TPreviousCoef = s_ipsc->rNumericArgs(9);
11466 :
11467 21 : if (!s_ipsc->lNumericFieldBlanks(10)) {
11468 1 : state.dataSurface->OSC(OSCNum).MinLimitPresent = true;
11469 1 : state.dataSurface->OSC(OSCNum).MinTempLimit = s_ipsc->rNumericArgs(10);
11470 1 : cOSCLimitsString = format("{:.3R}", s_ipsc->rNumericArgs(10));
11471 : } else {
11472 20 : cOSCLimitsString = "N/A";
11473 : }
11474 21 : if (!s_ipsc->lNumericFieldBlanks(11)) {
11475 1 : state.dataSurface->OSC(OSCNum).MaxLimitPresent = true;
11476 1 : state.dataSurface->OSC(OSCNum).MaxTempLimit = s_ipsc->rNumericArgs(11);
11477 1 : cOSCLimitsString += format(",{:.3R}", s_ipsc->rNumericArgs(10));
11478 : } else {
11479 20 : cOSCLimitsString += ",N/A";
11480 : }
11481 : }
11482 :
11483 822 : for (Loop = 1; Loop <= state.dataSurface->TotOSC; ++Loop) {
11484 21 : if (Loop == 1) {
11485 : static constexpr std::string_view OSCFormat1(
11486 : "! <Other Side Coefficients>,Name,Combined convective/radiative film coefficient {W/m2-K},User selected "
11487 : "Constant Temperature {C},Coefficient modifying the constant temperature term,Coefficient modifying the external "
11488 : "dry bulb temperature term,Coefficient modifying the ground temperature term,Coefficient modifying the wind speed "
11489 : "term {s/m},Coefficient modifying the zone air temperature term,Constant Temperature Schedule Name,Sinusoidal "
11490 : "Variation,Period of Sinusoidal Variation,Previous Other Side Temperature Coefficient,Minimum Other Side "
11491 : "Temperature {C},Maximum Other Side Temperature {C}");
11492 9 : print(state.files.eio, "{}\n", OSCFormat1);
11493 : }
11494 21 : if (state.dataSurface->OSC(Loop).SurfFilmCoef > 0.0) {
11495 1 : s_ipsc->cAlphaArgs(1) = format("{:.3R}", state.dataSurface->OSC(Loop).SurfFilmCoef);
11496 2 : SetupOutputVariable(state,
11497 : "Surface Other Side Coefficients Exterior Air Drybulb Temperature",
11498 : Constant::Units::C,
11499 1 : state.dataSurface->OSC(Loop).OSCTempCalc,
11500 : OutputProcessor::TimeStepType::System,
11501 : OutputProcessor::StoreType::Average,
11502 1 : state.dataSurface->OSC(Loop).Name);
11503 : } else {
11504 20 : s_ipsc->cAlphaArgs(1) = "N/A";
11505 : }
11506 :
11507 63 : print(state.files.eio,
11508 : "Other Side Coefficients,{},{},{},{:.3R},{:.3R},{:.3R},{:.3R},{:.3R},{},{},{:.3R},{:.3R},{}\n",
11509 21 : state.dataSurface->OSC(Loop).Name,
11510 21 : s_ipsc->cAlphaArgs(1),
11511 60 : (state.dataSurface->OSC(Loop).constTempSched != nullptr) ? "N/A" : format("{:.2R}", state.dataSurface->OSC(Loop).ConstTemp),
11512 21 : state.dataSurface->OSC(Loop).ConstTempCoef,
11513 21 : state.dataSurface->OSC(Loop).ExtDryBulbCoef,
11514 21 : state.dataSurface->OSC(Loop).GroundTempCoef,
11515 21 : state.dataSurface->OSC(Loop).WindSpeedCoef,
11516 21 : state.dataSurface->OSC(Loop).ZoneAirTempCoef,
11517 48 : (state.dataSurface->OSC(Loop).constTempSched == nullptr) ? "N/A" : state.dataSurface->OSC(Loop).constTempSched->Name,
11518 21 : s_ipsc->cAlphaArgs(3),
11519 21 : state.dataSurface->OSC(Loop).SinusoidPeriod,
11520 21 : state.dataSurface->OSC(Loop).TPreviousCoef,
11521 : cOSCLimitsString);
11522 : }
11523 801 : }
11524 :
11525 801 : void GetOSCMData(EnergyPlusData &state, bool &ErrorsFound)
11526 : {
11527 :
11528 : // SUBROUTINE INFORMATION:
11529 : // AUTHOR Brent Griffith
11530 : // DATE WRITTEN November 2004
11531 :
11532 : // PURPOSE OF THIS SUBROUTINE:
11533 : // This subroutine gets the OtherSideConditionsModel data.
11534 :
11535 : // REFERENCES:
11536 : // derived from GetOSCData subroutine by Linda Lawrie
11537 :
11538 : // OtherSideConditionsModel,
11539 : // \memo This object sets up modifying the other side conditions for a surface from other model results.
11540 : // A1, \field OtherSideConditionsModel Name
11541 : // \required-field
11542 : // \reference OSCMNames
11543 : // \reference OutFaceEnvNames
11544 : // A2; \field Type of Model to determine Boundary Conditions
11545 : // \type choice
11546 : // \key Transpired Collector
11547 : // \key Vented PV Cavity
11548 : // \key Hybrid PV Transpired Collector
11549 :
11550 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
11551 : int NumAlphas;
11552 : int NumProps;
11553 : int IOStat;
11554 :
11555 801 : auto &s_ipsc = state.dataIPShortCut;
11556 801 : s_ipsc->cCurrentModuleObject = "SurfaceProperty:OtherSideConditionsModel";
11557 801 : state.dataSurface->TotOSCM = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
11558 801 : state.dataSurface->OSCM.allocate(state.dataSurface->TotOSCM);
11559 : // OSCM is already initialized in derived type defn.
11560 :
11561 801 : int OSCMNum = 0;
11562 826 : for (int Loop = 1; Loop <= state.dataSurface->TotOSCM; ++Loop) {
11563 50 : state.dataInputProcessing->inputProcessor->getObjectItem(
11564 25 : state, s_ipsc->cCurrentModuleObject, Loop, s_ipsc->cAlphaArgs, NumAlphas, s_ipsc->rNumericArgs, NumProps, IOStat);
11565 25 : bool ErrorInName = false;
11566 25 : bool IsBlank = false;
11567 25 : Util::VerifyName(
11568 25 : state, s_ipsc->cAlphaArgs(1), state.dataSurface->OSCM, OSCMNum, ErrorInName, IsBlank, s_ipsc->cCurrentModuleObject + " Name");
11569 25 : if (ErrorInName) {
11570 0 : ErrorsFound = true;
11571 0 : continue;
11572 : }
11573 :
11574 25 : ++OSCMNum;
11575 25 : state.dataSurface->OSCM(OSCMNum).Name = s_ipsc->cAlphaArgs(1);
11576 : // Note no validation of the below at this time:
11577 25 : state.dataSurface->OSCM(OSCMNum).Class = s_ipsc->cAlphaArgs(2);
11578 : // setup output vars for modeled coefficients
11579 50 : SetupOutputVariable(state,
11580 : "Surface Other Side Conditions Modeled Convection Air Temperature",
11581 : Constant::Units::C,
11582 25 : state.dataSurface->OSCM(OSCMNum).TConv,
11583 : OutputProcessor::TimeStepType::System,
11584 : OutputProcessor::StoreType::Average,
11585 25 : state.dataSurface->OSCM(OSCMNum).Name);
11586 50 : SetupOutputVariable(state,
11587 : "Surface Other Side Conditions Modeled Convection Heat Transfer Coefficient",
11588 : Constant::Units::W_m2K,
11589 25 : state.dataSurface->OSCM(OSCMNum).HConv,
11590 : OutputProcessor::TimeStepType::System,
11591 : OutputProcessor::StoreType::Average,
11592 25 : state.dataSurface->OSCM(OSCMNum).Name);
11593 50 : SetupOutputVariable(state,
11594 : "Surface Other Side Conditions Modeled Radiation Temperature",
11595 : Constant::Units::C,
11596 25 : state.dataSurface->OSCM(OSCMNum).TRad,
11597 : OutputProcessor::TimeStepType::System,
11598 : OutputProcessor::StoreType::Average,
11599 25 : state.dataSurface->OSCM(OSCMNum).Name);
11600 50 : SetupOutputVariable(state,
11601 : "Surface Other Side Conditions Modeled Radiation Heat Transfer Coefficient",
11602 : Constant::Units::W_m2K,
11603 25 : state.dataSurface->OSCM(OSCMNum).HRad,
11604 : OutputProcessor::TimeStepType::System,
11605 : OutputProcessor::StoreType::Average,
11606 25 : state.dataSurface->OSCM(OSCMNum).Name);
11607 :
11608 25 : if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
11609 0 : SetupEMSActuator(state,
11610 : "Other Side Boundary Conditions",
11611 0 : state.dataSurface->OSCM(OSCMNum).Name,
11612 : "Convection Bulk Air Temperature",
11613 : "[C]",
11614 0 : state.dataSurface->OSCM(OSCMNum).EMSOverrideOnTConv,
11615 0 : state.dataSurface->OSCM(OSCMNum).EMSOverrideTConvValue);
11616 0 : SetupEMSActuator(state,
11617 : "Other Side Boundary Conditions",
11618 0 : state.dataSurface->OSCM(OSCMNum).Name,
11619 : "Convection Heat Transfer Coefficient",
11620 : "[W/m2-K]",
11621 0 : state.dataSurface->OSCM(OSCMNum).EMSOverrideOnHConv,
11622 0 : state.dataSurface->OSCM(OSCMNum).EMSOverrideHConvValue);
11623 0 : SetupEMSActuator(state,
11624 : "Other Side Boundary Conditions",
11625 0 : state.dataSurface->OSCM(OSCMNum).Name,
11626 : "Radiation Effective Temperature",
11627 : "[C]",
11628 0 : state.dataSurface->OSCM(OSCMNum).EMSOverrideOnTRad,
11629 0 : state.dataSurface->OSCM(OSCMNum).EMSOverrideTRadValue);
11630 0 : SetupEMSActuator(state,
11631 : "Other Side Boundary Conditions",
11632 0 : state.dataSurface->OSCM(OSCMNum).Name,
11633 : "Radiation Linear Heat Transfer Coefficient",
11634 : "[W/m2-K]",
11635 0 : state.dataSurface->OSCM(OSCMNum).EMSOverrideOnHrad,
11636 0 : state.dataSurface->OSCM(OSCMNum).EMSOverrideHradValue);
11637 : }
11638 : }
11639 :
11640 826 : for (int Loop = 1; Loop <= state.dataSurface->TotOSCM; ++Loop) {
11641 25 : if (Loop == 1) {
11642 : static constexpr std::string_view OSCMFormat1("! <Other Side Conditions Model>,Name,Class\n");
11643 12 : print(state.files.eio, OSCMFormat1);
11644 : }
11645 25 : print(state.files.eio, "Other Side Conditions Model,{},{}\n", state.dataSurface->OSCM(Loop).Name, state.dataSurface->OSCM(Loop).Class);
11646 : }
11647 801 : }
11648 :
11649 801 : void GetMovableInsulationData(EnergyPlusData &state, bool &ErrorsFound) // If errors found in input
11650 : {
11651 :
11652 : // SUBROUTINE INFORMATION:
11653 : // AUTHOR Linda Lawrie
11654 : // DATE WRITTEN May 2000
11655 :
11656 : // PURPOSE OF THIS SUBROUTINE:
11657 : // This subroutine gets the movable insulation data that can be associated with a surface.
11658 :
11659 : // REFERENCES:
11660 : // Movable Insulation Definition
11661 : // SurfaceControl:MovableInsulation,
11662 : // \memo Exterior or Interior Insulation on opaque surfaces
11663 : // A1, \field Insulation Type
11664 : // \required-field
11665 : // \type choice
11666 : // \key Outside
11667 : // \key Inside
11668 : // A2, \field Surface Name
11669 : // \required-field
11670 : // \type object-list
11671 : // \object-list SurfaceNames
11672 : // A3, \field Material Name
11673 : // \required-field
11674 : // \object-list MaterialName
11675 : // A4; \field Schedule Name
11676 : // \required-field
11677 : // \type object-list
11678 : // \object-list ScheduleNames
11679 :
11680 : static constexpr std::string_view routineName = "GetMovableInsulationInput";
11681 :
11682 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
11683 : int NAlphas;
11684 : int NNums;
11685 : int IOStat;
11686 :
11687 : enum class InsulationType
11688 : {
11689 : Invalid = -1,
11690 : Outside,
11691 : Inside,
11692 : Num
11693 : };
11694 801 : constexpr std::array<std::string_view, static_cast<int>(InsulationType::Num)> insulationTypeNamesUC = {"OUTSIDE", "INSIDE"};
11695 :
11696 801 : auto &s_ipsc = state.dataIPShortCut;
11697 801 : auto &s_mat = state.dataMaterial;
11698 :
11699 801 : s_ipsc->cCurrentModuleObject = "SurfaceControl:MovableInsulation";
11700 801 : int NMatInsul = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
11701 806 : for (int Loop = 1; Loop <= NMatInsul; ++Loop) {
11702 10 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
11703 5 : s_ipsc->cCurrentModuleObject,
11704 : Loop,
11705 5 : s_ipsc->cAlphaArgs,
11706 : NAlphas,
11707 5 : s_ipsc->rNumericArgs,
11708 : NNums,
11709 : IOStat,
11710 5 : s_ipsc->lNumericFieldBlanks,
11711 5 : s_ipsc->lAlphaFieldBlanks,
11712 5 : s_ipsc->cAlphaFieldNames,
11713 5 : s_ipsc->cNumericFieldNames);
11714 5 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
11715 :
11716 5 : InsulationType insulationType = static_cast<InsulationType>(getEnumValue(insulationTypeNamesUC, s_ipsc->cAlphaArgs(1)));
11717 5 : if (insulationType == InsulationType::Invalid) {
11718 0 : ShowSevereInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(1), s_ipsc->cAlphaArgs(1));
11719 0 : ErrorsFound = true;
11720 0 : continue;
11721 : }
11722 :
11723 : int SurfNum;
11724 5 : if ((SurfNum = Util::FindItemInList(s_ipsc->cAlphaArgs(2), state.dataSurface->Surface, state.dataSurface->TotSurfaces)) == 0) {
11725 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2));
11726 0 : ErrorsFound = true;
11727 0 : continue;
11728 : }
11729 :
11730 : int MaterNum;
11731 5 : if ((MaterNum = Material::GetMaterialNum(state, s_ipsc->cAlphaArgs(3))) == 0) {
11732 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3));
11733 0 : ErrorsFound = true;
11734 0 : continue;
11735 : }
11736 :
11737 5 : Sched::Schedule *sched = nullptr;
11738 5 : if (s_ipsc->lAlphaFieldBlanks(4)) {
11739 0 : ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(4));
11740 0 : ErrorsFound = true;
11741 0 : continue;
11742 5 : } else if ((sched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(4))) == nullptr) {
11743 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(4), s_ipsc->cAlphaArgs(4));
11744 0 : ErrorsFound = true;
11745 0 : continue;
11746 : }
11747 :
11748 5 : auto *thisMaterial = s_mat->materials(MaterNum);
11749 :
11750 : Array1D_string const cMaterialGroupType({-1, 18},
11751 : {"invalid",
11752 : "Material/Material:NoMass",
11753 : "Material:AirGap",
11754 : "WindowMaterial:Shade",
11755 : "WindowMaterial:Glazing*",
11756 : "WindowMaterial:Gas",
11757 : "WindowMaterial:Blind",
11758 : "WindowMaterial:GasMixture",
11759 : "WindowMaterial:Screen",
11760 : "Material:RoofVegetation",
11761 : "Material:InfraredTransparent",
11762 : "WindowMaterial:SimpleGlazingSystem",
11763 : "WindowMaterial:ComplexShade",
11764 : "WindowMaterial:Gap",
11765 : "WindowMaterial:Glazing:EquivalentLayer",
11766 : "WindowMaterial:Shade:EquivalentLayer",
11767 : "WindowMaterial:Drape:EquivalentLayer",
11768 : "WindowMaterial:Blind:EquivalentLayer",
11769 : "WindowMaterial:Screen:EquivalentLayer",
11770 5 : "WindowMaterial:Gap:EquivalentLayer"});
11771 :
11772 5 : Material::Group const MaterialLayerGroup = thisMaterial->group;
11773 5 : if ((MaterialLayerGroup == Material::Group::GlassSimple) || (MaterialLayerGroup == Material::Group::ShadeEQL) ||
11774 5 : (MaterialLayerGroup == Material::Group::DrapeEQL) || (MaterialLayerGroup == Material::Group::BlindEQL) ||
11775 5 : (MaterialLayerGroup == Material::Group::ScreenEQL) || (MaterialLayerGroup == Material::Group::WindowGapEQL)) {
11776 0 : ShowSevereError(state, format("Invalid movable insulation material for {}:", s_ipsc->cCurrentModuleObject));
11777 0 : ShowSevereError(
11778 0 : state, format("...Movable insulation material type specified = {}", cMaterialGroupType(static_cast<int>(MaterialLayerGroup))));
11779 0 : ShowSevereError(state, format("...Movable insulation material name specified = {}", s_ipsc->cAlphaArgs(3)));
11780 0 : ErrorsFound = true;
11781 : }
11782 :
11783 5 : switch (insulationType) {
11784 2 : case InsulationType::Outside: {
11785 2 : auto &movInsul = state.dataSurface->extMovInsuls(SurfNum);
11786 2 : if (movInsul.matNum > 0) {
11787 0 : ShowSevereDuplicateAssignment(
11788 0 : state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2), s_mat->materials(movInsul.matNum)->Name);
11789 0 : ErrorsFound = true;
11790 : }
11791 :
11792 2 : movInsul.matNum = MaterNum;
11793 2 : movInsul.sched = sched;
11794 2 : state.dataSurface->AnyMovableInsulation = true;
11795 2 : state.dataSurface->extMovInsulSurfNums.push_back(SurfNum);
11796 :
11797 2 : if (thisMaterial->Resistance <= 0.0) {
11798 0 : if (thisMaterial->Conductivity <= 0.0 || thisMaterial->Thickness <= 0.0) {
11799 0 : ShowSevereError(state,
11800 0 : format("{}, {}=\"{}\", invalid material.",
11801 0 : s_ipsc->cCurrentModuleObject,
11802 0 : s_ipsc->cAlphaFieldNames(2),
11803 0 : s_ipsc->cAlphaArgs(2)));
11804 0 : ShowContinueError(state, "\"Outside\", invalid material for movable insulation.");
11805 0 : ShowContinueError(state,
11806 0 : format("Material=\"{}\",Resistance=[{:.3R}], must be > 0 for use in Movable Insulation.",
11807 0 : thisMaterial->Name,
11808 0 : thisMaterial->Resistance));
11809 0 : ErrorsFound = true;
11810 0 : } else if (thisMaterial->Conductivity > 0.0) {
11811 0 : thisMaterial->Resistance = thisMaterial->Thickness / thisMaterial->Conductivity;
11812 : }
11813 : }
11814 :
11815 2 : if (thisMaterial->Conductivity <= 0.0) {
11816 1 : if (thisMaterial->Resistance <= 0.0) {
11817 0 : ShowSevereError(state,
11818 0 : format("{}, {}=\"{}\", invalid material.",
11819 0 : s_ipsc->cCurrentModuleObject,
11820 0 : s_ipsc->cAlphaFieldNames(2),
11821 0 : s_ipsc->cAlphaArgs(2)));
11822 0 : ShowContinueError(state, "\"Outside\", invalid material for movable insulation.");
11823 0 : ShowContinueError(state,
11824 0 : format("Material=\"{}\",Conductivity=[{:.3R}], must be > 0 for use in Movable Insulation.",
11825 0 : thisMaterial->Name,
11826 0 : thisMaterial->Conductivity));
11827 0 : ErrorsFound = true;
11828 : }
11829 : }
11830 2 : } break;
11831 :
11832 3 : case InsulationType::Inside: {
11833 3 : auto &movInsul = state.dataSurface->intMovInsuls(SurfNum);
11834 3 : if (movInsul.matNum > 0) {
11835 0 : ShowSevereDuplicateAssignment(
11836 0 : state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2), s_mat->materials(movInsul.matNum)->Name);
11837 0 : ErrorsFound = true;
11838 : }
11839 :
11840 3 : movInsul.matNum = MaterNum;
11841 3 : movInsul.sched = sched;
11842 3 : state.dataSurface->AnyMovableInsulation = true;
11843 3 : state.dataSurface->intMovInsulSurfNums.push_back(SurfNum);
11844 3 : if (thisMaterial->Resistance <= 0.0) {
11845 0 : if (thisMaterial->Conductivity <= 0.0 || thisMaterial->Thickness <= 0.0) {
11846 0 : ShowSevereError(state,
11847 0 : format("{}, {}=\"{}\", invalid material.",
11848 0 : s_ipsc->cCurrentModuleObject,
11849 0 : s_ipsc->cAlphaFieldNames(2),
11850 0 : s_ipsc->cAlphaArgs(2)));
11851 0 : ShowContinueError(state, "\"Inside\", invalid material for movable insulation.");
11852 0 : ShowContinueError(state,
11853 0 : format("Material=\"{}\",Resistance=[{:.3R}], must be > 0 for use in Movable Insulation.",
11854 0 : thisMaterial->Name,
11855 0 : thisMaterial->Resistance));
11856 0 : ErrorsFound = true;
11857 0 : } else if (thisMaterial->Conductivity > 0.0) {
11858 0 : thisMaterial->Resistance = thisMaterial->Thickness / thisMaterial->Conductivity;
11859 : }
11860 : }
11861 3 : } break;
11862 0 : default: {
11863 0 : assert(false);
11864 : } break;
11865 : } // switch (inulationType)
11866 :
11867 5 : if (state.dataSurface->Surface(SurfNum).Class == SurfaceClass::Window) {
11868 0 : ShowSevereError(state, format("{}, {}=\"{}\"", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2)));
11869 0 : ShowContinueError(state, "invalid use on a Window. Use WindowShadingControl instead.");
11870 0 : ErrorsFound = true;
11871 : }
11872 5 : } // for (Loop)
11873 801 : } // GetMovableInsulationData()
11874 :
11875 : // Calculates the volume (m3) of a zone using the surfaces as possible.
11876 801 : void CalculateZoneVolume(EnergyPlusData &state)
11877 : {
11878 : // SUBROUTINE INFORMATION:
11879 : // AUTHOR Legacy Code
11880 : // DATE WRITTEN 1992-1994
11881 : // MODIFIED Sep 2007, Mar 2017
11882 :
11883 : // METHODOLOGY EMPLOYED:
11884 : // Uses surface area information for calculations. Modified to use the
11885 : // user-entered ceiling height (x floor area, if applicable) instead of using
11886 : // the calculated volume when the user enters the ceiling height.
11887 :
11888 : // REFERENCES:
11889 : // Legacy Code (IBLAST)
11890 :
11891 801 : Vectors::Polyhedron ZoneStruct;
11892 801 : bool initmsg = true;
11893 1602 : bool ShowZoneSurfaces = (state.dataInputProcessing->inputProcessor->getNumSectionsFound("SHOWZONESURFACES_DEBUG") > 0);
11894 801 : EPVector<int> surfacenotused;
11895 :
11896 : enum class ZoneVolumeCalcMethod
11897 : {
11898 : Invalid = -1,
11899 : Enclosed,
11900 : FloorAreaTimesHeight1,
11901 : FloorAreaTimesHeight2,
11902 : CeilingAreaTimesHeight,
11903 : OpWallAreaTimesDistance,
11904 : UserProvided,
11905 : Num
11906 : };
11907 :
11908 801 : int countNotFullyEnclosedZones = 0;
11909 6002 : for (auto &thisZone : state.dataHeatBal->Zone) {
11910 5201 : if (!thisZone.HasFloor) {
11911 4 : ShowWarningError(state,
11912 4 : format("No floor exists in Zone=\"{}\", zone floor area is zero. All values for this zone that are entered per "
11913 : "floor area will be zero.",
11914 2 : thisZone.Name));
11915 : }
11916 :
11917 5201 : Real64 SumAreas = 0.0;
11918 5201 : Real64 CalcVolume = 0.0;
11919 : // Use AllSurfaceFirst which includes air boundaries
11920 5201 : int NFaces = thisZone.AllSurfaceLast - thisZone.AllSurfaceFirst + 1;
11921 5201 : int notused = 0;
11922 5201 : ZoneStruct.NumSurfaceFaces = NFaces;
11923 5201 : ZoneStruct.SurfaceFace.allocate(NFaces);
11924 5201 : int NActFaces = 0;
11925 5201 : surfacenotused.dimension(NFaces, 0);
11926 :
11927 50801 : for (int SurfNum = thisZone.AllSurfaceFirst; SurfNum <= thisZone.AllSurfaceLast; ++SurfNum) {
11928 45600 : assert(SurfNum > 0);
11929 45600 : auto &thisSurface = state.dataSurface->Surface(SurfNum);
11930 : // Only include Base Surfaces in Calc.
11931 :
11932 45600 : if (thisSurface.Class != SurfaceClass::Wall && thisSurface.Class != SurfaceClass::Floor && thisSurface.Class != SurfaceClass::Roof) {
11933 9379 : ++notused;
11934 9379 : surfacenotused(notused) = SurfNum;
11935 9379 : continue;
11936 : }
11937 :
11938 36221 : ++NActFaces;
11939 36221 : auto &thisFace = ZoneStruct.SurfaceFace(NActFaces);
11940 36221 : thisFace.FacePoints.allocate(thisSurface.Sides);
11941 36221 : thisFace.NSides = thisSurface.Sides;
11942 36221 : thisFace.SurfNum = SurfNum;
11943 36221 : thisFace.FacePoints({1, thisSurface.Sides}) = thisSurface.Vertex({1, thisSurface.Sides});
11944 36221 : Vectors::CreateNewellAreaVector(thisFace.FacePoints, thisFace.NSides, thisFace.NewellAreaVector);
11945 36221 : SumAreas += Vectors::VecLength(thisFace.NewellAreaVector);
11946 : }
11947 5201 : ZoneStruct.NumSurfaceFaces = NActFaces;
11948 :
11949 5201 : bool isFloorHorizontal = false;
11950 5201 : bool isCeilingHorizontal = false;
11951 5201 : bool areWallsVertical = false;
11952 5201 : std::tie(isFloorHorizontal, isCeilingHorizontal, areWallsVertical) = areSurfaceHorizAndVert(state, ZoneStruct);
11953 5201 : Real64 oppositeWallArea = 0.0;
11954 5201 : Real64 distanceBetweenOppositeWalls = 0.0;
11955 :
11956 5201 : bool areWallsSameHeight = areWallHeightSame(state, ZoneStruct);
11957 :
11958 5201 : std::vector<EdgeOfSurf> listOfedgeNotUsedTwice;
11959 5201 : bool isZoneEnclosed = isEnclosedVolume(ZoneStruct, listOfedgeNotUsedTwice);
11960 : ZoneVolumeCalcMethod volCalcMethod;
11961 :
11962 5201 : Real64 floorAreaForVolume = (thisZone.FloorArea > 0.0) ? thisZone.FloorArea : thisZone.geometricFloorArea;
11963 5201 : Real64 ceilingAreaForVolume = (thisZone.CeilingArea > 0.0) ? thisZone.CeilingArea : thisZone.geometricCeilingArea;
11964 :
11965 5201 : if (isZoneEnclosed) {
11966 5174 : CalcVolume = Vectors::CalcPolyhedronVolume(state, ZoneStruct);
11967 5174 : volCalcMethod = ZoneVolumeCalcMethod::Enclosed;
11968 27 : } else if (floorAreaForVolume > 0.0 && thisZone.CeilingHeight > 0.0 && areFloorAndCeilingSame(state, ZoneStruct)) {
11969 17 : CalcVolume = floorAreaForVolume * thisZone.CeilingHeight;
11970 17 : volCalcMethod = ZoneVolumeCalcMethod::FloorAreaTimesHeight1;
11971 10 : } else if (isFloorHorizontal && areWallsVertical && areWallsSameHeight && floorAreaForVolume > 0.0 && thisZone.CeilingHeight > 0.0) {
11972 3 : CalcVolume = floorAreaForVolume * thisZone.CeilingHeight;
11973 3 : volCalcMethod = ZoneVolumeCalcMethod::FloorAreaTimesHeight2;
11974 7 : } else if (isCeilingHorizontal && areWallsVertical && areWallsSameHeight && ceilingAreaForVolume > 0.0 && thisZone.CeilingHeight > 0.0) {
11975 0 : CalcVolume = ceilingAreaForVolume * thisZone.CeilingHeight;
11976 0 : volCalcMethod = ZoneVolumeCalcMethod::CeilingAreaTimesHeight;
11977 7 : } else if (areOppositeWallsSame(state, ZoneStruct, oppositeWallArea, distanceBetweenOppositeWalls)) {
11978 5 : CalcVolume = oppositeWallArea * distanceBetweenOppositeWalls;
11979 5 : volCalcMethod = ZoneVolumeCalcMethod::OpWallAreaTimesDistance;
11980 2 : } else if (thisZone.Volume == Constant::AutoCalculate) { // no user entered zone volume
11981 0 : ShowSevereError(state,
11982 0 : format("For zone: {} it is not possible to calculate the volume from the surrounding surfaces so either provide the "
11983 : "volume value or define all the surfaces to fully enclose the zone.",
11984 0 : thisZone.Name));
11985 0 : CalcVolume = 0.;
11986 0 : volCalcMethod = ZoneVolumeCalcMethod::Invalid;
11987 : } else {
11988 2 : CalcVolume = 0.;
11989 2 : volCalcMethod = ZoneVolumeCalcMethod::UserProvided;
11990 : }
11991 5201 : if (!isZoneEnclosed) {
11992 27 : ++countNotFullyEnclosedZones;
11993 27 : if (state.dataGlobal->DisplayExtraWarnings) { // report missing
11994 0 : ShowWarningError(state,
11995 0 : format("CalculateZoneVolume: The Zone=\"{}\" is not fully enclosed. To be fully enclosed, each edge of a "
11996 : "surface must also be an edge on one other surface.",
11997 0 : thisZone.Name));
11998 0 : switch (volCalcMethod) {
11999 0 : case ZoneVolumeCalcMethod::FloorAreaTimesHeight1:
12000 0 : ShowContinueError(state,
12001 : " The zone volume was calculated using the floor area times ceiling height method where the floor and "
12002 : "ceiling are the same except for the z-coordinates.");
12003 0 : break;
12004 0 : case ZoneVolumeCalcMethod::FloorAreaTimesHeight2:
12005 0 : ShowContinueError(state,
12006 : " The zone volume was calculated using the floor area times ceiling height method where the floor is "
12007 : "horizontal, the walls are vertical, and the wall heights are all the same.");
12008 0 : break;
12009 0 : case ZoneVolumeCalcMethod::CeilingAreaTimesHeight:
12010 0 : ShowContinueError(state,
12011 : " The zone volume was calculated using the ceiling area times ceiling height method where the ceiling is "
12012 : "horizontal, the walls are vertical, and the wall heights are all the same.");
12013 0 : break;
12014 0 : case ZoneVolumeCalcMethod::OpWallAreaTimesDistance:
12015 0 : ShowContinueError(state,
12016 : " The zone volume was calculated using the opposite wall area times the distance between them method ");
12017 0 : break;
12018 0 : case ZoneVolumeCalcMethod::UserProvided:
12019 0 : ShowContinueError(state, " The zone volume was provided as an input to the ZONE object ");
12020 0 : break;
12021 0 : case ZoneVolumeCalcMethod::Invalid:
12022 0 : ShowContinueError(state, " The zone volume was not calculated and an error exists. ");
12023 0 : break;
12024 0 : case ZoneVolumeCalcMethod::Enclosed: // should not be called but completes enumeration
12025 0 : ShowContinueError(state, " The zone volume was calculated using multiple pyramids and was fully enclosed. ");
12026 0 : break;
12027 0 : default:
12028 0 : assert(false);
12029 : }
12030 0 : for (auto &edge : listOfedgeNotUsedTwice) {
12031 0 : if (edge.count < 2) {
12032 0 : ShowContinueError(
12033 : state,
12034 0 : fmt::format(" The surface \"{}\" has an edge that was used only once: it is not an edge on another surface",
12035 0 : state.dataSurface->Surface(edge.surfNum).Name));
12036 :
12037 : } else {
12038 0 : ShowContinueError(
12039 : state,
12040 0 : fmt::format(" The surface \"{}\" has an edge that was used {} times: it is an edge on three or more surfaces: ",
12041 0 : state.dataSurface->Surface(edge.surfNum).Name,
12042 0 : edge.count));
12043 0 : std::string surfaceNames = " It was found on the following Surfaces: ";
12044 0 : for (int surfNum : edge.otherSurfNums) {
12045 0 : surfaceNames += fmt::format("'{}' ", state.dataSurface->Surface(surfNum).Name);
12046 0 : }
12047 0 : ShowContinueError(state, surfaceNames);
12048 0 : }
12049 0 : ShowContinueError(state, format(" Vertex start {{ {:.4R}, {:.4R}, {:.4R}}}", edge.start.x, edge.start.y, edge.start.z));
12050 0 : ShowContinueError(state, format(" Vertex end {{ {:.4R}, {:.4R}, {:.4R}}}", edge.end.x, edge.end.y, edge.end.z));
12051 0 : }
12052 : }
12053 : }
12054 5201 : if (thisZone.Volume > 0.0) { // User entered zone volume, produce message if not near calculated
12055 2487 : if (CalcVolume > 0.0) {
12056 2485 : if (std::abs(CalcVolume - thisZone.Volume) / thisZone.Volume > 0.05) {
12057 4 : ++state.dataSurfaceGeometry->ErrCount5;
12058 4 : if (state.dataSurfaceGeometry->ErrCount5 == 1 && !state.dataGlobal->DisplayExtraWarnings) {
12059 2 : if (initmsg) {
12060 4 : ShowMessage(state,
12061 : "Note that the following warning(s) may/will occur if you have not enclosed your zone completely.");
12062 2 : initmsg = false;
12063 : }
12064 4 : ShowWarningError(state, "Entered Zone Volumes differ from calculated zone volume(s).");
12065 6 : ShowContinueError(state, "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on individual zones.");
12066 : }
12067 4 : if (state.dataGlobal->DisplayExtraWarnings) {
12068 0 : if (initmsg) {
12069 0 : ShowMessage(state,
12070 : "Note that the following warning(s) may/will occur if you have not enclosed your zone completely.");
12071 0 : initmsg = false;
12072 : }
12073 : // Warn user of using specified Zone Volume
12074 0 : ShowWarningError(
12075 : state,
12076 0 : format("Entered Volume entered for Zone=\"{}\" significantly different from calculated Volume", thisZone.Name));
12077 0 : ShowContinueError(state,
12078 0 : format("Entered Zone Volume value={:.2R}, Calculated Zone Volume value={:.2R}, entered volume will be "
12079 : "used in calculations.",
12080 0 : thisZone.Volume,
12081 : CalcVolume));
12082 : }
12083 : }
12084 : }
12085 2714 : } else if (thisZone.ceilingHeightEntered) { // User did not enter zone volume, but entered ceiling height
12086 129 : if (floorAreaForVolume > 0.0) {
12087 129 : thisZone.Volume = floorAreaForVolume * thisZone.CeilingHeight;
12088 : } else { // ceiling height entered but floor area zero
12089 0 : thisZone.Volume = CalcVolume;
12090 : }
12091 : } else { // Neither ceiling height nor volume entered
12092 2585 : thisZone.Volume = CalcVolume;
12093 : }
12094 :
12095 5201 : if (thisZone.Volume <= 0.0) {
12096 0 : ShowWarningError(state, format("Indicated Zone Volume <= 0.0 for Zone={}", thisZone.Name));
12097 0 : ShowContinueError(state, format("The calculated Zone Volume was={:.2R}", thisZone.Volume));
12098 0 : ShowContinueError(state, "The simulation will continue with the Zone Volume set to 10.0 m3. ");
12099 0 : ShowContinueError(state, "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on individual zones.");
12100 0 : thisZone.Volume = 10.;
12101 : }
12102 : // For now - pro-rate space volumes by floor area, if not entered
12103 10414 : for (int spaceNum : thisZone.spaceIndexes) {
12104 5213 : auto &thisSpace = state.dataHeatBal->space(spaceNum);
12105 : // don't touch if already user-specified
12106 5213 : if (thisSpace.Volume > 0.0) {
12107 3 : continue;
12108 : }
12109 5210 : if (thisZone.numSpaces == 1) {
12110 5192 : thisSpace.Volume = thisZone.Volume;
12111 18 : } else if (thisZone.geometricFloorArea > 0.0) {
12112 18 : thisSpace.Volume = thisZone.Volume * thisSpace.FloorArea / thisZone.geometricFloorArea;
12113 : }
12114 5201 : }
12115 5201 : Real64 totSpacesVolume = 0.0;
12116 10414 : for (int spaceNum : thisZone.spaceIndexes) {
12117 5213 : totSpacesVolume += state.dataHeatBal->space(spaceNum).Volume;
12118 5201 : }
12119 5201 : if (totSpacesVolume > 0.0) {
12120 10414 : for (int spaceNum : thisZone.spaceIndexes) {
12121 5213 : state.dataHeatBal->space(spaceNum).fracZoneVolume = state.dataHeatBal->space(spaceNum).Volume / totSpacesVolume;
12122 5201 : }
12123 : } // else leave fractions at zero
12124 :
12125 5201 : if (ShowZoneSurfaces) {
12126 0 : if (state.dataSurfaceGeometry->ShowZoneSurfaceHeaders) {
12127 0 : print(state.files.debug, "{}\n", "===================================");
12128 0 : print(state.files.debug, "{}\n", "showing zone surfaces used and not used in volume calculation");
12129 0 : print(state.files.debug, "{}\n", "for volume calculation, only floors, walls and roofs/ceilings are used");
12130 0 : print(state.files.debug, "{}\n", "surface class, 1=wall, 2=floor, 3=roof/ceiling");
12131 0 : print(state.files.debug, "{}\n", "unused surface class(es), 5=internal mass, 11=window, 12=glass door");
12132 0 : print(state.files.debug, "{}\n", " 13=door, 14=shading, 15=overhang, 16=fin");
12133 0 : print(state.files.debug, "{}\n", " 17=TDD Dome, 18=TDD Diffuser");
12134 0 : state.dataSurfaceGeometry->ShowZoneSurfaceHeaders = false;
12135 : }
12136 0 : print(state.files.debug, "{}\n", "===================================");
12137 0 : print(state.files.debug, "zone={} calc volume={}\n", thisZone.Name, CalcVolume);
12138 0 : print(state.files.debug, " nsurfaces={} nactual={}\n", NFaces, NActFaces);
12139 : }
12140 41422 : for (int faceNum = 1; faceNum <= ZoneStruct.NumSurfaceFaces; ++faceNum) {
12141 36221 : auto &thisFace = ZoneStruct.SurfaceFace(faceNum);
12142 36221 : if (ShowZoneSurfaces) {
12143 0 : if (faceNum <= NActFaces) {
12144 0 : auto &thisSurface = state.dataSurface->Surface(thisFace.SurfNum);
12145 0 : print(state.files.debug, "surface={} nsides={}\n", thisFace.SurfNum, thisFace.NSides);
12146 0 : print(state.files.debug, "surface name={} class={}\n", thisSurface.Name, thisSurface.Class);
12147 0 : print(state.files.debug, "area={}\n", thisSurface.GrossArea);
12148 0 : for (int iside = 1; iside <= thisFace.NSides; ++iside) {
12149 0 : auto const &FacePoint(thisFace.FacePoints(iside));
12150 0 : print(state.files.debug, "{} {} {}\n", FacePoint.x, FacePoint.y, FacePoint.z);
12151 : }
12152 : }
12153 : }
12154 36221 : thisFace.FacePoints.deallocate();
12155 : }
12156 5201 : if (ShowZoneSurfaces) {
12157 0 : for (int SurfNum = 1; SurfNum <= notused; ++SurfNum) {
12158 0 : print(state.files.debug,
12159 : "notused:surface={} name={} class={}\n",
12160 : surfacenotused(SurfNum),
12161 0 : state.dataSurface->Surface(surfacenotused(SurfNum)).Name,
12162 0 : state.dataSurface->Surface(surfacenotused(SurfNum)).Class);
12163 : }
12164 : }
12165 :
12166 5201 : ZoneStruct.SurfaceFace.deallocate();
12167 5201 : surfacenotused.deallocate();
12168 :
12169 6002 : } // zone loop
12170 801 : if (!state.dataGlobal->DisplayExtraWarnings) {
12171 750 : if (countNotFullyEnclosedZones == 1) {
12172 51 : ShowWarningError(
12173 : state, "CalculateZoneVolume: 1 zone is not fully enclosed. For more details use: Output:Diagnostics,DisplayExtrawarnings; ");
12174 733 : } else if (countNotFullyEnclosedZones > 1) {
12175 10 : ShowWarningError(state,
12176 10 : format("CalculateZoneVolume: {} zones are not fully enclosed. For more details use: "
12177 : "Output:Diagnostics,DisplayExtrawarnings; ",
12178 : countNotFullyEnclosedZones));
12179 : }
12180 : }
12181 801 : }
12182 :
12183 : // test if the volume described by the polyhedron if full enclosed (would not leak)
12184 5201 : bool isEnclosedVolume(DataVectorTypes::Polyhedron const &zonePoly, std::vector<EdgeOfSurf> &edgeNot2)
12185 : {
12186 : // J. Glazer - March 2017
12187 :
12188 5201 : std::vector<Vector> uniqueVertices = makeListOfUniqueVertices(zonePoly);
12189 :
12190 5201 : std::vector<EdgeOfSurf> edgeNot2orig = edgesNotTwoForEnclosedVolumeTest(zonePoly, uniqueVertices);
12191 : // if all edges had two counts then it is fully enclosed
12192 5201 : if (edgeNot2orig.empty()) {
12193 4188 : edgeNot2 = edgeNot2orig;
12194 4188 : return true;
12195 : } 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
12196 : // on the "other side" of the edge Go through all the points looking for the number that are colinear and see if that is
12197 : // consistent with the number of edges found that didn't have a count of two
12198 : DataVectorTypes::Polyhedron updatedZonePoly = updateZonePolygonsForMissingColinearPoints(
12199 1013 : zonePoly, uniqueVertices); // this is done after initial test since it is computationally intensive.
12200 1013 : std::vector<EdgeOfSurf> edgeNot2again = edgesNotTwoForEnclosedVolumeTest(updatedZonePoly, uniqueVertices);
12201 1013 : if (edgeNot2again.empty()) {
12202 986 : return true;
12203 : } else {
12204 54 : edgeNot2 = edgesInBoth(edgeNot2orig,
12205 27 : edgeNot2again); // only return a list of those edges that appear in both the original edge and the
12206 : // revised edges this eliminates added edges that will confuse users and edges that
12207 : // were caught by the updateZonePoly routine
12208 27 : return false;
12209 : }
12210 1013 : }
12211 5201 : }
12212 :
12213 : // returns a vector of edges that are in both vectors
12214 27 : std::vector<EdgeOfSurf> edgesInBoth(std::vector<EdgeOfSurf> const &edges1, std::vector<EdgeOfSurf> const &edges2)
12215 : {
12216 : // J. Glazer - June 2017
12217 : // this is not optimized but the number of edges for a typical polyhedron is 12 and is probably rarely bigger than 20.
12218 :
12219 27 : std::vector<EdgeOfSurf> inBoth;
12220 427 : for (const auto &e1 : edges1) {
12221 6641 : for (const auto &e2 : edges2) {
12222 6593 : if (edgesEqualOnSameSurface(e1, e2)) {
12223 352 : inBoth.push_back(e1);
12224 352 : break;
12225 : }
12226 400 : }
12227 27 : }
12228 27 : return inBoth;
12229 0 : }
12230 :
12231 : // returns true if the edges match - including the surface number
12232 6593 : bool edgesEqualOnSameSurface(EdgeOfSurf a, EdgeOfSurf b)
12233 : {
12234 6593 : if (a.surfNum != b.surfNum) {
12235 5753 : return false;
12236 : }
12237 :
12238 : // vertex comparison (we compare indices, so absolute equal)
12239 840 : return ((a.start == b.start && a.end == b.end) || (a.start == b.end && a.end == b.start));
12240 : }
12241 :
12242 : // returns the number of times the edges of the polyhedron of the zone are not used twice by the sides
12243 6214 : std::vector<EdgeOfSurf> edgesNotTwoForEnclosedVolumeTest(DataVectorTypes::Polyhedron const &zonePoly, std::vector<Vector> const &uniqueVertices)
12244 : {
12245 : // J. Glazer - March 2017
12246 :
12247 : struct EdgeByPts
12248 : {
12249 : int start;
12250 : int end;
12251 : int count;
12252 : int firstSurfNum;
12253 : std::vector<int> otherSurfNums;
12254 97188 : EdgeByPts() : start(0), end(0), count(0), firstSurfNum(0)
12255 : {
12256 97188 : }
12257 : };
12258 6214 : std::vector<EdgeByPts> uniqueEdges;
12259 6214 : uniqueEdges.reserve(zonePoly.NumSurfaceFaces * 6);
12260 :
12261 : // construct list of unique edges
12262 6214 : Vector curVertex;
12263 : int curVertexIndex;
12264 51152 : for (int iFace = 1; iFace <= zonePoly.NumSurfaceFaces; ++iFace) {
12265 44938 : Vector prevVertex;
12266 : int prevVertexIndex;
12267 229731 : for (int jVertex = 1; jVertex <= zonePoly.SurfaceFace(iFace).NSides; ++jVertex) {
12268 184793 : if (jVertex == 1) {
12269 44938 : prevVertex = zonePoly.SurfaceFace(iFace).FacePoints(zonePoly.SurfaceFace(iFace).NSides); // the last point
12270 44938 : prevVertexIndex = findIndexOfVertex(prevVertex, uniqueVertices);
12271 : } else {
12272 139855 : prevVertex = curVertex;
12273 139855 : prevVertexIndex = curVertexIndex;
12274 : }
12275 184793 : curVertex = zonePoly.SurfaceFace(iFace).FacePoints(jVertex);
12276 184793 : curVertexIndex = findIndexOfVertex(curVertex, uniqueVertices); // uses isAlmostEqual3dPt
12277 369586 : auto it = std::find_if(uniqueEdges.begin(), uniqueEdges.end(), [&curVertexIndex, &prevVertexIndex](const auto &edge) {
12278 3391693 : return ((edge.start == curVertexIndex && edge.end == prevVertexIndex) ||
12279 3391693 : (edge.start == prevVertexIndex && edge.end == curVertexIndex));
12280 369586 : });
12281 184793 : if (it == uniqueEdges.end()) {
12282 97188 : EdgeByPts curEdge;
12283 97188 : curEdge.start = prevVertexIndex;
12284 97188 : curEdge.end = curVertexIndex;
12285 97188 : curEdge.count = 1;
12286 97188 : curEdge.firstSurfNum = zonePoly.SurfaceFace(iFace).SurfNum;
12287 97188 : uniqueEdges.emplace_back(curEdge);
12288 97188 : } else {
12289 87605 : ++(it->count);
12290 87605 : it->otherSurfNums.push_back(zonePoly.SurfaceFace(iFace).SurfNum);
12291 : }
12292 184793 : }
12293 44938 : }
12294 : // All edges for an enclosed polyhedron should be shared by two (and only two) sides.
12295 : // So if the count is not two for all edges, the polyhedron is not enclosed
12296 6214 : std::vector<EdgeOfSurf> edgesNotTwoCount;
12297 103402 : for (const auto &anEdge : uniqueEdges) {
12298 97188 : if (anEdge.count != 2) {
12299 9831 : EdgeOfSurf curEdgeOne;
12300 9831 : curEdgeOne.surfNum = anEdge.firstSurfNum;
12301 9831 : curEdgeOne.start = uniqueVertices[anEdge.start];
12302 9831 : curEdgeOne.end = uniqueVertices[anEdge.end];
12303 9831 : curEdgeOne.count = anEdge.count;
12304 9831 : curEdgeOne.otherSurfNums = anEdge.otherSurfNums;
12305 9831 : edgesNotTwoCount.push_back(curEdgeOne);
12306 9831 : }
12307 6214 : }
12308 12428 : return edgesNotTwoCount;
12309 6214 : }
12310 :
12311 : // create a list of unique vertices given the polyhedron describing the zone
12312 5201 : std::vector<Vector> makeListOfUniqueVertices(DataVectorTypes::Polyhedron const &zonePoly)
12313 : {
12314 : // J. Glazer - March 2017
12315 :
12316 5201 : std::vector<Vector> uniqVertices;
12317 5201 : uniqVertices.reserve(zonePoly.NumSurfaceFaces * 6);
12318 :
12319 41422 : for (int iFace = 1; iFace <= zonePoly.NumSurfaceFaces; ++iFace) {
12320 181992 : for (int jVertex = 1; jVertex <= zonePoly.SurfaceFace(iFace).NSides; ++jVertex) {
12321 145771 : Vector curVertex = zonePoly.SurfaceFace(iFace).FacePoints(jVertex);
12322 145771 : if (uniqVertices.size() == 0) {
12323 5201 : uniqVertices.emplace_back(curVertex);
12324 : } else {
12325 140570 : bool found = false;
12326 870476 : for (const auto &unqV : uniqVertices) {
12327 826502 : if (isAlmostEqual3dPt(curVertex, unqV)) {
12328 96596 : found = true;
12329 96596 : break;
12330 : }
12331 140570 : }
12332 140570 : if (!found) {
12333 43974 : uniqVertices.emplace_back(curVertex);
12334 : }
12335 : }
12336 145771 : }
12337 : }
12338 5201 : return uniqVertices;
12339 0 : }
12340 :
12341 : // updates the polyhedron used to describe a zone to include points on an edge that are between and collinear to points already describing
12342 : // the edge
12343 1013 : DataVectorTypes::Polyhedron updateZonePolygonsForMissingColinearPoints(DataVectorTypes::Polyhedron const &zonePoly,
12344 : std::vector<Vector> const &uniqVertices)
12345 : {
12346 : // J. Glazer - March 2017
12347 :
12348 1013 : DataVectorTypes::Polyhedron updZonePoly = zonePoly; // set the return value to the original polyhedron describing the zone
12349 :
12350 11305 : for (auto &updFace : updZonePoly.SurfaceFace) {
12351 10292 : bool insertedVertext = true;
12352 34707 : while (insertedVertext) {
12353 14123 : insertedVertext = false;
12354 14123 : auto &vertices = updFace.FacePoints;
12355 63398 : for (auto it = vertices.begin(); it != vertices.end(); ++it) {
12356 :
12357 53106 : auto itnext = std::next(it);
12358 53106 : if (itnext == std::end(vertices)) {
12359 10014 : itnext = std::begin(vertices);
12360 : }
12361 :
12362 53106 : auto curVertex = *it; // (AUTO_OK_OBJ) can't tell if a copy is the intended behavior here
12363 53106 : auto nextVertex = *itnext; // (AUTO_OK_OBJ)
12364 :
12365 : // now go through all the vertices and see if they are colinear with start and end vertices
12366 944119 : for (const auto &testVertex : uniqVertices) {
12367 894844 : if (!isAlmostEqual3dPt(curVertex, testVertex) && !isAlmostEqual3dPt(nextVertex, testVertex)) {
12368 790662 : if (isPointOnLineBetweenPoints(curVertex, nextVertex, testVertex)) {
12369 3831 : vertices.insert(itnext, testVertex);
12370 3831 : ++updFace.NSides;
12371 3831 : insertedVertext = true;
12372 3831 : break;
12373 : }
12374 : }
12375 53106 : }
12376 : // Break out of the loop on vertices of the surface too, and start again at the while
12377 53106 : if (insertedVertext) {
12378 3831 : break;
12379 : }
12380 56937 : }
12381 : }
12382 : }
12383 1013 : return updZonePoly;
12384 0 : }
12385 :
12386 : // test if the ceiling and floor are the same except for their height difference by looking at the corners
12387 25 : bool areFloorAndCeilingSame(EnergyPlusData &state, DataVectorTypes::Polyhedron const &zonePoly)
12388 : {
12389 : // J. Glazer - March 2017
12390 :
12391 : // check if the floor and ceiling are the same
12392 : // this is almost equivalent to saying, if you ignore the z-coordinate, are the vertices the same
12393 : // so if you could all the unique vertices of the floor and ceiling, ignoring the z-coordinate, they
12394 : // should always be even (they would be two but you might define multiple surfaces that meet in a corner)
12395 :
12396 25 : std::vector<DataVectorTypes::Vector2dCount> floorCeilingXY;
12397 25 : floorCeilingXY.reserve(zonePoly.NumSurfaceFaces * 6);
12398 :
12399 : // make list of x and y coordinates for all faces that are on the floor or ceiling
12400 289 : for (int iFace = 1; iFace <= zonePoly.NumSurfaceFaces; ++iFace) {
12401 264 : int curSurfNum = zonePoly.SurfaceFace(iFace).SurfNum;
12402 486 : if (state.dataSurface->Surface(curSurfNum).Class == SurfaceClass::Floor ||
12403 222 : state.dataSurface->Surface(curSurfNum).Class == SurfaceClass::Roof) {
12404 445 : for (int jVertex = 1; jVertex <= zonePoly.SurfaceFace(iFace).NSides; ++jVertex) {
12405 356 : Vector curVertex = zonePoly.SurfaceFace(iFace).FacePoints(jVertex);
12406 356 : DataVectorTypes::Vector2dCount curXYc;
12407 356 : curXYc.x = curVertex.x;
12408 356 : curXYc.y = curVertex.y;
12409 356 : curXYc.count = 1;
12410 356 : bool found = false;
12411 1439 : for (DataVectorTypes::Vector2dCount &curFloorCeiling : floorCeilingXY) { // can't use just "auto" because updating floorCeilingXY
12412 1268 : if (isAlmostEqual2dPt(curXYc, curFloorCeiling)) { // count ignored in comparison
12413 185 : ++curFloorCeiling.count;
12414 185 : found = true;
12415 185 : break;
12416 : }
12417 356 : }
12418 356 : if (!found) {
12419 171 : floorCeilingXY.emplace_back(curXYc);
12420 : }
12421 356 : }
12422 : }
12423 : }
12424 : // now make sure every point has been counted and even number of times (usually twice)
12425 : // if they are then the ceiling and floor are (almost certainly) the same x and y coordinates.
12426 25 : bool areFlrAndClgSame = true;
12427 25 : if (floorCeilingXY.size() > 0) {
12428 122 : for (auto const &curFloorCeiling : floorCeilingXY) {
12429 105 : if (curFloorCeiling.count % 2 != 0) {
12430 8 : areFlrAndClgSame = false;
12431 8 : break;
12432 : }
12433 25 : }
12434 : } else {
12435 0 : areFlrAndClgSame = false;
12436 : }
12437 25 : return areFlrAndClgSame;
12438 25 : }
12439 :
12440 : // test if the walls of a zone are all the same height using the polyhedron describing the zone geometry
12441 5201 : bool areWallHeightSame(EnergyPlusData &state, DataVectorTypes::Polyhedron const &zonePoly)
12442 : {
12443 : // J. Glazer - March 2017
12444 :
12445 : // test if all the wall heights are the same (all walls have the same maximum z-coordinate
12446 :
12447 5201 : bool areWlHgtSame = true;
12448 5201 : Real64 wallHeightZ = -Constant::BigNumber;
12449 5201 : bool foundWallHeight = false;
12450 40422 : for (int iFace = 1; iFace <= zonePoly.NumSurfaceFaces; ++iFace) {
12451 35297 : int curSurfNum = zonePoly.SurfaceFace(iFace).SurfNum;
12452 35297 : if (state.dataSurface->Surface(curSurfNum).Class == SurfaceClass::Wall) {
12453 22685 : Real64 maxZ = -Constant::BigNumber;
12454 113354 : for (int jVertex = 1; jVertex <= zonePoly.SurfaceFace(iFace).NSides; ++jVertex) {
12455 90669 : Vector curVertex = zonePoly.SurfaceFace(iFace).FacePoints(jVertex);
12456 90669 : if (maxZ < curVertex.z) {
12457 22738 : maxZ = curVertex.z;
12458 : }
12459 90669 : }
12460 22685 : if (foundWallHeight) {
12461 17506 : if (std::abs(maxZ - wallHeightZ) > Constant::TwoCentimeters) {
12462 76 : areWlHgtSame = false;
12463 76 : break;
12464 : }
12465 : } else {
12466 5179 : wallHeightZ = maxZ;
12467 5179 : foundWallHeight = true;
12468 : }
12469 : }
12470 : }
12471 5201 : return areWlHgtSame;
12472 : }
12473 :
12474 : // tests if the floor is horizontal, ceiling is horizontal, and walls are vertical and returns all three as a tuple of booleans
12475 5201 : std::tuple<bool, bool, bool> areSurfaceHorizAndVert(EnergyPlusData &state, DataVectorTypes::Polyhedron const &zonePoly)
12476 : {
12477 : // J. Glazer - March 2017
12478 :
12479 : // check if floors and ceilings are horizontal and walls are vertical
12480 5201 : bool isFlrHoriz = true;
12481 5201 : bool isClgHoriz = true;
12482 5201 : bool areWlVert = true;
12483 41422 : for (int iFace = 1; iFace <= zonePoly.NumSurfaceFaces; ++iFace) {
12484 36221 : int curSurfNum = zonePoly.SurfaceFace(iFace).SurfNum;
12485 36221 : if (state.dataSurface->Surface(curSurfNum).Class == SurfaceClass::Floor) {
12486 7040 : if (std::abs(state.dataSurface->Surface(curSurfNum).Tilt - 180.) > 1.) { // with 1 degree angle
12487 0 : isFlrHoriz = false;
12488 : }
12489 29181 : } else if (state.dataSurface->Surface(curSurfNum).Class == SurfaceClass::Roof) { // includes ceilings
12490 5958 : if (std::abs(state.dataSurface->Surface(curSurfNum).Tilt) > 1.) { // with 1 degree angle of
12491 256 : isClgHoriz = false;
12492 : }
12493 23223 : } else if (state.dataSurface->Surface(curSurfNum).Class == SurfaceClass::Wall) {
12494 23223 : if (std::abs(state.dataSurface->Surface(curSurfNum).Tilt - 90) > 1.) { // with 1 degree angle
12495 2 : areWlVert = false;
12496 : }
12497 : }
12498 : }
12499 10402 : return std::make_tuple(isFlrHoriz, isClgHoriz, areWlVert);
12500 : }
12501 :
12502 : // tests whether a pair of walls in the zone are the same except offset from one another and facing the opposite direction and also
12503 : // returns the wall area and distance between
12504 7 : bool areOppositeWallsSame(EnergyPlusData &state,
12505 : DataVectorTypes::Polyhedron const &zonePoly,
12506 : Real64 &oppositeWallArea, // return the area of the wall that has an opposite wall
12507 : Real64 &distanceBetweenOppositeWalls // returns distance
12508 : )
12509 : {
12510 : // J. Glazer - March 2017
12511 :
12512 : // approach: if opposite surfaces have opposite azimuth and same area, then check the distance between the
12513 : // vertices( one counting backwards ) and if it is the same distance than assume that it is the same.
12514 7 : bool foundOppEqual = false;
12515 23 : for (int iFace = 1; iFace <= zonePoly.NumSurfaceFaces; ++iFace) {
12516 21 : int curSurfNum = zonePoly.SurfaceFace(iFace).SurfNum;
12517 21 : if (state.dataSurface->Surface(curSurfNum).Class == SurfaceClass::Wall) {
12518 21 : std::vector<int> facesAtAz = listOfFacesFacingAzimuth(state, zonePoly, state.dataSurface->Surface(curSurfNum).Azimuth);
12519 21 : bool allFacesEquidistant = true;
12520 21 : oppositeWallArea = 0.;
12521 46 : for (int curFace : facesAtAz) {
12522 41 : int possOppFace = findPossibleOppositeFace(state, zonePoly, curFace);
12523 41 : if (possOppFace > 0) { // an opposite fact was found
12524 27 : oppositeWallArea += state.dataSurface->Surface(zonePoly.SurfaceFace(curFace).SurfNum).Area;
12525 27 : if (!areCornersEquidistant(zonePoly, curFace, possOppFace, distanceBetweenOppositeWalls)) {
12526 2 : allFacesEquidistant = false;
12527 2 : break;
12528 : }
12529 : } else {
12530 14 : allFacesEquidistant = false;
12531 14 : break;
12532 : }
12533 21 : }
12534 21 : if (allFacesEquidistant) {
12535 5 : foundOppEqual = true;
12536 5 : break; // only need to find the first case where opposite walls are the same
12537 : }
12538 21 : }
12539 : }
12540 7 : return foundOppEqual;
12541 : }
12542 :
12543 : // provides a list of indices of polyhedron faces that are facing a specific azimuth
12544 21 : std::vector<int> listOfFacesFacingAzimuth(EnergyPlusData &state, DataVectorTypes::Polyhedron const &zonePoly, Real64 const azimuth)
12545 : {
12546 : // J. Glazer - March 2017
12547 :
12548 21 : std::vector<int> facingAzimuth;
12549 21 : facingAzimuth.reserve(zonePoly.NumSurfaceFaces);
12550 :
12551 263 : for (int iFace = 1; iFace <= zonePoly.NumSurfaceFaces; ++iFace) {
12552 242 : int curSurfNum = zonePoly.SurfaceFace(iFace).SurfNum;
12553 242 : if (General::rotAzmDiffDeg(state.dataSurface->Surface(curSurfNum).Azimuth, azimuth) < 1.) {
12554 66 : facingAzimuth.emplace_back(iFace);
12555 : }
12556 : }
12557 21 : return facingAzimuth;
12558 0 : }
12559 :
12560 : // returns the index of the face of a polyhedron that is probably opposite of the face index provided
12561 41 : int findPossibleOppositeFace(EnergyPlusData &state, DataVectorTypes::Polyhedron const &zonePoly, int const faceIndex)
12562 : {
12563 : // J. Glazer - March 2017
12564 :
12565 41 : int selectedSurNum = zonePoly.SurfaceFace(faceIndex).SurfNum;
12566 41 : Real64 selectedAzimuth = state.dataSurface->Surface(selectedSurNum).Azimuth;
12567 41 : Real64 oppositeAzimuth = fmod(selectedAzimuth + 180., 360.);
12568 41 : Real64 selectedArea = state.dataSurface->Surface(selectedSurNum).Area;
12569 41 : int selectedNumCorners = zonePoly.SurfaceFace(faceIndex).NSides;
12570 41 : int found = -1;
12571 :
12572 296 : for (int iFace = 1; iFace <= zonePoly.NumSurfaceFaces; ++iFace) {
12573 282 : int curSurfNum = zonePoly.SurfaceFace(iFace).SurfNum;
12574 564 : if ((zonePoly.SurfaceFace(iFace).NSides == selectedNumCorners) &&
12575 564 : (std::abs(state.dataSurface->Surface(curSurfNum).Area - selectedArea) < 0.01) &&
12576 94 : (std::abs(state.dataSurface->Surface(curSurfNum).Azimuth - oppositeAzimuth) < 1.)) {
12577 27 : found = iFace;
12578 27 : break;
12579 : }
12580 : }
12581 41 : return found;
12582 : }
12583 :
12584 : // tests if the corners of one face of the polyhedron are the same distance from corners of another face
12585 27 : bool areCornersEquidistant(DataVectorTypes::Polyhedron const &zonePoly, int const faceIndex, int const opFaceIndex, Real64 &distanceBetween)
12586 : {
12587 : // J. Glazer - March 2017
12588 :
12589 27 : bool allAreEquidistant = true;
12590 27 : Real64 firstDistance = -99.;
12591 27 : if (zonePoly.SurfaceFace(faceIndex).NSides == zonePoly.SurfaceFace(opFaceIndex).NSides) { // double check that the number of sides match
12592 130 : for (int iVertex = 1; iVertex <= zonePoly.SurfaceFace(faceIndex).NSides; ++iVertex) {
12593 105 : int iVertexOpp = 1 + zonePoly.SurfaceFace(faceIndex).NSides - iVertex; // count backwards for opposite face
12594 : Real64 curDistBetwCorners =
12595 105 : distance(zonePoly.SurfaceFace(faceIndex).FacePoints(iVertex), zonePoly.SurfaceFace(opFaceIndex).FacePoints(iVertexOpp));
12596 105 : if (iVertex == 1) {
12597 27 : firstDistance = curDistBetwCorners;
12598 : } else {
12599 78 : if (std::abs(curDistBetwCorners - firstDistance) > Constant::OneCentimeter) {
12600 2 : allAreEquidistant = false;
12601 2 : break;
12602 : }
12603 : }
12604 : }
12605 : } else {
12606 0 : allAreEquidistant = false;
12607 : }
12608 27 : if (allAreEquidistant) {
12609 25 : distanceBetween = firstDistance;
12610 : }
12611 27 : return allAreEquidistant;
12612 : }
12613 :
12614 : // test if two points in space are in the same position based on a small tolerance
12615 20402295 : bool isAlmostEqual3dPt(DataVectorTypes::Vector v1, DataVectorTypes::Vector v2)
12616 : {
12617 : // J. Glazer - March 2017
12618 :
12619 21261320 : return ((std::abs(v1.x - v2.x) < Constant::OneCentimeter) && (std::abs(v1.y - v2.y) < Constant::OneCentimeter) &&
12620 21261320 : (std::abs(v1.z - v2.z) < Constant::OneCentimeter));
12621 : }
12622 :
12623 : // test if two points on a plane are in the same position based on a small tolerance
12624 1268 : bool isAlmostEqual2dPt(DataVectorTypes::Vector_2d v1, DataVectorTypes::Vector_2d v2)
12625 : {
12626 : // J. Glazer - March 2017
12627 :
12628 1268 : return ((std::abs(v1.x - v2.x) < Constant::OneCentimeter) && (std::abs(v1.y - v2.y) < Constant::OneCentimeter));
12629 : }
12630 :
12631 : // test if two points on a plane are in the same position based on a small tolerance (based on Vector2dCount comparison)
12632 0 : bool isAlmostEqual2dPt(DataVectorTypes::Vector2dCount v1, DataVectorTypes::Vector2dCount v2)
12633 : {
12634 : // J. Glazer - March 2017
12635 :
12636 0 : return ((std::abs(v1.x - v2.x) < Constant::OneCentimeter) && (std::abs(v1.y - v2.y) < Constant::OneCentimeter));
12637 : }
12638 :
12639 : // returns the index of vertex in a list that is in the same position in space as the given vertex
12640 229731 : int findIndexOfVertex(DataVectorTypes::Vector vertexToFind, std::vector<DataVectorTypes::Vector> const &listOfVertices)
12641 : {
12642 : // J. Glazer - March 2017
12643 :
12644 1488139 : for (std::size_t i = 0; i < listOfVertices.size(); i++) {
12645 1488139 : if (isAlmostEqual3dPt(listOfVertices[i], vertexToFind)) {
12646 229731 : return i;
12647 : }
12648 : }
12649 0 : return -1;
12650 : }
12651 :
12652 : // returns the distance between two points in space
12653 1065168 : Real64 distance(DataVectorTypes::Vector v1, DataVectorTypes::Vector v2)
12654 : {
12655 : // J. Glazer - March 2017
12656 :
12657 1065168 : return sqrt(pow(v1.x - v2.x, 2) + pow(v1.y - v2.y, 2) + pow(v1.z - v2.z, 2));
12658 : }
12659 :
12660 7273811 : Real64 distanceFromPointToLine(DataVectorTypes::Vector start, DataVectorTypes::Vector end, DataVectorTypes::Vector test)
12661 : {
12662 : // np.linalg.norm(np.cross(e-s,p-s)/np.linalg.norm(e-s))
12663 7273811 : DataVectorTypes::Vector t = end - start;
12664 7273811 : t.normalize(); // Unit vector of start to end
12665 :
12666 7273811 : DataVectorTypes::Vector other = test - start;
12667 :
12668 7273811 : DataVectorTypes::Vector projection = DataVectorTypes::cross(t, other); // normal unit vector, that's the distance component
12669 14547622 : return projection.length();
12670 7273811 : }
12671 :
12672 : // tests if a point in space lies on the line segment defined by two other points
12673 7273811 : bool isPointOnLineBetweenPoints(DataVectorTypes::Vector start, DataVectorTypes::Vector end, DataVectorTypes::Vector test)
12674 : {
12675 : // J. Glazer - March 2017
12676 : // 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
12677 : // floor to the roof, cf #7383 compute the shortest distance from the point to the line first to avoid false positive
12678 7273811 : if (distanceFromPointToLine(start, end, test) <
12679 : Constant::OneCentimeter) { // distanceFromPointToLine always positive, it's calculated as norml_L2
12680 294264 : return (std::abs((distance(start, end) - (distance(start, test) + distance(test, end)))) < Constant::OneCentimeter);
12681 : }
12682 6979547 : return false;
12683 : }
12684 :
12685 1417824 : bool EdgeOfSurf::operator==(const EdgeOfSurf &other) const
12686 : {
12687 4261938 : return ((isAlmostEqual3dPt(this->start, other.start) && isAlmostEqual3dPt(this->end, other.end)) ||
12688 2844114 : (isAlmostEqual3dPt(this->start, other.end) && isAlmostEqual3dPt(this->end, other.start)));
12689 : }
12690 :
12691 0 : bool EdgeOfSurf::operator!=(const EdgeOfSurf &other) const
12692 : {
12693 0 : return !(*this == other);
12694 : }
12695 :
12696 6569118 : bool EdgeOfSurf::containsPoints(const Vector &vertex) const
12697 : {
12698 19621385 : return (!isAlmostEqual3dPt(this->start, vertex) && !isAlmostEqual3dPt(this->end, vertex) &&
12699 19621385 : isPointOnLineBetweenPoints(this->start, this->end, vertex));
12700 : }
12701 :
12702 7256 : double EdgeOfSurf::length() const
12703 : {
12704 7256 : return distance(this->start, this->end);
12705 : }
12706 :
12707 44753 : void ProcessSurfaceVertices(EnergyPlusData &state, int const ThisSurf, bool &ErrorsFound)
12708 : {
12709 : // SUBROUTINE INFORMATION:
12710 : // AUTHOR Legacy Code (Walton)
12711 : // DATE WRITTEN 1976
12712 : // MODIFIED FW, Mar 2002: Add triangular windows
12713 : // FW, May 2002: modify test for 4-sided but non-rectangular subsurfaces
12714 : // FW, Sep 2002: add shape for base surfaces (walls and detached shading surfaces)
12715 :
12716 : // PURPOSE OF THIS SUBROUTINE:
12717 : // This subroutine processes each surface into the vertex representation used
12718 : // by the shading procedures.
12719 :
12720 : // METHODOLOGY EMPLOYED:
12721 : // Detached Shading, Base Surfaces, Attached Shading surfaces are represented in the
12722 : // same manner as original. Subsurfaces (windows, doors) are a "relative coordinate".
12723 :
12724 : static constexpr std::string_view RoutineName("ProcessSurfaceVertices: ");
12725 :
12726 : Real64 X1; // Intermediate Result
12727 : Real64 Y1; // Intermediate Result
12728 : Real64 Z1; // Intermediate Result
12729 : Real64 XLLC; // X-coordinate of lower left corner
12730 : Real64 YLLC; // Y-coordinate of lower left corner
12731 : Real64 ZLLC; // Z-coordinate of lower left corner
12732 : int n; // Vertex Number in Loop
12733 : int ThisBaseSurface; // Current base surface
12734 : Real64 Xp;
12735 : Real64 Yp;
12736 : Real64 Zp;
12737 : Real64 SurfWorldAz; // Surface Azimuth (facing)
12738 : Real64 SurfTilt; // Surface Tilt
12739 44753 : DataSurfaces::SurfaceShape ThisShape(DataSurfaces::SurfaceShape::None);
12740 : bool BaseSurface; // True if a base surface or a detached shading surface
12741 : Real64 ThisSurfAz;
12742 : Real64 ThisSurfTilt;
12743 : Real64 ThisReveal;
12744 : Real64 ThisWidth;
12745 : Real64 ThisHeight;
12746 : Real64 FrWidth; // Frame width for exterior windows (m)
12747 : Real64 FrArea; // Frame area for exterior windows(m2)
12748 : Real64 DivWidth; // Divider width for exterior windows (m)
12749 : Real64 DivArea; // Divider area for exterior windows (m2)
12750 : Real64 DivFrac; // Fraction of divider area without overlaps
12751 : bool ErrorInSurface; // false/true, depending on pass through routine
12752 : bool HeatTransSurf;
12753 : Real64 OutOfLine;
12754 :
12755 : // Object Data
12756 44753 : Vectors::PlaneEq BasePlane;
12757 44753 : Vector TVect;
12758 44753 : Vector CoordinateTransVector;
12759 :
12760 44753 : if (state.dataSurface->Surface(ThisSurf).VerticesProcessed) {
12761 0 : return;
12762 : }
12763 :
12764 44753 : ErrorInSurface = false;
12765 :
12766 44753 : if (state.dataSurfaceGeometry->ProcessSurfaceVerticesOneTimeFlag) {
12767 770 : state.dataSurfaceGeometry->Xpsv.allocate(state.dataSurface->MaxVerticesPerSurface);
12768 770 : state.dataSurfaceGeometry->Ypsv.allocate(state.dataSurface->MaxVerticesPerSurface);
12769 770 : state.dataSurfaceGeometry->Zpsv.allocate(state.dataSurface->MaxVerticesPerSurface);
12770 770 : state.dataSurfaceGeometry->Xpsv = 0.0;
12771 770 : state.dataSurfaceGeometry->Ypsv = 0.0;
12772 770 : state.dataSurfaceGeometry->Zpsv = 0.0;
12773 770 : state.dataSurfaceGeometry->ProcessSurfaceVerticesOneTimeFlag = false;
12774 : }
12775 :
12776 : // Categorize this surface
12777 44753 : auto &surf = state.dataSurface->Surface(ThisSurf);
12778 44753 : BaseSurface = (surf.BaseSurf == 0 || surf.BaseSurf == ThisSurf);
12779 :
12780 44753 : ThisBaseSurface = surf.BaseSurf; // Dont know if this is still needed or not
12781 44753 : HeatTransSurf = surf.HeatTransSurf;
12782 :
12783 : // Kludge for daylighting shelves
12784 44753 : if (surf.IsShadowing) {
12785 1690 : ThisBaseSurface = ThisSurf;
12786 1690 : HeatTransSurf = true;
12787 : }
12788 :
12789 : // IF (Surface(ThisSurf)%Name(1:3) /= 'Mir') THEN
12790 44753 : if (!surf.MirroredSurf) {
12791 : bool IsCoPlanar;
12792 : int LastVertexInError;
12793 43908 : Vectors::CalcCoPlanarNess(surf.Vertex, surf.Sides, IsCoPlanar, OutOfLine, LastVertexInError);
12794 43908 : if (!IsCoPlanar) {
12795 0 : if (OutOfLine > 0.01) {
12796 0 : ShowSevereError(state,
12797 0 : format("{}Suspected non-planar surface:\"{}\", Max \"out of line\"={:.5T} at Vertex # {}",
12798 : RoutineName,
12799 0 : surf.Name,
12800 : OutOfLine,
12801 : LastVertexInError));
12802 : } else {
12803 0 : ShowWarningError(state,
12804 0 : format("{}Possible non-planar surface:\"{}\", Max \"out of line\"={:.5T} at Vertex # {}",
12805 : RoutineName,
12806 0 : surf.Name,
12807 : OutOfLine,
12808 : LastVertexInError));
12809 : }
12810 : // ErrorInSurface=.TRUE.
12811 : }
12812 : }
12813 :
12814 44753 : if (BaseSurface) {
12815 37913 : SurfWorldAz = surf.Azimuth;
12816 37913 : SurfTilt = surf.Tilt;
12817 190408 : for (n = 1; n <= surf.Sides; ++n) {
12818 152495 : state.dataSurfaceGeometry->Xpsv(n) = surf.Vertex(n).x;
12819 152495 : state.dataSurfaceGeometry->Ypsv(n) = surf.Vertex(n).y;
12820 152495 : state.dataSurfaceGeometry->Zpsv(n) = surf.Vertex(n).z;
12821 : }
12822 37913 : TVect = surf.Vertex(3) - surf.Vertex(2);
12823 37913 : ThisWidth = Vectors::VecLength(TVect);
12824 37913 : TVect = surf.Vertex(2) - surf.Vertex(1);
12825 37913 : ThisHeight = Vectors::VecLength(TVect);
12826 37913 : surf.Width = ThisWidth;
12827 37913 : surf.Height = ThisHeight; // For a horizontal surface this is actually length!
12828 37913 : if (surf.Sides == 3) {
12829 197 : surf.Shape = DataSurfaces::SurfaceShape::Triangle;
12830 37716 : } else if (surf.Sides == 4) {
12831 : // Test for rectangularity
12832 37519 : if (isRectangle(state, ThisSurf)) {
12833 32229 : surf.Shape = DataSurfaces::SurfaceShape::Rectangle;
12834 : } else {
12835 5290 : surf.Shape = DataSurfaces::SurfaceShape::Quadrilateral;
12836 : }
12837 : } else { // Surface( ThisSurf ).Sides > 4
12838 197 : surf.Shape = DataSurfaces::SurfaceShape::Polygonal;
12839 197 : if (std::abs(ThisHeight * ThisWidth - surf.GrossArea) > 0.001) {
12840 197 : surf.Width = std::sqrt(surf.GrossArea);
12841 197 : surf.Height = surf.Width;
12842 197 : ThisWidth = surf.Width;
12843 197 : ThisHeight = surf.Height;
12844 : }
12845 : }
12846 :
12847 : } else { // It's a subsurface to previous basesurface in this set of calls
12848 :
12849 6840 : ThisSurfAz = surf.Azimuth;
12850 6840 : ThisSurfTilt = surf.Tilt;
12851 :
12852 : // Retrieve base surface info
12853 6840 : Real64 const baseSurfWorldAz = state.dataSurface->Surface(ThisBaseSurface).Azimuth;
12854 6840 : Real64 const baseSurfTilt = state.dataSurface->Surface(ThisBaseSurface).Tilt;
12855 6840 : Real64 const BaseCosAzimuth = std::cos(baseSurfWorldAz * Constant::DegToRad);
12856 6840 : Real64 const BaseSinAzimuth = std::sin(baseSurfWorldAz * Constant::DegToRad);
12857 6840 : Real64 const BaseCosTilt = std::cos(baseSurfTilt * Constant::DegToRad);
12858 6840 : Real64 const BaseSinTilt = std::sin(baseSurfTilt * Constant::DegToRad);
12859 6840 : Real64 const BaseXLLC = state.dataSurface->Surface(ThisBaseSurface).Vertex(2).x;
12860 6840 : Real64 const BaseYLLC = state.dataSurface->Surface(ThisBaseSurface).Vertex(2).y;
12861 6840 : Real64 const BaseZLLC = state.dataSurface->Surface(ThisBaseSurface).Vertex(2).z;
12862 :
12863 6840 : if (HeatTransSurf) {
12864 :
12865 6840 : if (surf.Sides == 4) {
12866 6838 : ThisShape = DataSurfaces::SurfaceShape::RectangularDoorWindow;
12867 2 : } else if (surf.Sides == 3 && surf.Class == SurfaceClass::Window) {
12868 2 : ThisShape = DataSurfaces::SurfaceShape::TriangularWindow;
12869 0 : } else if (surf.Sides == 3 && surf.Class == SurfaceClass::Door) {
12870 0 : ThisShape = DataSurfaces::SurfaceShape::TriangularDoor;
12871 : } else {
12872 0 : assert(false);
12873 : }
12874 :
12875 : } else { // this is a shadowing subsurface
12876 :
12877 0 : if (std::abs(state.dataSurface->Surface(surf.BaseSurf).Tilt - ThisSurfTilt) <= 0.01) {
12878 : // left or right fin
12879 0 : if (ThisSurfAz < 0.0) {
12880 0 : ThisSurfAz += 360.0;
12881 : }
12882 0 : if (ThisSurfAz > state.dataSurface->Surface(surf.BaseSurf).Azimuth) {
12883 0 : ThisShape = DataSurfaces::SurfaceShape::RectangularLeftFin;
12884 : } else {
12885 0 : ThisShape = DataSurfaces::SurfaceShape::RectangularRightFin;
12886 : }
12887 : } else {
12888 0 : ThisShape = DataSurfaces::SurfaceShape::RectangularOverhang;
12889 : }
12890 : }
12891 :
12892 : // Setting relative coordinates for shadowing calculations for subsurfaces
12893 : bool SError; // Bool used for return value of calls to PlaneEquation
12894 6840 : switch (ThisShape) {
12895 6838 : case DataSurfaces::SurfaceShape::RectangularDoorWindow: { // Rectangular heat transfer subsurface
12896 13676 : Vectors::PlaneEquation(
12897 6838 : state.dataSurface->Surface(surf.BaseSurf).Vertex, state.dataSurface->Surface(surf.BaseSurf).Sides, BasePlane, SError);
12898 6838 : if (SError) {
12899 0 : ShowSevereError(state, format("{}Degenerate surface (likely two vertices equal):\"{}\".", RoutineName, surf.Name));
12900 0 : ErrorInSurface = true;
12901 : }
12902 6838 : ThisReveal = -Vectors::Pt2Plane(surf.Vertex(2), BasePlane);
12903 6838 : if (std::abs(ThisReveal) < 0.0002) {
12904 6669 : ThisReveal = 0.0;
12905 : }
12906 6838 : surf.Reveal = ThisReveal;
12907 6838 : Xp = surf.Vertex(2).x - BaseXLLC;
12908 6838 : Yp = surf.Vertex(2).y - BaseYLLC;
12909 6838 : Zp = surf.Vertex(2).z - BaseZLLC;
12910 6838 : XLLC = -Xp * BaseCosAzimuth + Yp * BaseSinAzimuth;
12911 6838 : YLLC = -Xp * BaseSinAzimuth * BaseCosTilt - Yp * BaseCosAzimuth * BaseCosTilt + Zp * BaseSinTilt;
12912 6838 : ZLLC = Xp * BaseSinAzimuth * BaseSinTilt + Yp * BaseCosAzimuth * BaseSinTilt + Zp * BaseCosTilt;
12913 6838 : TVect = surf.Vertex(3) - surf.Vertex(2);
12914 6838 : ThisWidth = Vectors::VecLength(TVect);
12915 6838 : TVect = surf.Vertex(2) - surf.Vertex(1);
12916 6838 : ThisHeight = Vectors::VecLength(TVect);
12917 6838 : surf.Width = ThisWidth;
12918 6838 : surf.Height = ThisHeight;
12919 :
12920 : // Processing of 4-sided but non-rectangular Window, Door or GlassDoor, for use in calc of convective air flow.
12921 6838 : if (!isRectangle(state, ThisSurf)) {
12922 :
12923 : // Transform the surface into an equivalent rectangular surface with the same area and aspect ratio.
12924 1 : MakeEquivalentRectangle(state, ThisSurf, ErrorsFound);
12925 :
12926 1 : if (state.dataGlobal->DisplayExtraWarnings) {
12927 0 : ShowWarningError(state, format("{}Suspected 4-sided but non-rectangular Window, Door or GlassDoor:", RoutineName));
12928 0 : ShowContinueError(
12929 : state,
12930 0 : format("Surface={} is transformed into an equivalent rectangular surface with the same area and aspect ratio. ",
12931 0 : surf.Name));
12932 : }
12933 : }
12934 :
12935 6838 : state.dataSurfaceGeometry->Xpsv(1) = XLLC;
12936 6838 : state.dataSurfaceGeometry->Xpsv(2) = XLLC;
12937 6838 : state.dataSurfaceGeometry->Xpsv(3) = XLLC + surf.Width;
12938 6838 : state.dataSurfaceGeometry->Xpsv(4) = XLLC + surf.Width;
12939 6838 : state.dataSurfaceGeometry->Ypsv(1) = YLLC + surf.Height;
12940 6838 : state.dataSurfaceGeometry->Ypsv(4) = YLLC + surf.Height;
12941 6838 : state.dataSurfaceGeometry->Ypsv(2) = YLLC;
12942 6838 : state.dataSurfaceGeometry->Ypsv(3) = YLLC;
12943 6838 : state.dataSurfaceGeometry->Zpsv(1) = ZLLC;
12944 6838 : state.dataSurfaceGeometry->Zpsv(2) = ZLLC;
12945 6838 : state.dataSurfaceGeometry->Zpsv(3) = ZLLC;
12946 6838 : state.dataSurfaceGeometry->Zpsv(4) = ZLLC;
12947 :
12948 6838 : if (surf.Class == SurfaceClass::Window && surf.ExtBoundCond == DataSurfaces::ExternalEnvironment && surf.FrameDivider > 0) {
12949 381 : int FrDivNum = surf.FrameDivider;
12950 : // Set flag for calculating beam solar reflection from outside and/or inside window reveal
12951 0 : if ((surf.Reveal > 0.0 && state.dataSurface->FrameDivider(FrDivNum).OutsideRevealSolAbs > 0.0) ||
12952 381 : (state.dataSurface->FrameDivider(FrDivNum).InsideSillDepth > 0.0 &&
12953 762 : state.dataSurface->FrameDivider(FrDivNum).InsideSillSolAbs > 0.0) ||
12954 378 : (state.dataSurface->FrameDivider(FrDivNum).InsideReveal > 0.0 &&
12955 0 : state.dataSurface->FrameDivider(FrDivNum).InsideRevealSolAbs > 0.0)) {
12956 3 : state.dataHeatBal->CalcWindowRevealReflection = true;
12957 : }
12958 :
12959 : // For exterior window with frame, subtract frame area from base surface
12960 : // (only rectangular windows are allowed to have a frame and/or divider;
12961 : // Surface(ThisSurf)%FrameDivider will be 0 for triangular windows)
12962 381 : FrWidth = state.dataSurface->FrameDivider(FrDivNum).FrameWidth;
12963 381 : if (FrWidth > 0.0) {
12964 130 : FrArea = (surf.Height + 2.0 * FrWidth) * (surf.Width + 2.0 * FrWidth) - surf.Area / surf.Multiplier;
12965 130 : state.dataSurface->SurfWinFrameArea(ThisSurf) = FrArea * surf.Multiplier;
12966 130 : if ((state.dataSurface->Surface(surf.BaseSurf).Area - state.dataSurface->SurfWinFrameArea(ThisSurf)) <= 0.0) {
12967 0 : ShowSevereError(state, format("{}Base Surface=\"{}\", ", RoutineName, state.dataSurface->Surface(surf.BaseSurf).Name));
12968 0 : ShowContinueError(state,
12969 0 : format("Window Surface=\"{}\" area (with frame) is too large to fit on the surface.", surf.Name));
12970 0 : ShowContinueError(state,
12971 0 : format("Base surface area (-windows and doors)=[{:.2T}] m2, frame area=[{:.2T}] m2.",
12972 0 : state.dataSurface->Surface(surf.BaseSurf).Area,
12973 0 : state.dataSurface->SurfWinFrameArea(ThisSurf)));
12974 0 : ErrorInSurface = true;
12975 : }
12976 130 : state.dataSurface->Surface(surf.BaseSurf).Area -= state.dataSurface->SurfWinFrameArea(ThisSurf);
12977 : }
12978 : // If exterior window has divider, subtract divider area to get glazed area
12979 381 : DivWidth = state.dataSurface->FrameDivider(surf.FrameDivider).DividerWidth;
12980 381 : if (DivWidth > 0.0 && !ErrorInSurface) {
12981 64 : DivArea = DivWidth * (state.dataSurface->FrameDivider(FrDivNum).HorDividers * surf.Width +
12982 64 : state.dataSurface->FrameDivider(FrDivNum).VertDividers * surf.Height -
12983 64 : state.dataSurface->FrameDivider(FrDivNum).HorDividers *
12984 64 : state.dataSurface->FrameDivider(FrDivNum).VertDividers * DivWidth);
12985 64 : state.dataSurface->SurfWinDividerArea(ThisSurf) = DivArea * surf.Multiplier;
12986 64 : if ((surf.Area - state.dataSurface->SurfWinDividerArea(ThisSurf)) <= 0.0) {
12987 0 : ShowSevereError(state, format("{}Divider area exceeds glazed opening for window {}", RoutineName, surf.Name));
12988 0 : ShowContinueError(state,
12989 0 : format("Window surface area=[{:.2T}] m2, divider area=[{:.2T}] m2.",
12990 0 : surf.Area,
12991 0 : state.dataSurface->SurfWinDividerArea(ThisSurf)));
12992 0 : ErrorInSurface = true;
12993 : }
12994 64 : surf.Area -= state.dataSurface->SurfWinDividerArea(ThisSurf); // Glazed area
12995 64 : if (DivArea <= 0.0) {
12996 0 : ShowWarningError(state, format("{}Calculated Divider Area <= 0.0 for Window={}", RoutineName, surf.Name));
12997 0 : if (state.dataSurface->FrameDivider(FrDivNum).HorDividers == 0) {
12998 0 : ShowContinueError(state, "..Number of Horizontal Dividers = 0.");
12999 : }
13000 0 : if (state.dataSurface->FrameDivider(FrDivNum).VertDividers == 0) {
13001 0 : ShowContinueError(state, "..Number of Vertical Dividers = 0.");
13002 : }
13003 : } else {
13004 64 : auto &surfWin = state.dataSurface->SurfaceWindow(ThisSurf);
13005 64 : surfWin.glazedFrac = surf.Area / (surf.Area + state.dataSurface->SurfWinDividerArea(ThisSurf));
13006 : // Correction factor for portion of divider subject to divider projection correction
13007 64 : DivFrac = (1.0 - state.dataSurface->FrameDivider(FrDivNum).HorDividers *
13008 64 : state.dataSurface->FrameDivider(FrDivNum).VertDividers * pow_2(DivWidth) / DivArea);
13009 64 : state.dataSurface->SurfWinProjCorrDivOut(ThisSurf) =
13010 64 : DivFrac * state.dataSurface->FrameDivider(FrDivNum).DividerProjectionOut / DivWidth;
13011 64 : state.dataSurface->SurfWinProjCorrDivIn(ThisSurf) =
13012 64 : DivFrac * state.dataSurface->FrameDivider(FrDivNum).DividerProjectionIn / DivWidth;
13013 : // Correction factor for portion of frame subject to frame projection correction
13014 64 : if (FrWidth > 0.0) {
13015 64 : state.dataSurface->SurfWinProjCorrFrOut(ThisSurf) =
13016 64 : (state.dataSurface->FrameDivider(FrDivNum).FrameProjectionOut / FrWidth) *
13017 128 : (ThisHeight + ThisWidth -
13018 64 : (state.dataSurface->FrameDivider(FrDivNum).HorDividers +
13019 64 : state.dataSurface->FrameDivider(FrDivNum).VertDividers) *
13020 64 : DivWidth) /
13021 64 : (ThisHeight + ThisWidth + 2 * FrWidth);
13022 64 : state.dataSurface->SurfWinProjCorrFrIn(ThisSurf) =
13023 64 : (state.dataSurface->FrameDivider(FrDivNum).FrameProjectionIn / FrWidth) *
13024 128 : (ThisHeight + ThisWidth -
13025 64 : (state.dataSurface->FrameDivider(FrDivNum).HorDividers +
13026 64 : state.dataSurface->FrameDivider(FrDivNum).VertDividers) *
13027 64 : DivWidth) /
13028 64 : (ThisHeight + ThisWidth + 2 * FrWidth);
13029 : }
13030 : }
13031 : }
13032 : }
13033 6838 : } break;
13034 2 : case DataSurfaces::SurfaceShape::TriangularWindow:
13035 : case DataSurfaces::SurfaceShape::TriangularDoor: {
13036 4 : Vectors::PlaneEquation(
13037 2 : state.dataSurface->Surface(surf.BaseSurf).Vertex, state.dataSurface->Surface(surf.BaseSurf).Sides, BasePlane, SError);
13038 2 : if (SError) {
13039 0 : ShowSevereError(state, format("{}Degenerate surface (likely two vertices equal):\"{}\".", RoutineName, surf.Name));
13040 0 : ErrorInSurface = true;
13041 : }
13042 2 : ThisReveal = -Vectors::Pt2Plane(surf.Vertex(2), BasePlane);
13043 2 : if (std::abs(ThisReveal) < 0.0002) {
13044 2 : ThisReveal = 0.0;
13045 : }
13046 2 : surf.Reveal = ThisReveal;
13047 2 : Xp = surf.Vertex(2).x - BaseXLLC;
13048 2 : Yp = surf.Vertex(2).y - BaseYLLC;
13049 2 : Zp = surf.Vertex(2).z - BaseZLLC;
13050 2 : state.dataSurfaceGeometry->Xpsv(2) = -Xp * BaseCosAzimuth + Yp * BaseSinAzimuth;
13051 2 : state.dataSurfaceGeometry->Ypsv(2) = -Xp * BaseSinAzimuth * BaseCosTilt - Yp * BaseCosAzimuth * BaseCosTilt + Zp * BaseSinTilt;
13052 2 : state.dataSurfaceGeometry->Zpsv(2) = Xp * BaseSinAzimuth * BaseSinTilt + Yp * BaseCosAzimuth * BaseSinTilt + Zp * BaseCosTilt;
13053 2 : TVect = surf.Vertex(3) - surf.Vertex(2);
13054 2 : ThisWidth = Vectors::VecLength(TVect);
13055 2 : TVect = surf.Vertex(2) - surf.Vertex(1);
13056 2 : ThisHeight = Vectors::VecLength(TVect);
13057 2 : surf.Width = ThisWidth;
13058 : // Effective height and width of a triangular window for use in calc of convective air flow
13059 : // in gap between glass and shading device when shading device is present
13060 2 : surf.Height = 4.0 * surf.Area / (3.0 * surf.Width);
13061 2 : surf.Width *= 0.75;
13062 :
13063 2 : Xp = surf.Vertex(1).x - BaseXLLC;
13064 2 : Yp = surf.Vertex(1).y - BaseYLLC;
13065 2 : Zp = surf.Vertex(1).z - BaseZLLC;
13066 2 : state.dataSurfaceGeometry->Xpsv(1) = -Xp * BaseCosAzimuth + Yp * BaseSinAzimuth;
13067 2 : state.dataSurfaceGeometry->Ypsv(1) = -Xp * BaseSinAzimuth * BaseCosTilt - Yp * BaseCosAzimuth * BaseCosTilt + Zp * BaseSinTilt;
13068 2 : state.dataSurfaceGeometry->Zpsv(1) = Xp * BaseSinAzimuth * BaseSinTilt + Yp * BaseCosAzimuth * BaseSinTilt + Zp * BaseCosTilt;
13069 :
13070 2 : Xp = surf.Vertex(3).x - BaseXLLC;
13071 2 : Yp = surf.Vertex(3).y - BaseYLLC;
13072 2 : Zp = surf.Vertex(3).z - BaseZLLC;
13073 2 : state.dataSurfaceGeometry->Xpsv(3) = -Xp * BaseCosAzimuth + Yp * BaseSinAzimuth;
13074 2 : state.dataSurfaceGeometry->Ypsv(3) = -Xp * BaseSinAzimuth * BaseCosTilt - Yp * BaseCosAzimuth * BaseCosTilt + Zp * BaseSinTilt;
13075 2 : state.dataSurfaceGeometry->Zpsv(3) = Xp * BaseSinAzimuth * BaseSinTilt + Yp * BaseCosAzimuth * BaseSinTilt + Zp * BaseCosTilt;
13076 2 : } break;
13077 0 : case DataSurfaces::SurfaceShape::RectangularOverhang: {
13078 0 : Xp = surf.Vertex(2).x - BaseXLLC;
13079 0 : Yp = surf.Vertex(2).y - BaseYLLC;
13080 0 : Zp = surf.Vertex(2).z - BaseZLLC;
13081 0 : XLLC = -Xp * BaseCosAzimuth + Yp * BaseSinAzimuth;
13082 0 : YLLC = -Xp * BaseSinAzimuth * BaseCosTilt - Yp * BaseCosAzimuth * BaseCosTilt + Zp * BaseSinTilt;
13083 0 : ZLLC = Xp * BaseSinAzimuth * BaseSinTilt + Yp * BaseCosAzimuth * BaseSinTilt + Zp * BaseCosTilt;
13084 0 : TVect = surf.Vertex(3) - surf.Vertex(2);
13085 0 : ThisWidth = Vectors::VecLength(TVect);
13086 0 : TVect = surf.Vertex(2) - surf.Vertex(1);
13087 0 : ThisHeight = Vectors::VecLength(TVect);
13088 0 : surf.Width = ThisWidth;
13089 0 : surf.Height = ThisHeight;
13090 0 : state.dataSurfaceGeometry->Xpsv(1) = XLLC;
13091 0 : state.dataSurfaceGeometry->Xpsv(2) = XLLC;
13092 0 : state.dataSurfaceGeometry->Xpsv(3) = XLLC + surf.Width;
13093 0 : state.dataSurfaceGeometry->Xpsv(4) = XLLC + surf.Width;
13094 0 : state.dataSurfaceGeometry->Ypsv(1) = YLLC;
13095 0 : state.dataSurfaceGeometry->Ypsv(2) = YLLC;
13096 0 : state.dataSurfaceGeometry->Ypsv(3) = YLLC;
13097 0 : state.dataSurfaceGeometry->Ypsv(4) = YLLC;
13098 0 : state.dataSurfaceGeometry->Zpsv(1) = surf.Height;
13099 0 : state.dataSurfaceGeometry->Zpsv(4) = surf.Height;
13100 0 : state.dataSurfaceGeometry->Zpsv(2) = 0.0;
13101 0 : state.dataSurfaceGeometry->Zpsv(3) = 0.0;
13102 0 : } break;
13103 0 : case DataSurfaces::SurfaceShape::RectangularLeftFin: {
13104 0 : Xp = surf.Vertex(2).x - BaseXLLC;
13105 0 : Yp = surf.Vertex(2).y - BaseYLLC;
13106 0 : Zp = surf.Vertex(2).z - BaseZLLC;
13107 0 : XLLC = -Xp * BaseCosAzimuth + Yp * BaseSinAzimuth;
13108 0 : YLLC = -Xp * BaseSinAzimuth * BaseCosTilt - Yp * BaseCosAzimuth * BaseCosTilt + Zp * BaseSinTilt;
13109 0 : ZLLC = Xp * BaseSinAzimuth * BaseSinTilt + Yp * BaseCosAzimuth * BaseSinTilt + Zp * BaseCosTilt;
13110 0 : TVect = surf.Vertex(3) - surf.Vertex(2);
13111 0 : ThisWidth = Vectors::VecLength(TVect);
13112 0 : TVect = surf.Vertex(2) - surf.Vertex(1);
13113 0 : ThisHeight = Vectors::VecLength(TVect);
13114 0 : surf.Width = ThisWidth;
13115 0 : surf.Height = ThisHeight;
13116 0 : state.dataSurfaceGeometry->Xpsv(1) = XLLC;
13117 0 : state.dataSurfaceGeometry->Xpsv(2) = XLLC;
13118 0 : state.dataSurfaceGeometry->Xpsv(3) = XLLC;
13119 0 : state.dataSurfaceGeometry->Xpsv(4) = XLLC;
13120 0 : state.dataSurfaceGeometry->Ypsv(1) = YLLC;
13121 0 : state.dataSurfaceGeometry->Ypsv(2) = YLLC;
13122 0 : state.dataSurfaceGeometry->Ypsv(3) = YLLC + surf.Width;
13123 0 : state.dataSurfaceGeometry->Ypsv(4) = YLLC + surf.Width;
13124 0 : state.dataSurfaceGeometry->Zpsv(1) = surf.Height;
13125 0 : state.dataSurfaceGeometry->Zpsv(4) = surf.Height;
13126 0 : state.dataSurfaceGeometry->Zpsv(2) = 0.0;
13127 0 : state.dataSurfaceGeometry->Zpsv(3) = 0.0;
13128 0 : } break;
13129 0 : case DataSurfaces::SurfaceShape::RectangularRightFin: {
13130 0 : Xp = surf.Vertex(2).x - BaseXLLC;
13131 0 : Yp = surf.Vertex(2).y - BaseYLLC;
13132 0 : Zp = surf.Vertex(2).z - BaseZLLC;
13133 0 : XLLC = -Xp * BaseCosAzimuth + Yp * BaseSinAzimuth;
13134 0 : YLLC = -Xp * BaseSinAzimuth * BaseCosTilt - Yp * BaseCosAzimuth * BaseCosTilt + Zp * BaseSinTilt;
13135 0 : ZLLC = Xp * BaseSinAzimuth * BaseSinTilt + Yp * BaseCosAzimuth * BaseSinTilt + Zp * BaseCosTilt;
13136 0 : TVect = surf.Vertex(3) - surf.Vertex(2);
13137 0 : ThisWidth = Vectors::VecLength(TVect);
13138 0 : TVect = surf.Vertex(2) - surf.Vertex(1);
13139 0 : ThisHeight = Vectors::VecLength(TVect);
13140 0 : surf.Width = ThisWidth;
13141 0 : surf.Height = ThisHeight;
13142 0 : state.dataSurfaceGeometry->Xpsv(1) = XLLC;
13143 0 : state.dataSurfaceGeometry->Xpsv(2) = XLLC;
13144 0 : state.dataSurfaceGeometry->Xpsv(3) = XLLC;
13145 0 : state.dataSurfaceGeometry->Xpsv(4) = XLLC;
13146 0 : state.dataSurfaceGeometry->Ypsv(1) = YLLC + surf.Width;
13147 0 : state.dataSurfaceGeometry->Ypsv(2) = YLLC + surf.Width;
13148 0 : state.dataSurfaceGeometry->Ypsv(3) = YLLC;
13149 0 : state.dataSurfaceGeometry->Ypsv(4) = YLLC;
13150 0 : state.dataSurfaceGeometry->Zpsv(1) = surf.Height;
13151 0 : state.dataSurfaceGeometry->Zpsv(4) = surf.Height;
13152 0 : state.dataSurfaceGeometry->Zpsv(2) = 0.0;
13153 0 : state.dataSurfaceGeometry->Zpsv(3) = 0.0;
13154 0 : } break;
13155 0 : default: {
13156 : // Error Condition
13157 0 : ShowSevereError(state, format("{}Incorrect surface shape number.", RoutineName), OptionalOutputFileRef{state.files.eso});
13158 0 : ShowContinueError(state, "Please notify EnergyPlus support of this error and send input file.");
13159 0 : ErrorInSurface = true;
13160 0 : } break;
13161 : }
13162 :
13163 34198 : for (n = 1; n <= surf.Sides; ++n) {
13164 : // if less than 1/10 inch
13165 27358 : state.dataSurfaceGeometry->Xpsv(n) = nint64(10000.0 * state.dataSurfaceGeometry->Xpsv(n)) / 10000.0;
13166 27358 : if (std::abs(state.dataSurfaceGeometry->Xpsv(n)) < 0.0025) {
13167 1096 : state.dataSurfaceGeometry->Xpsv(n) = 0.0;
13168 : }
13169 27358 : state.dataSurfaceGeometry->Ypsv(n) = nint64(10000.0 * state.dataSurfaceGeometry->Ypsv(n)) / 10000.0;
13170 27358 : if (std::abs(state.dataSurfaceGeometry->Ypsv(n)) < 0.0025) {
13171 2076 : state.dataSurfaceGeometry->Ypsv(n) = 0.0;
13172 : }
13173 27358 : state.dataSurfaceGeometry->Zpsv(n) = nint64(10000.0 * state.dataSurfaceGeometry->Zpsv(n)) / 10000.0;
13174 27358 : if (std::abs(state.dataSurfaceGeometry->Zpsv(n)) < 0.0025) {
13175 26770 : state.dataSurfaceGeometry->Zpsv(n) = 0.0;
13176 : }
13177 : }
13178 :
13179 6840 : surf.Shape = ThisShape;
13180 :
13181 : } // End of check if ThisSurf is a base surface
13182 :
13183 44753 : if (ErrorInSurface) {
13184 0 : ErrorsFound = true;
13185 0 : return;
13186 : }
13187 :
13188 : // Transfer to XV,YV,ZV arrays
13189 :
13190 44753 : state.dataSurface->ShadeV(ThisSurf).NVert = surf.Sides;
13191 44753 : state.dataSurface->ShadeV(ThisSurf).XV.allocate(surf.Sides);
13192 44753 : state.dataSurface->ShadeV(ThisSurf).YV.allocate(surf.Sides);
13193 44753 : state.dataSurface->ShadeV(ThisSurf).ZV.allocate(surf.Sides);
13194 :
13195 224606 : for (n = 1; n <= surf.Sides; ++n) {
13196 : // if less than 1/10 inch
13197 179853 : state.dataSurface->ShadeV(ThisSurf).XV(n) = state.dataSurfaceGeometry->Xpsv(n);
13198 179853 : state.dataSurface->ShadeV(ThisSurf).YV(n) = state.dataSurfaceGeometry->Ypsv(n);
13199 179853 : state.dataSurface->ShadeV(ThisSurf).ZV(n) = state.dataSurfaceGeometry->Zpsv(n);
13200 : }
13201 :
13202 : // Process Surfaces According to Type of Coordinate Origin.
13203 44753 : if (BaseSurface) {
13204 :
13205 : // General Surfaces:
13206 37913 : CalcCoordinateTransformation(state, ThisSurf, CoordinateTransVector); // X00,Y00,Z00,X,Y,Z,A) ! Compute Coordinate Transformation
13207 :
13208 : // RECORD DIRECTION COSINES.
13209 37913 : if (HeatTransSurf) { // This is a general surface but not detached shading surface
13210 :
13211 : // RECORD COORDINATE TRANSFORMATION FOR BASE SURFACES.
13212 37895 : state.dataSurface->X0(ThisBaseSurface) = CoordinateTransVector.x;
13213 37895 : state.dataSurface->Y0(ThisBaseSurface) = CoordinateTransVector.y;
13214 37895 : state.dataSurface->Z0(ThisBaseSurface) = CoordinateTransVector.z;
13215 :
13216 : // COMPUTE INVERSE TRANSFORMATION.
13217 37895 : X1 = state.dataSurfaceGeometry->Xpsv(2) - CoordinateTransVector.x;
13218 37895 : Y1 = state.dataSurfaceGeometry->Ypsv(2) - CoordinateTransVector.y;
13219 37895 : Z1 = state.dataSurfaceGeometry->Zpsv(2) - CoordinateTransVector.z;
13220 : // Store the relative coordinate shift values for later use by any subsurfaces
13221 75790 : state.dataSurface->Surface(ThisBaseSurface).XShift = state.dataSurface->Surface(ThisBaseSurface).lcsx.x * X1 +
13222 37895 : state.dataSurface->Surface(ThisBaseSurface).lcsx.y * Y1 +
13223 37895 : state.dataSurface->Surface(ThisBaseSurface).lcsx.z * Z1;
13224 75790 : state.dataSurface->Surface(ThisBaseSurface).YShift = state.dataSurface->Surface(ThisBaseSurface).lcsy.x * X1 +
13225 37895 : state.dataSurface->Surface(ThisBaseSurface).lcsy.y * Y1 +
13226 37895 : state.dataSurface->Surface(ThisBaseSurface).lcsy.z * Z1;
13227 37895 : state.dataSurface->Surface(ThisBaseSurface).VerticesProcessed = true;
13228 : }
13229 :
13230 : // SUBSURFACES: (Surface(ThisSurf)%BaseSurf /= ThisSurf)
13231 : } else {
13232 : // WINDOWS OR DOORS:
13233 :
13234 : // SHIFT RELATIVE COORDINATES FROM LOWER LEFT CORNER TO ORIGIN DEFINED
13235 : // BY CTRAN AND SET DIRECTION COSINES SAME AS BASE SURFACE.
13236 6840 : if (!state.dataSurface->Surface(ThisBaseSurface).VerticesProcessed) {
13237 :
13238 0 : if (surf.IsAirBoundarySurf) {
13239 0 : ProcessSurfaceVertices(state, ThisBaseSurface, ErrorsFound);
13240 : } else {
13241 :
13242 0 : ShowSevereError(state, format("{}Developer error for Subsurface={}", RoutineName, surf.Name));
13243 0 : ShowContinueError(state,
13244 0 : format("Base surface={} vertices must be processed before any subsurfaces.",
13245 0 : state.dataSurface->Surface(ThisBaseSurface).Name));
13246 0 : ShowFatalError(state, std::string{RoutineName});
13247 : }
13248 : }
13249 :
13250 34198 : for (n = 1; n <= surf.Sides; ++n) {
13251 27358 : state.dataSurface->ShadeV(ThisSurf).XV(n) += state.dataSurface->Surface(ThisBaseSurface).XShift;
13252 27358 : state.dataSurface->ShadeV(ThisSurf).YV(n) += state.dataSurface->Surface(ThisBaseSurface).YShift;
13253 : }
13254 : }
13255 44753 : }
13256 :
13257 37913 : void CalcCoordinateTransformation(EnergyPlusData &state,
13258 : int const SurfNum, // Surface Number
13259 : Vector &CompCoordTranslVector // Coordinate Translation Vector
13260 : )
13261 : {
13262 : // SUBROUTINE INFORMATION:
13263 : // AUTHOR George Walton, BLAST
13264 : // DATE WRITTEN August 1976
13265 : // MODIFIED LKL, May 2004 -- >4 sided polygons
13266 : // RE-ENGINEERED Yes
13267 :
13268 : // PURPOSE OF THIS SUBROUTINE:
13269 : // This subroutine develops a coordinate transformation such that the X-axis goes
13270 : // through points 2 and 3 and the Y-axis goes through point 1
13271 : // of a plane figure in 3-d space.
13272 :
13273 : // REFERENCES:
13274 : // 'NECAP' - NASA'S Energy-Cost Analysis Program
13275 :
13276 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
13277 : Real64 Gamma; // Intermediate Result
13278 : Real64 DotSelfX23;
13279 :
13280 : // Object Data
13281 37913 : Vector x21;
13282 37913 : Vector x23;
13283 :
13284 : // Determine Components of the Coordinate Translation Vector.
13285 37913 : auto const &surf = state.dataSurface->Surface(SurfNum);
13286 :
13287 37913 : x21 = surf.Vertex(2) - surf.Vertex(1);
13288 37913 : x23 = surf.Vertex(2) - surf.Vertex(3);
13289 :
13290 37913 : DotSelfX23 = magnitude_squared(x23);
13291 :
13292 37913 : if (DotSelfX23 <= Constant::OneMillionth) {
13293 0 : ShowSevereError(state, format("CalcCoordinateTransformation: Invalid dot product, surface=\"{}\":", surf.Name));
13294 0 : for (int I = 1; I <= surf.Sides; ++I) {
13295 0 : auto const &point = surf.Vertex(I);
13296 0 : ShowContinueError(state, format(" ({:8.3F},{:8.3F},{:8.3F})", point.x, point.y, point.z));
13297 : }
13298 0 : ShowFatalError(
13299 0 : state, "CalcCoordinateTransformation: Program terminates due to preceding condition.", OptionalOutputFileRef{state.files.eso});
13300 0 : return;
13301 : }
13302 :
13303 37913 : Gamma = dot(x21, x23) / magnitude_squared(x23);
13304 :
13305 37913 : CompCoordTranslVector = surf.Vertex(2) + Gamma * (surf.Vertex(3) - surf.Vertex(2));
13306 37913 : }
13307 :
13308 18 : void CreateShadedWindowConstruction(EnergyPlusData &state,
13309 : int const SurfNum, // Surface number
13310 : int const WSCPtr, // Pointer to WindowShadingControl for SurfNum
13311 : int const ShDevNum, // Shading device material number for WSCptr
13312 : int const shadeControlIndex // index to the Surface().windowShadingControlList,
13313 : // Surface().shadedConstructionList, and Surface().shadedStormWinConstructionList
13314 : )
13315 : {
13316 : // SUBROUTINE INFORMATION:
13317 : // AUTHOR Fred Winkelmann
13318 : // DATE WRITTEN Nov 2001
13319 :
13320 : // PURPOSE OF THIS SUBROUTINE:
13321 : // Creates a shaded window construction for windows whose WindowShadingControl
13322 : // has a shading device specified instead of a shaded construction
13323 :
13324 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
13325 : int ConstrNewSh; // Number of shaded construction that is created
13326 18 : std::string ConstrNameSh; // Shaded construction name
13327 :
13328 18 : auto &s_mat = state.dataMaterial;
13329 18 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
13330 :
13331 18 : std::string const &ShDevName = s_mat->materials(ShDevNum)->Name;
13332 18 : int ConstrNum = surfTemp.Construction;
13333 18 : std::string const &ConstrName = state.dataConstruction->Construct(ConstrNum).Name;
13334 :
13335 18 : if (ANY_INTERIOR_SHADE_BLIND(state.dataSurface->WindowShadingControl(WSCPtr).ShadingType)) {
13336 18 : ConstrNameSh = ConstrName + ':' + ShDevName + ":INT";
13337 : } else {
13338 0 : ConstrNameSh = ConstrName + ':' + ShDevName + ":EXT";
13339 : }
13340 :
13341 : // If this construction name already exists, set the surface's shaded construction number to it
13342 :
13343 18 : ConstrNewSh = Util::FindItemInList(ConstrNameSh, state.dataConstruction->Construct);
13344 :
13345 18 : if (ConstrNewSh > 0) {
13346 0 : surfTemp.shadedConstructionList[shadeControlIndex] = ConstrNewSh;
13347 0 : surfTemp.activeShadedConstruction = ConstrNewSh; // set the active to the current for now
13348 : } else {
13349 :
13350 : // Create new construction
13351 :
13352 18 : ConstrNewSh = state.dataHeatBal->TotConstructs + 1;
13353 18 : surfTemp.shadedConstructionList[shadeControlIndex] = ConstrNewSh;
13354 18 : surfTemp.activeShadedConstruction = ConstrNewSh; // set the active to the current for now
13355 18 : state.dataHeatBal->TotConstructs = ConstrNewSh;
13356 18 : state.dataConstruction->Construct.redimension(state.dataHeatBal->TotConstructs);
13357 18 : state.dataHeatBal->NominalRforNominalUCalculation.redimension(state.dataHeatBal->TotConstructs);
13358 18 : state.dataHeatBal->NominalRforNominalUCalculation(state.dataHeatBal->TotConstructs) = 0.0;
13359 18 : state.dataHeatBal->NominalU.redimension(state.dataHeatBal->TotConstructs);
13360 18 : state.dataHeatBal->NominalU(state.dataHeatBal->TotConstructs) = 0.0;
13361 18 : state.dataHeatBal->NominalUBeforeAdjusted.redimension(state.dataHeatBal->TotConstructs);
13362 18 : state.dataHeatBal->CoeffAdjRatio.redimension(state.dataHeatBal->TotConstructs) = 1.0;
13363 :
13364 18 : state.dataConstruction->Construct(state.dataHeatBal->TotConstructs).setArraysBasedOnMaxSolidWinLayers(state);
13365 :
13366 18 : int TotLayersOld = state.dataConstruction->Construct(ConstrNum).TotLayers;
13367 18 : int TotLayersNew = TotLayersOld + 1;
13368 :
13369 18 : state.dataConstruction->Construct(ConstrNewSh).LayerPoint = 0;
13370 :
13371 18 : auto const *thisMaterialSh = s_mat->materials(ShDevNum);
13372 18 : auto &thisConstructNewSh = state.dataConstruction->Construct(ConstrNewSh);
13373 18 : if (state.dataSurface->WindowShadingControl(WSCPtr).ShadingType == DataSurfaces::WinShadingType::IntShade ||
13374 0 : state.dataSurface->WindowShadingControl(WSCPtr).ShadingType == DataSurfaces::WinShadingType::IntBlind) {
13375 : // Interior shading device
13376 18 : thisConstructNewSh.LayerPoint({1, TotLayersOld}) = state.dataConstruction->Construct(ConstrNum).LayerPoint({1, TotLayersOld});
13377 18 : thisConstructNewSh.LayerPoint(TotLayersNew) = ShDevNum;
13378 18 : thisConstructNewSh.InsideAbsorpSolar = thisMaterialSh->AbsorpSolar;
13379 18 : auto const *thisMaterialShLayer1 = s_mat->materials(state.dataConstruction->Construct(ConstrNewSh).LayerPoint(1));
13380 18 : thisConstructNewSh.OutsideAbsorpSolar = thisMaterialShLayer1->AbsorpSolar;
13381 18 : thisConstructNewSh.OutsideAbsorpThermal = thisMaterialShLayer1->AbsorpThermalFront;
13382 : } else {
13383 : // Exterior shading device
13384 0 : thisConstructNewSh.LayerPoint(1) = ShDevNum;
13385 0 : thisConstructNewSh.LayerPoint({2, TotLayersNew}) = state.dataConstruction->Construct(ConstrNum).LayerPoint({1, TotLayersOld});
13386 0 : auto const *thisMaterialShInside = s_mat->materials(state.dataConstruction->Construct(ConstrNewSh).LayerPoint(TotLayersNew));
13387 0 : thisConstructNewSh.InsideAbsorpSolar = thisMaterialShInside->AbsorpSolar;
13388 0 : thisConstructNewSh.OutsideAbsorpSolar = thisMaterialSh->AbsorpSolar;
13389 0 : thisConstructNewSh.OutsideAbsorpThermal = thisMaterialSh->AbsorpThermalFront;
13390 : }
13391 : // The following InsideAbsorpThermal applies only to inside glass; it is corrected
13392 : // later in InitGlassOpticalCalculations if construction has inside shade or blind.
13393 18 : thisConstructNewSh.InsideAbsorpThermal =
13394 18 : s_mat->materials(state.dataConstruction->Construct(ConstrNum).LayerPoint(TotLayersOld))->AbsorpThermalBack;
13395 18 : thisConstructNewSh.OutsideRoughness = Material::SurfaceRoughness::VerySmooth;
13396 18 : thisConstructNewSh.DayltPropPtr = 0;
13397 18 : thisConstructNewSh.CTFCross.fill(0.0);
13398 18 : thisConstructNewSh.CTFFlux.fill(0.0);
13399 18 : thisConstructNewSh.CTFInside.fill(0.0);
13400 18 : thisConstructNewSh.CTFOutside.fill(0.0);
13401 18 : thisConstructNewSh.CTFSourceIn.fill(0.0);
13402 18 : thisConstructNewSh.CTFSourceOut.fill(0.0);
13403 18 : thisConstructNewSh.CTFTimeStep = 0.0;
13404 18 : thisConstructNewSh.CTFTSourceOut.fill(0.0);
13405 18 : thisConstructNewSh.CTFTSourceIn.fill(0.0);
13406 18 : thisConstructNewSh.CTFTSourceQ.fill(0.0);
13407 18 : thisConstructNewSh.CTFTUserOut.fill(0.0);
13408 18 : thisConstructNewSh.CTFTUserIn.fill(0.0);
13409 18 : thisConstructNewSh.CTFTUserSource.fill(0.0);
13410 18 : thisConstructNewSh.NumHistories = 0;
13411 18 : thisConstructNewSh.NumCTFTerms = 0;
13412 18 : thisConstructNewSh.UValue = 0.0;
13413 18 : thisConstructNewSh.SourceSinkPresent = false;
13414 18 : thisConstructNewSh.SolutionDimensions = 0;
13415 18 : thisConstructNewSh.SourceAfterLayer = 0;
13416 18 : thisConstructNewSh.TempAfterLayer = 0;
13417 18 : thisConstructNewSh.ThicknessPerpend = 0.0;
13418 18 : thisConstructNewSh.AbsDiff = 0.0;
13419 18 : thisConstructNewSh.AbsDiffBack = 0.0;
13420 18 : thisConstructNewSh.AbsDiffShade = 0.0;
13421 18 : thisConstructNewSh.AbsDiffBackShade = 0.0;
13422 18 : thisConstructNewSh.ShadeAbsorpThermal = 0.0;
13423 18 : std::fill(thisConstructNewSh.AbsBeamShadeCoef.begin(), thisConstructNewSh.AbsBeamShadeCoef.end(), 0.0);
13424 18 : thisConstructNewSh.TransDiff = 0.0;
13425 18 : thisConstructNewSh.TransDiffVis = 0.0;
13426 18 : thisConstructNewSh.ReflectSolDiffBack = 0.0;
13427 18 : thisConstructNewSh.ReflectSolDiffFront = 0.0;
13428 18 : thisConstructNewSh.ReflectVisDiffBack = 0.0;
13429 18 : thisConstructNewSh.ReflectVisDiffFront = 0.0;
13430 18 : std::fill(thisConstructNewSh.TransSolBeamCoef.begin(), thisConstructNewSh.TransSolBeamCoef.end(), 0.0);
13431 18 : std::fill(thisConstructNewSh.TransVisBeamCoef.begin(), thisConstructNewSh.TransVisBeamCoef.end(), 0.0);
13432 18 : std::fill(thisConstructNewSh.ReflSolBeamFrontCoef.begin(), thisConstructNewSh.ReflSolBeamFrontCoef.end(), 0.0);
13433 18 : std::fill(thisConstructNewSh.ReflSolBeamBackCoef.begin(), thisConstructNewSh.ReflSolBeamBackCoef.end(), 0.0);
13434 18 : thisConstructNewSh.W5FrameDivider = 0;
13435 18 : thisConstructNewSh.FromWindow5DataFile = false;
13436 :
13437 18 : thisConstructNewSh.Name = ConstrNameSh;
13438 18 : thisConstructNewSh.TotLayers = TotLayersNew;
13439 18 : thisConstructNewSh.TotSolidLayers = state.dataConstruction->Construct(ConstrNum).TotSolidLayers + 1;
13440 18 : thisConstructNewSh.TotGlassLayers = state.dataConstruction->Construct(ConstrNum).TotGlassLayers;
13441 18 : thisConstructNewSh.TypeIsWindow = true;
13442 18 : thisConstructNewSh.IsUsed = true;
13443 :
13444 144 : for (int Layer = 1; Layer <= state.dataHeatBal->MaxSolidWinLayers; ++Layer) {
13445 126 : std::fill(thisConstructNewSh.AbsBeamCoef(Layer).begin(), thisConstructNewSh.AbsBeamCoef(Layer).end(), 0.0);
13446 126 : std::fill(thisConstructNewSh.AbsBeamBackCoef(Layer).begin(), thisConstructNewSh.AbsBeamBackCoef(Layer).end(), 0.0);
13447 : }
13448 : }
13449 18 : }
13450 :
13451 1 : void CreateStormWindowConstructions(EnergyPlusData &state)
13452 : {
13453 : // For windows with an associated StormWindow object, creates a construction
13454 : // consisting of the base construction plus a storm window and air gap on the outside.
13455 : // If the window has an interior or between-glass shade/blind, also creates a
13456 : // construction consisting of the storm window added to the shaded construction.
13457 1 : DisplayString(state, "Creating Storm Window Constructions");
13458 :
13459 1 : auto &s_mat = state.dataMaterial;
13460 :
13461 2 : for (int StormWinNum = 1; StormWinNum <= state.dataSurface->TotStormWin; ++StormWinNum) {
13462 1 : int SurfNum = state.dataSurface->StormWindow(StormWinNum).BaseWindowNum; // Surface number
13463 1 : auto &surf = state.dataSurface->Surface(SurfNum);
13464 1 : int ConstrNum = surf.Construction; // Number of unshaded construction
13465 : // Fatal error if base construction has more than three glass layers
13466 1 : if (state.dataConstruction->Construct(ConstrNum).TotGlassLayers > 3) {
13467 0 : ShowFatalError(state, format("Window={} has more than 3 glass layers; a storm window cannot be applied.", surf.Name));
13468 : }
13469 :
13470 : // create unshaded construction with storm window
13471 1 : const std::string ChrNum = fmt::to_string(StormWinNum);
13472 1 : std::string ConstrNameSt = "BARECONSTRUCTIONWITHSTORMWIN:" + ChrNum; // Name of unshaded construction with storm window
13473 : // If this construction name already exists, set the surface's storm window construction number to it
13474 1 : int ConstrNewSt = Util::FindItemInList(ConstrNameSt,
13475 1 : state.dataConstruction->Construct,
13476 1 : state.dataHeatBal->TotConstructs); // Number of unshaded storm window construction that is created
13477 : // If necessary, create new material corresponding to the air layer between the storm window and the rest of the window
13478 1 : int MatNewStAir = createAirMaterialFromDistance(state, state.dataSurface->StormWindow(StormWinNum).StormWinDistance, "AIR:STORMWIN:");
13479 1 : if (ConstrNewSt == 0) {
13480 1 : ConstrNewSt = createConstructionWithStorm(
13481 1 : state, ConstrNum, ConstrNameSt, state.dataSurface->StormWindow(StormWinNum).StormWinMaterialNum, MatNewStAir);
13482 : }
13483 1 : state.dataSurface->SurfWinStormWinConstr(SurfNum) = ConstrNewSt;
13484 :
13485 : // create shaded constructions with storm window
13486 1 : surf.shadedStormWinConstructionList.resize(surf.shadedConstructionList.size(),
13487 1 : 0); // make the shaded storm window size the same size as the number of shaded constructions
13488 1 : for (std::size_t iConstruction = 0; iConstruction < surf.shadedConstructionList.size(); ++iConstruction) {
13489 0 : int curConstruction = surf.shadedConstructionList[iConstruction];
13490 : // Set ShAndSt, which is true if the window has a shaded construction to which a storm window
13491 : // can be added. (A storm window can be added if there is an interior shade or blind and up to three
13492 : // glass layers, or there is a between-glass shade or blind and two glass layers.)
13493 0 : bool ShAndSt = false; // True if unshaded and shaded window can have a storm window
13494 0 : int TotLayers = state.dataConstruction->Construct(curConstruction).TotLayers; // Total layers in a construction
13495 0 : int MatIntSh = state.dataConstruction->Construct(curConstruction).LayerPoint(TotLayers); // Material number of interior shade or blind
13496 0 : int MatBetweenGlassSh = 0; // Material number of between-glass shade or blind
13497 0 : if (TotLayers == 5) {
13498 0 : MatBetweenGlassSh = state.dataConstruction->Construct(curConstruction).LayerPoint(3);
13499 : }
13500 0 : if (state.dataConstruction->Construct(curConstruction).TotGlassLayers <= 3 &&
13501 0 : (s_mat->materials(MatIntSh)->group == Material::Group::Shade || s_mat->materials(MatIntSh)->group == Material::Group::Blind)) {
13502 0 : ShAndSt = true;
13503 : }
13504 0 : if (MatBetweenGlassSh > 0) {
13505 0 : if (s_mat->materials(MatBetweenGlassSh)->group == Material::Group::Shade ||
13506 0 : s_mat->materials(MatBetweenGlassSh)->group == Material::Group::Blind) {
13507 0 : ShAndSt = true;
13508 : } else {
13509 0 : ShowContinueError(state, format("Window={} has a shaded construction to which a storm window cannot be applied.", surf.Name));
13510 0 : ShowContinueError(state, "Storm windows can only be applied to shaded constructions that:");
13511 0 : ShowContinueError(state, "have an interior shade or blind and up to three glass layers, or");
13512 0 : ShowContinueError(state, "have a between-glass shade or blind and two glass layers.");
13513 0 : ShowFatalError(state, "EnergyPlus is exiting due to reason stated above.");
13514 : }
13515 : }
13516 0 : if (ShAndSt) {
13517 0 : std::string ConstrNameStSh = "SHADEDCONSTRUCTIONWITHSTORMWIN:" + state.dataConstruction->Construct(iConstruction).Name + ":" +
13518 0 : ChrNum; // Name of shaded construction with storm window
13519 0 : int ConstrNewStSh = createConstructionWithStorm(
13520 0 : state, ConstrNum, ConstrNameStSh, state.dataSurface->StormWindow(StormWinNum).StormWinMaterialNum, MatNewStAir);
13521 0 : surf.shadedStormWinConstructionList[iConstruction] = ConstrNewStSh; // put in same index as the shaded construction
13522 0 : }
13523 : } // end of loop for shaded constructions
13524 1 : } // end of loop over storm window objects
13525 1 : }
13526 :
13527 1 : int createAirMaterialFromDistance(EnergyPlusData &state, Real64 distance, std::string_view namePrefix)
13528 : {
13529 1 : auto const &s_mat = state.dataMaterial;
13530 :
13531 1 : int mmDistance = int(1000 * distance); // Thickness of air gap in mm (usually between storm window and rest of window)
13532 1 : std::string MatNameStAir = format("{}{}MM", namePrefix, mmDistance); // Name of created air layer material
13533 1 : int matNum = Material::GetMaterialNum(state, MatNameStAir);
13534 1 : if (matNum != 0) {
13535 0 : return matNum;
13536 : }
13537 :
13538 : // Create new material
13539 1 : auto *mat = new Material::MaterialGasMix;
13540 1 : mat->Name = MatNameStAir;
13541 1 : mat->group = Material::Group::Gas;
13542 :
13543 1 : s_mat->materials.push_back(mat);
13544 1 : mat->Num = s_mat->materials.isize();
13545 1 : s_mat->materialMap.insert_or_assign(Util::makeUPPER(mat->Name), mat->Num);
13546 :
13547 1 : mat->Roughness = Material::SurfaceRoughness::MediumRough;
13548 1 : mat->Conductivity = 0.0;
13549 1 : mat->Density = 0.0;
13550 1 : mat->Resistance = 0.0;
13551 1 : mat->SpecHeat = 0.0;
13552 1 : mat->Thickness = distance;
13553 1 : mat->numGases = 1;
13554 1 : mat->gases[0] = Material::gases[(int)Material::GasType::Air];
13555 1 : mat->gasFracts[0] = 1.0;
13556 1 : mat->AbsorpSolar = 0.0;
13557 1 : mat->AbsorpThermal = 0.0;
13558 1 : mat->AbsorpVisible = 0.0;
13559 1 : return mat->Num;
13560 1 : }
13561 :
13562 : // create a new construction with storm based on an old construction and storm and gap materials
13563 1 : int createConstructionWithStorm(EnergyPlusData &state, int oldConstruction, std::string name, int stormMaterial, int gapMaterial)
13564 : {
13565 1 : int newConstruct = Util::FindItemInList(name,
13566 1 : state.dataConstruction->Construct,
13567 1 : state.dataHeatBal->TotConstructs); // Number of shaded storm window construction that is created
13568 1 : if (newConstruct == 0) {
13569 1 : auto &s_mat = state.dataMaterial;
13570 1 : state.dataHeatBal->TotConstructs = state.dataHeatBal->TotConstructs + 1;
13571 1 : newConstruct = state.dataHeatBal->TotConstructs;
13572 1 : state.dataConstruction->Construct.redimension(state.dataHeatBal->TotConstructs);
13573 1 : state.dataHeatBal->NominalRforNominalUCalculation.redimension(state.dataHeatBal->TotConstructs);
13574 1 : state.dataHeatBal->NominalU.redimension(state.dataHeatBal->TotConstructs);
13575 1 : state.dataHeatBal->NominalUBeforeAdjusted.redimension(state.dataHeatBal->TotConstructs);
13576 1 : state.dataHeatBal->CoeffAdjRatio.redimension(state.dataHeatBal->TotConstructs) = 1.0;
13577 :
13578 1 : auto &thisConstruct = state.dataConstruction->Construct(state.dataHeatBal->TotConstructs);
13579 : // these Construct arrays dimensioned based on MaxSolidWinLayers
13580 1 : thisConstruct.setArraysBasedOnMaxSolidWinLayers(state);
13581 :
13582 1 : int TotLayersOld = state.dataConstruction->Construct(oldConstruction).TotLayers;
13583 1 : thisConstruct.LayerPoint({1, Construction::MaxLayersInConstruct}) = 0;
13584 1 : thisConstruct.LayerPoint(1) = stormMaterial;
13585 1 : thisConstruct.LayerPoint(2) = gapMaterial;
13586 1 : thisConstruct.LayerPoint({3, TotLayersOld + 2}) = state.dataConstruction->Construct(oldConstruction).LayerPoint({1, TotLayersOld});
13587 1 : thisConstruct.Name = name;
13588 1 : thisConstruct.TotLayers = TotLayersOld + 2;
13589 1 : thisConstruct.TotSolidLayers = state.dataConstruction->Construct(oldConstruction).TotSolidLayers + 1;
13590 1 : thisConstruct.TotGlassLayers = state.dataConstruction->Construct(oldConstruction).TotGlassLayers + 1;
13591 1 : thisConstruct.TypeIsWindow = true;
13592 1 : thisConstruct.InsideAbsorpVis = 0.0;
13593 1 : thisConstruct.OutsideAbsorpVis = 0.0;
13594 1 : thisConstruct.InsideAbsorpSolar = 0.0;
13595 1 : thisConstruct.OutsideAbsorpSolar = 0.0;
13596 1 : thisConstruct.InsideAbsorpThermal = state.dataConstruction->Construct(oldConstruction).InsideAbsorpThermal;
13597 1 : thisConstruct.OutsideAbsorpThermal = s_mat->materials(stormMaterial)->AbsorpThermalFront;
13598 1 : thisConstruct.OutsideRoughness = Material::SurfaceRoughness::VerySmooth;
13599 1 : thisConstruct.DayltPropPtr = 0;
13600 1 : thisConstruct.CTFCross.fill(0.0);
13601 1 : thisConstruct.CTFFlux.fill(0.0);
13602 1 : thisConstruct.CTFInside.fill(0.0);
13603 1 : thisConstruct.CTFOutside.fill(0.0);
13604 1 : thisConstruct.CTFSourceIn.fill(0.0);
13605 1 : thisConstruct.CTFSourceOut.fill(0.0);
13606 1 : thisConstruct.CTFTimeStep = 0.0;
13607 1 : thisConstruct.CTFTSourceOut.fill(0.0);
13608 1 : thisConstruct.CTFTSourceIn.fill(0.0);
13609 1 : thisConstruct.CTFTSourceQ.fill(0.0);
13610 1 : thisConstruct.CTFTUserOut.fill(0.0);
13611 1 : thisConstruct.CTFTUserIn.fill(0.0);
13612 1 : thisConstruct.CTFTUserSource.fill(0.0);
13613 1 : thisConstruct.NumHistories = 0;
13614 1 : thisConstruct.NumCTFTerms = 0;
13615 1 : thisConstruct.UValue = 0.0;
13616 1 : thisConstruct.SourceSinkPresent = false;
13617 1 : thisConstruct.SolutionDimensions = 0;
13618 1 : thisConstruct.SourceAfterLayer = 0;
13619 1 : thisConstruct.TempAfterLayer = 0;
13620 1 : thisConstruct.ThicknessPerpend = 0.0;
13621 1 : thisConstruct.AbsDiffIn = 0.0;
13622 1 : thisConstruct.AbsDiffOut = 0.0;
13623 1 : thisConstruct.AbsDiff = 0.0;
13624 1 : thisConstruct.AbsDiffBack = 0.0;
13625 1 : thisConstruct.AbsDiffShade = 0.0;
13626 1 : thisConstruct.AbsDiffBackShade = 0.0;
13627 1 : thisConstruct.ShadeAbsorpThermal = 0.0;
13628 1 : std::fill(thisConstruct.AbsBeamShadeCoef.begin(), thisConstruct.AbsBeamShadeCoef.end(), 0.0);
13629 1 : thisConstruct.TransDiff = 0.0;
13630 1 : thisConstruct.TransDiffVis = 0.0;
13631 1 : thisConstruct.ReflectSolDiffBack = 0.0;
13632 1 : thisConstruct.ReflectSolDiffFront = 0.0;
13633 1 : thisConstruct.ReflectVisDiffBack = 0.0;
13634 1 : thisConstruct.ReflectVisDiffFront = 0.0;
13635 1 : std::fill(thisConstruct.TransSolBeamCoef.begin(), thisConstruct.TransSolBeamCoef.end(), 0.0);
13636 1 : std::fill(thisConstruct.TransVisBeamCoef.begin(), thisConstruct.TransVisBeamCoef.end(), 0.0);
13637 1 : std::fill(thisConstruct.ReflSolBeamFrontCoef.begin(), thisConstruct.ReflSolBeamFrontCoef.end(), 0.0);
13638 1 : std::fill(thisConstruct.ReflSolBeamBackCoef.begin(), thisConstruct.ReflSolBeamBackCoef.end(), 0.0);
13639 1 : thisConstruct.W5FrameDivider = 0;
13640 1 : thisConstruct.FromWindow5DataFile = false;
13641 1 : thisConstruct.W5FileMullionWidth = 0.0;
13642 1 : thisConstruct.W5FileMullionOrientation = DataWindowEquivalentLayer::Orientation::Invalid;
13643 1 : thisConstruct.W5FileGlazingSysWidth = 0.0;
13644 1 : thisConstruct.W5FileGlazingSysHeight = 0.0;
13645 8 : for (int Layer = 1; Layer <= state.dataHeatBal->MaxSolidWinLayers; ++Layer) {
13646 7 : std::fill(thisConstruct.AbsBeamCoef(Layer).begin(), thisConstruct.AbsBeamCoef(Layer).end(), 0.0);
13647 7 : std::fill(thisConstruct.AbsBeamBackCoef(Layer).begin(), thisConstruct.AbsBeamBackCoef(Layer).end(), 0.0);
13648 : }
13649 : }
13650 1 : return (newConstruct);
13651 : }
13652 :
13653 8 : void ModifyWindow(EnergyPlusData &state,
13654 : int const SurfNum, // SurfNum has construction of glazing system from Window5 Data File;
13655 : bool &ErrorsFound, // Set to true if errors found
13656 : int &AddedSubSurfaces // Subsurfaces added when window references a
13657 : )
13658 : {
13659 : // SUBROUTINE INFORMATION:
13660 : // AUTHOR Fred Winkelmann
13661 : // DATE WRITTEN Feb 2002
13662 : // MODIFIED June 2004, FCW: SinAzim, CosAzim, SinTilt, CosTilt, OutNormVec, GrossArea
13663 : // and Perimeter weren't being set for created window for case when
13664 : // window from Window5DataFile had two different glazing systems. Also,
13665 : // GrossArea and Perimeter of original window were not being recalculated.
13666 : // October 2007, LKL: Net area for shading calculations was not being
13667 : // recalculated.
13668 :
13669 : // PURPOSE OF THIS SUBROUTINE:
13670 : // If a window from the Window5DataFile has one glazing system, modify the
13671 : // vertex coordinates of the original window to correspond to the dimensions
13672 : // of the glazing system on the Data File.
13673 : // If a window from the Window5DataFile has two different glazing systems, split
13674 : // the window into two separate windows with different properties and adjust the
13675 : // vertices of these windows taking into account the dimensions of the glazing systems
13676 : // on the Data File and the width and orientation of the mullion that separates
13677 : // the glazing systems.
13678 :
13679 : // SUBROUTINE ARGUMENT DEFINITIONS:
13680 : // If there is a second glazing system on the Data File, SurfNum+1
13681 : // has the construction of the second glazing system.
13682 :
13683 : // 2-glazing system Window5 data file entry
13684 :
13685 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
13686 : Real64 H; // Height and width of original window (m)
13687 : Real64 W;
13688 : // unused1208 REAL(r64) :: MulWidth ! Mullion width (m)
13689 : Real64 h1; // height and width of first glazing system (m)
13690 : Real64 w1;
13691 : // unused1208 REAL(r64) :: h2,w2 ! height and width of second glazing system (m)
13692 : // unused1208 type (rectangularwindow) :: NewCoord
13693 : int IConst; // Construction number of first glazing system
13694 : int IConst2; // Construction number of second glazing system
13695 8 : std::string Const2Name; // Name of construction of second glazing system
13696 : // unused1208 REAL(r64) :: AreaNew ! Sum of areas of the two glazing systems (m2)
13697 :
13698 8 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
13699 :
13700 : struct rectangularwindow
13701 : {
13702 : // Members
13703 : Array1D<Vector> Vertex;
13704 :
13705 : // Default Constructor
13706 8 : rectangularwindow() : Vertex(4)
13707 : {
13708 8 : }
13709 : };
13710 :
13711 : // Object Data
13712 8 : Vector TVect;
13713 8 : rectangularwindow OriginalCoord;
13714 :
13715 8 : IConst = surfTemp.Construction;
13716 :
13717 : // Height and width of original window
13718 8 : TVect = surfTemp.Vertex(3) - surfTemp.Vertex(2);
13719 8 : W = Vectors::VecLength(TVect); // SQRT((X(3)-X(2))**2 + (Y(3)-Y(2))**2 + (Z(3)-Z(2))**2)
13720 8 : TVect = surfTemp.Vertex(2) - surfTemp.Vertex(1);
13721 8 : H = Vectors::VecLength(TVect); // SQRT((X(1)-X(2))**2 + (Y(1)-Y(2))**2 + (Z(1)-Z(2))**2)
13722 :
13723 : // Save coordinates of original window in case Window 5 data overwrites.
13724 8 : OriginalCoord.Vertex({1, surfTemp.Sides}) = surfTemp.Vertex({1, surfTemp.Sides});
13725 :
13726 : // Height and width of first glazing system
13727 8 : h1 = state.dataConstruction->Construct(IConst).W5FileGlazingSysHeight;
13728 8 : w1 = state.dataConstruction->Construct(IConst).W5FileGlazingSysWidth;
13729 :
13730 8 : Const2Name = state.dataConstruction->Construct(IConst).Name + ":2";
13731 8 : IConst2 = Util::FindItemInList(Const2Name, state.dataConstruction->Construct);
13732 :
13733 8 : if (IConst2 == 0) { // Only one glazing system on Window5 Data File for this window.
13734 :
13735 : // So... original dimensions and area of window are used (entered in IDF)
13736 : // Warning if dimensions of original window differ from those on Data File by more than 10%
13737 :
13738 8 : if (std::abs((H - h1) / H) > 0.10 || std::abs((W - w1) / W) > 0.10) {
13739 :
13740 8 : if (state.dataGlobal->DisplayExtraWarnings) {
13741 0 : ShowWarningError(state,
13742 0 : format("SurfaceGeometry: ModifyWindow: Window {} uses the Window5 Data File Construction {}",
13743 0 : surfTemp.Name,
13744 0 : state.dataConstruction->Construct(IConst).Name));
13745 0 : ShowContinueError(state, format("The height {:.3R}(m) or width (m) of this window differs by more than 10%{:.3R}", H, W));
13746 0 : ShowContinueError(state,
13747 0 : format("from the corresponding height {:.3R} (m) or width (m) on the Window5 Data file.{:.3R}", h1, w1));
13748 0 : ShowContinueError(state, "This will affect the frame heat transfer calculation if the frame in the Data File entry");
13749 0 : ShowContinueError(state, "is not uniform, i.e., has sections with different geometry and/or thermal properties.");
13750 : } else {
13751 8 : ++state.dataSurfaceGeometry->Warning1Count;
13752 : }
13753 : }
13754 :
13755 : // Calculate net area for base surface
13756 8 : state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).Area -= surfTemp.Area;
13757 8 : if (state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).Area <= 0.0) {
13758 0 : ShowSevereError(
13759 : state,
13760 0 : format("Subsurfaces have too much area for base surface={}", state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).Name));
13761 0 : ShowContinueError(state, format("Subsurface creating error={}", surfTemp.Name));
13762 0 : ErrorsFound = true;
13763 : }
13764 :
13765 : // Net area of base surface with unity window multipliers (used in shadowing checks)
13766 8 : state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).NetAreaShadowCalc -= surfTemp.Area / surfTemp.Multiplier;
13767 :
13768 : } else { // Two glazing systems on Window5 data file for this window
13769 :
13770 : // if exterior window, okay.
13771 :
13772 0 : if (surfTemp.ExtBoundCond == DataSurfaces::ExternalEnvironment) {
13773 : // There are two glazing systems (separated by a vertical or horizontal mullion) on the Window5 Data File.
13774 : // Fill in geometry data for the second window (corresponding to the second glazing system on the data file.
13775 : // The first glazing system is assumed to be at left for vertical mullion, at bottom for horizontal mullion.
13776 : // The second glazing system is assumed to be at right for vertical mullion, at top for horizontal mullion.
13777 : // The lower left-hand corner of the original window (its vertex #2) is assumed to coincide with
13778 : // vertex #2 of the first glazing system.
13779 :
13780 0 : if (state.dataGlobal->DisplayExtraWarnings) {
13781 0 : ShowMessage(state,
13782 0 : format("SurfaceGeometry: ModifyWindow: Window {} has been replaced with the Window 5/6 two glazing system=\"{}\".",
13783 0 : surfTemp.Name,
13784 0 : state.dataConstruction->Construct(IConst).Name));
13785 0 : ShowContinueError(state, "Note that originally entered dimensions are overridden.");
13786 : } else {
13787 0 : ++state.dataSurfaceGeometry->Warning2Count;
13788 : }
13789 :
13790 : // Allocate another window
13791 0 : AddWindow(state, SurfNum, ErrorsFound, AddedSubSurfaces);
13792 :
13793 0 : } else if (surfTemp.ExtBoundCond > 0) { // Interior window, specified ! not external environment
13794 :
13795 0 : if (state.dataGlobal->DisplayExtraWarnings) {
13796 0 : ShowWarningError(
13797 : state,
13798 0 : format("SurfaceGeometry: ModifyWindow: Interior Window {} has been replaced with the Window 5/6 two glazing system=\"{}\".",
13799 0 : surfTemp.Name,
13800 0 : state.dataConstruction->Construct(IConst).Name));
13801 0 : ShowContinueError(
13802 : state, "Please check to make sure interior window is correct. Note that originally entered dimensions are overridden.");
13803 : } else {
13804 0 : ++state.dataSurfaceGeometry->Warning3Count;
13805 : }
13806 :
13807 0 : AddWindow(state, SurfNum, ErrorsFound, AddedSubSurfaces);
13808 :
13809 : } else { // Interior window, specified not entered
13810 :
13811 0 : ShowSevereError(state, format("SurfaceGeometry: ModifyWindow: Interior Window {} is a window in an adjacent zone.", surfTemp.Name));
13812 0 : ShowContinueError(
13813 : state,
13814 0 : format("Attempted to add/reverse Window 5/6 multiple glazing system=\"{}\".", state.dataConstruction->Construct(IConst).Name));
13815 0 : ShowContinueError(state, "Cannot use these Window 5/6 constructs for these Interior Windows. Program will terminate.");
13816 0 : ErrorsFound = true;
13817 : }
13818 :
13819 : } // End of check if one or two glazing systems are on the Window5 Data File
13820 8 : }
13821 :
13822 0 : void AddWindow(EnergyPlusData &state,
13823 : int const SurfNum, // SurfNum has construction of glazing system from Window5 Data File;
13824 : bool &ErrorsFound, // Set to true if errors found
13825 : int &AddedSubSurfaces // Subsurfaces added when window references a
13826 : )
13827 : {
13828 : // SUBROUTINE INFORMATION:
13829 : // AUTHOR Linda Lawrie
13830 : // DATE WRITTEN Nov 2008
13831 :
13832 : // PURPOSE OF THIS SUBROUTINE:
13833 : // This routine is called from ModifyWindow to add a window. Allows it to be
13834 : // called in more than one place in the calling routine so as to be able to have
13835 : // specific warnings or errors issued.
13836 :
13837 : // SUBROUTINE ARGUMENT DEFINITIONS:
13838 : // If there is a second glazing system on the Data File, SurfNum+1
13839 : // has the construction of the second glazing system.
13840 :
13841 : // 2-glazing system Window5 data file entry
13842 :
13843 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
13844 : int loop; // DO loop index
13845 : Real64 H; // Height and width of original window (m)
13846 : Real64 W;
13847 : Real64 MulWidth; // Mullion width (m)
13848 : Real64 h1; // height and width of first glazing system (m)
13849 : Real64 w1;
13850 : Real64 h2; // height and width of second glazing system (m)
13851 : Real64 w2;
13852 : Real64 xa; // Vertex intermediate variables (m)
13853 : Real64 ya;
13854 : Real64 za;
13855 : Real64 xb;
13856 : Real64 yb;
13857 : Real64 zb;
13858 : Real64 dx; // Vertex displacements from original window (m)
13859 : Real64 dy;
13860 : int IConst; // Construction number of first glazing system
13861 : int IConst2; // Construction number of second glazing system
13862 0 : std::string Const2Name; // Name of construction of second glazing system
13863 : Real64 AreaNew; // Sum of areas of the two glazing systems (m2)
13864 :
13865 : struct rectangularwindow
13866 : {
13867 : // Members
13868 : Array1D<Vector> Vertex;
13869 :
13870 : // Default Constructor
13871 0 : rectangularwindow() : Vertex(4)
13872 : {
13873 0 : }
13874 : };
13875 :
13876 : // Object Data
13877 0 : Vector TVect;
13878 0 : rectangularwindow NewCoord;
13879 0 : rectangularwindow OriginalCoord;
13880 :
13881 0 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
13882 :
13883 0 : IConst = surfTemp.Construction;
13884 :
13885 : // Height and width of original window
13886 0 : TVect = surfTemp.Vertex(3) - surfTemp.Vertex(2);
13887 0 : W = Vectors::VecLength(TVect); // SQRT((X(3)-X(2))**2 + (Y(3)-Y(2))**2 + (Z(3)-Z(2))**2)
13888 0 : TVect = surfTemp.Vertex(2) - surfTemp.Vertex(1);
13889 0 : H = Vectors::VecLength(TVect); // SQRT((X(1)-X(2))**2 + (Y(1)-Y(2))**2 + (Z(1)-Z(2))**2)
13890 :
13891 : // Save coordinates of original window in case Window 5 data overwrites.
13892 0 : OriginalCoord.Vertex({1, surfTemp.Sides}) = surfTemp.Vertex({1, surfTemp.Sides});
13893 :
13894 : // Height and width of first glazing system
13895 0 : h1 = state.dataConstruction->Construct(IConst).W5FileGlazingSysHeight;
13896 0 : w1 = state.dataConstruction->Construct(IConst).W5FileGlazingSysWidth;
13897 :
13898 0 : Const2Name = state.dataConstruction->Construct(IConst).Name + ":2";
13899 0 : IConst2 = Util::FindItemInList(Const2Name, state.dataConstruction->Construct);
13900 :
13901 0 : ++AddedSubSurfaces;
13902 0 : state.dataSurfaceGeometry->SurfaceTmp.redimension(++state.dataSurface->TotSurfaces);
13903 :
13904 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Vertex.allocate(4);
13905 :
13906 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Name = surfTemp.Name + ":2";
13907 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Construction = IConst2;
13908 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).ConstructionStoredInputValue = IConst2;
13909 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Class = surfTemp.Class;
13910 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Azimuth = surfTemp.Azimuth;
13911 : // Sine and cosine of azimuth and tilt
13912 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).SinAzim = surfTemp.SinAzim;
13913 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).CosAzim = surfTemp.CosAzim;
13914 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).SinTilt = surfTemp.SinTilt;
13915 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).CosTilt = surfTemp.CosTilt;
13916 : // Outward normal unit vector (pointing away from room)
13917 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Centroid = surfTemp.Centroid;
13918 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).lcsx = surfTemp.lcsx;
13919 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).lcsy = surfTemp.lcsy;
13920 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).lcsz = surfTemp.lcsz;
13921 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).NewellAreaVector = surfTemp.NewellAreaVector;
13922 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).OutNormVec = surfTemp.OutNormVec;
13923 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Reveal = surfTemp.Reveal;
13924 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Shape = surfTemp.Shape;
13925 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Sides = surfTemp.Sides;
13926 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Tilt = surfTemp.Tilt;
13927 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).convOrientation = Convect::GetSurfConvOrientation(surfTemp.Tilt);
13928 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).HeatTransSurf = surfTemp.HeatTransSurf;
13929 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).BaseSurfName = surfTemp.BaseSurfName;
13930 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).BaseSurf = surfTemp.BaseSurf;
13931 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).ZoneName = surfTemp.ZoneName;
13932 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Zone = surfTemp.Zone;
13933 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).ExtBoundCondName = surfTemp.ExtBoundCondName;
13934 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).ExtBoundCond = surfTemp.ExtBoundCond;
13935 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).ExtSolar = surfTemp.ExtSolar;
13936 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).ExtWind = surfTemp.ExtWind;
13937 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).ViewFactorGround = surfTemp.ViewFactorGround;
13938 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).ViewFactorSky = surfTemp.ViewFactorSky;
13939 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).ViewFactorGroundIR = surfTemp.ViewFactorGroundIR;
13940 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).ViewFactorSkyIR = surfTemp.ViewFactorSkyIR;
13941 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).OSCPtr = surfTemp.OSCPtr;
13942 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).shadowSurfSched = surfTemp.shadowSurfSched;
13943 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).activeWindowShadingControl = surfTemp.activeWindowShadingControl;
13944 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).windowShadingControlList = surfTemp.windowShadingControlList;
13945 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).HasShadeControl = surfTemp.HasShadeControl;
13946 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).activeShadedConstruction = surfTemp.activeShadedConstruction;
13947 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).windowShadingControlList = surfTemp.windowShadingControlList;
13948 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).shadedStormWinConstructionList =
13949 0 : surfTemp.shadedStormWinConstructionList;
13950 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).FrameDivider = surfTemp.FrameDivider;
13951 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Multiplier = surfTemp.Multiplier;
13952 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).NetAreaShadowCalc = surfTemp.NetAreaShadowCalc;
13953 :
13954 0 : MulWidth = state.dataConstruction->Construct(IConst).W5FileMullionWidth;
13955 0 : w2 = state.dataConstruction->Construct(IConst2).W5FileGlazingSysWidth;
13956 0 : h2 = state.dataConstruction->Construct(IConst2).W5FileGlazingSysHeight;
13957 :
13958 : // Correction to net area of base surface. Add back in the original glazing area and subtract the
13959 : // area of the two glazing systems. Note that for Surface(SurfNum)%Class = 'Window' the effect
13960 : // of a window multiplier is included in the glazing area. Note that frame areas are subtracted later.
13961 :
13962 0 : AreaNew = surfTemp.Multiplier * (h1 * w1 + h2 * w2); // both glazing systems
13963 : // Adjust net area for base surface
13964 0 : state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).Area -= AreaNew;
13965 :
13966 : // Net area of base surface with unity window multipliers (used in shadowing checks)
13967 0 : state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).NetAreaShadowCalc -= AreaNew / surfTemp.Multiplier;
13968 :
13969 : // Reset area, etc. of original window
13970 0 : surfTemp.Area = surfTemp.Multiplier * (h1 * w1);
13971 0 : surfTemp.GrossArea = surfTemp.Area;
13972 0 : surfTemp.NetAreaShadowCalc = h1 * w1;
13973 0 : surfTemp.Perimeter = 2 * (h1 + w1);
13974 0 : surfTemp.Height = h1;
13975 0 : surfTemp.Width = w1;
13976 : // Set area, etc. of new window
13977 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Area =
13978 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Multiplier * (h2 * w2);
13979 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).GrossArea =
13980 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Area;
13981 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).NetAreaShadowCalc = h2 * w2;
13982 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Perimeter = 2 * (h2 + w2);
13983 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Height = h2;
13984 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Width = w2;
13985 :
13986 0 : if (state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).Area <= 0.0) {
13987 0 : ShowSevereError(state,
13988 0 : format("SurfaceGeometry: ModifyWindow: Subsurfaces have too much area for base surface={}",
13989 0 : state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).Name));
13990 0 : ShowContinueError(state, format("Subsurface (window) creating error={}", surfTemp.Name));
13991 0 : ShowContinueError(state,
13992 0 : format("This window has been replaced by two windows from the Window5 Data File of total area {:.2R} m2", AreaNew));
13993 0 : ErrorsFound = true;
13994 : }
13995 :
13996 : // Assign vertices to the new window; modify vertices of original window.
13997 : // In the following, vertices are numbered counter-clockwise with vertex #1 at the upper left.
13998 :
13999 0 : if (state.dataConstruction->Construct(IConst).W5FileMullionOrientation == DataWindowEquivalentLayer::Orientation::Vertical) {
14000 :
14001 : // VERTICAL MULLION: original window is modified to become left-hand glazing (system #1);
14002 : // new window is created to become right-hand glazing (system #2)
14003 :
14004 : // Left-hand glazing
14005 :
14006 : // Vertex 1
14007 0 : dx = 0.0;
14008 0 : dy = H - h1;
14009 0 : xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
14010 0 : ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
14011 0 : za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
14012 0 : xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
14013 0 : yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
14014 0 : zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
14015 0 : NewCoord.Vertex(1).x = xa + (dx / W) * (xb - xa);
14016 0 : NewCoord.Vertex(1).y = ya + (dx / W) * (yb - ya);
14017 0 : NewCoord.Vertex(1).z = za + (dx / W) * (zb - za);
14018 :
14019 : // Vertex 2
14020 0 : dx = 0.0;
14021 0 : dy = H;
14022 0 : xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
14023 0 : ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
14024 0 : za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
14025 0 : xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
14026 0 : yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
14027 0 : zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
14028 0 : NewCoord.Vertex(2).x = xa + (dx / W) * (xb - xa);
14029 0 : NewCoord.Vertex(2).y = ya + (dx / W) * (yb - ya);
14030 0 : NewCoord.Vertex(2).z = za + (dx / W) * (zb - za);
14031 :
14032 : // Vertex 3
14033 0 : dx = w1;
14034 0 : dy = H;
14035 0 : xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
14036 0 : ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
14037 0 : za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
14038 0 : xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
14039 0 : yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
14040 0 : zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
14041 0 : NewCoord.Vertex(3).x = xa + (dx / W) * (xb - xa);
14042 0 : NewCoord.Vertex(3).y = ya + (dx / W) * (yb - ya);
14043 0 : NewCoord.Vertex(3).z = za + (dx / W) * (zb - za);
14044 :
14045 : // Vertex 4
14046 0 : dx = w1;
14047 0 : dy = H - h1;
14048 0 : xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
14049 0 : ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
14050 0 : za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
14051 0 : xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
14052 0 : yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
14053 0 : zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
14054 0 : NewCoord.Vertex(4).x = xa + (dx / W) * (xb - xa);
14055 0 : NewCoord.Vertex(4).y = ya + (dx / W) * (yb - ya);
14056 0 : NewCoord.Vertex(4).z = za + (dx / W) * (zb - za);
14057 :
14058 0 : for (loop = 1; loop <= surfTemp.Sides; ++loop) {
14059 0 : surfTemp.Vertex(loop) = NewCoord.Vertex(loop);
14060 : }
14061 :
14062 : // Right-hand glazing
14063 :
14064 : // Vertex 1
14065 0 : dx = w1 + MulWidth;
14066 0 : dy = H - (h1 + h2) / 2.0;
14067 0 : xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
14068 0 : ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
14069 0 : za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
14070 0 : xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
14071 0 : yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
14072 0 : zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
14073 0 : NewCoord.Vertex(1).x = xa + (dx / W) * (xb - xa);
14074 0 : NewCoord.Vertex(1).y = ya + (dx / W) * (yb - ya);
14075 0 : NewCoord.Vertex(1).z = za + (dx / W) * (zb - za);
14076 :
14077 : // Vertex 2
14078 0 : dx = w1 + MulWidth;
14079 0 : dy = H + (h2 - h1) / 2.0;
14080 0 : xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
14081 0 : ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
14082 0 : za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
14083 0 : xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
14084 0 : yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
14085 0 : zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
14086 0 : NewCoord.Vertex(2).x = xa + (dx / W) * (xb - xa);
14087 0 : NewCoord.Vertex(2).y = ya + (dx / W) * (yb - ya);
14088 0 : NewCoord.Vertex(2).z = za + (dx / W) * (zb - za);
14089 :
14090 : // Vertex 3
14091 0 : dx = w1 + MulWidth + w2;
14092 0 : dy = H + (h2 - h1) / 2.0;
14093 0 : xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
14094 0 : ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
14095 0 : za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
14096 0 : xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
14097 0 : yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
14098 0 : zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
14099 0 : NewCoord.Vertex(3).x = xa + (dx / W) * (xb - xa);
14100 0 : NewCoord.Vertex(3).y = ya + (dx / W) * (yb - ya);
14101 0 : NewCoord.Vertex(3).z = za + (dx / W) * (zb - za);
14102 :
14103 : // Vertex 4
14104 0 : dx = w1 + MulWidth + w2;
14105 0 : dy = H - (h1 + h2) / 2.0;
14106 0 : xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
14107 0 : ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
14108 0 : za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
14109 0 : xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
14110 0 : yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
14111 0 : zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
14112 0 : NewCoord.Vertex(4).x = xa + (dx / W) * (xb - xa);
14113 0 : NewCoord.Vertex(4).y = ya + (dx / W) * (yb - ya);
14114 0 : NewCoord.Vertex(4).z = za + (dx / W) * (zb - za);
14115 :
14116 0 : for (loop = 1; loop <= state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Sides; ++loop) {
14117 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Vertex(loop) = NewCoord.Vertex(loop);
14118 : }
14119 :
14120 : } else { // Horizontal mullion
14121 :
14122 : // HORIZONTAL MULLION: original window is modified to become bottom glazing (system #1);
14123 : // new window is created to become top glazing (system #2)
14124 :
14125 : // Bottom glazing
14126 :
14127 : // Vertex 1
14128 0 : dx = 0.0;
14129 0 : dy = H - h1;
14130 0 : xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
14131 0 : ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
14132 0 : za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
14133 0 : xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
14134 0 : yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
14135 0 : zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
14136 0 : NewCoord.Vertex(1).x = xa + (dx / W) * (xb - xa);
14137 0 : NewCoord.Vertex(1).y = ya + (dx / W) * (yb - ya);
14138 0 : NewCoord.Vertex(1).z = za + (dx / W) * (zb - za);
14139 :
14140 : // Vertex 2
14141 0 : dx = 0.0;
14142 0 : dy = H;
14143 0 : xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
14144 0 : ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
14145 0 : za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
14146 0 : xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
14147 0 : yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
14148 0 : zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
14149 0 : NewCoord.Vertex(2).x = xa + (dx / W) * (xb - xa);
14150 0 : NewCoord.Vertex(2).y = ya + (dx / W) * (yb - ya);
14151 0 : NewCoord.Vertex(2).z = za + (dx / W) * (zb - za);
14152 :
14153 : // Vertex 3
14154 0 : dx = w1;
14155 0 : dy = H;
14156 0 : xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
14157 0 : ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
14158 0 : za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
14159 0 : xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
14160 0 : yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
14161 0 : zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
14162 0 : NewCoord.Vertex(3).x = xa + (dx / W) * (xb - xa);
14163 0 : NewCoord.Vertex(3).y = ya + (dx / W) * (yb - ya);
14164 0 : NewCoord.Vertex(3).z = za + (dx / W) * (zb - za);
14165 :
14166 : // Vertex 4
14167 0 : dx = w1;
14168 0 : dy = H - h1;
14169 0 : xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
14170 0 : ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
14171 0 : za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
14172 0 : xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
14173 0 : yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
14174 0 : zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
14175 0 : NewCoord.Vertex(4).x = xa + (dx / W) * (xb - xa);
14176 0 : NewCoord.Vertex(4).y = ya + (dx / W) * (yb - ya);
14177 0 : NewCoord.Vertex(4).z = za + (dx / W) * (zb - za);
14178 :
14179 0 : for (loop = 1; loop <= surfTemp.Sides; ++loop) {
14180 0 : surfTemp.Vertex(loop) = NewCoord.Vertex(loop);
14181 : }
14182 :
14183 : // Top glazing
14184 :
14185 : // Vertex 1
14186 0 : dx = (w1 - w2) / 2.0;
14187 0 : dy = H - (h1 + h2 + MulWidth);
14188 0 : xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
14189 0 : ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
14190 0 : za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
14191 0 : xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
14192 0 : yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
14193 0 : zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
14194 0 : NewCoord.Vertex(1).x = xa + (dx / W) * (xb - xa);
14195 0 : NewCoord.Vertex(1).y = ya + (dx / W) * (yb - ya);
14196 0 : NewCoord.Vertex(1).z = za + (dx / W) * (zb - za);
14197 :
14198 : // Vertex 2
14199 0 : dx = (w1 - w2) / 2.0;
14200 0 : dy = H - (h1 + MulWidth);
14201 0 : xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
14202 0 : ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
14203 0 : za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
14204 0 : xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
14205 0 : yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
14206 0 : zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
14207 0 : NewCoord.Vertex(2).x = xa + (dx / W) * (xb - xa);
14208 0 : NewCoord.Vertex(2).y = ya + (dx / W) * (yb - ya);
14209 0 : NewCoord.Vertex(2).z = za + (dx / W) * (zb - za);
14210 :
14211 : // Vertex 3
14212 0 : dx = (w1 + w2) / 2.0;
14213 0 : dy = H - (h1 + MulWidth);
14214 0 : xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
14215 0 : ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
14216 0 : za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
14217 0 : xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
14218 0 : yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
14219 0 : zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
14220 0 : NewCoord.Vertex(3).x = xa + (dx / W) * (xb - xa);
14221 0 : NewCoord.Vertex(3).y = ya + (dx / W) * (yb - ya);
14222 0 : NewCoord.Vertex(3).z = za + (dx / W) * (zb - za);
14223 :
14224 : // Vertex 4
14225 0 : dx = (w1 + w2) / 2.0;
14226 0 : dy = H - (h1 + h2 + MulWidth);
14227 0 : xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
14228 0 : ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
14229 0 : za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
14230 0 : xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
14231 0 : yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
14232 0 : zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
14233 0 : NewCoord.Vertex(4).x = xa + (dx / W) * (xb - xa);
14234 0 : NewCoord.Vertex(4).y = ya + (dx / W) * (yb - ya);
14235 0 : NewCoord.Vertex(4).z = za + (dx / W) * (zb - za);
14236 :
14237 0 : for (loop = 1; loop <= state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Sides; ++loop) {
14238 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Vertex(loop) = NewCoord.Vertex(loop);
14239 : }
14240 :
14241 : } // End of check if vertical or horizontal mullion
14242 0 : }
14243 :
14244 43538 : void TransformVertsByAspect(EnergyPlusData &state,
14245 : int const SurfNum, // Current surface number
14246 : int const NSides // Number of sides to figure
14247 : )
14248 : {
14249 : // SUBROUTINE INFORMATION:
14250 : // AUTHOR Brent T Griffith
14251 : // DATE WRITTEN April 2003
14252 :
14253 : // PURPOSE OF THIS SUBROUTINE:
14254 : // Alter input for surface geometry
14255 : // Optimizing building design for energy can involve
14256 : // altering building geometry. Rather than assemble routines to transform
14257 : // geometry through pre-processing on input, it may be simpler to change
14258 : // vertices within EnergyPlus since it already reads the data from the input
14259 : // file and there would no longer be a need to rewrite the text data.
14260 : // This is essentially a crude hack to allow adjusting geometry with
14261 : // a single parameter...
14262 :
14263 : // METHODOLOGY EMPLOYED:
14264 : // once vertices have been converted to WCS, change them to reflect a different aspect
14265 : // ratio for the entire building based on user input.
14266 : // This routine is called once for each surface by subroutine GetVertices
14267 :
14268 45078 : static std::string const CurrentModuleObject("GeometryTransform");
14269 :
14270 43538 : Array1D_string cAlphas(1);
14271 43538 : Array1D<Real64> rNumerics(2);
14272 43538 : auto &OldAspectRatio = state.dataSurfaceGeometry->OldAspectRatio;
14273 43538 : auto &NewAspectRatio = state.dataSurfaceGeometry->NewAspectRatio;
14274 : int n;
14275 : Real64 Xo;
14276 : Real64 XnoRot;
14277 : Real64 Xtrans;
14278 : Real64 Yo;
14279 : Real64 YnoRot;
14280 : Real64 Ytrans;
14281 : // begin execution
14282 : // get user input...
14283 :
14284 43538 : auto &s_ipsc = state.dataIPShortCut;
14285 43538 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
14286 :
14287 43538 : if (state.dataSurfaceGeometry->firstTime) {
14288 770 : if (state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject) == 1) {
14289 : int NAlphas;
14290 : int NNum;
14291 : int IOStat;
14292 1 : auto &s_ipsc = state.dataIPShortCut;
14293 1 : auto &transformPlane = state.dataSurfaceGeometry->transformPlane;
14294 2 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
14295 : CurrentModuleObject,
14296 : 1,
14297 : cAlphas,
14298 : NAlphas,
14299 : rNumerics,
14300 : NNum,
14301 : IOStat,
14302 1 : s_ipsc->lNumericFieldBlanks,
14303 1 : s_ipsc->lAlphaFieldBlanks,
14304 1 : s_ipsc->cAlphaFieldNames,
14305 1 : s_ipsc->cNumericFieldNames);
14306 1 : OldAspectRatio = rNumerics(1);
14307 1 : NewAspectRatio = rNumerics(2);
14308 1 : transformPlane = cAlphas(1);
14309 1 : if (transformPlane != "XY") {
14310 0 : ShowWarningError(state, format("{}: invalid {}=\"{}...ignored.", CurrentModuleObject, s_ipsc->cAlphaFieldNames(1), cAlphas(1)));
14311 : }
14312 1 : state.dataSurfaceGeometry->firstTime = false;
14313 1 : state.dataSurfaceGeometry->noTransform = false;
14314 1 : state.dataSurface->AspectTransform = true;
14315 1 : if (state.dataSurface->WorldCoordSystem) {
14316 0 : ShowWarningError(state, format("{}: must use Relative Coordinate System. Transform request ignored.", CurrentModuleObject));
14317 0 : state.dataSurfaceGeometry->noTransform = true;
14318 0 : state.dataSurface->AspectTransform = false;
14319 : }
14320 : } else {
14321 769 : state.dataSurfaceGeometry->firstTime = false;
14322 : }
14323 : }
14324 43538 : if (state.dataSurfaceGeometry->noTransform) {
14325 43490 : return;
14326 : }
14327 :
14328 : // check surface type.
14329 48 : if (!surfTemp.HeatTransSurf) {
14330 : // Site Shading do not get transformed.
14331 2 : if (surfTemp.Class == SurfaceClass::Detached_F) {
14332 0 : return;
14333 : }
14334 : }
14335 :
14336 : // testing method of transforming x and y coordinates as follows
14337 :
14338 : // this works if not rotated wrt north axis ... but if it is, then trouble
14339 : // try to first derotate it , transform by aspect and then rotate back.
14340 :
14341 240 : for (n = 1; n <= NSides; ++n) {
14342 192 : Xo = surfTemp.Vertex(n).x; // world coordinates.... shifted by relative north angle...
14343 192 : Yo = surfTemp.Vertex(n).y;
14344 : // next derotate the building
14345 192 : XnoRot = Xo * state.dataSurfaceGeometry->CosBldgRelNorth + Yo * state.dataSurfaceGeometry->SinBldgRelNorth;
14346 192 : YnoRot = Yo * state.dataSurfaceGeometry->CosBldgRelNorth - Xo * state.dataSurfaceGeometry->SinBldgRelNorth;
14347 : // translate
14348 192 : Xtrans = XnoRot * std::sqrt(NewAspectRatio / OldAspectRatio);
14349 192 : Ytrans = YnoRot * std::sqrt(OldAspectRatio / NewAspectRatio);
14350 : // rerotate
14351 192 : surfTemp.Vertex(n).x = Xtrans * state.dataSurfaceGeometry->CosBldgRelNorth - Ytrans * state.dataSurfaceGeometry->SinBldgRelNorth;
14352 :
14353 192 : surfTemp.Vertex(n).y = Xtrans * state.dataSurfaceGeometry->SinBldgRelNorth + Ytrans * state.dataSurfaceGeometry->CosBldgRelNorth;
14354 : }
14355 87028 : }
14356 :
14357 801 : void CalcSurfaceCentroid(EnergyPlusData &state)
14358 : {
14359 : // SUBROUTINE INFORMATION:
14360 : // AUTHOR B. Griffith
14361 : // DATE WRITTEN Feb. 2004
14362 :
14363 : // PURPOSE OF THIS SUBROUTINE:
14364 : // compute centroid of all the surfaces in the main
14365 : // surface structure. Store the vertex coordinates of
14366 : // the centroid in the 'SURFACE' derived type.
14367 :
14368 : // METHODOLOGY EMPLOYED:
14369 : // The centroid of triangle is easily computed by averaging the vertices
14370 : // The centroid of a quadrilateral is computed by area weighting the centroids
14371 : // of two triangles.
14372 : // (Algorithm would need to be changed for higher order
14373 : // polygons with more than four sides).
14374 :
14375 801 : auto &Triangle1 = state.dataSurfaceGeometry->Triangle1;
14376 801 : auto &Triangle2 = state.dataSurfaceGeometry->Triangle2;
14377 801 : static Vector const zero_vector(0.0);
14378 801 : Vector centroid;
14379 :
14380 801 : int negZcount(0); // for warning error in surface centroids
14381 :
14382 : // loop through all the surfaces
14383 48091 : for (int ThisSurf = 1; ThisSurf <= state.dataSurface->TotSurfaces; ++ThisSurf) {
14384 47290 : auto &surface = state.dataSurface->Surface(ThisSurf);
14385 :
14386 47290 : if (surface.Class == SurfaceClass::IntMass) {
14387 2537 : continue;
14388 : }
14389 :
14390 44753 : auto const &vertex = surface.Vertex;
14391 :
14392 44753 : if (surface.Sides == 3) { // 3-sided polygon
14393 :
14394 199 : centroid = cen(vertex(1), vertex(2), vertex(3));
14395 :
14396 44554 : } else if (surface.Sides == 4) { // 4-sided polygon
14397 :
14398 : // split into 2 3-sided polygons (Triangle 1 and Triangle 2)
14399 44357 : Triangle1(1) = vertex(1);
14400 44357 : Triangle1(2) = vertex(2);
14401 44357 : Triangle1(3) = vertex(3);
14402 44357 : Triangle2(1) = vertex(1);
14403 44357 : Triangle2(2) = vertex(3);
14404 44357 : Triangle2(3) = vertex(4);
14405 :
14406 : // get total Area of quad.
14407 44357 : Real64 TotalArea(surface.GrossArea);
14408 44357 : if (TotalArea <= 0.0) {
14409 : // catch a problem....
14410 0 : ShowWarningError(state, format("CalcSurfaceCentroid: zero area surface, for surface={}", surface.Name));
14411 0 : continue;
14412 : }
14413 :
14414 : // get area fraction of triangles.
14415 44357 : Real64 Tri1Area(Vectors::AreaPolygon(3, Triangle1) / TotalArea);
14416 44357 : Real64 Tri2Area(Vectors::AreaPolygon(3, Triangle2) / TotalArea);
14417 :
14418 : // check if sum of fractions are slightly greater than 1.0 which is a symptom of the triangles for a non-convex
14419 : // quadrilateral using the wrong two triangles
14420 44357 : if ((Tri1Area + Tri2Area) > 1.05) {
14421 :
14422 : // if so repeat the process with the other two possible triangles (notice the vertices are in a different order this
14423 : // time) split into 2 3-sided polygons (Triangle 1 and Triangle 2)
14424 20 : Triangle1(1) = vertex(1);
14425 20 : Triangle1(2) = vertex(2);
14426 20 : Triangle1(3) = vertex(4);
14427 20 : Triangle2(1) = vertex(2);
14428 20 : Triangle2(2) = vertex(3);
14429 20 : Triangle2(3) = vertex(4);
14430 :
14431 : // get area fraction of triangles.
14432 20 : Real64 AreaTriangle1 = Vectors::AreaPolygon(3, Triangle1);
14433 20 : Real64 AreaTriangle2 = Vectors::AreaPolygon(3, Triangle2);
14434 20 : TotalArea = AreaTriangle1 + AreaTriangle2;
14435 20 : Tri1Area = AreaTriangle1 / TotalArea;
14436 20 : Tri2Area = AreaTriangle2 / TotalArea;
14437 : }
14438 :
14439 : // get centroid of Triangle 1
14440 44357 : Vector cen1(cen(Triangle1(1), Triangle1(2), Triangle1(3)));
14441 :
14442 : // get centroid of Triangle 2
14443 44357 : Vector cen2(cen(Triangle2(1), Triangle2(2), Triangle2(3)));
14444 :
14445 : // find area weighted combination of the two centroids (coded to avoid temporary Vectors)
14446 44357 : cen1 *= Tri1Area;
14447 44357 : cen2 *= Tri2Area;
14448 44357 : centroid = cen1;
14449 44357 : centroid += cen2;
14450 :
14451 44554 : } else if (surface.Sides >= 5) { // multi-sided polygon
14452 : // (Maybe triangulate? For now, use old "z" average method")
14453 : // and X and Y -- straight average
14454 :
14455 : // X1=MINVAL(Surface(ThisSurf)%Vertex(1:Surface(ThisSurf)%Sides)%x)
14456 : // X2=MAXVAL(Surface(ThisSurf)%Vertex(1:Surface(ThisSurf)%Sides)%x)
14457 : // Y1=MINVAL(Surface(ThisSurf)%Vertex(1:Surface(ThisSurf)%Sides)%y)
14458 : // Y2=MAXVAL(Surface(ThisSurf)%Vertex(1:Surface(ThisSurf)%Sides)%y)
14459 : // Z1=MINVAL(Surface(ThisSurf)%Vertex(1:Surface(ThisSurf)%Sides)%z)
14460 : // Z2=MAXVAL(Surface(ThisSurf)%Vertex(1:Surface(ThisSurf)%Sides)%z)
14461 : // Xcm=(X1+X2)/2.0d0
14462 : // Ycm=(Y1+Y2)/2.0d0
14463 : // Zcm=(Z1+Z2)/2.0d0
14464 :
14465 : // Calc centroid as average of surfaces
14466 197 : centroid = 0.0;
14467 2025 : for (int vert = 1; vert <= surface.Sides; ++vert) {
14468 1828 : centroid += vertex(vert);
14469 : }
14470 197 : centroid /= double(surface.Sides);
14471 :
14472 : } else {
14473 :
14474 0 : if (!surface.Name.empty()) {
14475 0 : ShowWarningError(state, format("CalcSurfaceCentroid: caught problem with # of sides, for surface={}", surface.Name));
14476 0 : ShowContinueError(state, format("... number of sides must be >= 3, this surface # sides={}", surface.Sides));
14477 : } else {
14478 0 : ShowWarningError(state, format("CalcSurfaceCentroid: caught problem with # of sides, for surface=#{}", ThisSurf));
14479 0 : ShowContinueError(state,
14480 : "...surface name is blank. Examine surfaces -- this may be a problem with ill-formed interzone surfaces.");
14481 0 : ShowContinueError(state, format("... number of sides must be >= 3, this surface # sides={}", surface.Sides));
14482 : }
14483 0 : centroid = 0.0;
14484 : }
14485 :
14486 : // store result in the surface structure in DataSurfaces
14487 44753 : surface.Centroid = centroid;
14488 :
14489 44753 : if (centroid.z < 0.0) {
14490 305 : if (surface.ExtWind || surface.ExtBoundCond == DataSurfaces::ExternalEnvironment) {
14491 34 : ++negZcount;
14492 : }
14493 : }
14494 :
14495 : } // loop through surfaces
14496 :
14497 801 : if (negZcount > 0) {
14498 4 : ShowWarningError(state, format("CalcSurfaceCentroid: {} Surfaces have the Z coordinate < 0.", negZcount));
14499 8 : ShowContinueError(state, "...in any calculations, Wind Speed will be 0.0 for these surfaces.");
14500 8 : ShowContinueError(state,
14501 8 : format("...in any calculations, Outside temperatures will be the outside temperature + {:.3R} for these surfaces.",
14502 4 : state.dataEnvrn->WeatherFileTempModCoeff));
14503 12 : ShowContinueError(state, "...that is, these surfaces will have conditions as though at ground level.");
14504 : }
14505 801 : }
14506 :
14507 801 : void SetupShadeSurfacesForSolarCalcs(EnergyPlusData &state)
14508 : {
14509 : // SUBROUTINE INFORMATION:
14510 : // AUTHOR B. Griffith
14511 : // DATE WRITTEN Dec. 2008
14512 :
14513 : // PURPOSE OF THIS SUBROUTINE:
14514 : // determine if Shading surfaces need full solar calcs because they
14515 : // are also used to define geometry of an active solar component.
14516 : // Normally, a shading surface is not included in calculations of incident solar, only shading
14517 :
14518 : // METHODOLOGY EMPLOYED:
14519 : // Mine solar renewables input and collect surface names.
14520 : // find shading surfaces with names that match those in solar objects.
14521 : // setup flags for shading surfaces so that the solar renewables can reuse incident solar calcs
14522 : // new solar component models that use shading surfaces will have to extend the code here.
14523 :
14524 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
14525 801 : Array1D_string TmpCandidateSurfaceNames;
14526 801 : Array1D_string TmpCandidateICSSurfaceNames;
14527 801 : Array1D_string TmpCandidateICSBCTypeNames;
14528 : int NumAlphas; // Number of alpha names being passed
14529 : int NumNumbers; // Number of numeric parameters being passed
14530 : int IOStatus;
14531 :
14532 801 : auto &s_ipsc = state.dataIPShortCut;
14533 : // First collect names of surfaces referenced by active solar components
14534 801 : s_ipsc->cCurrentModuleObject = "SolarCollector:FlatPlate:Water";
14535 801 : int NumOfFlatPlateUnits = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
14536 801 : s_ipsc->cCurrentModuleObject = "SolarCollector:FlatPlate:PhotovoltaicThermal";
14537 801 : int NumPVTs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
14538 801 : s_ipsc->cCurrentModuleObject = "Generator:Photovoltaic";
14539 801 : int NumPVs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
14540 801 : s_ipsc->cCurrentModuleObject = "SolarCollector:IntegralCollectorStorage";
14541 801 : int NumOfICSUnits = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
14542 :
14543 801 : int NumCandidateNames = NumOfFlatPlateUnits + NumPVTs + NumPVs + NumOfICSUnits;
14544 801 : int NumOfCollectors = NumOfFlatPlateUnits + NumOfICSUnits;
14545 :
14546 801 : TmpCandidateSurfaceNames.allocate(NumCandidateNames);
14547 801 : TmpCandidateICSSurfaceNames.allocate(NumOfCollectors);
14548 801 : TmpCandidateICSBCTypeNames.allocate(NumOfCollectors);
14549 :
14550 801 : if (NumOfCollectors > 0) {
14551 3 : s_ipsc->cCurrentModuleObject = "SolarCollector:FlatPlate:Water";
14552 11 : for (int CollectorNum = 1; CollectorNum <= NumOfFlatPlateUnits; ++CollectorNum) {
14553 :
14554 16 : state.dataInputProcessing->inputProcessor->getObjectItem(
14555 8 : state, s_ipsc->cCurrentModuleObject, CollectorNum, s_ipsc->cAlphaArgs, NumAlphas, s_ipsc->rNumericArgs, NumNumbers, IOStatus);
14556 :
14557 8 : TmpCandidateSurfaceNames(CollectorNum) = s_ipsc->cAlphaArgs(3);
14558 8 : TmpCandidateICSBCTypeNames(CollectorNum) = "";
14559 : }
14560 : }
14561 :
14562 801 : if (NumPVTs > 0) {
14563 2 : s_ipsc->cCurrentModuleObject = "SolarCollector:FlatPlate:PhotovoltaicThermal";
14564 22 : for (int PVTnum = 1; PVTnum <= NumPVTs; ++PVTnum) {
14565 :
14566 40 : state.dataInputProcessing->inputProcessor->getObjectItem(
14567 20 : state, s_ipsc->cCurrentModuleObject, PVTnum, s_ipsc->cAlphaArgs, NumAlphas, s_ipsc->rNumericArgs, NumNumbers, IOStatus);
14568 :
14569 20 : TmpCandidateSurfaceNames(NumOfFlatPlateUnits + PVTnum) = s_ipsc->cAlphaArgs(2);
14570 : }
14571 : }
14572 :
14573 801 : if (NumPVs > 0) {
14574 7 : s_ipsc->cCurrentModuleObject = "Generator:Photovoltaic";
14575 65 : for (int PVnum = 1; PVnum <= NumPVs; ++PVnum) {
14576 116 : state.dataInputProcessing->inputProcessor->getObjectItem(
14577 58 : state, s_ipsc->cCurrentModuleObject, PVnum, s_ipsc->cAlphaArgs, NumAlphas, s_ipsc->rNumericArgs, NumNumbers, IOStatus);
14578 58 : TmpCandidateSurfaceNames(NumOfFlatPlateUnits + NumPVTs + PVnum) = s_ipsc->cAlphaArgs(2);
14579 : }
14580 : }
14581 :
14582 801 : if (NumOfICSUnits > 0) {
14583 1 : s_ipsc->cCurrentModuleObject = "SolarCollector:IntegralCollectorStorage";
14584 3 : for (int CollectorNum = 1; CollectorNum <= NumOfICSUnits; ++CollectorNum) {
14585 4 : state.dataInputProcessing->inputProcessor->getObjectItem(
14586 2 : state, s_ipsc->cCurrentModuleObject, CollectorNum, s_ipsc->cAlphaArgs, NumAlphas, s_ipsc->rNumericArgs, NumNumbers, IOStatus);
14587 2 : TmpCandidateSurfaceNames(NumOfFlatPlateUnits + NumPVTs + NumPVs + CollectorNum) = s_ipsc->cAlphaArgs(3);
14588 2 : TmpCandidateICSSurfaceNames(NumOfFlatPlateUnits + CollectorNum) = s_ipsc->cAlphaArgs(3);
14589 2 : TmpCandidateICSBCTypeNames(NumOfFlatPlateUnits + CollectorNum) = s_ipsc->cAlphaArgs(4);
14590 : }
14591 : }
14592 :
14593 : // loop through all the surfaces
14594 48091 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
14595 47290 : auto &surf = state.dataSurface->Surface(SurfNum);
14596 47290 : int Found = Util::FindItemInList(surf.Name, TmpCandidateSurfaceNames, NumCandidateNames);
14597 47290 : if (Found > 0) {
14598 58 : if (!surf.HeatTransSurf) { // not BIPV, must be a shading surf with solar device
14599 : // Setup missing values to allow shading surfaces to model incident solar and wind
14600 21 : surf.ExtSolar = true;
14601 21 : surf.ExtWind = true;
14602 21 : surf.ViewFactorGround = 0.5 * (1.0 - surf.CosTilt);
14603 : }
14604 : // check if this surface is used for ICS collector mounting and has OthersideCondictionsModel as its
14605 : // boundary condition
14606 58 : if (NumOfICSUnits > 0) {
14607 6 : for (int CollectorNum = 1; CollectorNum <= NumOfCollectors; ++CollectorNum) {
14608 6 : if (Util::SameString(surf.Name, TmpCandidateICSSurfaceNames(CollectorNum)) &&
14609 6 : Util::SameString(TmpCandidateICSBCTypeNames(CollectorNum), "OTHERSIDECONDITIONSMODEL")) {
14610 2 : state.dataSurface->SurfIsICS(SurfNum) = true;
14611 2 : state.dataSurface->SurfICSPtr(SurfNum) = CollectorNum;
14612 : }
14613 : }
14614 : }
14615 :
14616 : } // end of IF (Found > 0) Then
14617 : }
14618 801 : }
14619 :
14620 : void
14621 1602 : SetupEnclosuresAndAirBoundaries(EnergyPlusData &state,
14622 : EPVector<DataViewFactorInformation::EnclosureViewFactorInformation> &Enclosures, // Radiant or Solar Enclosures
14623 : SurfaceGeometry::enclosureType const EnclosureType, // Radiant or Solar
14624 : bool &ErrorsFound) // Set to true if errors found
14625 : {
14626 : static constexpr std::string_view RoutineName = "SetupEnclosuresAndAirBoundaries";
14627 1602 : bool anyGroupedSpaces = false;
14628 1602 : bool radiantSetup = false;
14629 1602 : bool solarSetup = false;
14630 1602 : std::string RadiantOrSolar = "";
14631 1602 : int enclosureNum = 0;
14632 1602 : if (EnclosureType == RadiantEnclosures) {
14633 801 : radiantSetup = true;
14634 801 : RadiantOrSolar = "Radiant";
14635 801 : state.dataViewFactor->EnclRadInfo.allocate(state.dataGlobal->numSpaces);
14636 801 : } else if (EnclosureType == SolarEnclosures) {
14637 801 : solarSetup = true;
14638 801 : RadiantOrSolar = "Solar";
14639 801 : state.dataViewFactor->EnclSolInfo.allocate(state.dataGlobal->numSpaces);
14640 : } else {
14641 0 : ShowFatalError(
14642 0 : state, format("{}: Illegal call to this function. Second argument must be 'RadiantEnclosures' or 'SolarEnclosures'", RoutineName));
14643 : }
14644 1602 : if (std::any_of(state.dataConstruction->Construct.begin(),
14645 1602 : state.dataConstruction->Construct.end(),
14646 12171 : [](Construction::ConstructionProps const &e) { return e.TypeIsAirBoundary; })) {
14647 10 : int errorCount = 0;
14648 632 : for (int surfNum = 1; surfNum <= state.dataSurface->TotSurfaces; ++surfNum) {
14649 622 : auto &surf = state.dataSurface->Surface(surfNum);
14650 622 : if (surf.Construction == 0) {
14651 40 : continue;
14652 : }
14653 582 : auto &constr = state.dataConstruction->Construct(surf.Construction);
14654 582 : if (!constr.TypeIsAirBoundary) {
14655 546 : continue;
14656 : }
14657 36 : surf.IsAirBoundarySurf = true;
14658 :
14659 : // Check for invalid air boundary surfaces - valid only on non-adiabatic interzone surfaces
14660 : // Only check this once during radiant setup, skip for solar setup
14661 36 : if (radiantSetup && (surf.ExtBoundCond <= 0 || surf.ExtBoundCond == surfNum)) {
14662 0 : ErrorsFound = true;
14663 0 : if (!state.dataGlobal->DisplayExtraWarnings) {
14664 0 : ++errorCount;
14665 : } else {
14666 0 : ShowSevereError(
14667 0 : state, format("{}: Surface=\"{}\" uses Construction:AirBoundary in a non-interzone surface.", RoutineName, surf.Name));
14668 : }
14669 : } else {
14670 : // Process air boundary - set surface properties and set up enclosures Radiant exchange, Boundary is grouped - assign enclosure
14671 36 : state.dataHeatBal->AnyAirBoundary = true;
14672 36 : int thisSideEnclosureNum = 0;
14673 36 : int otherSideEnclosureNum = 0;
14674 36 : if (radiantSetup) {
14675 : // Radiant enclosure setup
14676 18 : constr.IsUsedCTF = false;
14677 18 : surf.HeatTransSurf = false;
14678 18 : surf.HeatTransferAlgorithm = DataSurfaces::HeatTransferModel::AirBoundaryNoHT;
14679 18 : thisSideEnclosureNum = state.dataHeatBal->space(surf.spaceNum).radiantEnclosureNum;
14680 18 : otherSideEnclosureNum = state.dataHeatBal->space(state.dataSurface->Surface(surf.ExtBoundCond).spaceNum).radiantEnclosureNum;
14681 : } else {
14682 : // Solar enclosure setup
14683 18 : thisSideEnclosureNum = state.dataHeatBal->space(surf.spaceNum).solarEnclosureNum;
14684 18 : otherSideEnclosureNum = state.dataHeatBal->space(state.dataSurface->Surface(surf.ExtBoundCond).spaceNum).solarEnclosureNum;
14685 : }
14686 36 : anyGroupedSpaces = true;
14687 36 : if ((thisSideEnclosureNum == 0) && (otherSideEnclosureNum == 0)) {
14688 : // Neither zone is assigned to an enclosure, so increment the counter and assign to both
14689 10 : ++enclosureNum;
14690 10 : auto &thisEnclosure = Enclosures(enclosureNum);
14691 10 : thisSideEnclosureNum = enclosureNum;
14692 10 : thisEnclosure.Name = format("{} Enclosure {}", RadiantOrSolar, enclosureNum);
14693 10 : thisEnclosure.spaceNames.push_back(state.dataHeatBal->space(surf.spaceNum).Name);
14694 10 : thisEnclosure.spaceNums.push_back(surf.spaceNum);
14695 10 : thisEnclosure.FloorArea += state.dataHeatBal->space(surf.spaceNum).FloorArea;
14696 10 : otherSideEnclosureNum = enclosureNum;
14697 10 : int otherSideSpaceNum = state.dataSurface->Surface(surf.ExtBoundCond).spaceNum;
14698 10 : if (otherSideSpaceNum != surf.spaceNum) {
14699 10 : thisEnclosure.spaceNames.push_back(state.dataHeatBal->space(otherSideSpaceNum).Name);
14700 10 : thisEnclosure.spaceNums.push_back(otherSideSpaceNum);
14701 10 : thisEnclosure.FloorArea += state.dataHeatBal->space(otherSideSpaceNum).FloorArea;
14702 : }
14703 10 : if (radiantSetup) {
14704 5 : state.dataHeatBal->space(surf.spaceNum).radiantEnclosureNum = thisSideEnclosureNum;
14705 5 : state.dataHeatBal->space(state.dataSurface->Surface(surf.ExtBoundCond).spaceNum).radiantEnclosureNum =
14706 : otherSideEnclosureNum;
14707 : } else {
14708 5 : thisEnclosure.ExtWindowArea += state.dataHeatBal->space(surf.spaceNum).extWindowArea;
14709 5 : thisEnclosure.TotalSurfArea += state.dataHeatBal->space(surf.spaceNum).totalSurfArea;
14710 5 : if (otherSideSpaceNum != surf.spaceNum) {
14711 5 : thisEnclosure.ExtWindowArea += state.dataHeatBal->space(otherSideSpaceNum).extWindowArea;
14712 5 : thisEnclosure.TotalSurfArea += state.dataHeatBal->space(otherSideSpaceNum).totalSurfArea;
14713 : }
14714 5 : state.dataHeatBal->space(surf.spaceNum).solarEnclosureNum = thisSideEnclosureNum;
14715 5 : state.dataHeatBal->space(state.dataSurface->Surface(surf.ExtBoundCond).spaceNum).solarEnclosureNum =
14716 : otherSideEnclosureNum;
14717 : }
14718 36 : } else if (thisSideEnclosureNum == 0) {
14719 : // Other side is assigned, so use that one for both
14720 0 : thisSideEnclosureNum = otherSideEnclosureNum;
14721 0 : auto &thisEnclosure = Enclosures(thisSideEnclosureNum);
14722 0 : thisEnclosure.spaceNames.push_back(state.dataHeatBal->space(surf.spaceNum).Name);
14723 0 : thisEnclosure.spaceNums.push_back(surf.spaceNum);
14724 0 : thisEnclosure.FloorArea += state.dataHeatBal->space(surf.spaceNum).FloorArea;
14725 0 : if (radiantSetup) {
14726 0 : state.dataHeatBal->space(surf.spaceNum).radiantEnclosureNum = thisSideEnclosureNum;
14727 : } else {
14728 0 : thisEnclosure.ExtWindowArea += state.dataHeatBal->space(surf.spaceNum).extWindowArea;
14729 0 : thisEnclosure.TotalSurfArea += state.dataHeatBal->space(surf.spaceNum).totalSurfArea;
14730 0 : state.dataHeatBal->space(surf.spaceNum).solarEnclosureNum = thisSideEnclosureNum;
14731 : }
14732 26 : } else if (otherSideEnclosureNum == 0) {
14733 : // This side is assigned, so use that one for both
14734 4 : otherSideEnclosureNum = thisSideEnclosureNum;
14735 4 : auto &thisEnclosure = Enclosures(thisSideEnclosureNum);
14736 4 : thisEnclosure.spaceNames.push_back(state.dataHeatBal->space(state.dataSurface->Surface(surf.ExtBoundCond).spaceNum).Name);
14737 4 : thisEnclosure.spaceNums.push_back(state.dataSurface->Surface(surf.ExtBoundCond).spaceNum);
14738 4 : thisEnclosure.FloorArea += state.dataHeatBal->space(state.dataSurface->Surface(surf.ExtBoundCond).spaceNum).FloorArea;
14739 4 : if (radiantSetup) {
14740 2 : state.dataHeatBal->space(state.dataSurface->Surface(surf.ExtBoundCond).spaceNum).radiantEnclosureNum =
14741 : otherSideEnclosureNum;
14742 : } else {
14743 2 : thisEnclosure.ExtWindowArea +=
14744 2 : state.dataHeatBal->space(state.dataSurface->Surface(surf.ExtBoundCond).spaceNum).extWindowArea;
14745 2 : thisEnclosure.TotalSurfArea +=
14746 2 : state.dataHeatBal->space(state.dataSurface->Surface(surf.ExtBoundCond).spaceNum).totalSurfArea;
14747 2 : state.dataHeatBal->space(state.dataSurface->Surface(surf.ExtBoundCond).spaceNum).solarEnclosureNum =
14748 : otherSideEnclosureNum;
14749 : }
14750 22 : } else if (thisSideEnclosureNum != otherSideEnclosureNum) {
14751 : // If both sides are already assigned to an enclosure, then merge the two enclosures
14752 0 : auto const &thisEnclosure = Enclosures(thisSideEnclosureNum);
14753 0 : auto &otherEnclosure = Enclosures(otherSideEnclosureNum);
14754 0 : for (const auto &zName : thisEnclosure.spaceNames) {
14755 0 : otherEnclosure.spaceNames.push_back(zName);
14756 0 : }
14757 0 : for (int zNum : thisEnclosure.spaceNums) {
14758 0 : otherEnclosure.spaceNums.push_back(zNum);
14759 0 : if (radiantSetup) {
14760 0 : state.dataHeatBal->space(zNum).radiantEnclosureNum = otherSideEnclosureNum;
14761 : } else {
14762 0 : state.dataHeatBal->space(zNum).solarEnclosureNum = otherSideEnclosureNum;
14763 : }
14764 0 : }
14765 0 : otherEnclosure.FloorArea += thisEnclosure.FloorArea;
14766 0 : otherEnclosure.ExtWindowArea += thisEnclosure.ExtWindowArea;
14767 0 : otherEnclosure.TotalSurfArea += thisEnclosure.TotalSurfArea;
14768 : // Move any enclosures beyond thisEnclosure down one slot - at this point all enclosures are named "Radiant
14769 : // Enclosure N"
14770 0 : for (int enclNum = thisSideEnclosureNum; enclNum < enclosureNum; ++enclNum) {
14771 0 : std::string saveName = Enclosures(enclNum).Name;
14772 0 : Enclosures(enclNum) = Enclosures(enclNum + 1);
14773 0 : Enclosures(enclNum).Name = saveName;
14774 0 : for (int sNum : Enclosures(enclNum).spaceNums) {
14775 0 : if (radiantSetup) {
14776 0 : state.dataHeatBal->space(sNum).radiantEnclosureNum = enclNum;
14777 : } else {
14778 0 : state.dataHeatBal->space(sNum).solarEnclosureNum = enclNum;
14779 : }
14780 0 : }
14781 0 : }
14782 : // Clear the last rad enclosure and reduce the total number of enclosures by 1
14783 0 : Enclosures(enclosureNum).Name.clear();
14784 0 : Enclosures(enclosureNum).spaceNames.clear();
14785 0 : Enclosures(enclosureNum).spaceNums.clear();
14786 0 : Enclosures(enclosureNum).FloorArea = 0;
14787 0 : Enclosures(enclosureNum).ExtWindowArea = 0;
14788 0 : Enclosures(enclosureNum).TotalSurfArea = 0;
14789 0 : enclosureNum -= 1;
14790 : }
14791 36 : if (solarSetup && constr.TypeIsAirBoundaryMixing) {
14792 : // Set up mixing air boundaries only once, during solar setup
14793 12 : int spaceNum1 = min(surf.spaceNum, state.dataSurface->Surface(surf.ExtBoundCond).spaceNum);
14794 12 : int spaceNum2 = max(surf.spaceNum, state.dataSurface->Surface(surf.ExtBoundCond).spaceNum);
14795 : // This pair already saved?
14796 12 : bool found = false;
14797 24 : for (auto const &thisAirBoundaryMixing : state.dataHeatBal->airBoundaryMixing) {
14798 18 : if ((spaceNum1 == thisAirBoundaryMixing.space1) && (spaceNum2 == thisAirBoundaryMixing.space2)) {
14799 6 : found = true;
14800 6 : break;
14801 : }
14802 12 : }
14803 12 : if (!found) {
14804 : // Store the space pairs, schedule, and flow rate to use later to create cross mixing objects
14805 6 : DataHeatBalance::AirBoundaryMixingSpecs newAirBoundaryMixing;
14806 6 : newAirBoundaryMixing.space1 = spaceNum1;
14807 6 : newAirBoundaryMixing.space2 = spaceNum2;
14808 6 : newAirBoundaryMixing.sched = state.dataConstruction->Construct(surf.Construction).airBoundaryMixingSched;
14809 6 : Real64 mixingVolume = state.dataConstruction->Construct(surf.Construction).AirBoundaryACH *
14810 6 : min(state.dataHeatBal->space(spaceNum1).Volume, state.dataHeatBal->space(spaceNum2).Volume) /
14811 6 : Constant::rSecsInHour;
14812 6 : newAirBoundaryMixing.mixingVolumeFlowRate = mixingVolume;
14813 6 : state.dataHeatBal->airBoundaryMixing.push_back(newAirBoundaryMixing);
14814 : }
14815 : }
14816 : }
14817 : }
14818 10 : if (errorCount > 0) {
14819 0 : ShowSevereError(state, format("{}: {} surfaces use Construction:AirBoundary in non-interzone surfaces.", RoutineName, errorCount));
14820 0 : ShowContinueError(state, "For explicit details on each use, use Output:Diagnostics,DisplayExtraWarnings;");
14821 : }
14822 : }
14823 : // Check for any spaces defined only by floor surface(s) and group them
14824 12004 : for (auto const &zone : state.dataHeatBal->Zone) {
14825 10402 : int newEnclosureNum = 0;
14826 20828 : for (int const spaceNum : zone.spaceIndexes) {
14827 10426 : int spaceEnclosureNum = 0;
14828 10426 : bool spaceHasOnlyFloors = false;
14829 10426 : if (radiantSetup) {
14830 5213 : spaceEnclosureNum = state.dataHeatBal->space(spaceNum).radiantEnclosureNum;
14831 : } else {
14832 5213 : spaceEnclosureNum = state.dataHeatBal->space(spaceNum).solarEnclosureNum;
14833 : }
14834 10426 : if (spaceEnclosureNum == 0) {
14835 10402 : spaceHasOnlyFloors = true;
14836 10748 : for (int const surfNum : state.dataHeatBal->space(spaceNum).surfaces) {
14837 10736 : if (state.dataSurface->Surface(surfNum).Class == SurfaceClass::IntMass) {
14838 8 : continue;
14839 : }
14840 10728 : if (state.dataSurface->Surface(surfNum).Class != SurfaceClass::Floor) {
14841 10390 : spaceHasOnlyFloors = false;
14842 10390 : break;
14843 : }
14844 10402 : }
14845 : }
14846 10426 : if (spaceEnclosureNum == 0 && spaceHasOnlyFloors) {
14847 12 : anyGroupedSpaces = true;
14848 12 : if (newEnclosureNum == 0) {
14849 : // Assign one new enclosure for all loose floors in this zone
14850 6 : ++enclosureNum;
14851 6 : newEnclosureNum = enclosureNum;
14852 : }
14853 12 : if (radiantSetup) {
14854 6 : state.dataHeatBal->space(spaceNum).radiantEnclosureNum = enclosureNum;
14855 : } else {
14856 6 : state.dataHeatBal->space(spaceNum).solarEnclosureNum = enclosureNum;
14857 : }
14858 12 : auto &thisEnclosure = Enclosures(enclosureNum);
14859 : // Give this enclosure the zone name and assign this to the zone-remainder space if it exists
14860 12 : thisEnclosure.Name = zone.Name;
14861 12 : thisEnclosure.spaceNames.push_back(state.dataHeatBal->space(spaceNum).Name);
14862 12 : thisEnclosure.spaceNums.push_back(spaceNum);
14863 12 : thisEnclosure.FloorArea = state.dataHeatBal->space(spaceNum).FloorArea;
14864 12 : thisEnclosure.ExtWindowArea = state.dataHeatBal->space(spaceNum).extWindowArea;
14865 12 : thisEnclosure.TotalSurfArea = state.dataHeatBal->space(spaceNum).totalSurfArea;
14866 : }
14867 10402 : }
14868 1602 : }
14869 :
14870 1602 : if (anyGroupedSpaces) {
14871 : // All grouped spaces have been assigned to an enclosure, now assign remaining spaces
14872 94 : for (int spaceNum = 1; spaceNum <= state.dataGlobal->numSpaces; ++spaceNum) {
14873 84 : auto &curSpace = state.dataHeatBal->space(spaceNum);
14874 84 : int spaceEnclosureNum = 0;
14875 84 : if (radiantSetup) {
14876 42 : spaceEnclosureNum = curSpace.radiantEnclosureNum;
14877 : } else {
14878 42 : spaceEnclosureNum = curSpace.solarEnclosureNum;
14879 : }
14880 84 : if (spaceEnclosureNum == 0) {
14881 48 : if (Util::SameString(curSpace.Name, state.dataHeatBal->Zone(curSpace.zoneNum).Name + "-REMAINDER")) {
14882 : // Search for existing enclosure with same name as the zone
14883 6 : spaceEnclosureNum = Util::FindItemInList(state.dataHeatBal->Zone(curSpace.zoneNum).Name, Enclosures);
14884 : }
14885 48 : if (spaceEnclosureNum == 0) {
14886 : // Otherwise add a new one named for the space
14887 42 : ++enclosureNum;
14888 42 : spaceEnclosureNum = enclosureNum;
14889 42 : Enclosures(spaceEnclosureNum).Name = curSpace.Name;
14890 : }
14891 48 : if (radiantSetup) {
14892 24 : curSpace.radiantEnclosureNum = spaceEnclosureNum;
14893 : } else {
14894 24 : curSpace.solarEnclosureNum = spaceEnclosureNum;
14895 : }
14896 48 : auto &thisEnclosure = Enclosures(spaceEnclosureNum);
14897 48 : thisEnclosure.spaceNames.push_back(curSpace.Name);
14898 48 : thisEnclosure.spaceNums.push_back(spaceNum);
14899 48 : thisEnclosure.FloorArea += curSpace.FloorArea;
14900 48 : thisEnclosure.ExtWindowArea += curSpace.extWindowArea;
14901 48 : thisEnclosure.TotalSurfArea += curSpace.totalSurfArea;
14902 : }
14903 : }
14904 10 : if (radiantSetup) {
14905 5 : state.dataViewFactor->NumOfRadiantEnclosures = enclosureNum;
14906 : } else {
14907 5 : state.dataViewFactor->NumOfSolarEnclosures = enclosureNum;
14908 : }
14909 : } else {
14910 : // There are no grouped radiant air boundaries, assign each space to it's own radiant enclosure
14911 11934 : for (int spaceNum = 1; spaceNum <= state.dataGlobal->numSpaces; ++spaceNum) {
14912 10342 : auto &thisEnclosure = Enclosures(spaceNum);
14913 10342 : thisEnclosure.Name = state.dataHeatBal->space(spaceNum).Name;
14914 10342 : thisEnclosure.spaceNames.push_back(state.dataHeatBal->space(spaceNum).Name);
14915 10342 : thisEnclosure.spaceNums.push_back(spaceNum);
14916 10342 : thisEnclosure.FloorArea = state.dataHeatBal->space(spaceNum).FloorArea;
14917 10342 : if (radiantSetup) {
14918 5171 : state.dataHeatBal->space(spaceNum).radiantEnclosureNum = spaceNum;
14919 : } else {
14920 5171 : state.dataHeatBal->space(spaceNum).solarEnclosureNum = spaceNum;
14921 5171 : thisEnclosure.ExtWindowArea = state.dataHeatBal->space(spaceNum).extWindowArea;
14922 5171 : thisEnclosure.TotalSurfArea = state.dataHeatBal->space(spaceNum).totalSurfArea;
14923 : }
14924 : }
14925 1592 : if (radiantSetup) {
14926 796 : state.dataViewFactor->NumOfRadiantEnclosures = state.dataGlobal->numSpaces;
14927 : } else {
14928 796 : state.dataViewFactor->NumOfSolarEnclosures = state.dataGlobal->numSpaces;
14929 : }
14930 : }
14931 1602 : if (radiantSetup) {
14932 801 : assert(state.dataViewFactor->NumOfRadiantEnclosures <= int(Enclosures.size()));
14933 801 : Enclosures.resize(state.dataViewFactor->NumOfRadiantEnclosures);
14934 : } else {
14935 801 : assert(state.dataViewFactor->NumOfSolarEnclosures <= int(Enclosures.size()));
14936 801 : Enclosures.resize(state.dataViewFactor->NumOfSolarEnclosures);
14937 : }
14938 :
14939 12002 : for (auto &thisEnclosure : state.dataViewFactor->EnclRadInfo) {
14940 20800 : SetupOutputVariable(state,
14941 : "Enclosure Mean Radiant Temperature",
14942 : Constant::Units::C,
14943 10400 : thisEnclosure.MRT,
14944 : OutputProcessor::TimeStepType::Zone,
14945 : OutputProcessor::StoreType::Average,
14946 10400 : thisEnclosure.Name);
14947 1602 : }
14948 :
14949 : // TODO MJW: For now, set the max and min enclosure numbers for each zone to be used in CalcInteriorRadExchange with ZoneToResimulate
14950 12004 : for (int zoneNum = 1; zoneNum <= state.dataGlobal->NumOfZones; ++zoneNum) {
14951 20828 : for (int spaceNum : state.dataHeatBal->Zone(zoneNum).spaceIndexes) {
14952 10426 : if (state.dataHeatBal->Zone(zoneNum).zoneRadEnclosureFirst == -1) { // initial value
14953 5201 : state.dataHeatBal->Zone(zoneNum).zoneRadEnclosureFirst = state.dataHeatBal->space(spaceNum).radiantEnclosureNum;
14954 : } else {
14955 5225 : state.dataHeatBal->Zone(zoneNum).zoneRadEnclosureFirst =
14956 5225 : min(state.dataHeatBal->Zone(zoneNum).zoneRadEnclosureFirst, state.dataHeatBal->space(spaceNum).radiantEnclosureNum);
14957 : }
14958 10426 : state.dataHeatBal->Zone(zoneNum).zoneRadEnclosureLast =
14959 10426 : max(state.dataHeatBal->Zone(zoneNum).zoneRadEnclosureLast, state.dataHeatBal->space(spaceNum).radiantEnclosureNum);
14960 10402 : }
14961 10402 : assert(state.dataHeatBal->Zone(zoneNum).zoneRadEnclosureFirst != -1);
14962 10402 : assert(state.dataHeatBal->Zone(zoneNum).zoneRadEnclosureLast != -1);
14963 10402 : assert(state.dataHeatBal->Zone(zoneNum).zoneRadEnclosureFirst <= state.dataHeatBal->Zone(zoneNum).zoneRadEnclosureLast);
14964 : }
14965 1602 : }
14966 :
14967 43281 : void CheckConvexity(EnergyPlusData &state,
14968 : int const SurfNum, // Current surface number
14969 : int const NSides // Number of sides to figure
14970 : )
14971 : {
14972 : // SUBROUTINE INFORMATION:
14973 : // AUTHOR Tyler Hoyt
14974 : // DATE WRITTEN December 2010
14975 : // MODIFIED CR8752 - incorrect note of non-convex polygons
14976 :
14977 : // PURPOSE OF THIS SUBROUTINE: This subroutine verifies the convexity of a
14978 : // surface that is exposed to the sun in the case that full shading calculations
14979 : // are required. The calculation conveniently detects collinear points as well,
14980 : // and returns a list of indices that are collinear within the plane of the surface.
14981 :
14982 : // METHODOLOGY EMPLOYED: First the surface is determined to have dimension 2 in
14983 : // either the xy, yz, or xz plane. That plane is selected to do the testing.
14984 : // Vectors representing the edges of the polygon and the perpendicular dot product
14985 : // between adjacent edges are computed. This allows the turning angle to be determined.
14986 : // If the turning angle is greater than pi/2, it turns to the right, and if it is
14987 : // less than pi/2, it turns left. The direction of the turn is stored, and if it
14988 : // changes as the edges are iterated the surface is not convex. Meanwhile it stores
14989 : // the indices of vertices that are collinear and are later removed.
14990 :
14991 : // REFERENCES:
14992 : // http://mathworld.wolfram.com/ConvexPolygon.html
14993 :
14994 43281 : constexpr Real64 TurnThreshold = 0.000001; // Sensitivity of convexity test, in radians
14995 :
14996 43281 : Real64 LastTheta = 0.0; // Angle between edge vectors
14997 : bool SignFlag; // Direction of edge turn : true is right, false is left
14998 43281 : bool PrevSignFlag(false); // Container for the sign of the previous iteration's edge turn
14999 43281 : bool PrevSignFlagInitialized(false); // Whether we picked a PrevSignFlag already or not
15000 43281 : auto &X = state.dataSurfaceGeometry->X; // containers for x,y,z vertices of the surface
15001 43281 : auto &Y = state.dataSurfaceGeometry->Y;
15002 43281 : auto &Z = state.dataSurfaceGeometry->Z;
15003 43281 : auto &A = state.dataSurfaceGeometry->A; // containers for convexity test
15004 43281 : auto &B = state.dataSurfaceGeometry->B;
15005 43281 : auto &VertSize = state.dataSurfaceGeometry->VertSize; // size of X,Y,Z,A,B arrays
15006 :
15007 43281 : std::vector<int> surfCollinearVerts; // index of vertices to remove, 1-indexed
15008 43281 : surfCollinearVerts.reserve(NSides + 2);
15009 :
15010 43281 : if (state.dataSurfaceGeometry->CheckConvexityFirstTime) {
15011 765 : X.allocate(state.dataSurface->MaxVerticesPerSurface + 2);
15012 765 : Y.allocate(state.dataSurface->MaxVerticesPerSurface + 2);
15013 765 : Z.allocate(state.dataSurface->MaxVerticesPerSurface + 2);
15014 765 : A.allocate(state.dataSurface->MaxVerticesPerSurface + 2);
15015 765 : B.allocate(state.dataSurface->MaxVerticesPerSurface + 2);
15016 765 : VertSize = state.dataSurface->MaxVerticesPerSurface;
15017 765 : state.dataSurfaceGeometry->CheckConvexityFirstTime = false;
15018 : }
15019 :
15020 43281 : if (NSides > VertSize) {
15021 33 : X.deallocate();
15022 33 : Y.deallocate();
15023 33 : Z.deallocate();
15024 33 : A.deallocate();
15025 33 : B.deallocate();
15026 33 : X.allocate(state.dataSurface->MaxVerticesPerSurface + 2);
15027 33 : Y.allocate(state.dataSurface->MaxVerticesPerSurface + 2);
15028 33 : Z.allocate(state.dataSurface->MaxVerticesPerSurface + 2);
15029 33 : A.allocate(state.dataSurface->MaxVerticesPerSurface + 2);
15030 33 : B.allocate(state.dataSurface->MaxVerticesPerSurface + 2);
15031 33 : VertSize = state.dataSurface->MaxVerticesPerSurface;
15032 : }
15033 :
15034 43281 : auto &surfaceTmp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
15035 43281 : auto &vertices = surfaceTmp.Vertex;
15036 :
15037 217268 : for (int n = 1; n <= NSides; ++n) {
15038 173987 : X(n) = vertices(n).x;
15039 173987 : Y(n) = vertices(n).y;
15040 173987 : Z(n) = vertices(n).z;
15041 : }
15042 43281 : X(NSides + 1) = vertices(1).x;
15043 43281 : Y(NSides + 1) = vertices(1).y;
15044 43281 : Z(NSides + 1) = vertices(1).z;
15045 43281 : X(NSides + 2) = vertices(2).x;
15046 43281 : Y(NSides + 2) = vertices(2).y;
15047 43281 : Z(NSides + 2) = vertices(2).z;
15048 :
15049 : // Determine a suitable plane in which to do the tests
15050 43281 : Real64 Det = 0.0;
15051 217268 : for (int n = 1; n <= NSides; ++n) {
15052 173987 : Det += X(n) * Y(n + 1) - X(n + 1) * Y(n);
15053 : }
15054 43281 : if (std::abs(Det) > Constant::SmallDistance) {
15055 13982 : A = X;
15056 13982 : B = Y;
15057 : } else {
15058 29299 : Det = 0.0;
15059 146399 : for (int n = 1; n <= NSides; ++n) {
15060 117100 : Det += X(n) * Z(n + 1) - X(n + 1) * Z(n);
15061 : }
15062 29299 : if (std::abs(Det) > Constant::SmallDistance) {
15063 19645 : A = X;
15064 19645 : B = Z;
15065 : } else {
15066 9654 : Det = 0.0;
15067 48202 : for (int n = 1; n <= NSides; ++n) {
15068 38548 : Det += Y(n) * Z(n + 1) - Y(n + 1) * Z(n);
15069 : }
15070 9654 : if (std::abs(Det) > Constant::SmallDistance) {
15071 9654 : A = Y;
15072 9654 : B = Z;
15073 : } else {
15074 : // This condition should not be reached if the surfaces are guaranteed to be planar already
15075 0 : ShowSevereError(state, format("CheckConvexity: Surface=\"{}\" is non-planar.", surfaceTmp.Name));
15076 0 : ShowContinueError(state, "Coincident Vertices will be removed as possible.");
15077 0 : for (int n = 1; n <= surfaceTmp.Sides; ++n) {
15078 0 : auto const &point = vertices(n);
15079 : static constexpr std::string_view ErrFmt = " ({:8.3F},{:8.3F},{:8.3F})";
15080 0 : ShowContinueError(state, format(ErrFmt, point.x, point.y, point.z));
15081 : }
15082 : }
15083 : }
15084 : }
15085 :
15086 217268 : for (int n = 1; n <= NSides; ++n) { // perform convexity test in the plane determined above.
15087 :
15088 173987 : DataVectorTypes::Vector_2d pt0(A(n), B(n));
15089 173987 : DataVectorTypes::Vector_2d pt1(A(n + 1), B(n + 1));
15090 173987 : DataVectorTypes::Vector_2d pt2(A(n + 2), B(n + 2));
15091 :
15092 173987 : DataVectorTypes::Vector_2d V1 = pt1 - pt0;
15093 173987 : DataVectorTypes::Vector_2d V2 = pt2 - pt1;
15094 :
15095 173987 : Real64 V1len = V1.length(); // = norm_L2()
15096 173987 : Real64 V2len = V2.length();
15097 173987 : if (V1len <= 1.e-8 || V2len <= 1.e-8) {
15098 : // At least two points are coincident. Should this happen? GetVertices is supposed to pop these vertices
15099 0 : continue;
15100 : }
15101 173987 : Real64 CrossProd = V1.cross(V2);
15102 173987 : Real64 sinarg = CrossProd / (V1len * V2len);
15103 173987 : if (sinarg < -1.0) {
15104 890 : sinarg = -1.0;
15105 173097 : } else if (sinarg > 1.0) {
15106 665 : sinarg = 1.0;
15107 : }
15108 173987 : Real64 Theta = std::asin(sinarg);
15109 173987 : if (Theta > TurnThreshold) {
15110 86002 : SignFlag = true;
15111 87985 : } else if (Theta < -TurnThreshold) {
15112 87985 : SignFlag = false;
15113 : } else { // std::abs(Theta) < TurnThreshold
15114 : // Store the index of the collinear vertex for removal
15115 0 : int colinearIndex = n + 1;
15116 0 : if (colinearIndex > NSides) {
15117 0 : colinearIndex -= NSides;
15118 : }
15119 0 : if (state.dataGlobal->DisplayExtraWarnings) {
15120 0 : ShowWarningError(
15121 : state,
15122 0 : format("CheckConvexity: Surface=\"{}\", vertex {} is colinear with previous and next.", surfaceTmp.Name, colinearIndex));
15123 : }
15124 0 : ++state.dataErrTracking->TotalCoincidentVertices;
15125 0 : surfCollinearVerts.push_back(colinearIndex);
15126 0 : continue;
15127 0 : }
15128 :
15129 173987 : if (!PrevSignFlagInitialized) {
15130 43281 : PrevSignFlag = SignFlag;
15131 43281 : LastTheta = Theta;
15132 43281 : PrevSignFlagInitialized = true;
15133 43281 : continue;
15134 : }
15135 :
15136 130706 : if (SignFlag != PrevSignFlag) {
15137 801 : if (state.dataGlobal->DisplayExtraWarnings && surfaceTmp.ExtSolar &&
15138 0 : (state.dataHeatBal->SolarDistribution != DataHeatBalance::Shadowing::Minimal) && surfaceTmp.IsConvex &&
15139 801 : !state.dataSysVars->SutherlandHodgman &&
15140 0 : (state.dataSysVars->shadingMethod == DataSystemVariables::ShadingMethod::PolygonClipping)) {
15141 0 : ShowWarningError(state,
15142 0 : format("CheckConvexity: Zone=\"{}\", Surface=\"{}\" is non-convex.",
15143 0 : state.dataHeatBal->Zone(surfaceTmp.Zone).Name,
15144 0 : surfaceTmp.Name));
15145 0 : int Np1 = n + 1;
15146 0 : if (Np1 > NSides) {
15147 0 : Np1 -= NSides;
15148 : }
15149 0 : int Np2 = n + 2;
15150 0 : if (Np2 > NSides) {
15151 0 : Np2 -= NSides;
15152 : }
15153 0 : ShowContinueError(state, format("...vertex {} to vertex {} to vertex {}", n, Np1, Np2));
15154 0 : ShowContinueError(state, format("...vertex {}=[{:.2R},{:.2R},{:.2R}]", n, X(n), Y(n), Z(n)));
15155 0 : ShowContinueError(state, format("...vertex {}=[{:.2R},{:.2R},{:.2R}]", Np1, X(n + 1), Y(n + 1), Z(n + 1)));
15156 0 : ShowContinueError(state, format("...vertex {}=[{:.2R},{:.2R},{:.2R}]", Np2, X(n + 2), Y(n + 2), Z(n + 2)));
15157 : // ShowContinueError(state, format("...theta angle=[{:.6R}]", Theta));
15158 : // ShowContinueError(state, format("...last theta angle=[{:.6R}]", LastTheta));
15159 : }
15160 801 : surfaceTmp.IsConvex = false;
15161 : // #10103 - We do not want to break early, because we do want to consistently remove colinear vertices
15162 : // to avoid potential vertex size mismatch fatal errors
15163 : // break;
15164 : }
15165 130706 : PrevSignFlag = SignFlag;
15166 130706 : LastTheta = Theta;
15167 347111 : }
15168 :
15169 : // must check to make sure don't remove NSides below 3
15170 43281 : int M = surfCollinearVerts.size();
15171 43281 : if (M > 0) { // Remove the collinear points determined above
15172 0 : if (NSides - M >= 3) {
15173 0 : surfaceTmp.Sides = NSides - M;
15174 0 : if (state.dataGlobal->DisplayExtraWarnings) {
15175 0 : ShowWarningError(state,
15176 0 : format("CheckConvexity: Surface=\"{}\" has [{}] collinear points that have been removed.", surfaceTmp.Name, M));
15177 : }
15178 : } else { // too many
15179 0 : if (state.dataGlobal->DisplayExtraWarnings) {
15180 0 : ShowWarningError(state, format("CheckConvexity: Surface=\"{}\" has [{}] collinear points.", surfaceTmp.Name, M));
15181 0 : ShowContinueError(state, "...too many to remove all. Will leave the surface with 3 sides. But this is now a degenerate surface");
15182 : }
15183 0 : ++state.dataErrTracking->TotalDegenerateSurfaces;
15184 0 : surfaceTmp.Sides = 3; // max(NSides - M, 3) = 3 since NSide - M is < 3;
15185 0 : surfCollinearVerts.resize(NSides - 3);
15186 : }
15187 :
15188 : // remove duplicated points: For that we construct a new array of vertices, only copying indices that aren't in SurfCollinearVerts
15189 : // Then we move that array into the original one
15190 0 : Array1D<Vector> newVertices;
15191 0 : newVertices.allocate(surfaceTmp.Sides);
15192 :
15193 0 : int n = 0;
15194 0 : for (int i = 1; i <= NSides; ++i) {
15195 0 : if (std::find(surfCollinearVerts.cbegin(), surfCollinearVerts.cend(), i) == surfCollinearVerts.cend()) {
15196 0 : newVertices(++n) = vertices(i);
15197 : }
15198 : }
15199 0 : vertices = std::move(newVertices);
15200 :
15201 0 : if (state.dataGlobal->DisplayExtraWarnings) {
15202 0 : ShowWarningError(state,
15203 0 : format("CheckConvexity: Surface=\"{}\": The vertex points has been reprocessed as Sides = {}",
15204 0 : surfaceTmp.Name,
15205 0 : surfaceTmp.Sides));
15206 : }
15207 0 : }
15208 43281 : }
15209 :
15210 44358 : bool isRectangle(EnergyPlusData &state, int const ThisSurf // Surface number
15211 : )
15212 : {
15213 : // SUBROUTINE INFORMATION:
15214 : // AUTHOR M.J. Witte
15215 : // DATE WRITTEN October 2015
15216 :
15217 : // PURPOSE: Check if a 4-sided surface is a rectangle
15218 :
15219 : Real64 Diagonal1; // Length of diagonal of 4-sided figure from vertex 1 to vertex 3 (m)
15220 : Real64 Diagonal2; // Length of diagonal of 4-sided figure from vertex 2 to vertex 4 (m)
15221 : Real64 DotProd; // Dot product of two adjacent sides - to test for right angle
15222 44358 : Real64 const cos89deg = std::cos(89.0 * Constant::DegToRad); // tolerance for right angle
15223 44358 : Vector Vect32; // normalized vector from vertex 3 to vertex 2
15224 44358 : Vector Vect21; // normalized vector from vertex 2 to vertex 1
15225 :
15226 44358 : auto &surf = state.dataSurface->Surface(ThisSurf);
15227 44358 : Diagonal1 = Vectors::VecLength(surf.Vertex(1) - surf.Vertex(3));
15228 44358 : Diagonal2 = Vectors::VecLength(surf.Vertex(2) - surf.Vertex(4));
15229 : // Test for rectangularity
15230 44358 : if (std::abs(Diagonal1 - Diagonal2) < 0.020) { // This tolerance based on coincident vertex tolerance of 0.01
15231 42899 : Vect32 = Vectors::VecNormalize(surf.Vertex(3) - surf.Vertex(2));
15232 42899 : Vect21 = Vectors::VecNormalize(surf.Vertex(2) - surf.Vertex(1));
15233 42899 : DotProd = dot(Vect32, Vect21);
15234 42899 : if (std::abs(DotProd) <= cos89deg) {
15235 39066 : return true;
15236 : } else {
15237 3833 : return false;
15238 : }
15239 : } else {
15240 1459 : return false;
15241 : }
15242 44358 : }
15243 :
15244 1 : void MakeEquivalentRectangle(EnergyPlusData &state,
15245 : int const SurfNum, // Surface number
15246 : bool &ErrorsFound // Error flag indicator (true if errors found)
15247 : )
15248 : {
15249 : // SUBROUTINE INFORMATION:
15250 : // AUTHOR R. Zhang, LBNL
15251 : // DATE WRITTEN September 2016
15252 :
15253 : // PURPOSE OF THIS SUBROUTINE:
15254 : // Processing of 4-sided but non-rectangular Window, Door or GlassDoor.
15255 : // Calculate the effective height and width of the surface.
15256 : //
15257 : // METHODOLOGY EMPLOYED:
15258 : // Transform the surface into an equivalent rectangular surface with the same area and aspect ratio.
15259 :
15260 : Real64 AspectRatio; // Aspect ratio
15261 : Real64 WidthEff; // Effective width of the surface
15262 : Real64 WidthMax; // X difference between the vertex on the most left and the one on the most right
15263 : Real64 HeightEff; // Effective height of the surface
15264 : Real64 HeightMax; // Y difference between the lowest and highest vertices
15265 : Real64 Xp;
15266 : Real64 Yp;
15267 : Real64 Zp;
15268 : Real64 XLLC;
15269 : Real64 YLLC;
15270 : Real64 ZLLC;
15271 :
15272 1 : if (SurfNum == 0) {
15273 : // invalid surface
15274 0 : ErrorsFound = true;
15275 0 : return;
15276 : }
15277 :
15278 1 : auto &surf = state.dataSurface->Surface(SurfNum);
15279 1 : if (surf.Sides != 4) {
15280 : // the method is designed for 4-sided surface
15281 0 : return;
15282 1 : } else if (isRectangle(state, SurfNum)) {
15283 : // no need to transform
15284 0 : return;
15285 : }
15286 :
15287 1 : Real64 SurfWorldAz = surf.Azimuth;
15288 1 : Real64 SurfTilt = surf.Tilt;
15289 1 : Real64 BaseCosAzimuth = std::cos(SurfWorldAz * Constant::DegToRad);
15290 1 : Real64 BaseSinAzimuth = std::sin(SurfWorldAz * Constant::DegToRad);
15291 1 : Real64 BaseCosTilt = std::cos(SurfTilt * Constant::DegToRad);
15292 1 : Real64 BaseSinTilt = std::sin(SurfTilt * Constant::DegToRad);
15293 1 : int NumSurfSides = surf.Sides;
15294 :
15295 : // Calculate WidthMax and HeightMax
15296 1 : WidthMax = 0.0;
15297 1 : HeightMax = 0.0;
15298 4 : for (int i = 1; i < NumSurfSides; ++i) {
15299 9 : for (int j = i + 1; j <= NumSurfSides; ++j) {
15300 :
15301 6 : Xp = surf.Vertex(j).x - surf.Vertex(i).x;
15302 6 : Yp = surf.Vertex(j).y - surf.Vertex(i).y;
15303 6 : Zp = surf.Vertex(j).z - surf.Vertex(i).z;
15304 :
15305 6 : XLLC = -Xp * BaseCosAzimuth + Yp * BaseSinAzimuth;
15306 6 : YLLC = -Xp * BaseSinAzimuth * BaseCosTilt - Yp * BaseCosAzimuth * BaseCosTilt + Zp * BaseSinTilt;
15307 6 : ZLLC = Xp * BaseSinAzimuth * BaseSinTilt + Yp * BaseCosAzimuth * BaseSinTilt + Zp * BaseCosTilt;
15308 :
15309 6 : if (std::abs(XLLC) > WidthMax) {
15310 1 : WidthMax = std::abs(XLLC);
15311 : }
15312 6 : if (std::abs(YLLC) > WidthMax) {
15313 1 : HeightMax = std::abs(YLLC);
15314 : }
15315 : }
15316 : }
15317 :
15318 : // Perform transformation by calculating WidthEff and HeightEff
15319 1 : if ((WidthMax > 0) && (HeightMax > 0)) {
15320 1 : AspectRatio = WidthMax / HeightMax;
15321 : } else {
15322 0 : AspectRatio = 1;
15323 : }
15324 1 : WidthEff = std::sqrt(surf.Area * AspectRatio);
15325 1 : HeightEff = std::sqrt(surf.Area / AspectRatio);
15326 :
15327 : // Assign the effective width and length to the surface
15328 1 : surf.Width = WidthEff;
15329 1 : surf.Height = HeightEff;
15330 : }
15331 :
15332 8937 : void CheckForReversedLayers(EnergyPlusData &state,
15333 : bool &RevLayerDiffs, // true when differences are discovered in interzone constructions
15334 : int const ConstrNum, // construction index
15335 : int const ConstrNumRev, // construction index for reversed construction
15336 : int const TotalLayers // total layers for construction definition
15337 : )
15338 : {
15339 8937 : auto &s_mat = state.dataMaterial;
15340 8937 : RevLayerDiffs = false;
15341 :
15342 27895 : for (int LayerNo = 1; LayerNo <= TotalLayers; ++LayerNo) {
15343 :
15344 18960 : int thisConstLayer = state.dataConstruction->Construct(ConstrNum).LayerPoint(LayerNo);
15345 18960 : int revConstLayer = state.dataConstruction->Construct(ConstrNumRev).LayerPoint(TotalLayers - LayerNo + 1);
15346 18960 : if (thisConstLayer == revConstLayer) {
15347 18958 : continue;
15348 : }
15349 :
15350 2 : auto const *mat = s_mat->materials(thisConstLayer);
15351 2 : auto const *matRev = s_mat->materials(revConstLayer);
15352 :
15353 : // If not point to the same layer, check to see if this is window glass which might need to have
15354 : // front and back material properties reversed.
15355 2 : Real64 constexpr SmallDiff = 0.0001;
15356 2 : if ((mat->group == Material::Group::Glass) && (matRev->group == Material::Group::Glass)) {
15357 0 : auto const *matGlass = dynamic_cast<Material::MaterialGlass const *>(mat);
15358 0 : auto const *matGlassRev = dynamic_cast<Material::MaterialGlass const *>(matRev);
15359 0 : assert(matGlass != nullptr);
15360 0 : assert(matGlassRev != nullptr);
15361 :
15362 : // Both layers are window glass, so need to check to see if the properties are reversed
15363 0 : if ((abs(matGlass->Thickness - matGlassRev->Thickness) > SmallDiff) ||
15364 0 : (abs(matGlass->ReflectSolBeamBack - matGlassRev->ReflectSolBeamFront) > SmallDiff) ||
15365 0 : (abs(matGlass->ReflectSolBeamFront - matGlassRev->ReflectSolBeamBack) > SmallDiff) ||
15366 0 : (abs(matGlass->TransVis - matGlassRev->TransVis) > SmallDiff) ||
15367 0 : (abs(matGlass->ReflectVisBeamBack - matGlassRev->ReflectVisBeamFront) > SmallDiff) ||
15368 0 : (abs(matGlass->ReflectVisBeamFront - matGlassRev->ReflectVisBeamBack) > SmallDiff) ||
15369 0 : (abs(matGlass->TransThermal - matGlassRev->TransThermal) > SmallDiff) ||
15370 0 : (abs(matGlass->AbsorpThermalBack - matGlassRev->AbsorpThermalFront) > SmallDiff) ||
15371 0 : (abs(matGlass->AbsorpThermalFront - matGlassRev->AbsorpThermalBack) > SmallDiff) ||
15372 0 : (abs(matGlass->Conductivity - matGlassRev->Conductivity) > SmallDiff) ||
15373 0 : (abs(matGlass->GlassTransDirtFactor - matGlassRev->GlassTransDirtFactor) > SmallDiff) ||
15374 0 : (matGlass->SolarDiffusing != matGlassRev->SolarDiffusing) ||
15375 0 : (abs(matGlass->YoungModulus - matGlassRev->YoungModulus) > SmallDiff) ||
15376 0 : (abs(matGlass->PoissonsRatio - matGlassRev->PoissonsRatio) > SmallDiff)) {
15377 0 : RevLayerDiffs = true;
15378 0 : break; // exit when diff
15379 : } // If none of the above conditions is met, then these should be the same layers in reverse (RevLayersDiffs = false)
15380 2 : } else if ((mat->group == Material::Group::GlassEQL) && (matRev->group == Material::Group::GlassEQL)) {
15381 0 : auto const *matGlass = dynamic_cast<Material::MaterialGlassEQL const *>(mat);
15382 0 : auto const *matGlassRev = dynamic_cast<Material::MaterialGlassEQL const *>(matRev);
15383 :
15384 0 : if ((abs(matGlass->TAR.Sol.Bk.Bm[0].BmTra - matGlassRev->TAR.Sol.Ft.Bm[0].BmTra) > SmallDiff) ||
15385 0 : (abs(matGlass->TAR.Sol.Ft.Bm[0].BmTra - matGlassRev->TAR.Sol.Bk.Bm[0].BmTra) > SmallDiff) ||
15386 0 : (abs(matGlass->TAR.Sol.Bk.Bm[0].BmRef - matGlassRev->TAR.Sol.Ft.Bm[0].BmRef) > SmallDiff) ||
15387 0 : (abs(matGlass->TAR.Sol.Ft.Bm[0].BmRef - matGlassRev->TAR.Sol.Bk.Bm[0].BmRef) > SmallDiff) ||
15388 0 : (abs(matGlass->TAR.Vis.Bk.Bm[0].BmTra - matGlassRev->TAR.Vis.Ft.Bm[0].BmTra) > SmallDiff) ||
15389 0 : (abs(matGlass->TAR.Vis.Ft.Bm[0].BmTra - matGlassRev->TAR.Vis.Bk.Bm[0].BmTra) > SmallDiff) ||
15390 0 : (abs(matGlass->TAR.Vis.Bk.Bm[0].BmRef - matGlassRev->TAR.Vis.Ft.Bm[0].BmRef) > SmallDiff) ||
15391 0 : (abs(matGlass->TAR.Vis.Ft.Bm[0].BmRef - matGlassRev->TAR.Vis.Bk.Bm[0].BmRef) > SmallDiff) ||
15392 0 : (abs(matGlass->TAR.Sol.Bk.Bm[0].DfTra - matGlassRev->TAR.Sol.Ft.Bm[0].DfTra) > SmallDiff) ||
15393 0 : (abs(matGlass->TAR.Sol.Ft.Bm[0].DfTra - matGlassRev->TAR.Sol.Bk.Bm[0].DfTra) > SmallDiff) ||
15394 0 : (abs(matGlass->TAR.Sol.Bk.Bm[0].DfRef - matGlassRev->TAR.Sol.Ft.Bm[0].DfRef) > SmallDiff) ||
15395 0 : (abs(matGlass->TAR.Sol.Ft.Bm[0].DfRef - matGlassRev->TAR.Sol.Bk.Bm[0].DfRef) > SmallDiff) ||
15396 0 : (abs(matGlass->TAR.Vis.Bk.Bm[0].DfTra - matGlassRev->TAR.Vis.Ft.Bm[0].DfTra) > SmallDiff) ||
15397 0 : (abs(matGlass->TAR.Vis.Ft.Bm[0].DfTra - matGlassRev->TAR.Vis.Bk.Bm[0].DfTra) > SmallDiff) ||
15398 0 : (abs(matGlass->TAR.Vis.Bk.Bm[0].DfRef - matGlassRev->TAR.Vis.Ft.Bm[0].DfRef) > SmallDiff) ||
15399 0 : (abs(matGlass->TAR.Vis.Ft.Bm[0].DfRef - matGlassRev->TAR.Vis.Bk.Bm[0].DfRef) > SmallDiff) ||
15400 0 : (abs(matGlass->TAR.Sol.Ft.Df.Tra - matGlassRev->TAR.Sol.Ft.Df.Tra) > SmallDiff) ||
15401 0 : (abs(matGlass->TAR.Sol.Bk.Df.Ref - matGlassRev->TAR.Sol.Ft.Df.Ref) > SmallDiff) ||
15402 0 : (abs(matGlass->TAR.Sol.Ft.Df.Ref - matGlassRev->TAR.Sol.Bk.Df.Ref) > SmallDiff) ||
15403 0 : (abs(matGlass->TAR.Vis.Ft.Df.Tra - matGlassRev->TAR.Vis.Ft.Df.Tra) > SmallDiff) ||
15404 0 : (abs(matGlass->TAR.Vis.Bk.Df.Ref - matGlassRev->TAR.Vis.Ft.Df.Ref) > SmallDiff) ||
15405 0 : (abs(matGlass->TAR.Vis.Ft.Df.Ref - matGlassRev->TAR.Vis.Bk.Df.Ref) > SmallDiff) ||
15406 0 : (abs(matGlass->TAR.IR.Ft.Tra - matGlassRev->TAR.IR.Ft.Tra) > SmallDiff) ||
15407 0 : (abs(matGlass->TAR.IR.Bk.Emi - matGlassRev->TAR.IR.Ft.Emi) > SmallDiff) ||
15408 0 : (abs(matGlass->TAR.IR.Ft.Emi - matGlassRev->TAR.IR.Bk.Emi) > SmallDiff) ||
15409 0 : (abs(matGlass->Resistance - matGlassRev->Resistance) > SmallDiff)) {
15410 0 : RevLayerDiffs = true;
15411 0 : break; // exit when diff
15412 : } // If none of the above conditions is met, then these should be the same layers in reverse (RevLayersDiffs = false)
15413 :
15414 0 : } else {
15415 : // Other material types do not have reversed constructions so if they are not the same layer there is a problem
15416 : // (RevLayersDiffs = true)
15417 2 : RevLayerDiffs = true;
15418 2 : break; // exit when diff
15419 : } // End check of whether or not these are WindowGlass
15420 : }
15421 8937 : }
15422 :
15423 801 : void GetGeoSummaryRoof(EnergyPlusData const &state, GeoSummary &geoSummaryRoof)
15424 : {
15425 801 : std::vector<Vector> uniqueRoofVertices;
15426 801 : std::vector<SurfaceGeometry::EdgeOfSurf> uniqEdgeOfSurfs; // I'm only partially using this
15427 48091 : for (const auto &surface : state.dataSurface->Surface) {
15428 :
15429 47290 : if (surface.ExtBoundCond != DataSurfaces::ExternalEnvironment) {
15430 27429 : continue;
15431 : }
15432 19861 : if (!surface.HeatTransSurf) {
15433 1689 : continue;
15434 : }
15435 :
15436 18172 : if (surface.Tilt > 45.0) { // TODO Double check tilt wrt outside vs inside?
15437 15518 : continue;
15438 : }
15439 :
15440 2654 : Real64 const z_min(minval(surface.Vertex, &Vector::z));
15441 2654 : Real64 const z_max(maxval(surface.Vertex, &Vector::z));
15442 2654 : Real64 const verticalHeight = z_max - z_min;
15443 2654 : geoSummaryRoof.Height += verticalHeight * surface.Area;
15444 2654 : geoSummaryRoof.Tilt += surface.Tilt * surface.Area;
15445 2654 : geoSummaryRoof.Azimuth += surface.Azimuth * surface.Area;
15446 2654 : geoSummaryRoof.Area += surface.Area;
15447 :
15448 13458 : for (auto it = surface.Vertex.begin(); it != surface.Vertex.end(); ++it) {
15449 :
15450 10804 : auto itnext = std::next(it);
15451 21608 : if (itnext == std::end(surface.Vertex)) {
15452 5308 : itnext = std::begin(surface.Vertex);
15453 : }
15454 :
15455 10804 : auto &curVertex = *it;
15456 10804 : auto &nextVertex = *itnext;
15457 21608 : auto it2 = std::find_if(uniqueRoofVertices.begin(), uniqueRoofVertices.end(), [&curVertex](const auto &unqV) {
15458 395612 : return SurfaceGeometry::isAlmostEqual3dPt(curVertex, unqV);
15459 21608 : });
15460 10804 : if (it2 == std::end(uniqueRoofVertices)) {
15461 8110 : uniqueRoofVertices.emplace_back(curVertex);
15462 : }
15463 :
15464 10804 : SurfaceGeometry::EdgeOfSurf thisEdge;
15465 10804 : thisEdge.start = std::move(curVertex);
15466 10804 : thisEdge.end = std::move(nextVertex);
15467 10804 : thisEdge.count = 1;
15468 :
15469 : // Uses the custom operator== that uses isAlmostEqual3dPt internally and doesn't care about order of the start/end
15470 10804 : auto itEdge = std::find(uniqEdgeOfSurfs.begin(), uniqEdgeOfSurfs.end(), thisEdge);
15471 10804 : if (itEdge == uniqEdgeOfSurfs.end()) {
15472 9681 : uniqEdgeOfSurfs.emplace_back(std::move(thisEdge));
15473 : } else {
15474 1123 : ++(itEdge->count);
15475 : }
15476 10804 : }
15477 801 : }
15478 :
15479 801 : if (geoSummaryRoof.Area > 0) {
15480 748 : geoSummaryRoof.Height /= geoSummaryRoof.Area;
15481 748 : geoSummaryRoof.Tilt /= geoSummaryRoof.Area;
15482 748 : geoSummaryRoof.Azimuth /= geoSummaryRoof.Area;
15483 : } else {
15484 53 : geoSummaryRoof.Height = 0.0;
15485 53 : geoSummaryRoof.Tilt = 0.0;
15486 53 : geoSummaryRoof.Azimuth = 0.0;
15487 : }
15488 :
15489 : // Remove the ones that are already used twice
15490 1602 : uniqEdgeOfSurfs.erase(
15491 11283 : std::remove_if(uniqEdgeOfSurfs.begin(), uniqEdgeOfSurfs.end(), [](const auto &edge) -> bool { return edge.count == 2; }),
15492 1602 : uniqEdgeOfSurfs.end());
15493 :
15494 : // Intersect with unique vertices as much as needed
15495 801 : bool insertedVertext = true;
15496 2558 : while (insertedVertext) {
15497 1757 : insertedVertext = false;
15498 :
15499 44121 : for (auto &edge : uniqEdgeOfSurfs) {
15500 :
15501 : // now go through all the vertices and see if they are colinear with start and end vertices
15502 6611482 : for (const auto &testVertex : uniqueRoofVertices) {
15503 6569118 : if (edge.containsPoints(testVertex)) {
15504 956 : SurfaceGeometry::EdgeOfSurf newEdgeOfSurface;
15505 956 : newEdgeOfSurface.start = testVertex;
15506 956 : newEdgeOfSurface.end = edge.end;
15507 956 : edge.end = testVertex;
15508 956 : uniqEdgeOfSurfs.emplace_back(std::move(newEdgeOfSurface));
15509 956 : insertedVertext = true;
15510 956 : break;
15511 956 : }
15512 43320 : }
15513 : // Break out of the loop on edges, and start again at the while
15514 43320 : if (insertedVertext) {
15515 956 : break;
15516 : }
15517 1757 : }
15518 : }
15519 :
15520 : // recount
15521 10315 : for (auto &edge : uniqEdgeOfSurfs) {
15522 9514 : edge.count = std::count(uniqEdgeOfSurfs.begin(), uniqEdgeOfSurfs.end(), edge);
15523 801 : }
15524 :
15525 1602 : uniqEdgeOfSurfs.erase(
15526 11116 : std::remove_if(uniqEdgeOfSurfs.begin(), uniqEdgeOfSurfs.end(), [](const auto &edge) -> bool { return edge.count == 2; }),
15527 1602 : uniqEdgeOfSurfs.end());
15528 :
15529 801 : geoSummaryRoof.Perimeter =
15530 801 : std::accumulate(uniqEdgeOfSurfs.cbegin(), uniqEdgeOfSurfs.cend(), 0.0, [](const double &sum, const SurfaceGeometry::EdgeOfSurf &edge) {
15531 7256 : return sum + edge.length();
15532 : });
15533 801 : }
15534 :
15535 : } // namespace SurfaceGeometry
15536 :
15537 : } // namespace EnergyPlus
|