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 240 : void AllocateSurfaceWindows(EnergyPlusData &state, int NumSurfaces)
118 : {
119 240 : state.dataSurface->SurfWinA.dimension(state.dataSurface->TotSurfaces, DataWindowEquivalentLayer::CFSMAXNL + 1, 0.0);
120 240 : state.dataSurface->SurfWinADiffFront.dimension(state.dataSurface->TotSurfaces, DataWindowEquivalentLayer::CFSMAXNL + 1, 0.0);
121 240 : state.dataSurface->SurfWinACFOverlap.dimension(state.dataSurface->TotSurfaces, state.dataHeatBal->MaxSolidWinLayers, 0.0);
122 :
123 240 : state.dataSurface->SurfWinFrameQRadOutAbs.dimension(NumSurfaces, 0);
124 240 : state.dataSurface->SurfWinFrameQRadInAbs.dimension(NumSurfaces, 0);
125 240 : state.dataSurface->SurfWinDividerQRadOutAbs.dimension(NumSurfaces, 0);
126 240 : state.dataSurface->SurfWinDividerQRadInAbs.dimension(NumSurfaces, 0);
127 240 : state.dataSurface->SurfWinExtBeamAbsByShade.dimension(NumSurfaces, 0);
128 240 : state.dataSurface->SurfWinExtDiffAbsByShade.dimension(NumSurfaces, 0);
129 240 : state.dataSurface->SurfWinIntBeamAbsByShade.dimension(NumSurfaces, 0);
130 240 : state.dataSurface->SurfWinIntSWAbsByShade.dimension(NumSurfaces, 0);
131 240 : state.dataSurface->SurfWinInitialDifSolAbsByShade.dimension(NumSurfaces, 0);
132 240 : state.dataSurface->SurfWinIntLWAbsByShade.dimension(NumSurfaces, 0);
133 240 : state.dataSurface->SurfWinConvHeatFlowNatural.dimension(NumSurfaces, 0);
134 240 : state.dataSurface->SurfWinConvHeatGainToZoneAir.dimension(NumSurfaces, 0);
135 240 : state.dataSurface->SurfWinRetHeatGainToZoneAir.dimension(NumSurfaces, 0);
136 240 : state.dataSurface->SurfWinDividerHeatGain.dimension(NumSurfaces, 0);
137 240 : state.dataSurface->SurfWinBlTsolBmBm.dimension(NumSurfaces, 0);
138 240 : state.dataSurface->SurfWinBlTsolBmDif.dimension(NumSurfaces, 0);
139 240 : state.dataSurface->SurfWinBlTsolDifDif.dimension(NumSurfaces, 0);
140 240 : state.dataSurface->SurfWinBlGlSysTsolBmBm.dimension(NumSurfaces, 0);
141 240 : state.dataSurface->SurfWinBlGlSysTsolDifDif.dimension(NumSurfaces, 0);
142 240 : state.dataSurface->SurfWinScTsolBmBm.dimension(NumSurfaces, 0);
143 240 : state.dataSurface->SurfWinScTsolBmDif.dimension(NumSurfaces, 0);
144 240 : state.dataSurface->SurfWinScTsolDifDif.dimension(NumSurfaces, 0);
145 240 : state.dataSurface->SurfWinScGlSysTsolBmBm.dimension(NumSurfaces, 0);
146 240 : state.dataSurface->SurfWinScGlSysTsolDifDif.dimension(NumSurfaces, 0);
147 240 : state.dataSurface->SurfWinGlTsolBmBm.dimension(NumSurfaces, 0);
148 240 : state.dataSurface->SurfWinGlTsolBmDif.dimension(NumSurfaces, 0);
149 240 : state.dataSurface->SurfWinGlTsolDifDif.dimension(NumSurfaces, 0);
150 240 : state.dataSurface->SurfWinBmSolTransThruIntWinRep.dimension(NumSurfaces, 0);
151 240 : state.dataSurface->SurfWinBmSolAbsdOutsReveal.dimension(NumSurfaces, 0);
152 240 : state.dataSurface->SurfWinBmSolRefldOutsRevealReport.dimension(NumSurfaces, 0);
153 240 : state.dataSurface->SurfWinBmSolAbsdInsReveal.dimension(NumSurfaces, 0);
154 240 : state.dataSurface->SurfWinBmSolRefldInsReveal.dimension(NumSurfaces, 0);
155 240 : state.dataSurface->SurfWinBmSolRefldInsRevealReport.dimension(NumSurfaces, 0);
156 240 : state.dataSurface->SurfWinOutsRevealDiffOntoGlazing.dimension(NumSurfaces, 0);
157 240 : state.dataSurface->SurfWinInsRevealDiffOntoGlazing.dimension(NumSurfaces, 0);
158 240 : state.dataSurface->SurfWinInsRevealDiffIntoZone.dimension(NumSurfaces, 0);
159 240 : state.dataSurface->SurfWinOutsRevealDiffOntoFrame.dimension(NumSurfaces, 0);
160 240 : state.dataSurface->SurfWinInsRevealDiffOntoFrame.dimension(NumSurfaces, 0);
161 240 : state.dataSurface->SurfWinInsRevealDiffOntoGlazingReport.dimension(NumSurfaces, 0);
162 240 : state.dataSurface->SurfWinInsRevealDiffIntoZoneReport.dimension(NumSurfaces, 0);
163 240 : state.dataSurface->SurfWinInsRevealDiffOntoFrameReport.dimension(NumSurfaces, 0);
164 240 : state.dataSurface->SurfWinBmSolAbsdInsRevealReport.dimension(NumSurfaces, 0);
165 240 : state.dataSurface->SurfWinBmSolTransThruIntWinRepEnergy.dimension(NumSurfaces, 0);
166 240 : state.dataSurface->SurfWinBmSolRefldOutsRevealRepEnergy.dimension(NumSurfaces, 0);
167 240 : state.dataSurface->SurfWinBmSolRefldInsRevealRepEnergy.dimension(NumSurfaces, 0);
168 240 : state.dataSurface->SurfWinProfileAngHor.dimension(NumSurfaces, 0);
169 240 : state.dataSurface->SurfWinProfileAngVert.dimension(NumSurfaces, 0);
170 :
171 240 : state.dataSurface->SurfWinShadingFlag.dimension(NumSurfaces, DataSurfaces::WinShadingType::ShadeOff);
172 240 : state.dataSurface->SurfWinShadingFlagEMSOn.dimension(NumSurfaces, 0);
173 240 : state.dataSurface->SurfWinShadingFlagEMSValue.dimension(NumSurfaces, 0.0);
174 240 : state.dataSurface->SurfWinStormWinFlag.dimension(NumSurfaces, 0);
175 240 : state.dataSurface->SurfWinStormWinFlagPrevDay.dimension(NumSurfaces, 0);
176 240 : state.dataSurface->SurfWinFracTimeShadingDeviceOn.dimension(NumSurfaces, 0);
177 240 : state.dataSurface->SurfWinExtIntShadePrevTS.dimension(NumSurfaces, DataSurfaces::WinShadingType::ShadeOff);
178 240 : state.dataSurface->SurfWinHasShadeOrBlindLayer.dimension(NumSurfaces, 0);
179 240 : state.dataSurface->SurfWinSurfDayLightInit.dimension(NumSurfaces, 0);
180 240 : state.dataSurface->SurfWinDaylFacPoint.dimension(NumSurfaces, 0);
181 240 : state.dataSurface->SurfWinVisTransSelected.dimension(NumSurfaces, 0);
182 240 : state.dataSurface->SurfWinSwitchingFactor.dimension(NumSurfaces, 0);
183 240 : state.dataSurface->SurfWinVisTransRatio.dimension(NumSurfaces, 0);
184 240 : state.dataSurface->SurfWinIRfromParentZone.dimension(NumSurfaces, 0);
185 240 : state.dataSurface->SurfWinFrameArea.dimension(NumSurfaces, 0);
186 240 : state.dataSurface->SurfWinFrameConductance.dimension(NumSurfaces, 0);
187 240 : state.dataSurface->SurfWinFrameSolAbsorp.dimension(NumSurfaces, 0);
188 240 : state.dataSurface->SurfWinFrameVisAbsorp.dimension(NumSurfaces, 0);
189 240 : state.dataSurface->SurfWinFrameEmis.dimension(NumSurfaces, 0);
190 240 : state.dataSurface->SurfWinFrEdgeToCenterGlCondRatio.dimension(NumSurfaces, 1.0);
191 240 : state.dataSurface->SurfWinFrameEdgeArea.dimension(NumSurfaces, 0);
192 240 : state.dataSurface->SurfWinFrameTempIn.dimension(NumSurfaces, 23.0);
193 240 : state.dataSurface->SurfWinFrameTempInOld.dimension(NumSurfaces, 23.0);
194 240 : state.dataSurface->SurfWinFrameTempSurfOut.dimension(NumSurfaces, 23.0);
195 240 : state.dataSurface->SurfWinProjCorrFrOut.dimension(NumSurfaces, 0);
196 240 : state.dataSurface->SurfWinProjCorrFrIn.dimension(NumSurfaces, 0);
197 240 : state.dataSurface->SurfWinDividerType.dimension(NumSurfaces, DataSurfaces::FrameDividerType::DividedLite);
198 240 : state.dataSurface->SurfWinDividerArea.dimension(NumSurfaces, 0);
199 240 : state.dataSurface->SurfWinDividerConductance.dimension(NumSurfaces, 0);
200 240 : state.dataSurface->SurfWinDividerSolAbsorp.dimension(NumSurfaces, 0);
201 240 : state.dataSurface->SurfWinDividerVisAbsorp.dimension(NumSurfaces, 0);
202 240 : state.dataSurface->SurfWinDividerEmis.dimension(NumSurfaces, 0);
203 240 : state.dataSurface->SurfWinDivEdgeToCenterGlCondRatio.dimension(NumSurfaces, 1);
204 240 : state.dataSurface->SurfWinDividerEdgeArea.dimension(NumSurfaces, 0);
205 240 : state.dataSurface->SurfWinDividerTempIn.dimension(NumSurfaces, 23.0);
206 240 : state.dataSurface->SurfWinDividerTempInOld.dimension(NumSurfaces, 23.0);
207 240 : state.dataSurface->SurfWinDividerTempSurfOut.dimension(NumSurfaces, 23.0);
208 240 : state.dataSurface->SurfWinProjCorrDivOut.dimension(NumSurfaces, 0);
209 240 : state.dataSurface->SurfWinProjCorrDivIn.dimension(NumSurfaces, 0);
210 240 : state.dataSurface->SurfWinShadeAbsFacFace1.dimension(NumSurfaces, 0.5);
211 240 : state.dataSurface->SurfWinShadeAbsFacFace2.dimension(NumSurfaces, 0.5);
212 240 : state.dataSurface->SurfWinConvCoeffWithShade.dimension(NumSurfaces, 0);
213 240 : state.dataSurface->SurfWinOtherConvHeatGain.dimension(NumSurfaces, 0);
214 240 : state.dataSurface->SurfWinEffInsSurfTemp.dimension(NumSurfaces, 23.0);
215 240 : state.dataSurface->SurfWinTotGlazingThickness.dimension(NumSurfaces, 0);
216 240 : state.dataSurface->SurfWinTanProfileAngHor.dimension(NumSurfaces, 0);
217 240 : state.dataSurface->SurfWinTanProfileAngVert.dimension(NumSurfaces, 0);
218 240 : state.dataSurface->SurfWinInsideSillDepth.dimension(NumSurfaces, 0);
219 240 : state.dataSurface->SurfWinInsideReveal.dimension(NumSurfaces, 0);
220 240 : state.dataSurface->SurfWinInsideSillSolAbs.dimension(NumSurfaces, 0);
221 240 : state.dataSurface->SurfWinInsideRevealSolAbs.dimension(NumSurfaces, 0);
222 240 : state.dataSurface->SurfWinOutsideRevealSolAbs.dimension(NumSurfaces, 0);
223 240 : state.dataSurface->SurfWinAirflowSource.dimension(NumSurfaces, DataSurfaces::WindowAirFlowSource::Invalid);
224 240 : state.dataSurface->SurfWinAirflowDestination.dimension(NumSurfaces, DataSurfaces::WindowAirFlowDestination::Invalid);
225 240 : state.dataSurface->SurfWinAirflowReturnNodePtr.dimension(NumSurfaces, 0);
226 240 : state.dataSurface->SurfWinMaxAirflow.dimension(NumSurfaces, 0);
227 240 : state.dataSurface->SurfWinAirflowControlType.dimension(NumSurfaces, DataSurfaces::WindowAirFlowControlType::Invalid);
228 240 : state.dataSurface->SurfWinAirflowHasSchedule.dimension(NumSurfaces, 0);
229 240 : state.dataSurface->SurfWinAirflowScheds.dimension(NumSurfaces, nullptr);
230 240 : state.dataSurface->SurfWinAirflowThisTS.dimension(NumSurfaces, 0);
231 240 : state.dataSurface->SurfWinTAirflowGapOutlet.dimension(NumSurfaces, 0);
232 240 : state.dataSurface->SurfWinWindowCalcIterationsRep.dimension(NumSurfaces, 0);
233 240 : state.dataSurface->SurfWinVentingOpenFactorMultRep.dimension(NumSurfaces, 0);
234 240 : state.dataSurface->SurfWinInsideTempForVentingRep.dimension(NumSurfaces, 0);
235 240 : state.dataSurface->SurfWinVentingAvailabilityRep.dimension(NumSurfaces, 0);
236 240 : state.dataSurface->SurfWinSkyGndSolarInc.dimension(NumSurfaces, 0);
237 240 : state.dataSurface->SurfWinBmGndSolarInc.dimension(NumSurfaces, 0);
238 240 : state.dataSurface->SurfWinSolarDiffusing.dimension(NumSurfaces, 0);
239 240 : state.dataSurface->SurfWinFrameHeatGain.dimension(NumSurfaces, 0);
240 240 : state.dataSurface->SurfWinFrameHeatLoss.dimension(NumSurfaces, 0);
241 240 : state.dataSurface->SurfWinDividerHeatLoss.dimension(NumSurfaces, 0);
242 240 : state.dataSurface->SurfWinTCLayerTemp.dimension(NumSurfaces, 0);
243 240 : state.dataSurface->SurfWinSpecTemp.dimension(NumSurfaces, 0);
244 240 : state.dataSurface->SurfWinWindowModelType.dimension(NumSurfaces, DataSurfaces::WindowModel::Detailed);
245 240 : state.dataSurface->SurfWinTDDPipeNum.dimension(NumSurfaces, 0);
246 240 : state.dataSurface->SurfWinStormWinConstr.dimension(NumSurfaces, 0);
247 240 : state.dataSurface->SurfActiveConstruction.dimension(NumSurfaces, 0);
248 240 : state.dataSurface->SurfWinActiveShadedConstruction.dimension(NumSurfaces, 0);
249 240 : }
250 :
251 193 : 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 386 : state.dataSurfaceGeometry->CosBldgRelNorth =
274 193 : std::cos(-(state.dataHeatBal->BuildingAzimuth + state.dataHeatBal->BuildingRotationAppendixG) * Constant::DegToRad);
275 386 : state.dataSurfaceGeometry->SinBldgRelNorth =
276 193 : 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 193 : state.dataSurfaceGeometry->CosBldgRotAppGonly = std::cos(-state.dataHeatBal->BuildingRotationAppendixG * Constant::DegToRad);
280 193 : state.dataSurfaceGeometry->SinBldgRotAppGonly = std::sin(-state.dataHeatBal->BuildingRotationAppendixG * Constant::DegToRad);
281 :
282 193 : state.dataSurfaceGeometry->CosZoneRelNorth.allocate(state.dataGlobal->NumOfZones);
283 193 : state.dataSurfaceGeometry->SinZoneRelNorth.allocate(state.dataGlobal->NumOfZones);
284 :
285 469 : for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
286 :
287 276 : state.dataSurfaceGeometry->CosZoneRelNorth(ZoneNum) = std::cos(-state.dataHeatBal->Zone(ZoneNum).RelNorth * Constant::DegToRad);
288 276 : state.dataSurfaceGeometry->SinZoneRelNorth(ZoneNum) = std::sin(-state.dataHeatBal->Zone(ZoneNum).RelNorth * Constant::DegToRad);
289 : }
290 193 : GetSurfaceData(state, ErrorsFound);
291 :
292 192 : if (ErrorsFound) {
293 0 : state.dataSurfaceGeometry->CosZoneRelNorth.deallocate();
294 0 : state.dataSurfaceGeometry->SinZoneRelNorth.deallocate();
295 0 : return;
296 : }
297 :
298 192 : ZoneEquipmentManager::GetZoneEquipment(state); // Necessary to get this before window air gap code
299 :
300 192 : GetWindowGapAirflowControlData(state, ErrorsFound);
301 :
302 192 : GetStormWindowData(state, ErrorsFound);
303 :
304 192 : if (!ErrorsFound && state.dataSurface->TotStormWin > 0) CreateStormWindowConstructions(state);
305 :
306 192 : DataHeatBalance::SetFlagForWindowConstructionWithShadeOrBlindLayer(state);
307 :
308 192 : state.dataSurfaceGeometry->CosZoneRelNorth.deallocate();
309 192 : state.dataSurfaceGeometry->SinZoneRelNorth.deallocate();
310 :
311 192 : state.dataHeatBal->CalcWindowRevealReflection = false; // Set to True in ProcessSurfaceVertices if beam solar reflection from window reveals
312 : // is requested for one or more exterior windows.
313 192 : state.dataSurface->BuildingShadingCount = 0;
314 192 : state.dataSurface->FixedShadingCount = 0;
315 192 : state.dataSurface->AttachedShadingCount = 0;
316 192 : state.dataSurface->ShadingSurfaceFirst = 0;
317 192 : state.dataSurface->ShadingSurfaceLast = -1;
318 :
319 : // Reserve space to avoid excess allocations
320 192 : state.dataSurface->AllExtSolAndShadingSurfaceList.reserve(state.dataSurface->TotSurfaces);
321 :
322 1883 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) { // Loop through all surfaces...
323 1691 : auto &thisSurface = state.dataSurface->Surface(SurfNum);
324 :
325 1691 : state.dataSurface->SurfAirSkyRadSplit(SurfNum) = std::sqrt(0.5 * (1.0 + thisSurface.CosTilt));
326 :
327 : // Set flag that determines whether a surface is a shadowing surface
328 1691 : thisSurface.IsShadowing = false;
329 1691 : if (thisSurface.Class == SurfaceClass::Shading || thisSurface.Class == SurfaceClass::Detached_F ||
330 1637 : thisSurface.Class == SurfaceClass::Detached_B) {
331 74 : thisSurface.IsShadowing = true;
332 74 : if (state.dataSurface->ShadingSurfaceFirst == 0) state.dataSurface->ShadingSurfaceFirst = SurfNum;
333 74 : state.dataSurface->ShadingSurfaceLast = SurfNum;
334 : }
335 1691 : if ((thisSurface.HeatTransSurf && thisSurface.ExtSolar) || thisSurface.IsShadowing) {
336 : // Some attached shading surfaces may be true for both
337 1091 : state.dataSurface->AllExtSolAndShadingSurfaceList.push_back(SurfNum);
338 : }
339 1691 : if (thisSurface.Class == SurfaceClass::Shading) ++state.dataSurface->AttachedShadingCount;
340 1691 : if (thisSurface.Class == SurfaceClass::Detached_F) ++state.dataSurface->FixedShadingCount;
341 1691 : if (thisSurface.Class == SurfaceClass::Detached_B) ++state.dataSurface->BuildingShadingCount;
342 :
343 1691 : if (thisSurface.Class != SurfaceClass::IntMass) ProcessSurfaceVertices(state, SurfNum, ErrorsFound);
344 : }
345 :
346 467 : for (auto &e : state.dataHeatBal->Zone) {
347 275 : e.ExtWindowArea = 0.0;
348 275 : e.HasWindow = false;
349 275 : e.ExtGrossWallArea = 0.0;
350 275 : e.ExtNetWallArea = 0.0;
351 275 : e.TotalSurfArea = 0.0;
352 : }
353 :
354 489 : for (auto &s : state.dataHeatBal->space) {
355 297 : s.extWindowArea = 0.0;
356 297 : s.totalSurfArea = 0.0;
357 : }
358 384 : bool DetailedWWR = (state.dataInputProcessing->inputProcessor->getNumSectionsFound("DETAILEDWWR_DEBUG") > 0);
359 192 : if (DetailedWWR) {
360 0 : print(state.files.debug, "{}", "=======User Entered Classification =================");
361 0 : print(state.files.debug, "{}", "Surface,Class,Area,Tilt");
362 : }
363 :
364 1883 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) { // Loop through all surfaces to find windows...
365 1691 : auto &thisSurface = state.dataSurface->Surface(SurfNum);
366 :
367 1691 : if (!thisSurface.HeatTransSurf && !thisSurface.IsAirBoundarySurf) continue; // Skip shadowing (sub)surfaces
368 1617 : auto &thisZone = state.dataHeatBal->Zone(thisSurface.Zone);
369 1617 : auto &thisSpace = state.dataHeatBal->space(thisSurface.spaceNum);
370 :
371 1617 : thisZone.TotalSurfArea += thisSurface.Area;
372 1617 : thisSpace.totalSurfArea += thisSurface.Area;
373 1617 : if (thisSurface.Class == SurfaceClass::Roof) {
374 257 : thisZone.geometricCeilingArea += thisSurface.GrossArea;
375 1360 : } else if (thisSurface.Class == SurfaceClass::Floor) {
376 328 : thisZone.geometricFloorArea += thisSurface.GrossArea;
377 : }
378 1617 : if (state.dataConstruction->Construct(thisSurface.Construction).TypeIsWindow) {
379 125 : thisZone.TotalSurfArea += state.dataSurface->SurfWinFrameArea(SurfNum);
380 125 : thisZone.HasWindow = true;
381 125 : thisSpace.totalSurfArea += state.dataSurface->SurfWinFrameArea(SurfNum);
382 125 : if (((thisSurface.ExtBoundCond == DataSurfaces::ExternalEnvironment) ||
383 6 : (thisSurface.ExtBoundCond == DataSurfaces::OtherSideCondModeledExt)) &&
384 119 : (thisSurface.Class != SurfaceClass::TDD_Dome)) {
385 112 : thisZone.ExtWindowArea += thisSurface.GrossArea;
386 112 : thisSpace.extWindowArea += thisSurface.GrossArea;
387 112 : thisZone.ExtWindowArea_Multiplied =
388 112 : thisZone.ExtWindowArea + thisSurface.GrossArea * thisSurface.Multiplier * thisZone.Multiplier * thisZone.ListMultiplier;
389 112 : if (DetailedWWR) {
390 0 : print(state.files.debug,
391 : "{},Window,{:.2R},{:.1R}\n",
392 0 : thisSurface.Name,
393 0 : thisSurface.GrossArea * thisSurface.Multiplier * thisZone.Multiplier * thisZone.ListMultiplier,
394 0 : thisSurface.Tilt);
395 : }
396 : }
397 : } else {
398 1492 : if (thisSurface.ExtBoundCond == DataSurfaces::ExternalEnvironment ||
399 526 : thisSurface.ExtBoundCond == DataSurfaces::OtherSideCondModeledExt) {
400 967 : thisZone.ExteriorTotalSurfArea += thisSurface.GrossArea;
401 967 : thisSpace.ExteriorTotalSurfArea += thisSurface.GrossArea;
402 967 : if (thisSurface.Class == SurfaceClass::Wall) {
403 643 : thisZone.ExtNetWallArea += thisSurface.Area;
404 643 : thisZone.ExtGrossWallArea += thisSurface.GrossArea;
405 643 : thisSpace.ExtGrossWallArea += thisSurface.GrossArea;
406 643 : thisZone.ExtGrossWallArea_Multiplied += thisSurface.GrossArea * thisZone.Multiplier * thisZone.ListMultiplier;
407 643 : thisZone.extPerimeter += thisSurface.Width;
408 643 : thisSpace.extPerimeter += thisSurface.Width;
409 643 : if (DetailedWWR) {
410 0 : print(state.files.debug,
411 : "{},Wall,{:.2R},{:.1R}\n",
412 0 : thisSurface.Name,
413 0 : thisSurface.GrossArea * thisZone.Multiplier * thisZone.ListMultiplier,
414 0 : thisSurface.Tilt);
415 : }
416 : }
417 525 : } else if (thisSurface.ExtBoundCond == DataSurfaces::Ground || thisSurface.ExtBoundCond == DataSurfaces::GroundFCfactorMethod ||
418 419 : thisSurface.ExtBoundCond == DataSurfaces::KivaFoundation) {
419 106 : thisZone.ExteriorTotalGroundSurfArea += thisSurface.GrossArea;
420 106 : if (thisSurface.Class == SurfaceClass::Wall) {
421 3 : thisZone.ExtGrossGroundWallArea += thisSurface.GrossArea;
422 3 : thisZone.ExtGrossGroundWallArea_Multiplied += thisSurface.GrossArea * thisZone.Multiplier * thisZone.ListMultiplier;
423 3 : if (DetailedWWR) {
424 0 : print(state.files.debug,
425 : "{},Wall-GroundContact,{:.2R},{:.1R}\n",
426 0 : thisSurface.Name,
427 0 : thisSurface.GrossArea * thisZone.Multiplier * thisZone.ListMultiplier,
428 0 : thisSurface.Tilt);
429 : }
430 : }
431 : }
432 : }
433 :
434 : } // ...end of surfaces windows DO loop
435 :
436 192 : if (DetailedWWR) {
437 0 : print(state.files.debug, "{}\n", "========================");
438 0 : print(state.files.debug, "{}\n", "Zone,ExtWallArea,ExtWindowArea");
439 : }
440 :
441 467 : for (auto &thisZone : state.dataHeatBal->Zone) {
442 275 : int CeilCount = 0;
443 275 : int FloorCount = 0;
444 275 : int WallCount = 0;
445 275 : Real64 AverageHeight = 0.0; // Used to keep track of average height of a surface/zone
446 275 : Real64 ZMax = -99999.0; // Maximum Z of a surface (detailed outside coefficient calculation)
447 275 : Real64 ZMin = 99999.0; // Minimum Z of a surface (detailed outside coefficient calculation)
448 275 : Real64 ZCeilAvg = 0.0;
449 275 : Real64 ZFlrAvg = 0.0;
450 275 : if (DetailedWWR) {
451 0 : print(state.files.debug, "{},{:.2R},{:.2R}\n", thisZone.Name, thisZone.ExtGrossWallArea, thisZone.ExtWindowArea);
452 : }
453 572 : for (int spaceNum : thisZone.spaceIndexes) {
454 297 : auto const &thisSpace = state.dataHeatBal->space(spaceNum);
455 : // Use AllSurfaceFirst which includes air boundaries
456 1914 : for (int SurfNum = thisSpace.AllSurfaceFirst; SurfNum <= thisSpace.AllSurfaceLast; ++SurfNum) {
457 1617 : auto &thisSurface = state.dataSurface->Surface(SurfNum);
458 :
459 1617 : if (thisSurface.Class == SurfaceClass::Roof) {
460 : // Use Average Z for surface, more important for roofs than floors...
461 257 : ++CeilCount;
462 257 : Real64 Z1 = minval(thisSurface.Vertex, &Vector::z);
463 257 : Real64 Z2 = maxval(thisSurface.Vertex, &Vector::z);
464 : // ZCeilAvg=ZCeilAvg+(Z1+Z2)/2.d0
465 257 : ZCeilAvg += ((Z1 + Z2) / 2.0) * (thisSurface.GrossArea / thisZone.geometricCeilingArea);
466 : }
467 1617 : if (thisSurface.Class == SurfaceClass::Floor) {
468 : // Use Average Z for surface, more important for roofs than floors...
469 328 : ++FloorCount;
470 328 : Real64 Z1 = minval(thisSurface.Vertex, &Vector::z);
471 328 : Real64 Z2 = maxval(thisSurface.Vertex, &Vector::z);
472 : // ZFlrAvg=ZFlrAvg+(Z1+Z2)/2.d0
473 328 : ZFlrAvg += ((Z1 + Z2) / 2.0) * (thisSurface.GrossArea / thisZone.geometricFloorArea);
474 : }
475 1617 : if (thisSurface.Class == SurfaceClass::Wall) {
476 : // Use Wall calculation in case no roof & floor in zone
477 887 : ++WallCount;
478 887 : if (WallCount == 1) {
479 258 : ZMax = thisSurface.Vertex(1).z;
480 258 : ZMin = ZMax;
481 : }
482 887 : ZMax = max(ZMax, maxval(thisSurface.Vertex, &Vector::z));
483 887 : ZMin = min(ZMin, minval(thisSurface.Vertex, &Vector::z));
484 : }
485 : }
486 : }
487 275 : if (CeilCount > 0 && FloorCount > 0) {
488 197 : AverageHeight = ZCeilAvg - ZFlrAvg;
489 : } else {
490 78 : AverageHeight = (ZMax - ZMin);
491 : }
492 275 : if (AverageHeight <= 0.0) {
493 24 : AverageHeight = (ZMax - ZMin);
494 : }
495 :
496 275 : if (thisZone.CeilingHeight > 0.0) {
497 70 : thisZone.ceilingHeightEntered = true;
498 70 : if (AverageHeight > 0.0) {
499 67 : if (std::abs(AverageHeight - thisZone.CeilingHeight) / thisZone.CeilingHeight > 0.05) {
500 4 : if (state.dataSurfaceGeometry->ErrCount == 1 && !state.dataGlobal->DisplayExtraWarnings) {
501 0 : ShowWarningError(
502 : state,
503 0 : format("{}Entered Ceiling Height for some zone(s) significantly different from calculated Ceiling Height",
504 : RoutineName));
505 0 : ShowContinueError(state,
506 : "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on each max iteration exceeded.");
507 : }
508 4 : if (state.dataGlobal->DisplayExtraWarnings) {
509 0 : ShowWarningError(state,
510 0 : format("{}Entered Ceiling Height for Zone=\"{}\" significantly different from calculated Ceiling Height",
511 : RoutineName,
512 0 : thisZone.Name));
513 : static constexpr std::string_view ValFmt("{:.2F}");
514 0 : std::string String1 = format(ValFmt, thisZone.CeilingHeight);
515 0 : std::string String2 = format(ValFmt, AverageHeight);
516 0 : ShowContinueError(
517 : state,
518 0 : format("{}Entered Ceiling Height={}, Calculated Ceiling Height={}, entered height will be used in calculations.",
519 : RoutineName,
520 : String1,
521 : String2));
522 0 : }
523 : }
524 : }
525 : }
526 275 : if ((thisZone.CeilingHeight <= 0.0) && (AverageHeight > 0.0)) thisZone.CeilingHeight = AverageHeight;
527 : // Need to add check here - don't touch if already user-specified
528 : }
529 :
530 192 : CalculateZoneVolume(state); // Calculate Zone Volumes
531 :
532 : // Calculate zone centroid (and min/max x,y,z for zone)
533 : // Use AllSurfaceFirst which includes air boundaries
534 467 : for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
535 275 : auto &thisZone = state.dataHeatBal->Zone(ZoneNum);
536 275 : bool nonInternalMassSurfacesPresent = false;
537 275 : bool internalMassSurfacesPresent = false;
538 275 : Real64 TotSurfArea = 0.0;
539 275 : thisZone.Centroid = Vector(0.0, 0.0, 0.0);
540 275 : if ((thisZone.AllSurfaceFirst > 0) && (state.dataSurface->Surface(thisZone.AllSurfaceFirst).Sides > 0)) {
541 272 : thisZone.MinimumX = state.dataSurface->Surface(thisZone.AllSurfaceFirst).Vertex(1).x;
542 272 : thisZone.MaximumX = state.dataSurface->Surface(thisZone.AllSurfaceFirst).Vertex(1).x;
543 272 : thisZone.MinimumY = state.dataSurface->Surface(thisZone.AllSurfaceFirst).Vertex(1).y;
544 272 : thisZone.MaximumY = state.dataSurface->Surface(thisZone.AllSurfaceFirst).Vertex(1).y;
545 272 : thisZone.MinimumZ = state.dataSurface->Surface(thisZone.AllSurfaceFirst).Vertex(1).z;
546 272 : thisZone.MaximumZ = state.dataSurface->Surface(thisZone.AllSurfaceFirst).Vertex(1).z;
547 : }
548 572 : for (int spaceNum : thisZone.spaceIndexes) {
549 297 : auto const &thisSpace = state.dataHeatBal->space(spaceNum);
550 :
551 1914 : for (int SurfNum = thisSpace.AllSurfaceFirst; SurfNum <= thisSpace.AllSurfaceLast; ++SurfNum) {
552 1617 : auto &thisSurface = state.dataSurface->Surface(SurfNum);
553 1617 : if (thisSurface.Class == SurfaceClass::IntMass) {
554 6 : internalMassSurfacesPresent = true;
555 6 : continue;
556 : }
557 1611 : if (!thisSurface.IsAirBoundarySurf) nonInternalMassSurfacesPresent = true;
558 1611 : if (thisSurface.Class == SurfaceClass::Wall || (thisSurface.Class == SurfaceClass::Roof) ||
559 467 : (thisSurface.Class == SurfaceClass::Floor)) {
560 :
561 1472 : thisZone.Centroid.x += thisSurface.Centroid.x * thisSurface.GrossArea;
562 1472 : thisZone.Centroid.y += thisSurface.Centroid.y * thisSurface.GrossArea;
563 1472 : thisZone.Centroid.z += thisSurface.Centroid.z * thisSurface.GrossArea;
564 1472 : TotSurfArea += thisSurface.GrossArea;
565 : }
566 1611 : thisZone.MinimumX = min(thisZone.MinimumX, minval(thisSurface.Vertex, &Vector::x));
567 1611 : thisZone.MaximumX = max(thisZone.MaximumX, maxval(thisSurface.Vertex, &Vector::x));
568 1611 : thisZone.MinimumY = min(thisZone.MinimumY, minval(thisSurface.Vertex, &Vector::y));
569 1611 : thisZone.MaximumY = max(thisZone.MaximumY, maxval(thisSurface.Vertex, &Vector::y));
570 1611 : thisZone.MinimumZ = min(thisZone.MinimumZ, minval(thisSurface.Vertex, &Vector::z));
571 1611 : thisZone.MaximumZ = max(thisZone.MaximumZ, maxval(thisSurface.Vertex, &Vector::z));
572 : }
573 : }
574 275 : if (TotSurfArea > 0.0) {
575 272 : thisZone.Centroid.x /= TotSurfArea;
576 272 : thisZone.Centroid.y /= TotSurfArea;
577 272 : thisZone.Centroid.z /= TotSurfArea;
578 : }
579 275 : if (internalMassSurfacesPresent && !nonInternalMassSurfacesPresent) {
580 0 : ShowSevereError(
581 0 : state, format("{}Zone=\"{}\" has only internal mass surfaces. Need at least one other surface.", RoutineName, thisZone.Name));
582 0 : ErrorsFound = true;
583 : }
584 : }
585 :
586 192 : state.dataSurface->SurfAdjacentZone.dimension(state.dataSurface->TotSurfaces, 0);
587 : // note -- adiabatic surfaces will show same zone as surface
588 1883 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
589 1691 : if (state.dataSurface->Surface(SurfNum).ExtBoundCond <= 0) continue;
590 425 : state.dataSurface->SurfAdjacentZone(SurfNum) = state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).ExtBoundCond).Zone;
591 : }
592 :
593 467 : for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
594 4185 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
595 3910 : auto const &thisSurface = state.dataSurface->Surface(SurfNum);
596 3910 : if (!thisSurface.HeatTransSurf && thisSurface.ZoneName == state.dataHeatBal->Zone(ZoneNum).Name)
597 90 : ++state.dataHeatBal->Zone(ZoneNum).NumShadingSurfaces;
598 :
599 3910 : if (thisSurface.Zone != ZoneNum) continue;
600 :
601 1617 : if (thisSurface.HeatTransSurf &&
602 1575 : (thisSurface.Class == SurfaceClass::Wall || thisSurface.Class == SurfaceClass::Roof || thisSurface.Class == SurfaceClass::Floor))
603 1434 : ++state.dataHeatBal->Zone(ZoneNum).NumSurfaces;
604 :
605 1617 : if (thisSurface.HeatTransSurf && (thisSurface.Class == SurfaceClass::Window || thisSurface.Class == SurfaceClass::GlassDoor ||
606 1457 : thisSurface.Class == SurfaceClass::Door || thisSurface.Class == SurfaceClass::TDD_Dome ||
607 1440 : thisSurface.Class == SurfaceClass::TDD_Diffuser))
608 135 : ++state.dataHeatBal->Zone(ZoneNum).NumSubSurfaces;
609 :
610 : } // surfaces
611 : } // zones
612 :
613 1883 : for (int const SurfNum : state.dataSurface->AllSurfaceListReportOrder) {
614 1691 : auto const &thisSurface = state.dataSurface->Surface(SurfNum);
615 1691 : Real64 NominalUwithConvCoeffs = 0.0;
616 1691 : if (thisSurface.Construction > 0 && thisSurface.Construction <= state.dataHeatBal->TotConstructs) {
617 1617 : bool isWithConvCoefValid = false;
618 1617 : NominalUwithConvCoeffs = DataHeatBalance::ComputeNominalUwithConvCoeffs(state, SurfNum, isWithConvCoefValid);
619 : }
620 :
621 : // populate the predefined report related to u-values with films
622 : // only exterior surfaces including underground
623 1691 : DataSurfaces::SurfaceClass const SurfaceClass(thisSurface.Class);
624 1691 : if ((thisSurface.ExtBoundCond == DataSurfaces::ExternalEnvironment) || (thisSurface.ExtBoundCond == DataSurfaces::Ground) ||
625 426 : (thisSurface.ExtBoundCond == DataSurfaces::KivaFoundation) || (thisSurface.ExtBoundCond == DataSurfaces::GroundFCfactorMethod)) {
626 1265 : if ((SurfaceClass == SurfaceClass::Wall) || (SurfaceClass == SurfaceClass::Floor) || (SurfaceClass == SurfaceClass::Roof)) {
627 2136 : OutputReportPredefined::PreDefTableEntry(
628 3204 : state, state.dataOutRptPredefined->pdchOpUfactFilm, thisSurface.Name, NominalUwithConvCoeffs, 3);
629 197 : } else if (SurfaceClass == SurfaceClass::Door) {
630 8 : OutputReportPredefined::PreDefTableEntry(
631 12 : state, state.dataOutRptPredefined->pdchDrUfactFilm, thisSurface.Name, NominalUwithConvCoeffs, 3);
632 : }
633 : } else {
634 426 : if ((SurfaceClass == SurfaceClass::Wall) || (SurfaceClass == SurfaceClass::Floor) || (SurfaceClass == SurfaceClass::Roof)) {
635 808 : OutputReportPredefined::PreDefTableEntry(
636 1212 : state, state.dataOutRptPredefined->pdchIntOpUfactFilm, thisSurface.Name, NominalUwithConvCoeffs, 3);
637 22 : } else if (SurfaceClass == SurfaceClass::Door) {
638 16 : OutputReportPredefined::PreDefTableEntry(
639 24 : state, state.dataOutRptPredefined->pdchIntDrUfactFilm, thisSurface.Name, NominalUwithConvCoeffs, 3);
640 : }
641 : }
642 : } // surfaces
643 :
644 : // Write number of shadings to initialization output file
645 192 : print(state.files.eio,
646 : "! <Shading Summary>, Number of Fixed Detached Shades, Number of Building Detached Shades, Number of Attached Shades\n");
647 :
648 192 : print(state.files.eio,
649 : " Shading Summary,{},{},{}\n",
650 192 : state.dataSurface->FixedShadingCount,
651 192 : state.dataSurface->BuildingShadingCount,
652 192 : state.dataSurface->AttachedShadingCount);
653 :
654 : // Write number of zones header to initialization output file
655 192 : print(state.files.eio, "! <Zone Summary>, Number of Zones, Number of Zone Surfaces, Number of SubSurfaces\n");
656 :
657 192 : print(state.files.eio,
658 : " Zone Summary,{},{},{}\n",
659 192 : state.dataGlobal->NumOfZones,
660 192 : state.dataSurface->TotSurfaces - state.dataSurface->FixedShadingCount - state.dataSurface->BuildingShadingCount -
661 192 : state.dataSurface->AttachedShadingCount,
662 192 : sum(state.dataHeatBal->Zone, &DataHeatBalance::ZoneData::NumSubSurfaces));
663 :
664 : // Write Zone Information header to the initialization output file
665 : static constexpr std::string_view Format_721(
666 : "! <Zone Information>,Zone Name,North Axis {deg},Origin X-Coordinate {m},Origin Y-Coordinate {m},Origin Z-Coordinate "
667 : "{m},Centroid X-Coordinate {m},Centroid Y-Coordinate {m},Centroid Z-Coordinate {m},Type,Zone Multiplier,Zone List "
668 : "Multiplier,Minimum X {m},Maximum X {m},Minimum Y {m},Maximum Y {m},Minimum Z {m},Maximum Z {m},Ceiling Height {m},Volume "
669 : "{m3},Zone Inside Convection Algorithm {Simple-Detailed-CeilingDiffuser-TrombeWall},Zone Outside Convection Algorithm "
670 : "{Simple-Detailed-Tarp-MoWitt-DOE-2-BLAST}, Floor Area {m2},Exterior Gross Wall Area {m2},Exterior Net Wall Area {m2},Exterior "
671 : "Window "
672 : "Area {m2}, Number of Surfaces, Number of SubSurfaces, Number of Shading SubSurfaces, Part of Total Building Area");
673 192 : print(state.files.eio, "{}\n", Format_721);
674 :
675 467 : for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
676 : // Write Zone Information to the initialization output file
677 275 : std::string String1;
678 275 : std::string String2;
679 275 : std::string String3;
680 :
681 275 : switch (state.dataHeatBal->Zone(ZoneNum).IntConvAlgo) {
682 78 : case Convect::HcInt::ASHRAESimple: {
683 78 : String1 = "Simple";
684 78 : } break;
685 190 : case Convect::HcInt::ASHRAETARP: {
686 190 : String1 = "TARP";
687 190 : } break;
688 0 : case Convect::HcInt::CeilingDiffuser: {
689 0 : String1 = "CeilingDiffuser";
690 0 : } break;
691 0 : case Convect::HcInt::TrombeWall: {
692 0 : String1 = "TrombeWall";
693 0 : } break;
694 7 : case Convect::HcInt::AdaptiveConvectionAlgorithm: {
695 7 : String1 = "AdaptiveConvectionAlgorithm";
696 7 : } break;
697 0 : case Convect::HcInt::ASTMC1340: {
698 0 : String1 = "ASTMC1340";
699 0 : } break;
700 0 : default:
701 0 : break;
702 : }
703 :
704 275 : switch (state.dataHeatBal->Zone(ZoneNum).ExtConvAlgo) {
705 78 : case Convect::HcExt::ASHRAESimple: {
706 78 : String2 = "Simple";
707 78 : } break;
708 10 : case Convect::HcExt::ASHRAETARP: {
709 10 : String2 = "TARP";
710 10 : } break;
711 0 : case Convect::HcExt::TarpHcOutside: {
712 0 : String2 = "TARP";
713 0 : } break;
714 0 : case Convect::HcExt::MoWiTTHcOutside: {
715 0 : String2 = "MoWitt";
716 0 : } break;
717 187 : case Convect::HcExt::DOE2HcOutside: {
718 187 : String2 = "DOE-2";
719 187 : } break;
720 0 : case Convect::HcExt::AdaptiveConvectionAlgorithm: {
721 0 : String2 = "AdaptiveConvectionAlgorithm";
722 0 : } break;
723 0 : default:
724 0 : break;
725 : }
726 :
727 275 : String3 = (state.dataHeatBal->Zone(ZoneNum).isPartOfTotalArea) ? "Yes" : "No";
728 :
729 : static constexpr std::string_view Format_720(
730 : " Zone Information, "
731 : "{},{:.1R},{:.2R},{:.2R},{:.2R},{:.2R},{:.2R},{:.2R},{},{},{},{:.2R},{:.2R},{:.2R},{:.2R},{:.2R},{:.2R},"
732 : "{:.2R},{:.2R},{},{},{:.2R},{:.2R},{:.2R},{:.2R},{},{},{},{}\n");
733 :
734 275 : print(state.files.eio,
735 : Format_720,
736 275 : state.dataHeatBal->Zone(ZoneNum).Name,
737 275 : state.dataHeatBal->Zone(ZoneNum).RelNorth,
738 275 : state.dataHeatBal->Zone(ZoneNum).OriginX,
739 275 : state.dataHeatBal->Zone(ZoneNum).OriginY,
740 275 : state.dataHeatBal->Zone(ZoneNum).OriginZ,
741 275 : state.dataHeatBal->Zone(ZoneNum).Centroid.x,
742 275 : state.dataHeatBal->Zone(ZoneNum).Centroid.y,
743 275 : state.dataHeatBal->Zone(ZoneNum).Centroid.z,
744 275 : state.dataHeatBal->Zone(ZoneNum).OfType,
745 275 : state.dataHeatBal->Zone(ZoneNum).Multiplier,
746 275 : state.dataHeatBal->Zone(ZoneNum).ListMultiplier,
747 275 : state.dataHeatBal->Zone(ZoneNum).MinimumX,
748 275 : state.dataHeatBal->Zone(ZoneNum).MaximumX,
749 275 : state.dataHeatBal->Zone(ZoneNum).MinimumY,
750 275 : state.dataHeatBal->Zone(ZoneNum).MaximumY,
751 275 : state.dataHeatBal->Zone(ZoneNum).MinimumZ,
752 275 : state.dataHeatBal->Zone(ZoneNum).MaximumZ,
753 275 : state.dataHeatBal->Zone(ZoneNum).CeilingHeight,
754 275 : state.dataHeatBal->Zone(ZoneNum).Volume,
755 : String1,
756 : String2,
757 275 : state.dataHeatBal->Zone(ZoneNum).FloorArea,
758 275 : state.dataHeatBal->Zone(ZoneNum).ExtGrossWallArea,
759 275 : state.dataHeatBal->Zone(ZoneNum).ExtNetWallArea,
760 275 : state.dataHeatBal->Zone(ZoneNum).ExtWindowArea,
761 275 : state.dataHeatBal->Zone(ZoneNum).NumSurfaces,
762 275 : state.dataHeatBal->Zone(ZoneNum).NumSubSurfaces,
763 275 : state.dataHeatBal->Zone(ZoneNum).NumShadingSurfaces,
764 : String3);
765 :
766 275 : } // ZoneNum
767 :
768 : // Set up solar distribution enclosures allowing for any air boundaries
769 192 : SetupEnclosuresAndAirBoundaries(state, state.dataViewFactor->EnclSolInfo, SurfaceGeometry::enclosureType::SolarEnclosures, ErrorsFound);
770 :
771 : // Do the Stratosphere check
772 192 : DataHeatBalance::SetZoneOutBulbTempAt(state);
773 192 : DataHeatBalance::CheckZoneOutBulbTempAt(state);
774 : }
775 :
776 228 : void AllocateSurfaceArrays(EnergyPlusData &state)
777 : {
778 :
779 : // SUBROUTINE INFORMATION:
780 : // AUTHOR Rick Strand
781 : // DATE WRITTEN February 1998
782 :
783 : // PURPOSE OF THIS SUBROUTINE:
784 : // This subroutine allocates all of the arrays at the module level which require allocation.
785 :
786 : // METHODOLOGY EMPLOYED:
787 : // Allocation is dependent on the user input file.
788 :
789 228 : state.dataSurface->ShadeV.allocate(state.dataSurface->TotSurfaces);
790 2506 : for (auto &e : state.dataSurface->ShadeV)
791 2278 : e.NVert = 0;
792 : // Individual components (XV,YV,ZV) allocated in routine ProcessSurfaceVertices
793 228 : state.dataSurface->X0.dimension(state.dataSurface->TotSurfaces, 0.0);
794 228 : state.dataSurface->Y0.dimension(state.dataSurface->TotSurfaces, 0.0);
795 228 : state.dataSurface->Z0.dimension(state.dataSurface->TotSurfaces, 0.0);
796 :
797 : // Surface EMS arrays
798 228 : state.dataSurface->SurfEMSConstructionOverrideON.allocate(state.dataSurface->TotSurfaces);
799 228 : state.dataSurface->SurfEMSConstructionOverrideValue.allocate(state.dataSurface->TotSurfaces);
800 228 : state.dataSurface->SurfEMSOverrideIntConvCoef.allocate(state.dataSurface->TotSurfaces);
801 228 : state.dataSurface->SurfEMSValueForIntConvCoef.allocate(state.dataSurface->TotSurfaces);
802 228 : state.dataSurface->SurfEMSOverrideExtConvCoef.allocate(state.dataSurface->TotSurfaces);
803 228 : state.dataSurface->SurfEMSValueForExtConvCoef.allocate(state.dataSurface->TotSurfaces);
804 228 : state.dataSurface->SurfOutDryBulbTempEMSOverrideOn.allocate(state.dataSurface->TotSurfaces);
805 228 : state.dataSurface->SurfOutDryBulbTempEMSOverrideValue.allocate(state.dataSurface->TotSurfaces);
806 228 : state.dataSurface->SurfOutWetBulbTempEMSOverrideOn.allocate(state.dataSurface->TotSurfaces);
807 228 : state.dataSurface->SurfOutWetBulbTempEMSOverrideValue.allocate(state.dataSurface->TotSurfaces);
808 228 : state.dataSurface->SurfWindSpeedEMSOverrideOn.allocate(state.dataSurface->TotSurfaces);
809 228 : state.dataSurface->SurfWindSpeedEMSOverrideValue.allocate(state.dataSurface->TotSurfaces);
810 228 : state.dataSurface->SurfViewFactorGroundEMSOverrideOn.allocate(state.dataSurface->TotSurfaces);
811 228 : state.dataSurface->SurfViewFactorGroundEMSOverrideValue.allocate(state.dataSurface->TotSurfaces);
812 228 : state.dataSurface->SurfWindDirEMSOverrideOn.allocate(state.dataSurface->TotSurfaces);
813 228 : state.dataSurface->SurfWindDirEMSOverrideValue.allocate(state.dataSurface->TotSurfaces);
814 2506 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
815 2278 : state.dataSurface->SurfEMSConstructionOverrideON(SurfNum) = false;
816 2278 : state.dataSurface->SurfEMSConstructionOverrideValue(SurfNum) = 0.0;
817 2278 : state.dataSurface->SurfEMSOverrideIntConvCoef(SurfNum) = false;
818 2278 : state.dataSurface->SurfEMSValueForIntConvCoef(SurfNum) = 0.0;
819 2278 : state.dataSurface->SurfEMSOverrideExtConvCoef(SurfNum) = false;
820 2278 : state.dataSurface->SurfEMSValueForExtConvCoef(SurfNum) = 0.0;
821 2278 : state.dataSurface->SurfOutDryBulbTempEMSOverrideOn(SurfNum) = false;
822 2278 : state.dataSurface->SurfOutDryBulbTempEMSOverrideValue(SurfNum) = 0.0;
823 2278 : state.dataSurface->SurfOutWetBulbTempEMSOverrideOn(SurfNum) = false;
824 2278 : state.dataSurface->SurfOutWetBulbTempEMSOverrideValue(SurfNum) = 0.0;
825 2278 : state.dataSurface->SurfWindSpeedEMSOverrideOn(SurfNum) = false;
826 2278 : state.dataSurface->SurfWindSpeedEMSOverrideValue(SurfNum) = 0.0;
827 2278 : state.dataSurface->SurfViewFactorGroundEMSOverrideOn(SurfNum) = false;
828 2278 : state.dataSurface->SurfViewFactorGroundEMSOverrideValue(SurfNum) = 0.0;
829 2278 : state.dataSurface->SurfWindDirEMSOverrideOn(SurfNum) = false;
830 2278 : state.dataSurface->SurfWindDirEMSOverrideValue(SurfNum) = 0.0;
831 : }
832 : // Following are surface hb arrays
833 228 : state.dataSurface->SurfOutDryBulbTemp.allocate(state.dataSurface->TotSurfaces);
834 228 : state.dataSurface->SurfOutWetBulbTemp.allocate(state.dataSurface->TotSurfaces);
835 228 : state.dataSurface->SurfOutWindSpeed.allocate(state.dataSurface->TotSurfaces);
836 228 : state.dataSurface->SurfOutWindDir.allocate(state.dataSurface->TotSurfaces);
837 228 : state.dataSurface->SurfGenericContam.allocate(state.dataSurface->TotSurfaces);
838 228 : state.dataSurface->SurfPenumbraID.allocate(state.dataSurface->TotSurfaces);
839 228 : state.dataSurface->SurfAirSkyRadSplit.allocate(state.dataSurface->TotSurfaces);
840 2506 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
841 2278 : state.dataSurface->SurfOutDryBulbTemp(SurfNum) = 0.0;
842 2278 : state.dataSurface->SurfOutWetBulbTemp(SurfNum) = 0.0;
843 2278 : state.dataSurface->SurfOutWindSpeed(SurfNum) = 0.0;
844 2278 : state.dataSurface->SurfOutWindDir(SurfNum) = 0.0;
845 2278 : state.dataSurface->SurfGenericContam(SurfNum) = 0.0;
846 2278 : state.dataSurface->SurfPenumbraID(SurfNum) = -1;
847 2278 : state.dataSurface->SurfAirSkyRadSplit(SurfNum) = 0.0;
848 : }
849 : // Following are surface property arrays used in SurfaceGeometry
850 228 : state.dataSurface->SurfShadowRecSurfNum.allocate(state.dataSurface->TotSurfaces);
851 228 : state.dataSurface->SurfShadowDisabledZoneList.allocate(state.dataSurface->TotSurfaces);
852 228 : state.dataSurface->SurfShadowDiffuseSolRefl.allocate(state.dataSurface->TotSurfaces);
853 228 : state.dataSurface->SurfShadowDiffuseVisRefl.allocate(state.dataSurface->TotSurfaces);
854 228 : state.dataSurface->SurfShadowGlazingFrac.allocate(state.dataSurface->TotSurfaces);
855 228 : state.dataSurface->SurfShadowGlazingConstruct.allocate(state.dataSurface->TotSurfaces);
856 2506 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
857 2278 : state.dataSurface->SurfShadowRecSurfNum(SurfNum) = 0;
858 2278 : state.dataSurface->SurfShadowDiffuseSolRefl(SurfNum) = 0.0;
859 2278 : state.dataSurface->SurfShadowDiffuseVisRefl(SurfNum) = 0.0;
860 2278 : state.dataSurface->SurfShadowGlazingFrac(SurfNum) = 0.0;
861 2278 : state.dataSurface->SurfShadowGlazingConstruct(SurfNum) = 0;
862 : }
863 228 : state.dataSurface->SurfExtEcoRoof.allocate(state.dataSurface->TotSurfaces);
864 228 : state.dataSurface->SurfExtCavityPresent.allocate(state.dataSurface->TotSurfaces);
865 228 : state.dataSurface->SurfExtCavNum.allocate(state.dataSurface->TotSurfaces);
866 228 : state.dataSurface->SurfIsPV.allocate(state.dataSurface->TotSurfaces);
867 228 : state.dataSurface->SurfIsICS.allocate(state.dataSurface->TotSurfaces);
868 228 : state.dataSurface->SurfIsPool.allocate(state.dataSurface->TotSurfaces);
869 228 : state.dataSurface->SurfICSPtr.allocate(state.dataSurface->TotSurfaces);
870 228 : state.dataSurface->SurfIsRadSurfOrVentSlabOrPool.allocate(state.dataSurface->TotSurfaces);
871 228 : state.dataSurface->SurfDaylightingShelfInd.allocate(state.dataSurface->TotSurfaces);
872 2506 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
873 2278 : state.dataSurface->SurfExtEcoRoof(SurfNum) = false;
874 2278 : state.dataSurface->SurfExtCavityPresent(SurfNum) = false;
875 2278 : state.dataSurface->SurfExtCavNum(SurfNum) = 0;
876 2278 : state.dataSurface->SurfIsPV(SurfNum) = false;
877 2278 : state.dataSurface->SurfIsICS(SurfNum) = false;
878 2278 : state.dataSurface->SurfIsPool(SurfNum) = false;
879 2278 : state.dataSurface->SurfICSPtr(SurfNum) = 0;
880 2278 : state.dataSurface->SurfIsRadSurfOrVentSlabOrPool(SurfNum) = false;
881 2278 : state.dataSurface->SurfDaylightingShelfInd(SurfNum) = 0;
882 : }
883 228 : state.dataSurface->SurfLowTempErrCount.allocate(state.dataSurface->TotSurfaces);
884 228 : state.dataSurface->SurfHighTempErrCount.allocate(state.dataSurface->TotSurfaces);
885 228 : state.dataSurface->surfIntConv.allocate(state.dataSurface->TotSurfaces);
886 228 : state.dataSurface->SurfTAirRef.allocate(state.dataSurface->TotSurfaces);
887 228 : state.dataSurface->SurfTAirRefRpt.allocate(state.dataSurface->TotSurfaces);
888 228 : state.dataSurface->surfExtConv.allocate(state.dataSurface->TotSurfaces);
889 2506 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
890 2278 : state.dataSurface->SurfLowTempErrCount(SurfNum) = 0;
891 2278 : state.dataSurface->SurfHighTempErrCount(SurfNum) = 0;
892 2278 : state.dataSurface->surfIntConv(SurfNum) = DataSurfaces::SurfIntConv();
893 2278 : state.dataSurface->surfExtConv(SurfNum) = DataSurfaces::SurfExtConv();
894 2278 : state.dataSurface->SurfTAirRef(SurfNum) = DataSurfaces::RefAirTemp::Invalid;
895 2278 : state.dataSurface->SurfTAirRefRpt(SurfNum) = static_cast<int>(DataSurfaces::RefAirTemp::Invalid);
896 : }
897 :
898 228 : state.dataSurface->intMovInsuls.allocate(state.dataSurface->TotSurfaces);
899 228 : state.dataSurface->extMovInsuls.allocate(state.dataSurface->TotSurfaces);
900 228 : }
901 :
902 244 : void GetSurfaceData(EnergyPlusData &state, bool &ErrorsFound) // If errors found in input
903 : {
904 :
905 : // SUBROUTINE INFORMATION:
906 : // AUTHOR Richard Liesen
907 : // DATE WRITTEN November 1997
908 : // MODIFIED April 1999, Linda Lawrie
909 : // Dec. 2000, FW (add "one-wall zone" checks)
910 : // RE-ENGINEERED May 2000, Linda Lawrie (breakout surface type gets)
911 :
912 : // PURPOSE OF THIS SUBROUTINE:
913 : // The purpose of this subroutine is to read in the surface information
914 : // from the input data file and interpret and put in the derived type
915 :
916 : // METHODOLOGY EMPLOYED:
917 : // The order of surfaces does not matter and the surfaces are resorted into
918 : // the hierarchical order:
919 : // All Shading Surfaces
920 : // Airwalls for space x1
921 : // Base Surfaces for space x1
922 : // Opaque Subsurfaces for space x1
923 : // Window Subsurfaces for space x1
924 : // TDD Dome Surfaces for space x1
925 : // Airwalls for space x2
926 : // Base Surfaces for space x2
927 : // etc
928 : // Pointers are set in the spaces (AllSurfaceFirst/Last, HTSurfaceFirst/Last, OpaqOrIntMassSurfaceFirst/Last, WindowSurfaceFirst/Last,
929 : // OpaqOrWinSurfaceFirst/Last, TDDDomeFirst/Last)
930 :
931 : // REFERENCES:
932 : // This routine manages getting the input for the following Objects:
933 : // SurfaceGeometry
934 : // Surface:Shading:Detached
935 : // Surface:HeatTransfer
936 : // Surface:HeatTransfer:Sub
937 : // Surface:Shading:Attached
938 : // Surface:InternalMass
939 :
940 : // Vertex input:
941 : // N3 , \field Number of Surface Vertices -- Number of (X,Y,Z) groups in this surface
942 : // \note currently limited 3 or 4, later?
943 : // \min 3
944 : // \max 4
945 : // \memo vertices are given in SurfaceGeometry coordinates -- if relative, all surface coordinates
946 : // \memo are "relative" to the Zone Origin. if WCS, then building and zone origins are used
947 : // \memo for some internal calculations, but all coordinates are given in an "absolute" system.
948 : // N4, \field Vertex 1 X-coordinate
949 : // \units m
950 : // \type real
951 : // N5 , \field Vertex 1 Y-coordinate
952 : // \units m
953 : // \type real
954 : // N6 , \field Vertex 1 Z-coordinate
955 : // \units m
956 : // \type real
957 : // N7, \field Vertex 2 X-coordinate
958 : // \units m
959 : // \type real
960 : // N8, \field Vertex 2 Y-coordinate
961 : // \units m
962 : // \type real
963 : // N9, \field Vertex 2 Z-coordinate
964 : // \units m
965 : // \type real
966 : // N10, \field Vertex 3 X-coordinate
967 : // \units m
968 : // \type real
969 : // N11, \field Vertex 3 Y-coordinate
970 : // \units m
971 : // \type real
972 : // N12, \field Vertex 3 Z-coordinate
973 : // \units m
974 : // \type real
975 : // N13, \field Vertex 4 X-coordinate
976 : // \units m
977 : // \type real
978 : // N14, \field Vertex 4 Y-coordinate
979 : // \type real
980 : // \units m
981 : // N15; \field Vertex 4 Z-coordinate
982 : // \units m
983 : // \type real
984 :
985 : // The vertices are stored in the surface derived type.
986 : // +(1)-------------------------(4)+
987 : // | |
988 : // | |
989 : // | |
990 : // +(2)-------------------------(3)+
991 : // The above diagram shows the actual coordinate points of a typical wall
992 : // (you're on the outside looking toward the wall) as stored into
993 : // Surface%Vertex(1:<number-of-sides>)
994 :
995 : static constexpr std::string_view RoutineName = "GetSurfaceData: ";
996 : using namespace Vectors;
997 : using namespace DataErrorTracking;
998 :
999 : int ConstrNumFound; // Construction number of matching interzone surface
1000 244 : bool NonMatch(false); // Error for non-matching interzone surfaces
1001 : int MovedSurfs; // Number of Moved Surfaces (when sorting into hierarchical structure)
1002 244 : bool SurfError(false); // General Surface Error, causes fatal error at end of routine
1003 : int TotLay; // Total layers in a construction
1004 : int TotLayFound; // Total layers in the construction of a matching interzone surface
1005 : // Simple Surfaces (Rectangular)
1006 : int LayNumOutside; // Outside material numbers for a shaded construction
1007 : // entries with two glazing systems
1008 : int NeedToAddSurfaces; // Surfaces that will be added due to "unentered" other zone surface
1009 : int NeedToAddSubSurfaces; // SubSurfaces that will be added due to "unentered" other zone surface
1010 244 : int CurNewSurf = 0;
1011 : Real64 SurfWorldAz;
1012 : Real64 SurfTilt;
1013 :
1014 : int MultFound;
1015 : int MultSurfNum;
1016 : bool SubSurfaceSevereDisplayed;
1017 244 : bool subSurfaceError(false);
1018 : bool errFlag;
1019 :
1020 : bool izConstDiff; // differences in construction for IZ surfaces
1021 : bool izConstDiffMsg; // display message about hb diffs only once.
1022 :
1023 : // Get the total number of surfaces to allocate derived type and for surface loops
1024 :
1025 244 : if (state.dataSurfaceGeometry->GetSurfaceDataOneTimeFlag) {
1026 18 : return;
1027 : } else {
1028 226 : state.dataSurfaceGeometry->GetSurfaceDataOneTimeFlag = true;
1029 : }
1030 :
1031 226 : GetGeometryParameters(state, ErrorsFound);
1032 :
1033 226 : if (state.dataSurface->WorldCoordSystem) {
1034 82 : bool RelWarning = false;
1035 82 : if (state.dataHeatBal->BuildingAzimuth != 0.0) RelWarning = true;
1036 209 : for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
1037 127 : if (state.dataHeatBal->Zone(ZoneNum).RelNorth != 0.0) RelWarning = true;
1038 : }
1039 82 : if (RelWarning && !state.dataSurfaceGeometry->WarningDisplayed) {
1040 0 : ShowWarningError(
1041 : state,
1042 0 : format("{}World Coordinate System selected. Any non-zero Building/Zone North Axes or non-zero Zone Origins are ignored.",
1043 : RoutineName));
1044 0 : ShowContinueError(state,
1045 : "These may be used in daylighting reference point coordinate calculations but not in normal geometry inputs.");
1046 0 : state.dataSurfaceGeometry->WarningDisplayed = true;
1047 : }
1048 82 : RelWarning = false;
1049 209 : for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
1050 127 : if (state.dataHeatBal->Zone(ZoneNum).OriginX != 0.0) RelWarning = true;
1051 127 : if (state.dataHeatBal->Zone(ZoneNum).OriginY != 0.0) RelWarning = true;
1052 127 : if (state.dataHeatBal->Zone(ZoneNum).OriginZ != 0.0) RelWarning = true;
1053 : }
1054 82 : if (RelWarning && !state.dataSurfaceGeometry->WarningDisplayed) {
1055 2 : ShowWarningError(
1056 : state,
1057 2 : format("{}World Coordinate System selected. Any non-zero Building/Zone North Axes or non-zero Zone Origins are ignored.",
1058 : RoutineName));
1059 2 : ShowContinueError(state,
1060 : "These may be used in daylighting reference point coordinate calculations but not in normal geometry inputs.");
1061 1 : state.dataSurfaceGeometry->WarningDisplayed = true;
1062 : }
1063 : }
1064 :
1065 226 : int TotDetachedFixed = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Site:Detailed");
1066 226 : int TotDetachedBldg = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Building:Detailed");
1067 226 : int TotRectDetachedFixed = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Site");
1068 226 : int TotRectDetachedBldg = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Building");
1069 226 : int TotHTSurfs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "BuildingSurface:Detailed");
1070 226 : int TotDetailedWalls = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Wall:Detailed");
1071 226 : int TotDetailedRoofs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "RoofCeiling:Detailed");
1072 226 : int TotDetailedFloors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Floor:Detailed");
1073 226 : int TotHTSubs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "FenestrationSurface:Detailed");
1074 226 : int TotShdSubs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Zone:Detailed");
1075 226 : int TotOverhangs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Overhang");
1076 226 : int TotOverhangsProjection = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Overhang:Projection");
1077 226 : int TotFins = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Fin");
1078 226 : int TotFinsProjection = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Fin:Projection");
1079 226 : int TotRectWindows = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Window");
1080 226 : int TotRectDoors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Door");
1081 226 : int TotRectGlazedDoors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "GlazedDoor");
1082 226 : int TotRectIZWindows = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Window:Interzone");
1083 226 : int TotRectIZDoors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Door:Interzone");
1084 226 : int TotRectIZGlazedDoors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "GlazedDoor:Interzone");
1085 226 : int TotRectExtWalls = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Wall:Exterior");
1086 226 : int TotRectIntWalls = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Wall:Adiabatic");
1087 226 : int TotRectIZWalls = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Wall:Interzone");
1088 226 : int TotRectUGWalls = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Wall:Underground");
1089 226 : int TotRectRoofs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Roof");
1090 226 : int TotRectCeilings = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Ceiling:Adiabatic");
1091 226 : int TotRectIZCeilings = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Ceiling:Interzone");
1092 226 : int TotRectGCFloors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Floor:GroundContact");
1093 226 : int TotRectIntFloors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Floor:Adiabatic");
1094 226 : int TotRectIZFloors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Floor:Interzone");
1095 :
1096 226 : state.dataSurface->TotOSC = 0;
1097 :
1098 226 : int TotIntMassSurfaces = GetNumIntMassSurfaces(state);
1099 :
1100 452 : state.dataSurface->TotSurfaces = (TotDetachedFixed + TotDetachedBldg + TotRectDetachedFixed + TotRectDetachedBldg) * 2 + TotHTSurfs +
1101 226 : TotHTSubs + TotShdSubs * 2 + TotIntMassSurfaces + TotOverhangs * 2 + TotOverhangsProjection * 2 +
1102 226 : TotFins * 4 + TotFinsProjection * 4 + TotDetailedWalls + TotDetailedRoofs + TotDetailedFloors +
1103 226 : TotRectWindows + TotRectDoors + TotRectGlazedDoors + TotRectIZWindows + TotRectIZDoors +
1104 226 : TotRectIZGlazedDoors + TotRectExtWalls + TotRectIntWalls + TotRectIZWalls + TotRectUGWalls + TotRectRoofs +
1105 226 : TotRectCeilings + TotRectIZCeilings + TotRectGCFloors + TotRectIntFloors + TotRectIZFloors;
1106 :
1107 226 : state.dataSurfaceGeometry->SurfaceTmp.allocate(state.dataSurface->TotSurfaces); // Allocate the Surface derived type appropriately
1108 226 : state.dataSurfaceGeometry->UniqueSurfaceNames.reserve(state.dataSurface->TotSurfaces);
1109 : // SurfaceTmp structure is allocated via derived type initialization.
1110 :
1111 226 : int NumSurfs = 0;
1112 226 : int AddedSubSurfaces = 0;
1113 226 : state.dataErrTracking->AskForSurfacesReport = true;
1114 :
1115 226 : GetDetShdSurfaceData(state, ErrorsFound, NumSurfs, TotDetachedFixed, TotDetachedBldg);
1116 :
1117 226 : GetRectDetShdSurfaceData(state, ErrorsFound, NumSurfs, TotRectDetachedFixed, TotRectDetachedBldg);
1118 :
1119 226 : GetHTSurfaceData(state,
1120 : ErrorsFound,
1121 : NumSurfs,
1122 : TotHTSurfs,
1123 : TotDetailedWalls,
1124 : TotDetailedRoofs,
1125 : TotDetailedFloors,
1126 226 : state.dataSurfaceGeometry->BaseSurfCls,
1127 226 : state.dataSurfaceGeometry->BaseSurfIDs,
1128 : NeedToAddSurfaces);
1129 :
1130 226 : GetRectSurfaces(state,
1131 : ErrorsFound,
1132 : NumSurfs,
1133 : TotRectExtWalls,
1134 : TotRectIntWalls,
1135 : TotRectIZWalls,
1136 : TotRectUGWalls,
1137 : TotRectRoofs,
1138 : TotRectCeilings,
1139 : TotRectIZCeilings,
1140 : TotRectGCFloors,
1141 : TotRectIntFloors,
1142 : TotRectIZFloors,
1143 226 : state.dataSurfaceGeometry->BaseSurfIDs,
1144 : NeedToAddSurfaces);
1145 :
1146 226 : GetHTSubSurfaceData(state,
1147 : ErrorsFound,
1148 : NumSurfs,
1149 : TotHTSubs,
1150 226 : state.dataSurfaceGeometry->SubSurfCls,
1151 226 : state.dataSurfaceGeometry->SubSurfIDs,
1152 : AddedSubSurfaces,
1153 : NeedToAddSubSurfaces);
1154 :
1155 226 : GetRectSubSurfaces(state,
1156 : ErrorsFound,
1157 : NumSurfs,
1158 : TotRectWindows,
1159 : TotRectDoors,
1160 : TotRectGlazedDoors,
1161 : TotRectIZWindows,
1162 : TotRectIZDoors,
1163 : TotRectIZGlazedDoors,
1164 226 : state.dataSurfaceGeometry->SubSurfIDs,
1165 : AddedSubSurfaces,
1166 : NeedToAddSubSurfaces);
1167 :
1168 226 : GetAttShdSurfaceData(state, ErrorsFound, NumSurfs, TotShdSubs);
1169 :
1170 226 : GetSimpleShdSurfaceData(state, ErrorsFound, NumSurfs, TotOverhangs, TotOverhangsProjection, TotFins, TotFinsProjection);
1171 :
1172 226 : GetIntMassSurfaceData(state, ErrorsFound, NumSurfs);
1173 :
1174 226 : state.dataSurface->TotSurfaces = NumSurfs + AddedSubSurfaces + NeedToAddSurfaces + NeedToAddSubSurfaces;
1175 :
1176 226 : if (ErrorsFound) {
1177 4 : ShowFatalError(state, format("{}Errors discovered, program terminates.", RoutineName));
1178 : }
1179 :
1180 224 : state.dataSurface->Surface.allocate(state.dataSurface->TotSurfaces); // Allocate the Surface derived type appropriately
1181 224 : state.dataSurface->SurfaceWindow.allocate(state.dataSurface->TotSurfaces);
1182 224 : state.dataSurface->surfShades.allocate(state.dataSurface->TotSurfaces);
1183 224 : AllocateSurfaceArrays(state);
1184 224 : AllocateSurfaceWindows(state, state.dataSurface->TotSurfaces);
1185 :
1186 : // Have to make room for added surfaces, if needed
1187 224 : int FirstTotalSurfaces = NumSurfs + AddedSubSurfaces;
1188 224 : if (NeedToAddSurfaces + NeedToAddSubSurfaces > 0) {
1189 5 : state.dataSurfaceGeometry->SurfaceTmp.redimension(state.dataSurface->TotSurfaces);
1190 5 : CurNewSurf = FirstTotalSurfaces;
1191 : }
1192 :
1193 : // add the "need to add" surfaces
1194 : // Debug write(outputfiledebug,*) ' need to add ',NeedtoAddSurfaces+NeedToAddSubSurfaces
1195 2470 : for (int SurfNum = 1; SurfNum <= FirstTotalSurfaces; ++SurfNum) {
1196 2246 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
1197 2246 : if ((surfTemp.ExtBoundCond != unenteredAdjacentZoneSurface) && (surfTemp.ExtBoundCond != unenteredAdjacentSpaceSurface)) continue;
1198 : // Need to add surface
1199 16 : ++CurNewSurf;
1200 : // Debug write(outputfiledebug,*) ' adding surface=',curnewsurf
1201 16 : auto &newSurf = state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf);
1202 16 : newSurf = surfTemp;
1203 : // Basic parameters are the same for both surfaces.
1204 16 : if (surfTemp.ExtBoundCond == unenteredAdjacentZoneSurface) {
1205 12 : int Found = Util::FindItemInList(surfTemp.ExtBoundCondName, state.dataHeatBal->Zone, state.dataGlobal->NumOfZones);
1206 12 : if (Found == 0) continue;
1207 12 : newSurf.Zone = Found;
1208 12 : auto &newZone = state.dataHeatBal->Zone(Found);
1209 12 : newSurf.ZoneName = newZone.Name;
1210 12 : assert(newZone.spaceIndexes.size() >= 1);
1211 12 : newSurf.spaceNum = 0; // clear this here and set later
1212 4 : } else if (surfTemp.ExtBoundCond == unenteredAdjacentSpaceSurface) {
1213 4 : int Found = Util::FindItemInList(surfTemp.ExtBoundCondName, state.dataHeatBal->space, state.dataGlobal->numSpaces);
1214 4 : if (Found == 0) continue;
1215 4 : newSurf.spaceNum = Found;
1216 4 : int zoneNum = state.dataHeatBal->space(Found).zoneNum;
1217 4 : newSurf.Zone = zoneNum;
1218 4 : newSurf.ZoneName = state.dataHeatBal->Zone(zoneNum).Name;
1219 : }
1220 : // Reverse Construction
1221 16 : newSurf.Construction = DataHeatBalance::AssignReverseConstructionNumber(state, surfTemp.Construction, SurfError);
1222 16 : newSurf.ConstructionStoredInputValue = newSurf.Construction;
1223 : // Reverse Vertices
1224 16 : int NVert = surfTemp.Sides;
1225 80 : for (int Vert = 1; Vert <= surfTemp.Sides; ++Vert) {
1226 64 : newSurf.Vertex(Vert) = surfTemp.Vertex(NVert);
1227 64 : --NVert;
1228 : }
1229 16 : if (newSurf.Sides > 2) {
1230 16 : Vectors::CreateNewellAreaVector(newSurf.Vertex, newSurf.Sides, newSurf.NewellAreaVector);
1231 16 : newSurf.GrossArea = Vectors::VecLength(newSurf.NewellAreaVector);
1232 16 : newSurf.Area = newSurf.GrossArea;
1233 16 : newSurf.NetAreaShadowCalc = newSurf.Area;
1234 16 : Vectors::CreateNewellSurfaceNormalVector(newSurf.Vertex, newSurf.Sides, newSurf.NewellSurfaceNormalVector);
1235 16 : Vectors::DetermineAzimuthAndTilt(
1236 16 : newSurf.Vertex, SurfWorldAz, SurfTilt, newSurf.lcsx, newSurf.lcsy, newSurf.lcsz, newSurf.NewellSurfaceNormalVector);
1237 16 : newSurf.Azimuth = SurfWorldAz;
1238 16 : newSurf.Tilt = SurfTilt;
1239 16 : newSurf.convOrientation = Convect::GetSurfConvOrientation(newSurf.Tilt);
1240 :
1241 : // Sine and cosine of azimuth and tilt
1242 16 : newSurf.SinAzim = std::sin(SurfWorldAz * Constant::DegToRad);
1243 16 : newSurf.CosAzim = std::cos(SurfWorldAz * Constant::DegToRad);
1244 16 : newSurf.SinTilt = std::sin(SurfTilt * Constant::DegToRad);
1245 16 : newSurf.CosTilt = std::cos(SurfTilt * Constant::DegToRad);
1246 : // Outward normal unit vector (pointing away from room)
1247 16 : newSurf.OutNormVec = newSurf.NewellSurfaceNormalVector;
1248 64 : for (int n = 1; n <= 3; ++n) {
1249 48 : if (std::abs(newSurf.OutNormVec(n) - 1.0) < 1.e-06) newSurf.OutNormVec(n) = +1.0;
1250 48 : if (std::abs(newSurf.OutNormVec(n) + 1.0) < 1.e-06) newSurf.OutNormVec(n) = -1.0;
1251 48 : if (std::abs(newSurf.OutNormVec(n)) < 1.e-06) newSurf.OutNormVec(n) = 0.0;
1252 : }
1253 :
1254 : // Can perform tests on this surface here
1255 16 : newSurf.ViewFactorSky = 0.5 * (1.0 + newSurf.CosTilt);
1256 16 : newSurf.ViewFactorGround = 0.5 * (1.0 - newSurf.CosTilt);
1257 :
1258 : // The following IR view factors are modified in subr. SkyDifSolarShading if there are shadowing
1259 : // surfaces
1260 16 : newSurf.ViewFactorSkyIR = newSurf.ViewFactorSky;
1261 16 : newSurf.ViewFactorGroundIR = 0.5 * (1.0 - newSurf.CosTilt);
1262 : }
1263 :
1264 : // Change Name
1265 16 : newSurf.Name = "iz-" + surfTemp.Name;
1266 : // Debug write(outputfiledebug,*) ' new surf name=',TRIM(SurfaceTmp(CurNewSurf)%Name)
1267 : // Debug write(outputfiledebug,*) ' new surf in zone=',TRIM(surfacetmp(curnewsurf)%zoneName)
1268 16 : newSurf.ExtBoundCond = unreconciledZoneSurface;
1269 16 : surfTemp.ExtBoundCond = unreconciledZoneSurface;
1270 16 : newSurf.ExtBoundCondName = surfTemp.Name;
1271 16 : surfTemp.ExtBoundCondName = newSurf.Name;
1272 16 : if (newSurf.Class == SurfaceClass::Roof || newSurf.Class == SurfaceClass::Wall || newSurf.Class == SurfaceClass::Floor) {
1273 : // base surface
1274 10 : if (surfTemp.Class == SurfaceClass::Roof) {
1275 1 : newSurf.Class = SurfaceClass::Floor;
1276 : // Debug write(outputfiledebug,*) ' new surfaces is a floor'
1277 9 : } else if (surfTemp.Class == SurfaceClass::Floor) {
1278 3 : newSurf.Class = SurfaceClass::Roof;
1279 : // Debug write(outputfiledebug,*) ' new surfaces is a roof'
1280 : }
1281 10 : newSurf.BaseSurf = CurNewSurf;
1282 10 : newSurf.BaseSurfName = newSurf.Name;
1283 : // Debug write(outputfiledebug,*) ' basesurf, extboundcondname=',TRIM(SurfaceTmp(CurNewSurf)%ExtBoundCondName)
1284 : } else {
1285 : // subsurface
1286 : int Found =
1287 6 : Util::FindItemInList("iz-" + surfTemp.BaseSurfName, state.dataSurfaceGeometry->SurfaceTmp, FirstTotalSurfaces + CurNewSurf - 1);
1288 6 : if (Found > 0) {
1289 6 : newSurf.BaseSurfName = "iz-" + surfTemp.BaseSurfName;
1290 6 : newSurf.BaseSurf = Found;
1291 6 : auto &foundBaseSurf = state.dataSurfaceGeometry->SurfaceTmp(Found);
1292 6 : foundBaseSurf.Area -= newSurf.Area;
1293 6 : if (newSurf.Class == SurfaceClass::Window || newSurf.Class == SurfaceClass::GlassDoor) {
1294 3 : foundBaseSurf.NetAreaShadowCalc -= newSurf.Area / newSurf.Multiplier;
1295 : } else { // Door, TDD:Diffuser, TDD:DOME
1296 3 : foundBaseSurf.NetAreaShadowCalc -= newSurf.Area;
1297 : }
1298 6 : newSurf.ExtBoundCond = foundBaseSurf.ExtBoundCond;
1299 6 : newSurf.ExtBoundCondName = surfTemp.Name;
1300 6 : newSurf.ExtSolar = foundBaseSurf.ExtSolar;
1301 6 : newSurf.ExtWind = foundBaseSurf.ExtWind;
1302 6 : newSurf.Zone = foundBaseSurf.Zone;
1303 6 : newSurf.ZoneName = foundBaseSurf.ZoneName;
1304 6 : newSurf.spaceNum = foundBaseSurf.spaceNum;
1305 6 : newSurf.OSCPtr = foundBaseSurf.OSCPtr;
1306 : // Debug write(outputfiledebug,*) ' subsurf, extboundcondname=',TRIM(SurfaceTmp(CurNewSurf)%ExtBoundCondName)
1307 : // Debug write(outputfiledebug,*) ' subsurf, basesurf=',TRIM('iz-'//SurfaceTmp(SurfNum)%BaseSurfName)
1308 : } else {
1309 0 : ShowSevereError(state,
1310 0 : format("{}Adding unentered subsurface, could not find base surface=iz-{}", RoutineName, surfTemp.BaseSurfName));
1311 0 : SurfError = true;
1312 : }
1313 : }
1314 : }
1315 : //**********************************************************************************
1316 : // After all of the surfaces have been defined then the base surfaces for the
1317 : // sub-surfaces can be defined. Loop through surfaces and match with the sub-surface
1318 : // names.
1319 2486 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
1320 2262 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
1321 2262 : if (!surfTemp.HeatTransSurf) continue;
1322 :
1323 2178 : int Found = 0;
1324 : // why are we doing this again? this should have already been done.
1325 2178 : if (Util::SameString(surfTemp.BaseSurfName, surfTemp.Name)) {
1326 1951 : Found = SurfNum;
1327 : } else {
1328 227 : Found = Util::FindItemInList(surfTemp.BaseSurfName, state.dataSurfaceGeometry->SurfaceTmp, state.dataSurface->TotSurfaces);
1329 : }
1330 2178 : if (Found > 0) {
1331 2178 : surfTemp.BaseSurf = Found;
1332 2178 : if (SurfNum != Found) { // for subsurfaces
1333 227 : if (surfTemp.HeatTransSurf) ++state.dataSurfaceGeometry->SurfaceTmp(Found).NumSubSurfaces;
1334 227 : if (surfTemp.Class < SurfaceClass::Window || surfTemp.Class > SurfaceClass::TDD_Diffuser) {
1335 0 : if (surfTemp.Class == SurfaceClass::None) {
1336 0 : ShowSevereError(state, format("{}Invalid SubSurface detected, Surface={}", RoutineName, surfTemp.Name));
1337 : } else {
1338 0 : ShowSevereError(state,
1339 0 : format("{}Invalid SubSurface detected, Surface={}, class={} invalid class for subsurface",
1340 : RoutineName,
1341 0 : surfTemp.Name,
1342 0 : state.dataSurfaceGeometry->BaseSurfCls(int(surfTemp.Class))));
1343 0 : SurfError = true;
1344 : }
1345 : }
1346 : }
1347 : }
1348 :
1349 : } // ...end of the Surface DO loop for finding BaseSurf
1350 : //**********************************************************************************
1351 : // The surfaces need to be hierarchical by space. Input is allowed to be in any order. In
1352 : // this section the surfaces are reordered into:
1353 : // All shadowing surfaces (if mirrored, Mir- surface follows immediately after original)
1354 : // Shading:Site
1355 : // Shading:Building
1356 : // Shading:space (and variants)
1357 : // For each space:
1358 : // Walls
1359 : // Floors
1360 : // Roofs/Ceilings
1361 : // Internal Mass
1362 : // Non-Window subsurfaces (including doors)
1363 : // Window subsurfaces (including TubularDaylightingDiffusers)
1364 : // TubularDaylightingDomes
1365 : // After reordering, MovedSurfs should equal TotSurfaces
1366 :
1367 : // For reporting purposes, the legacy surface order is also saved in DataSurfaces::AllSurfaceListReportOrder:
1368 : // All shadowing surfaces (if mirrored, Mir- surface follows immediately after original)
1369 : // Shading:Site
1370 : // Shading:Building
1371 : // Shading:Zone (and variants)
1372 : // For each zone:
1373 : // Walls
1374 : // subsurfaces for each wall (windows, doors, in input order, not sorted) follow the base surface
1375 : // Floors
1376 : // subsurfaces for each floor (windows, doors, in input order, not sorted) follow the base surface
1377 : // Roofs/Ceilings
1378 : // subsurfaces for each roof/ceiling (windows, doors, in input order, not sorted) follow the base surface
1379 : // Internal Mass
1380 : // After reordering, MovedSurfs should equal TotSurfaces
1381 :
1382 224 : MovedSurfs = 0;
1383 224 : Array1D<bool> SurfaceTmpClassMoved; // Tmp class is moved
1384 224 : SurfaceTmpClassMoved.dimension(state.dataSurface->TotSurfaces, false);
1385 224 : state.dataSurface->AllSurfaceListReportOrder.reserve(state.dataSurface->TotSurfaces);
1386 :
1387 224 : CreateMissingSpaces(state, state.dataSurfaceGeometry->SurfaceTmp);
1388 :
1389 : // Old SurfNum to New SurfNum
1390 : // Old = order in state.dataSurfaceGeometry->SurfaceTmp
1391 : // New = order in state.dataSurface->Surface
1392 224 : EPVector<int> oldToNewSurfNums;
1393 224 : oldToNewSurfNums.resize(state.dataSurface->TotSurfaces, -1);
1394 :
1395 : // Move all shading Surfaces to Front
1396 2486 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
1397 2262 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
1398 2262 : if (surfTemp.Class != SurfaceClass::Detached_F && surfTemp.Class != SurfaceClass::Detached_B && surfTemp.Class != SurfaceClass::Shading)
1399 2178 : continue;
1400 :
1401 : // A shading surface
1402 84 : ++MovedSurfs;
1403 : // Store list of moved surface numbers in reporting order
1404 84 : state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
1405 84 : SurfaceTmpClassMoved(SurfNum) = true; //'Moved'
1406 84 : state.dataSurface->AllSurfaceListReportOrder.push_back(SurfNum);
1407 84 : oldToNewSurfNums(SurfNum) = MovedSurfs;
1408 : }
1409 :
1410 : // For each zone
1411 :
1412 578 : for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
1413 730 : for (int spaceNum : state.dataHeatBal->Zone(ZoneNum).spaceIndexes) {
1414 : // Group air boundary surfaces first within each space
1415 6667 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
1416 6291 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
1417 6291 : if (SurfaceTmpClassMoved(SurfNum)) continue;
1418 4085 : if (surfTemp.spaceNum != spaceNum) continue;
1419 2178 : int constNum = surfTemp.Construction;
1420 2178 : if (constNum == 0) continue;
1421 2178 : if (!state.dataConstruction->Construct(constNum).TypeIsAirBoundary) continue;
1422 :
1423 : // An air boundary surface
1424 42 : surfTemp.IsAirBoundarySurf = true;
1425 42 : ++MovedSurfs;
1426 42 : state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
1427 : // If base Surface Type (Wall, Floor, Roof/Ceiling)
1428 42 : if ((surfTemp.Class == state.dataSurfaceGeometry->BaseSurfIDs(1)) ||
1429 47 : (surfTemp.Class == state.dataSurfaceGeometry->BaseSurfIDs(2)) ||
1430 5 : (surfTemp.Class == state.dataSurfaceGeometry->BaseSurfIDs(3))) {
1431 : // Store list of moved surface numbers in reporting order. We use the old position, we'll reconcile later
1432 : // We don't do it for Air Door/Air Windows yet, we want them listed below each base surf they belong to
1433 38 : state.dataSurface->AllSurfaceListReportOrder.push_back(SurfNum);
1434 : }
1435 42 : oldToNewSurfNums(SurfNum) = MovedSurfs;
1436 42 : SurfaceTmpClassMoved(SurfNum) = true; //'Moved'
1437 : }
1438 :
1439 : // For each Base Surface Type (Wall, Floor, Roof/Ceiling) - put these first
1440 :
1441 1504 : for (const DataSurfaces::SurfaceClass Loop : state.dataSurfaceGeometry->BaseSurfIDs) {
1442 :
1443 20001 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
1444 18873 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
1445 :
1446 18873 : if (SurfaceTmpClassMoved(SurfNum)) continue;
1447 9444 : if (surfTemp.Zone == 0) continue;
1448 :
1449 9444 : if (surfTemp.spaceNum != spaceNum) continue;
1450 3723 : if (surfTemp.Class != Loop) continue;
1451 :
1452 1897 : ++MovedSurfs;
1453 1897 : state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
1454 1897 : oldToNewSurfNums(SurfNum) = MovedSurfs;
1455 1897 : SurfaceTmpClassMoved(SurfNum) = true; // 'Moved'
1456 : // Store list of moved surface numbers in order reporting order (subsurfaces follow their base surface)
1457 1897 : state.dataSurface->AllSurfaceListReportOrder.push_back(SurfNum);
1458 :
1459 : // Find all subsurfaces to this surface - just to update Report them in order
1460 41241 : for (int SubSurfNum = 1; SubSurfNum <= state.dataSurface->TotSurfaces; ++SubSurfNum) {
1461 : // Gotta avoid pushing myself again!
1462 39344 : if (SubSurfNum == SurfNum) continue;
1463 : // We don't check if already moved, because we didn't add them to AllSurfaceListReportOrder above!
1464 37447 : if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).Zone == 0) continue;
1465 36287 : if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).BaseSurf != SurfNum) continue;
1466 : // Add original sub-surface numbers as placeholders in surface list for reporting
1467 227 : state.dataSurface->AllSurfaceListReportOrder.push_back(SubSurfNum);
1468 : }
1469 : }
1470 : }
1471 :
1472 : // Internal mass goes next
1473 6667 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
1474 6291 : if (SurfaceTmpClassMoved(SurfNum)) continue;
1475 :
1476 2146 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
1477 2146 : if (surfTemp.spaceNum != spaceNum) continue;
1478 239 : if (surfTemp.Class != SurfaceClass::IntMass) continue;
1479 16 : ++MovedSurfs;
1480 16 : state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
1481 16 : oldToNewSurfNums(SurfNum) = MovedSurfs;
1482 16 : SurfaceTmpClassMoved(SurfNum) = true; // 'Moved'
1483 : // Store list of moved surface numbers in reporting order
1484 16 : state.dataSurface->AllSurfaceListReportOrder.push_back(SurfNum);
1485 : }
1486 :
1487 : // Opaque door goes next
1488 6667 : for (int SubSurfNum = 1; SubSurfNum <= state.dataSurface->TotSurfaces; ++SubSurfNum) {
1489 :
1490 6291 : if (SurfaceTmpClassMoved(SubSurfNum)) continue;
1491 2130 : if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).spaceNum != spaceNum) continue;
1492 223 : if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).Class != SurfaceClass::Door) continue;
1493 :
1494 21 : ++MovedSurfs;
1495 21 : state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum);
1496 21 : oldToNewSurfNums(SubSurfNum) = MovedSurfs;
1497 21 : SurfaceTmpClassMoved(SubSurfNum) = true; // 'Moved'
1498 : }
1499 :
1500 : // The exterior window subsurfaces (includes SurfaceClass::Window and SurfaceClass::GlassDoor) goes next
1501 6667 : for (int SubSurfNum = 1; SubSurfNum <= state.dataSurface->TotSurfaces; ++SubSurfNum) {
1502 :
1503 6291 : if (SurfaceTmpClassMoved(SubSurfNum)) continue;
1504 2109 : if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).spaceNum != spaceNum) continue;
1505 202 : if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).ExtBoundCond > 0) continue; // Exterior window
1506 225 : if ((state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).Class != SurfaceClass::Window) &&
1507 23 : (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).Class != SurfaceClass::GlassDoor))
1508 13 : continue;
1509 :
1510 189 : ++MovedSurfs;
1511 189 : state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum);
1512 189 : oldToNewSurfNums(SubSurfNum) = MovedSurfs;
1513 189 : SurfaceTmpClassMoved(SubSurfNum) = true; // 'Moved'
1514 : }
1515 :
1516 : // The interior window subsurfaces (includes SurfaceClass::Window and SurfaceClass::GlassDoor) goes next
1517 6667 : for (int SubSurfNum = 1; SubSurfNum <= state.dataSurface->TotSurfaces; ++SubSurfNum) {
1518 :
1519 6291 : if (SurfaceTmpClassMoved(SubSurfNum)) continue;
1520 1920 : if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).spaceNum != spaceNum) continue;
1521 13 : if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).ExtBoundCond <= 0) continue;
1522 0 : if ((state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).Class != SurfaceClass::Window) &&
1523 0 : (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).Class != SurfaceClass::GlassDoor))
1524 0 : continue;
1525 :
1526 0 : ++MovedSurfs;
1527 0 : state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum);
1528 0 : oldToNewSurfNums(SubSurfNum) = MovedSurfs;
1529 0 : SurfaceTmpClassMoved(SubSurfNum) = true; // 'Moved'
1530 : }
1531 :
1532 : // The SurfaceClass::TDD_Diffuser (OriginalClass = Window) goes next
1533 6667 : for (int SubSurfNum = 1; SubSurfNum <= state.dataSurface->TotSurfaces; ++SubSurfNum) {
1534 :
1535 6291 : if (SurfaceTmpClassMoved(SubSurfNum)) continue;
1536 1920 : if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).spaceNum != spaceNum) continue;
1537 13 : if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).Class != SurfaceClass::TDD_Diffuser) continue;
1538 :
1539 6 : ++MovedSurfs;
1540 6 : state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum);
1541 6 : oldToNewSurfNums(SubSurfNum) = MovedSurfs;
1542 6 : SurfaceTmpClassMoved(SubSurfNum) = true; // 'Moved'
1543 : }
1544 :
1545 : // Last but not least, SurfaceClass::TDD_Dome
1546 6667 : for (int SubSurfNum = 1; SubSurfNum <= state.dataSurface->TotSurfaces; ++SubSurfNum) {
1547 :
1548 6291 : if (SurfaceTmpClassMoved(SubSurfNum)) continue;
1549 1914 : if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).spaceNum != spaceNum) continue;
1550 7 : if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).Class != SurfaceClass::TDD_Dome) continue;
1551 :
1552 7 : ++MovedSurfs;
1553 7 : state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum);
1554 7 : oldToNewSurfNums(SubSurfNum) = MovedSurfs;
1555 7 : SurfaceTmpClassMoved(SubSurfNum) = true; // 'Moved'
1556 : }
1557 : }
1558 : }
1559 :
1560 : // Validity checking
1561 224 : assert(state.dataSurface->TotSurfaces == MovedSurfs);
1562 224 : assert(state.dataSurface->TotSurfaces == static_cast<int>(state.dataSurface->AllSurfaceListReportOrder.size()));
1563 224 : assert(state.dataSurface->TotSurfaces == static_cast<int>(oldToNewSurfNums.size()));
1564 :
1565 : // Assert validity of indices
1566 2486 : assert(std::find_if(state.dataSurface->AllSurfaceListReportOrder.cbegin(), state.dataSurface->AllSurfaceListReportOrder.cend(), [](int i) {
1567 : return i < 1;
1568 : }) == state.dataSurface->AllSurfaceListReportOrder.cend());
1569 :
1570 2486 : assert(std::find_if(oldToNewSurfNums.cbegin(), oldToNewSurfNums.cend(), [](int i) { return i < 1; }) == oldToNewSurfNums.cend());
1571 :
1572 224 : if (MovedSurfs != state.dataSurface->TotSurfaces) {
1573 0 : ShowSevereError(
1574 : state,
1575 0 : format("{}Reordered # of Surfaces ({}) not = Total # of Surfaces ({})", RoutineName, MovedSurfs, state.dataSurface->TotSurfaces));
1576 0 : SurfError = true;
1577 0 : for (int Loop = 1; Loop <= state.dataSurface->TotSurfaces; ++Loop) {
1578 0 : if (!SurfaceTmpClassMoved(Loop) && state.dataSurfaceGeometry->SurfaceTmp(Loop).Class == SurfaceClass::Invalid) {
1579 0 : ShowSevereError(state,
1580 0 : format("{}Error in Surface= \"{} indicated Zone=\"{}\"",
1581 : RoutineName,
1582 0 : state.dataSurfaceGeometry->SurfaceTmp(Loop).Name,
1583 0 : state.dataSurfaceGeometry->SurfaceTmp(Loop).ZoneName));
1584 : }
1585 : }
1586 0 : ShowWarningError(
1587 0 : state, format("{}Remaining surface checks will use \"reordered number of surfaces\", not number of original surfaces", RoutineName));
1588 : }
1589 :
1590 : // Realign the relationship: surface to base surface
1591 2486 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
1592 2262 : auto &movedSurf = state.dataSurface->Surface(SurfNum);
1593 2262 : if (movedSurf.BaseSurf > 0) {
1594 2178 : int newBaseSurfNum = oldToNewSurfNums(movedSurf.BaseSurf);
1595 2178 : movedSurf.BaseSurf = newBaseSurfNum;
1596 :
1597 2178 : if (newBaseSurfNum < 1) {
1598 0 : ShowFatalError(
1599 : state,
1600 0 : format("{}Couldn't find the new Surface Number for surface index {} named '{}'. Looking for BaseSurf old index of {}",
1601 : RoutineName,
1602 : SurfNum,
1603 0 : movedSurf.Name,
1604 0 : movedSurf.BaseSurf));
1605 : }
1606 : }
1607 2262 : auto &reportOrderNum = state.dataSurface->AllSurfaceListReportOrder[SurfNum - 1];
1608 2262 : if (reportOrderNum > 0) {
1609 2262 : int newReportOrderNum = oldToNewSurfNums(reportOrderNum);
1610 2262 : reportOrderNum = newReportOrderNum;
1611 : }
1612 : }
1613 :
1614 224 : state.dataSurfaceGeometry->SurfaceTmp.deallocate(); // DeAllocate the Temp Surface derived type
1615 :
1616 224 : createSpaceSurfaceLists(state);
1617 :
1618 : // For each Base Surface Type (Wall, Floor, Roof)
1619 :
1620 896 : for (const DataSurfaces::SurfaceClass Loop : state.dataSurfaceGeometry->BaseSurfIDs) {
1621 7458 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
1622 :
1623 6786 : if (state.dataSurface->Surface(SurfNum).Zone == 0) continue;
1624 :
1625 6534 : if (state.dataSurface->Surface(SurfNum).Class != Loop) continue;
1626 :
1627 : // Find all subsurfaces to this surface
1628 41861 : for (int SubSurfNum = 1; SubSurfNum <= state.dataSurface->TotSurfaces; ++SubSurfNum) {
1629 :
1630 39926 : if (SurfNum == SubSurfNum) continue;
1631 37991 : if (state.dataSurface->Surface(SubSurfNum).Zone == 0) continue;
1632 36831 : if (state.dataSurface->Surface(SubSurfNum).BaseSurf != SurfNum) continue;
1633 :
1634 : // Check facing angle of Sub compared to base
1635 227 : checkSubSurfAzTiltNorm(state, state.dataSurface->Surface(SurfNum), state.dataSurface->Surface(SubSurfNum), subSurfaceError);
1636 227 : if (subSurfaceError) SurfError = true;
1637 : }
1638 : }
1639 : }
1640 :
1641 : //**********************************************************************************
1642 : // Now, match up interzone surfaces
1643 224 : NonMatch = false;
1644 224 : izConstDiffMsg = false;
1645 2486 : for (int SurfNum = 1; SurfNum <= MovedSurfs; ++SurfNum) { // TotSurfaces
1646 : // Clean up Shading Surfaces, make sure they don't go through here.
1647 2262 : if (!state.dataSurface->Surface(SurfNum).HeatTransSurf) continue;
1648 : // If other surface, match it up
1649 : // Both interzone and "internal" surfaces have this pointer set
1650 : // Internal surfaces point to themselves, Interzone to another
1651 2178 : if (state.dataSurface->Surface(SurfNum).ExtBoundCond == unreconciledZoneSurface) {
1652 440 : if (not_blank(state.dataSurface->Surface(SurfNum).ExtBoundCondName)) {
1653 440 : int Found = 0;
1654 440 : if (state.dataSurface->Surface(SurfNum).ExtBoundCondName == state.dataSurface->Surface(SurfNum).Name) {
1655 245 : Found = SurfNum;
1656 : } else {
1657 195 : Found = Util::FindItemInList(state.dataSurface->Surface(SurfNum).ExtBoundCondName, state.dataSurface->Surface, MovedSurfs);
1658 : }
1659 440 : if (Found != 0) {
1660 440 : state.dataSurface->Surface(SurfNum).ExtBoundCond = Found;
1661 : // Check that matching surface is also "OtherZoneSurface"
1662 633 : if (state.dataSurface->Surface(Found).ExtBoundCond <= 0 &&
1663 193 : state.dataSurface->Surface(Found).ExtBoundCond != unreconciledZoneSurface) {
1664 0 : ShowSevereError(state, format("{}Potential \"OtherZoneSurface\" is not matched correctly:", RoutineName));
1665 :
1666 0 : ShowContinueError(state,
1667 0 : format("Surface={}, Zone={}",
1668 0 : state.dataSurface->Surface(SurfNum).Name,
1669 0 : state.dataSurface->Surface(SurfNum).ZoneName));
1670 0 : ShowContinueError(state,
1671 0 : format("Nonmatched Other/InterZone Surface={}, Zone={}",
1672 0 : state.dataSurface->Surface(Found).Name,
1673 0 : state.dataSurface->Surface(Found).ZoneName));
1674 0 : SurfError = true;
1675 : }
1676 : // Check that matching interzone surface has construction with reversed layers
1677 440 : if (Found != SurfNum) { // Interzone surface
1678 : // Make sure different zones too (CR 4110)
1679 195 : if (state.dataSurface->Surface(SurfNum).spaceNum == state.dataSurface->Surface(Found).spaceNum) {
1680 1 : ++state.dataSurfaceGeometry->ErrCount2;
1681 1 : if (state.dataSurfaceGeometry->ErrCount2 == 1 && !state.dataGlobal->DisplayExtraWarnings) {
1682 2 : ShowWarningError(state,
1683 2 : format("{}CAUTION -- Interspace surfaces are occurring in the same space(s).", RoutineName));
1684 3 : ShowContinueError(
1685 : state, "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on individual occurrences.");
1686 : }
1687 1 : if (state.dataGlobal->DisplayExtraWarnings) {
1688 0 : ShowWarningError(state, format("{}CAUTION -- Interspace surfaces are usually in different spaces", RoutineName));
1689 0 : ShowContinueError(state,
1690 0 : format("Surface={}, Space={}, Zone={}",
1691 0 : state.dataSurface->Surface(SurfNum).Name,
1692 0 : state.dataHeatBal->space(state.dataSurface->Surface(SurfNum).spaceNum).Name,
1693 0 : state.dataSurface->Surface(SurfNum).ZoneName));
1694 0 : ShowContinueError(state,
1695 0 : format("Surface={}, Space={}, Zone={}",
1696 0 : state.dataSurface->Surface(Found).Name,
1697 0 : state.dataHeatBal->space(state.dataSurface->Surface(Found).spaceNum).Name,
1698 0 : state.dataSurface->Surface(Found).ZoneName));
1699 : }
1700 : }
1701 195 : int ConstrNum = state.dataSurface->Surface(SurfNum).Construction;
1702 195 : int ConstrNumFound = state.dataSurface->Surface(Found).Construction;
1703 195 : if (ConstrNum <= 0 || ConstrNumFound <= 0) continue;
1704 195 : if (state.dataConstruction->Construct(ConstrNum).ReverseConstructionNumLayersWarning &&
1705 0 : state.dataConstruction->Construct(ConstrNumFound).ReverseConstructionNumLayersWarning)
1706 0 : continue;
1707 195 : if (state.dataConstruction->Construct(ConstrNum).ReverseConstructionLayersOrderWarning &&
1708 0 : state.dataConstruction->Construct(ConstrNumFound).ReverseConstructionLayersOrderWarning)
1709 0 : continue;
1710 195 : TotLay = state.dataConstruction->Construct(ConstrNum).TotLayers;
1711 195 : TotLayFound = state.dataConstruction->Construct(ConstrNumFound).TotLayers;
1712 195 : if (TotLay != TotLayFound) { // Different number of layers
1713 : // match on like Uvalues (nominal)
1714 0 : if (std::abs(state.dataHeatBal->NominalU(ConstrNum) - state.dataHeatBal->NominalU(ConstrNumFound)) > 0.001) {
1715 0 : ShowSevereError(state,
1716 0 : format("{}Construction {} of interzone surface {} does not have the same number of layers as the "
1717 : "construction {} of adjacent surface {}",
1718 : RoutineName,
1719 0 : state.dataConstruction->Construct(ConstrNum).Name,
1720 0 : state.dataSurface->Surface(SurfNum).Name,
1721 0 : state.dataConstruction->Construct(ConstrNumFound).Name,
1722 0 : state.dataSurface->Surface(Found).Name));
1723 0 : if (!state.dataConstruction->Construct(ConstrNum).ReverseConstructionNumLayersWarning ||
1724 0 : !state.dataConstruction->Construct(ConstrNumFound).ReverseConstructionNumLayersWarning) {
1725 0 : ShowContinueError(state, "...this problem for this pair will not be reported again.");
1726 0 : state.dataConstruction->Construct(ConstrNum).ReverseConstructionNumLayersWarning = true;
1727 0 : state.dataConstruction->Construct(ConstrNumFound).ReverseConstructionNumLayersWarning = true;
1728 : }
1729 0 : SurfError = true;
1730 : }
1731 : } else { // Same number of layers; check for reverse layers
1732 : // check layers as number of layers is the same
1733 195 : izConstDiff = false;
1734 : // ok if same nominal U
1735 195 : CheckForReversedLayers(state, izConstDiff, ConstrNum, ConstrNumFound, TotLay);
1736 195 : if (izConstDiff &&
1737 0 : std::abs(state.dataHeatBal->NominalU(ConstrNum) - state.dataHeatBal->NominalU(ConstrNumFound)) > 0.001) {
1738 0 : ShowSevereError(state,
1739 0 : format("{}Construction {} of interzone surface {} does not have the same materials in the "
1740 : "reverse order as the construction {} of adjacent surface {}",
1741 : RoutineName,
1742 0 : state.dataConstruction->Construct(ConstrNum).Name,
1743 0 : state.dataSurface->Surface(SurfNum).Name,
1744 0 : state.dataConstruction->Construct(ConstrNumFound).Name,
1745 0 : state.dataSurface->Surface(Found).Name));
1746 0 : ShowContinueError(state,
1747 : "or the properties of the reversed layers are not correct due to differing layer front and "
1748 : "back side values");
1749 0 : if (!state.dataConstruction->Construct(ConstrNum).ReverseConstructionLayersOrderWarning ||
1750 0 : !state.dataConstruction->Construct(ConstrNumFound).ReverseConstructionLayersOrderWarning) {
1751 0 : ShowContinueError(state, "...this problem for this pair will not be reported again.");
1752 0 : state.dataConstruction->Construct(ConstrNum).ReverseConstructionLayersOrderWarning = true;
1753 0 : state.dataConstruction->Construct(ConstrNumFound).ReverseConstructionLayersOrderWarning = true;
1754 : }
1755 0 : SurfError = true;
1756 195 : } else if (izConstDiff) {
1757 0 : ShowWarningError(state,
1758 0 : format("{}Construction {} of interzone surface {} does not have the same materials in the "
1759 : "reverse order as the construction {} of adjacent surface {}",
1760 : RoutineName,
1761 0 : state.dataConstruction->Construct(ConstrNum).Name,
1762 0 : state.dataSurface->Surface(SurfNum).Name,
1763 0 : state.dataConstruction->Construct(ConstrNumFound).Name,
1764 0 : state.dataSurface->Surface(Found).Name));
1765 0 : ShowContinueError(state,
1766 : "or the properties of the reversed layers are not correct due to differing layer front and "
1767 : "back side values");
1768 0 : ShowContinueError(
1769 : state,
1770 0 : format("...but Nominal U values are similar, diff=[{:.4R}] ... simulation proceeds.",
1771 0 : std::abs(state.dataHeatBal->NominalU(ConstrNum) - state.dataHeatBal->NominalU(ConstrNumFound))));
1772 0 : if (!izConstDiffMsg) {
1773 0 : ShowContinueError(state,
1774 : "...if the two zones are expected to have significantly different temperatures, the proper "
1775 : "\"reverse\" construction should be created.");
1776 0 : izConstDiffMsg = true;
1777 : }
1778 0 : if (!state.dataConstruction->Construct(ConstrNum).ReverseConstructionLayersOrderWarning ||
1779 0 : !state.dataConstruction->Construct(ConstrNumFound).ReverseConstructionLayersOrderWarning) {
1780 0 : ShowContinueError(state, "...this problem for this pair will not be reported again.");
1781 0 : state.dataConstruction->Construct(ConstrNum).ReverseConstructionLayersOrderWarning = true;
1782 0 : state.dataConstruction->Construct(ConstrNumFound).ReverseConstructionLayersOrderWarning = true;
1783 : }
1784 : }
1785 : }
1786 :
1787 : // If significantly different areas -- this would not be good
1788 195 : MultFound = state.dataHeatBal->Zone(state.dataSurface->Surface(Found).Zone).Multiplier *
1789 195 : state.dataHeatBal->Zone(state.dataSurface->Surface(Found).Zone).ListMultiplier;
1790 195 : MultSurfNum = state.dataHeatBal->Zone(state.dataSurface->Surface(SurfNum).Zone).Multiplier *
1791 195 : state.dataHeatBal->Zone(state.dataSurface->Surface(SurfNum).Zone).ListMultiplier;
1792 195 : if (state.dataSurface->Surface(Found).Area > 0.0) {
1793 195 : if (std::abs((state.dataSurface->Surface(Found).Area * MultFound -
1794 195 : state.dataSurface->Surface(SurfNum).Area * MultSurfNum) /
1795 195 : state.dataSurface->Surface(Found).Area * MultFound) > 0.02) { // 2% difference in areas
1796 0 : ++state.dataSurfaceGeometry->ErrCount4;
1797 0 : if (state.dataSurfaceGeometry->ErrCount4 == 1 && !state.dataGlobal->DisplayExtraWarnings) {
1798 0 : ShowWarningError(
1799 : state,
1800 0 : format("{}InterZone Surface Areas do not match as expected and might not satisfy conservation of energy:",
1801 : RoutineName));
1802 0 : ShowContinueError(
1803 : state, "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on individual mismatches.");
1804 : }
1805 0 : if (state.dataGlobal->DisplayExtraWarnings) {
1806 0 : ShowWarningError(
1807 : state,
1808 0 : format("{}InterZone Surface Areas do not match as expected and might not satisfy conservation of energy:",
1809 : RoutineName));
1810 :
1811 0 : if (MultFound == 1 && MultSurfNum == 1) {
1812 0 : ShowContinueError(state,
1813 0 : format(" Area={:.1T} in Surface={}, Zone={}",
1814 0 : state.dataSurface->Surface(SurfNum).Area,
1815 0 : state.dataSurface->Surface(SurfNum).Name,
1816 0 : state.dataSurface->Surface(SurfNum).ZoneName));
1817 0 : ShowContinueError(state,
1818 0 : format(" Area={:.1T} in Surface={}, Zone={}",
1819 0 : state.dataSurface->Surface(Found).Area,
1820 0 : state.dataSurface->Surface(Found).Name,
1821 0 : state.dataSurface->Surface(Found).ZoneName));
1822 : } else { // Show multiplier info
1823 0 : ShowContinueError(state,
1824 0 : format(" Area={:.1T}, Multipliers={}, Total Area={:.1T} in Surface={} Zone={}",
1825 0 : state.dataSurface->Surface(SurfNum).Area,
1826 : MultSurfNum,
1827 0 : state.dataSurface->Surface(SurfNum).Area * MultSurfNum,
1828 0 : state.dataSurface->Surface(SurfNum).Name,
1829 0 : state.dataSurface->Surface(SurfNum).ZoneName));
1830 :
1831 0 : ShowContinueError(state,
1832 0 : format(" Area={:.1T}, Multipliers={}, Total Area={:.1T} in Surface={} Zone={}",
1833 0 : state.dataSurface->Surface(Found).Area,
1834 : MultFound,
1835 0 : state.dataSurface->Surface(Found).Area * MultFound,
1836 0 : state.dataSurface->Surface(Found).Name,
1837 0 : state.dataSurface->Surface(Found).ZoneName));
1838 : }
1839 : }
1840 : }
1841 : }
1842 : // Check opposites Azimuth and Tilt
1843 : // Tilt
1844 195 : if (std::abs(std::abs(state.dataSurface->Surface(Found).Tilt + state.dataSurface->Surface(SurfNum).Tilt) - 180.0) > 1.0) {
1845 0 : ShowWarningError(state, format("{}InterZone Surface Tilts do not match as expected.", RoutineName));
1846 0 : ShowContinueError(state,
1847 0 : format(" Tilt={:.1T} in Surface={}, Zone={}",
1848 0 : state.dataSurface->Surface(SurfNum).Tilt,
1849 0 : state.dataSurface->Surface(SurfNum).Name,
1850 0 : state.dataSurface->Surface(SurfNum).ZoneName));
1851 0 : ShowContinueError(state,
1852 0 : format(" Tilt={:.1T} in Surface={}, Zone={}",
1853 0 : state.dataSurface->Surface(Found).Tilt,
1854 0 : state.dataSurface->Surface(Found).Name,
1855 0 : state.dataSurface->Surface(Found).ZoneName));
1856 : }
1857 : // check surface class match. interzone surface.
1858 :
1859 195 : if ((state.dataSurface->Surface(SurfNum).Class == SurfaceClass::Wall &&
1860 390 : state.dataSurface->Surface(Found).Class != SurfaceClass::Wall) ||
1861 195 : (state.dataSurface->Surface(SurfNum).Class != SurfaceClass::Wall &&
1862 71 : state.dataSurface->Surface(Found).Class == SurfaceClass::Wall)) {
1863 0 : ShowWarningError(state, format("{}InterZone Surface Classes do not match as expected.", RoutineName));
1864 0 : ShowContinueError(state,
1865 0 : format("Surface=\"{}\", surface class={}",
1866 0 : state.dataSurface->Surface(SurfNum).Name,
1867 0 : cSurfaceClass(state.dataSurface->Surface(SurfNum).Class)));
1868 0 : ShowContinueError(state,
1869 0 : format("Adjacent Surface=\"{}\", surface class={}",
1870 0 : state.dataSurface->Surface(Found).Name,
1871 0 : cSurfaceClass(state.dataSurface->Surface(Found).Class)));
1872 0 : ShowContinueError(state, "Other errors/warnings may follow about these surfaces.");
1873 : }
1874 195 : if ((state.dataSurface->Surface(SurfNum).Class == SurfaceClass::Roof &&
1875 390 : state.dataSurface->Surface(Found).Class != SurfaceClass::Floor) ||
1876 195 : (state.dataSurface->Surface(SurfNum).Class != SurfaceClass::Roof &&
1877 170 : state.dataSurface->Surface(Found).Class == SurfaceClass::Floor)) {
1878 0 : ShowWarningError(state, format("{}InterZone Surface Classes do not match as expected.", RoutineName));
1879 0 : ShowContinueError(state,
1880 0 : format("Surface=\"{}\", surface class={}",
1881 0 : state.dataSurface->Surface(SurfNum).Name,
1882 0 : cSurfaceClass(state.dataSurface->Surface(SurfNum).Class)));
1883 0 : ShowContinueError(state,
1884 0 : format("Adjacent Surface=\"{}\", surface class={}",
1885 0 : state.dataSurface->Surface(Found).Name,
1886 0 : cSurfaceClass(state.dataSurface->Surface(Found).Class)));
1887 0 : ShowContinueError(state, "Other errors/warnings may follow about these surfaces.");
1888 : }
1889 365 : if (state.dataSurface->Surface(SurfNum).Class != SurfaceClass::Roof &&
1890 170 : state.dataSurface->Surface(SurfNum).Class != SurfaceClass::Floor) {
1891 : // Walls, Windows, Doors, Glass Doors
1892 137 : if (state.dataSurface->Surface(SurfNum).Class != SurfaceClass::Wall) {
1893 : // Surface is a Door, Window or Glass Door
1894 13 : if (state.dataSurface->Surface(SurfNum).BaseSurf == 0) continue; // error detected elsewhere
1895 26 : if (state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Class == SurfaceClass::Roof ||
1896 13 : state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Class == SurfaceClass::Floor)
1897 0 : continue;
1898 : }
1899 137 : if (std::abs(std::abs(state.dataSurface->Surface(SurfNum).Azimuth - state.dataSurface->Surface(Found).Azimuth) -
1900 137 : 180.0) > 1.0) {
1901 24 : if (std::abs(state.dataSurface->Surface(SurfNum).SinTilt) > 0.5 || state.dataGlobal->DisplayExtraWarnings) {
1902 : // if horizontal surfaces, then these are windows/doors/etc in those items.
1903 24 : ShowWarningError(state, format("{}InterZone Surface Azimuths do not match as expected.", RoutineName));
1904 48 : ShowContinueError(state,
1905 48 : format(" Azimuth={:.1T}, Tilt={:.1T}, in Surface={}, Zone={}",
1906 24 : state.dataSurface->Surface(SurfNum).Azimuth,
1907 24 : state.dataSurface->Surface(SurfNum).Tilt,
1908 24 : state.dataSurface->Surface(SurfNum).Name,
1909 24 : state.dataSurface->Surface(SurfNum).ZoneName));
1910 48 : ShowContinueError(state,
1911 48 : format(" Azimuth={:.1T}, Tilt={:.1T}, in Surface={}, Zone={}",
1912 24 : state.dataSurface->Surface(Found).Azimuth,
1913 24 : state.dataSurface->Surface(Found).Tilt,
1914 24 : state.dataSurface->Surface(Found).Name,
1915 24 : state.dataSurface->Surface(Found).ZoneName));
1916 48 : ShowContinueError(
1917 : state,
1918 48 : format("..surface class of first surface={}", cSurfaceClass(state.dataSurface->Surface(SurfNum).Class)));
1919 48 : ShowContinueError(
1920 : state,
1921 48 : format("..surface class of second surface={}", cSurfaceClass(state.dataSurface->Surface(Found).Class)));
1922 : }
1923 : }
1924 : }
1925 :
1926 : // Make sure exposures (Sun, Wind) are the same.....and are "not"
1927 195 : if (state.dataSurface->Surface(SurfNum).ExtSolar || state.dataSurface->Surface(Found).ExtSolar) {
1928 0 : ShowWarningError(state, format("{}Interzone surfaces cannot be \"SunExposed\" -- removing SunExposed", RoutineName));
1929 0 : ShowContinueError(state,
1930 0 : format(" Surface={}, Zone={}",
1931 0 : state.dataSurface->Surface(SurfNum).Name,
1932 0 : state.dataSurface->Surface(SurfNum).ZoneName));
1933 0 : ShowContinueError(state,
1934 0 : format(" Surface={}, Zone={}",
1935 0 : state.dataSurface->Surface(Found).Name,
1936 0 : state.dataSurface->Surface(Found).ZoneName));
1937 0 : state.dataSurface->Surface(SurfNum).ExtSolar = false;
1938 0 : state.dataSurface->Surface(Found).ExtSolar = false;
1939 : }
1940 195 : if (state.dataSurface->Surface(SurfNum).ExtWind || state.dataSurface->Surface(Found).ExtWind) {
1941 0 : ShowWarningError(state,
1942 0 : format("{}Interzone surfaces cannot be \"WindExposed\" -- removing WindExposed", RoutineName));
1943 0 : ShowContinueError(state,
1944 0 : format(" Surface={}, Zone={}",
1945 0 : state.dataSurface->Surface(SurfNum).Name,
1946 0 : state.dataSurface->Surface(SurfNum).ZoneName));
1947 0 : ShowContinueError(state,
1948 0 : format(" Surface={}, Zone={}",
1949 0 : state.dataSurface->Surface(Found).Name,
1950 0 : state.dataSurface->Surface(Found).ZoneName));
1951 0 : state.dataSurface->Surface(SurfNum).ExtWind = false;
1952 0 : state.dataSurface->Surface(Found).ExtWind = false;
1953 : }
1954 : }
1955 : // Set opposing surface back to this one (regardless of error)
1956 440 : state.dataSurface->Surface(Found).ExtBoundCond = SurfNum;
1957 : // Check subsurfaces... make sure base surface is also an interzone surface
1958 440 : if (state.dataSurface->Surface(SurfNum).BaseSurf != SurfNum) { // Subsurface
1959 26 : if ((state.dataSurface->Surface(SurfNum).ExtBoundCond != SurfNum) &&
1960 13 : not_blank(state.dataSurface->Surface(SurfNum).ExtBoundCondName)) {
1961 : // if not internal subsurface
1962 13 : if (state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond ==
1963 13 : state.dataSurface->Surface(SurfNum).BaseSurf) {
1964 : // base surface is not interzone surface
1965 0 : ShowSevereError(state,
1966 0 : format("{}SubSurface=\"{}\" is an interzone subsurface.",
1967 : RoutineName,
1968 0 : state.dataSurface->Surface(SurfNum).Name));
1969 0 : ShowContinueError(state,
1970 0 : format("..but the Base Surface is not an interzone surface, Surface=\"{}\".",
1971 0 : state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Name));
1972 0 : SurfError = true;
1973 : }
1974 : }
1975 : }
1976 : } else {
1977 : // Seems unlikely that an internal surface would be missing itself, so this message
1978 : // only indicates for adjacent (interzone) surfaces.
1979 0 : ShowSevereError(state,
1980 0 : format("{}Adjacent Surface not found: {} adjacent to surface {}",
1981 : RoutineName,
1982 0 : state.dataSurface->Surface(SurfNum).ExtBoundCondName,
1983 0 : state.dataSurface->Surface(SurfNum).Name));
1984 0 : NonMatch = true;
1985 0 : SurfError = true;
1986 : }
1987 0 : } else if (state.dataSurface->Surface(SurfNum).BaseSurf != SurfNum) { // Subsurface
1988 0 : if (state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond > 0 &&
1989 0 : state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond !=
1990 0 : state.dataSurface->Surface(SurfNum).BaseSurf) { // If Interzone surface, subsurface must be also.
1991 0 : ShowSevereError(state, format("{}SubSurface on Interzone Surface must be an Interzone SubSurface.", RoutineName));
1992 0 : ShowContinueError(state,
1993 0 : format("...OutsideFaceEnvironment is blank, in Surface={}", state.dataSurface->Surface(SurfNum).Name));
1994 0 : SurfError = true;
1995 : } else {
1996 0 : ++state.dataSurfaceGeometry->ErrCount3;
1997 0 : if (state.dataSurfaceGeometry->ErrCount3 == 1 && !state.dataGlobal->DisplayExtraWarnings) {
1998 0 : ShowWarningError(state, format("{}Blank name for Outside Boundary Condition Objects.", RoutineName));
1999 0 : ShowContinueError(state, "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on individual surfaces.");
2000 : }
2001 0 : if (state.dataGlobal->DisplayExtraWarnings) {
2002 0 : ShowWarningError(state,
2003 0 : format("{}Blank name for Outside Boundary Condition Object, in surface={}",
2004 : RoutineName,
2005 0 : state.dataSurface->Surface(SurfNum).Name));
2006 0 : ShowContinueError(state,
2007 0 : format("Resetting this surface to be an internal zone surface, zone={}",
2008 0 : state.dataSurface->Surface(SurfNum).ZoneName));
2009 : }
2010 0 : state.dataSurface->Surface(SurfNum).ExtBoundCondName = state.dataSurface->Surface(SurfNum).Name;
2011 0 : state.dataSurface->Surface(SurfNum).ExtBoundCond = SurfNum;
2012 : }
2013 : } else {
2014 0 : ++state.dataSurfaceGeometry->ErrCount3;
2015 0 : if (state.dataSurfaceGeometry->ErrCount3 == 1 && !state.dataGlobal->DisplayExtraWarnings) {
2016 0 : ShowSevereError(state, format("{}Blank name for Outside Boundary Condition Objects.", RoutineName));
2017 0 : ShowContinueError(state, "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on individual surfaces.");
2018 : }
2019 0 : if (state.dataGlobal->DisplayExtraWarnings) {
2020 0 : ShowWarningError(state,
2021 0 : format("{}Blank name for Outside Boundary Condition Object, in surface={}",
2022 : RoutineName,
2023 0 : state.dataSurface->Surface(SurfNum).Name));
2024 0 : ShowContinueError(state,
2025 0 : format("Resetting this surface to be an internal zone (adiabatic) surface, zone={}",
2026 0 : state.dataSurface->Surface(SurfNum).ZoneName));
2027 : }
2028 0 : state.dataSurface->Surface(SurfNum).ExtBoundCondName = state.dataSurface->Surface(SurfNum).Name;
2029 0 : state.dataSurface->Surface(SurfNum).ExtBoundCond = SurfNum;
2030 0 : SurfError = true;
2031 : }
2032 : }
2033 :
2034 : } // ...end of the Surface DO loop for finding BaseSurf
2035 224 : if (NonMatch) {
2036 0 : ShowSevereError(state, format("{}Non matching interzone surfaces found", RoutineName));
2037 : }
2038 :
2039 : //**********************************************************************************
2040 : // Warn about interzone surfaces that have adiabatic windows/vice versa
2041 224 : SubSurfaceSevereDisplayed = false;
2042 2486 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
2043 2262 : if (!state.dataSurface->Surface(SurfNum).HeatTransSurf) continue;
2044 2178 : if (state.dataSurface->Surface(SurfNum).BaseSurf == SurfNum) continue; // base surface
2045 : // not base surface. Check it.
2046 227 : if (state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond <= 0) { // exterior or other base surface
2047 195 : if (state.dataSurface->Surface(SurfNum).ExtBoundCond !=
2048 195 : state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond) { // should match base surface
2049 0 : if (state.dataSurface->Surface(SurfNum).ExtBoundCond == SurfNum) {
2050 0 : ShowSevereError(
2051 : state,
2052 0 : format("{}Subsurface=\"{}\" exterior condition [adiabatic surface] in a base surface=\"{}\" with exterior condition [{}]",
2053 : RoutineName,
2054 0 : state.dataSurface->Surface(SurfNum).Name,
2055 0 : state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Name,
2056 : DataSurfaces::cExtBoundCondition(
2057 0 : state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond)));
2058 0 : SurfError = true;
2059 0 : } else if (state.dataSurface->Surface(SurfNum).ExtBoundCond > 0) {
2060 0 : ShowSevereError(
2061 : state,
2062 0 : format("{}Subsurface=\"{}\" exterior condition [interzone surface] in a base surface=\"{}\" with exterior condition [{}]",
2063 : RoutineName,
2064 0 : state.dataSurface->Surface(SurfNum).Name,
2065 0 : state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Name,
2066 : DataSurfaces::cExtBoundCondition(
2067 0 : state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond)));
2068 0 : SurfError = true;
2069 0 : } else if (state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond ==
2070 : DataSurfaces::OtherSideCondModeledExt) {
2071 0 : ShowWarningError(state,
2072 0 : format("{}Subsurface=\"{}\" exterior condition [{}] in a base surface=\"{}\" with exterior condition [{}]",
2073 : RoutineName,
2074 0 : state.dataSurface->Surface(SurfNum).Name,
2075 0 : DataSurfaces::cExtBoundCondition(state.dataSurface->Surface(SurfNum).ExtBoundCond),
2076 0 : state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Name,
2077 : DataSurfaces::cExtBoundCondition(
2078 0 : state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond)));
2079 0 : ShowContinueError(state, "...SubSurface will not use the exterior condition model of the base surface.");
2080 : } else {
2081 0 : ShowSevereError(state,
2082 0 : format("{}Subsurface=\"{}\" exterior condition [{}] in a base surface=\"{}\" with exterior condition [{}]",
2083 : RoutineName,
2084 0 : state.dataSurface->Surface(SurfNum).Name,
2085 0 : DataSurfaces::cExtBoundCondition(state.dataSurface->Surface(SurfNum).ExtBoundCond),
2086 0 : state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Name,
2087 : DataSurfaces::cExtBoundCondition(
2088 0 : state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond)));
2089 0 : SurfError = true;
2090 : }
2091 0 : if (!SubSurfaceSevereDisplayed && SurfError) {
2092 0 : ShowContinueError(state, "...calculations for heat balance would be compromised.");
2093 0 : SubSurfaceSevereDisplayed = true;
2094 : }
2095 : }
2096 32 : } else if (state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).BaseSurf ==
2097 32 : state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond) {
2098 : // adiabatic surface. make sure subsurfaces match
2099 0 : if (state.dataSurface->Surface(SurfNum).ExtBoundCond != SurfNum) { // not adiabatic surface
2100 0 : if (state.dataSurface->Surface(SurfNum).ExtBoundCond > 0) {
2101 0 : ShowSevereError(state,
2102 0 : format("{}Subsurface=\"{}\" exterior condition [interzone surface] in a base surface=\"{}\" with exterior "
2103 : "condition [adiabatic surface]",
2104 : RoutineName,
2105 0 : state.dataSurface->Surface(SurfNum).Name,
2106 0 : state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Name));
2107 : } else {
2108 0 : ShowSevereError(
2109 : state,
2110 0 : format("{}Subsurface=\"{}\" exterior condition [{}] in a base surface=\"{}\" with exterior condition [adiabatic surface]",
2111 : RoutineName,
2112 0 : state.dataSurface->Surface(SurfNum).Name,
2113 0 : DataSurfaces::cExtBoundCondition(state.dataSurface->Surface(SurfNum).ExtBoundCond),
2114 0 : state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Name));
2115 : }
2116 0 : if (!SubSurfaceSevereDisplayed) {
2117 0 : ShowContinueError(state, "...calculations for heat balance would be compromised.");
2118 0 : SubSurfaceSevereDisplayed = true;
2119 : }
2120 0 : SurfError = true;
2121 : }
2122 32 : } else if (state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond > 0) { // interzone surface
2123 32 : if (state.dataSurface->Surface(SurfNum).ExtBoundCond == SurfNum) {
2124 0 : ShowSevereError(state,
2125 0 : format("{}Subsurface=\"{}\" is an adiabatic surface in an Interzone base surface=\"{}\"",
2126 : RoutineName,
2127 0 : state.dataSurface->Surface(SurfNum).Name,
2128 0 : state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Name));
2129 0 : if (!SubSurfaceSevereDisplayed) {
2130 0 : ShowContinueError(state, "...calculations for heat balance would be compromised.");
2131 0 : SubSurfaceSevereDisplayed = true;
2132 : }
2133 : // SurfError=.TRUE.
2134 : }
2135 : }
2136 : }
2137 :
2138 224 : setSurfaceFirstLast(state);
2139 :
2140 : // Set up Floor Areas for Zones and Spaces
2141 224 : Real64 constexpr floorAreaTolerance(0.05);
2142 224 : Real64 constexpr floorAreaPercentTolerance(floorAreaTolerance * 100.0);
2143 224 : if (!SurfError) {
2144 224 : int ErrCount = 0;
2145 600 : for (auto &thisSpace : state.dataHeatBal->space) {
2146 376 : auto &thisZone = state.dataHeatBal->Zone(thisSpace.zoneNum);
2147 376 : Real64 calcFloorArea = 0.0; // Calculated floor area used for this space
2148 2512 : for (int SurfNum = thisSpace.HTSurfaceFirst; SurfNum <= thisSpace.HTSurfaceLast; ++SurfNum) {
2149 2136 : auto const &thisSurf = state.dataSurface->Surface(SurfNum);
2150 2136 : if (thisSurf.Class == SurfaceClass::Floor) {
2151 423 : thisZone.HasFloor = true;
2152 423 : thisSpace.hasFloor = true;
2153 423 : calcFloorArea += thisSurf.Area;
2154 : }
2155 2136 : if (thisSurf.Class == SurfaceClass::Roof) {
2156 343 : thisZone.CeilingArea += thisSurf.Area;
2157 343 : thisZone.HasRoof = true;
2158 : }
2159 : }
2160 376 : if (thisSpace.userEnteredFloorArea != Constant::AutoCalculate) {
2161 : // Check entered vs calculated
2162 5 : if (thisSpace.userEnteredFloorArea > 0.0) { // User entered Space floor area,
2163 : // produce message if not near calculated
2164 5 : if (calcFloorArea > 0.0) {
2165 5 : Real64 diffp = std::abs(calcFloorArea - thisSpace.userEnteredFloorArea) / thisSpace.userEnteredFloorArea;
2166 5 : if (diffp > floorAreaTolerance) {
2167 5 : ++ErrCount;
2168 5 : if (ErrCount == 1 && !state.dataGlobal->DisplayExtraWarnings) {
2169 6 : ShowWarningError(
2170 : state,
2171 6 : format("{}Entered Space Floor Area(s) differ more than {:.0R}% from calculated Space Floor Area(s).",
2172 6 : std::string(RoutineName),
2173 : floorAreaPercentTolerance));
2174 9 : ShowContinueError(state,
2175 : "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on individual Spaces.");
2176 : }
2177 5 : if (state.dataGlobal->DisplayExtraWarnings) {
2178 : // Warn user of using specified Space Floor Area
2179 0 : ShowWarningError(
2180 : state,
2181 0 : format("{}Entered Floor Area for Space=\"{}\" is {:.1R}% different from the calculated Floor Area.",
2182 0 : std::string(RoutineName),
2183 0 : thisSpace.Name,
2184 0 : diffp * 100.0));
2185 0 : ShowContinueError(state,
2186 0 : format("Entered Space Floor Area={:.2R}, Calculated Space Floor Area={:.2R}, entered "
2187 : "Floor Area will be used.",
2188 0 : thisSpace.userEnteredFloorArea,
2189 : calcFloorArea));
2190 : }
2191 : }
2192 : }
2193 5 : thisSpace.FloorArea = thisSpace.userEnteredFloorArea;
2194 5 : thisSpace.hasFloor = true;
2195 : }
2196 : } else {
2197 371 : thisSpace.FloorArea = calcFloorArea;
2198 : }
2199 : }
2200 224 : ErrCount = 0;
2201 578 : for (auto &thisZone : state.dataHeatBal->Zone) {
2202 : // Calculate zone floor area as sum of space floor areas
2203 354 : Real64 zoneCalcFloorArea = 0.0; // Calculated floor area excluding air boundary surfaces
2204 730 : for (int spaceNum : thisZone.spaceIndexes) {
2205 376 : zoneCalcFloorArea += state.dataHeatBal->space(spaceNum).FloorArea;
2206 376 : thisZone.HasFloor |= state.dataHeatBal->space(spaceNum).hasFloor;
2207 : }
2208 354 : if (thisZone.UserEnteredFloorArea != Constant::AutoCalculate) {
2209 : // Check entered vs calculated
2210 10 : if (thisZone.UserEnteredFloorArea > 0.0) { // User entered zone floor area,
2211 : // produce message if not near calculated
2212 9 : if (zoneCalcFloorArea > 0.0) {
2213 7 : Real64 diffp = std::abs(zoneCalcFloorArea - thisZone.UserEnteredFloorArea) / thisZone.UserEnteredFloorArea;
2214 7 : if (diffp > 0.05) {
2215 3 : ++ErrCount;
2216 3 : if (ErrCount == 1 && !state.dataGlobal->DisplayExtraWarnings) {
2217 4 : ShowWarningError(
2218 : state,
2219 4 : format("{}Entered Zone Floor Area(s) differ more than {:.0R}% from the sum of the Space Floor Area(s).",
2220 4 : std::string(RoutineName),
2221 : floorAreaPercentTolerance));
2222 6 : ShowContinueError(state,
2223 : "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on individual zones.");
2224 : }
2225 3 : if (state.dataGlobal->DisplayExtraWarnings) {
2226 : // Warn user of using specified Zone Floor Area
2227 0 : ShowWarningError(state,
2228 0 : format("{}Entered Floor Area for Zone=\"{}\" is {:.1R}% different from the sum of the "
2229 : "Space Floor Area(s).",
2230 0 : std::string(RoutineName),
2231 0 : thisZone.Name,
2232 0 : diffp * 100.0));
2233 0 : ShowContinueError(state,
2234 0 : format("Entered Zone Floor Area={:.2R}, Sum of Space Floor Area(s)={:.2R}",
2235 0 : thisZone.UserEnteredFloorArea,
2236 : zoneCalcFloorArea));
2237 0 : ShowContinueError(
2238 : state, "Entered Zone Floor Area will be used and Space Floor Area(s) will be adjusted proportionately.");
2239 : }
2240 : }
2241 : }
2242 9 : thisZone.FloorArea = thisZone.UserEnteredFloorArea;
2243 9 : thisZone.HasFloor = true;
2244 :
2245 : // Adjust space floor areas to match zone floor area
2246 9 : if (thisZone.numSpaces == 1) {
2247 : // If the zone contains only one space, then set the Space area to the Zone area
2248 8 : int spaceNum = thisZone.spaceIndexes(1);
2249 8 : state.dataHeatBal->space(spaceNum).FloorArea = thisZone.FloorArea;
2250 1 : } else if (zoneCalcFloorArea > 0.0) {
2251 : // Adjust space areas proportionately
2252 1 : Real64 areaRatio = thisZone.FloorArea / zoneCalcFloorArea;
2253 3 : for (int spaceNum : thisZone.spaceIndexes) {
2254 2 : state.dataHeatBal->space(spaceNum).FloorArea *= areaRatio;
2255 : }
2256 : } else {
2257 0 : if (state.dataGlobal->DisplayExtraWarnings) {
2258 : // Warn if calculated floor area was zero and there is more than one Space
2259 0 : ShowWarningError(
2260 : state,
2261 0 : format("{}Entered Floor Area entered for Zone=\"{}\" significantly different from sum of Space Floor Areas",
2262 : RoutineName,
2263 0 : thisZone.Name));
2264 0 : ShowContinueError(state,
2265 : "But the sum of the Space Floor Areas is zero and there is more than one Space in the zone."
2266 : "Unable to apportion the zone floor area. Space Floor Areas are zero.");
2267 : }
2268 : }
2269 : } else {
2270 1 : if (zoneCalcFloorArea > 0.0) thisZone.FloorArea = zoneCalcFloorArea;
2271 : }
2272 : } else {
2273 344 : thisZone.FloorArea = zoneCalcFloorArea;
2274 : }
2275 354 : Real64 totSpacesFloorArea = 0.0;
2276 730 : for (int spaceNum : thisZone.spaceIndexes) {
2277 376 : totSpacesFloorArea += state.dataHeatBal->space(spaceNum).FloorArea;
2278 : }
2279 354 : if (totSpacesFloorArea > 0.0) {
2280 674 : for (int spaceNum : thisZone.spaceIndexes) {
2281 348 : state.dataHeatBal->space(spaceNum).fracZoneFloorArea = state.dataHeatBal->space(spaceNum).FloorArea / totSpacesFloorArea;
2282 : }
2283 : } // else leave fractions at zero
2284 : }
2285 : }
2286 :
2287 2486 : for (int SurfNum = 1; SurfNum <= MovedSurfs; ++SurfNum) { // TotSurfaces
2288 2262 : if (state.dataSurface->Surface(SurfNum).Area < 1.e-06) {
2289 0 : ShowSevereError(state,
2290 0 : format("{}Zero or negative surface area[{:.5R}], Surface={}",
2291 : RoutineName,
2292 0 : state.dataSurface->Surface(SurfNum).Area,
2293 0 : state.dataSurface->Surface(SurfNum).Name));
2294 0 : SurfError = true;
2295 : }
2296 2262 : if (state.dataSurface->Surface(SurfNum).Area >= 1.e-06 && state.dataSurface->Surface(SurfNum).Area < 0.001) {
2297 0 : ShowWarningError(state,
2298 0 : format("{}Very small surface area[{:.5R}], Surface={}",
2299 : RoutineName,
2300 0 : state.dataSurface->Surface(SurfNum).Area,
2301 0 : state.dataSurface->Surface(SurfNum).Name));
2302 : }
2303 : }
2304 :
2305 2486 : for (int SurfNum = 1; SurfNum <= MovedSurfs; ++SurfNum) { // TotSurfaces
2306 2262 : auto &surf = state.dataSurface->Surface(SurfNum);
2307 : // GLASSDOORs and TDD:DIFFUSERs will be treated as windows in the subsequent heat transfer and daylighting
2308 : // calculations. Reset class to 'Window' after saving the original designation in SurfaceWindow.
2309 :
2310 2262 : surf.OriginalClass = surf.Class;
2311 :
2312 2262 : if (surf.Class == SurfaceClass::GlassDoor || surf.Class == SurfaceClass::TDD_Diffuser) surf.Class = SurfaceClass::Window;
2313 :
2314 2262 : if (surf.Class == SurfaceClass::TDD_Dome) {
2315 : // Reset the TDD:DOME subsurface to act as a base surface that can shade and be shaded
2316 : // NOTE: This must be set early so that subsequent shading calculations are done correctly
2317 7 : surf.BaseSurf = SurfNum;
2318 : }
2319 : }
2320 :
2321 224 : auto &s_mat = state.dataMaterial;
2322 :
2323 : // I don't think this entire loop matters
2324 224 : errFlag = false;
2325 224 : if (!SurfError) {
2326 2486 : for (int SurfNum = 1; SurfNum <= MovedSurfs; ++SurfNum) { // TotSurfaces
2327 2262 : auto &surf = state.dataSurface->Surface(SurfNum);
2328 2262 : if (!surf.HasShadeControl) continue;
2329 :
2330 11 : int ConstrNumSh = surf.activeShadedConstruction;
2331 11 : if (ConstrNumSh <= 0) continue;
2332 :
2333 11 : auto &winShadeCtrl = state.dataSurface->WindowShadingControl(surf.activeWindowShadingControl);
2334 11 : if (!ANY_BLIND(winShadeCtrl.ShadingType)) continue;
2335 : // use first item since others should be identical
2336 :
2337 8 : auto &surfShade = state.dataSurface->surfShades(SurfNum);
2338 : // TH 1/7/2010. CR 7930
2339 : // The old code did not consider between-glass blind. Also there should not be two blinds - both interior and exterior
2340 : // Use the new generic code (assuming only one blind) as follows
2341 16 : for (int iMatNum = 1; iMatNum <= state.dataConstruction->Construct(ConstrNumSh).TotLayers; ++iMatNum) {
2342 16 : auto *mat = s_mat->materials(state.dataConstruction->Construct(ConstrNumSh).LayerPoint(iMatNum));
2343 :
2344 16 : if (mat->group != Material::Group::Blind) continue;
2345 :
2346 8 : auto *matBlind = dynamic_cast<Material::MaterialBlind *>(mat);
2347 8 : assert(matBlind != nullptr);
2348 :
2349 8 : surfShade.blind.matNum = mat->Num;
2350 8 : break;
2351 : }
2352 :
2353 8 : if (errFlag) {
2354 0 : ErrorsFound = true;
2355 0 : ShowContinueError(state, format("WindowShadingControl {} has errors, program will terminate.", winShadeCtrl.Name));
2356 : }
2357 :
2358 8 : if (winShadeCtrl.slatAngleControl != DataSurfaces::SlatAngleControl::Fixed) {
2359 0 : surfShade.blind.movableSlats = true;
2360 0 : state.dataSurface->AnyMovableSlat = true;
2361 0 : state.dataHeatBalSurf->SurfMovSlatsIndexList.push_back(SurfNum);
2362 : }
2363 : } // End of surface loop
2364 :
2365 : // final associate fenestration surfaces referenced in WindowShadingControl
2366 224 : FinalAssociateWindowShadingControlFenestration(state, ErrorsFound);
2367 224 : CheckWindowShadingControlSimilarForWindow(state, ErrorsFound);
2368 : }
2369 :
2370 : // Check for zones with not enough surfaces
2371 578 : for (auto &thisZone : state.dataHeatBal->Zone) {
2372 354 : int OpaqueHTSurfs = 0; // Number of floors, walls and roofs in a zone
2373 354 : int OpaqueHTSurfsWithWin = 0; // Number of floors, walls and roofs with windows in a zone
2374 354 : int InternalMassSurfs = 0; // Number of internal mass surfaces in a zone
2375 354 : int priorBaseSurfNum = 0;
2376 :
2377 730 : for (int spaceNum : thisZone.spaceIndexes) {
2378 376 : auto const &thisSpace = state.dataHeatBal->space(spaceNum);
2379 376 : if (thisSpace.HTSurfaceFirst == 0) continue; // Zone with no surfaces
2380 2508 : for (int SurfNum = thisSpace.HTSurfaceFirst; SurfNum <= thisSpace.HTSurfaceLast; ++SurfNum) {
2381 2136 : auto const &thisSurf = state.dataSurface->Surface(SurfNum);
2382 2136 : if (thisSurf.Class == SurfaceClass::Floor || thisSurf.Class == SurfaceClass::Wall || thisSurf.Class == SurfaceClass::Roof)
2383 1897 : ++OpaqueHTSurfs;
2384 2136 : if (thisSurf.Class == SurfaceClass::IntMass) ++InternalMassSurfs;
2385 2136 : if (thisSurf.Class == SurfaceClass::Window) {
2386 : // Count base surface only once for multiple windows on a wall
2387 195 : int thisBaseSurfNum = thisSurf.BaseSurf;
2388 195 : if (thisBaseSurfNum != priorBaseSurfNum) {
2389 144 : ++OpaqueHTSurfsWithWin;
2390 144 : priorBaseSurfNum = thisBaseSurfNum;
2391 : }
2392 : }
2393 : }
2394 : }
2395 354 : if (OpaqueHTSurfsWithWin == 1 && OpaqueHTSurfs == 1 && InternalMassSurfs == 0) {
2396 0 : SurfError = true;
2397 0 : ShowSevereError(state,
2398 0 : format("{}Zone {} has only one floor, wall or roof, and this surface has a window.", RoutineName, thisZone.Name));
2399 0 : ShowContinueError(state, "Add more floors, walls or roofs, or an internal mass surface.");
2400 : }
2401 : }
2402 :
2403 : // set up vertex of centroid for each surface.
2404 224 : CalcSurfaceCentroid(state);
2405 :
2406 224 : SetupShadeSurfacesForSolarCalcs(state); // if shading surfaces are solar collectors or PV, then we need full solar calc.
2407 :
2408 224 : GetMovableInsulationData(state, ErrorsFound);
2409 :
2410 224 : if (state.dataSurface->CalcSolRefl) GetShadingSurfReflectanceData(state, ErrorsFound);
2411 :
2412 224 : LayNumOutside = 0;
2413 :
2414 2486 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
2415 2262 : auto &surf = state.dataSurface->Surface(SurfNum);
2416 : // Check for EcoRoof and only 1 allowed to be used.
2417 2262 : if (surf.Construction > 0)
2418 2178 : state.dataSurface->SurfExtEcoRoof(SurfNum) = state.dataConstruction->Construct(surf.Construction).TypeIsEcoRoof;
2419 2262 : if (!state.dataSurface->SurfExtEcoRoof(SurfNum)) continue;
2420 0 : if (LayNumOutside == 0) {
2421 0 : LayNumOutside = state.dataConstruction->Construct(surf.Construction).LayerPoint(1);
2422 0 : continue;
2423 : }
2424 0 : if (LayNumOutside != state.dataConstruction->Construct(surf.Construction).LayerPoint(1)) {
2425 0 : ShowSevereError(state, format("{}Only one EcoRoof Material is currently allowed for all constructions.", RoutineName));
2426 0 : ShowContinueError(state, format("... first material={}", s_mat->materials(LayNumOutside)->Name));
2427 0 : ShowContinueError(state,
2428 0 : format("... conflicting Construction={} uses material={}",
2429 0 : state.dataConstruction->Construct(surf.Construction).Name,
2430 0 : s_mat->materials(state.dataConstruction->Construct(surf.Construction).LayerPoint(1))->Name));
2431 0 : ErrorsFound = true;
2432 : }
2433 : }
2434 :
2435 : // Reserve space to avoid excess allocations
2436 224 : state.dataSurface->AllHTSurfaceList.reserve(state.dataSurface->TotSurfaces);
2437 224 : state.dataSurface->AllExtSolarSurfaceList.reserve(state.dataSurface->TotSurfaces);
2438 224 : state.dataSurface->AllShadowPossObstrSurfaceList.reserve(state.dataSurface->TotSurfaces);
2439 224 : state.dataSurface->AllIZSurfaceList.reserve(state.dataSurface->TotSurfaces);
2440 224 : state.dataSurface->AllHTNonWindowSurfaceList.reserve(state.dataSurface->TotSurfaces - state.dataSurface->TotWindows);
2441 224 : state.dataSurface->AllHTWindowSurfaceList.reserve(state.dataSurface->TotWindows);
2442 224 : state.dataSurface->AllExtSolWindowSurfaceList.reserve(state.dataSurface->TotWindows);
2443 224 : state.dataSurface->AllExtSolWinWithFrameSurfaceList.reserve(state.dataSurface->TotWindows);
2444 224 : state.dataSurface->AllHTKivaSurfaceList.reserve(state.dataSurface->TotSurfaces);
2445 :
2446 : // Set flag that determines whether a surface can be an exterior obstruction
2447 : // Also set associated surfaces for Kiva foundations and build heat transfer surface lists
2448 2486 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
2449 2262 : auto &surf = state.dataSurface->Surface(SurfNum);
2450 2262 : surf.IsShadowPossibleObstruction = false;
2451 2262 : if (surf.ExtSolar) {
2452 : // This may include some attached shading surfaces
2453 1408 : state.dataSurface->AllExtSolarSurfaceList.push_back(SurfNum);
2454 : }
2455 2262 : if (surf.HeatTransSurf) {
2456 : // Outside light shelves get tagged later as HeatTransSurf=true but they haven't been processed yet
2457 2136 : state.dataSurface->AllHTSurfaceList.push_back(SurfNum);
2458 2136 : int const zoneNum(surf.Zone);
2459 2136 : auto &surfZone(state.dataHeatBal->Zone(zoneNum));
2460 2136 : surfZone.ZoneHTSurfaceList.push_back(SurfNum);
2461 : // Sort window vs non-window surfaces
2462 2136 : if (surf.Class == DataSurfaces::SurfaceClass::Window) {
2463 195 : state.dataSurface->AllHTWindowSurfaceList.push_back(SurfNum);
2464 195 : surfZone.ZoneHTWindowSurfaceList.push_back(SurfNum);
2465 195 : if (surf.ExtSolar) {
2466 175 : state.dataSurface->AllExtSolWindowSurfaceList.push_back(SurfNum);
2467 175 : if (surf.FrameDivider > 0) {
2468 22 : state.dataSurface->AllExtSolWinWithFrameSurfaceList.push_back(SurfNum);
2469 : }
2470 : }
2471 : } else {
2472 1941 : state.dataSurface->AllHTNonWindowSurfaceList.push_back(SurfNum);
2473 1941 : surfZone.ZoneHTNonWindowSurfaceList.push_back(SurfNum);
2474 : }
2475 2136 : int const surfExtBoundCond(surf.ExtBoundCond);
2476 : // Build zone and interzone surface lists
2477 2136 : if ((surfExtBoundCond > 0) && (surfExtBoundCond != SurfNum)) {
2478 346 : state.dataSurface->AllIZSurfaceList.push_back(SurfNum);
2479 346 : surfZone.ZoneIZSurfaceList.push_back(SurfNum);
2480 346 : auto &adjZone(state.dataHeatBal->Zone(state.dataSurface->Surface(surfExtBoundCond).Zone));
2481 346 : adjZone.ZoneHTSurfaceList.push_back(SurfNum);
2482 346 : adjZone.ZoneIZSurfaceList.push_back(SurfNum);
2483 : // Sort window vs non-window surfaces
2484 346 : if (surf.Class == DataSurfaces::SurfaceClass::Window) {
2485 6 : adjZone.ZoneHTWindowSurfaceList.push_back(SurfNum);
2486 : } else {
2487 340 : adjZone.ZoneHTNonWindowSurfaceList.push_back(SurfNum);
2488 : }
2489 : }
2490 : }
2491 :
2492 : // Exclude non-exterior heat transfer surfaces (but not OtherSideCondModeledExt = -4 CR7640)
2493 2262 : if (surf.HeatTransSurf && surf.ExtBoundCond > 0) continue;
2494 1671 : if (surf.HeatTransSurf && surf.ExtBoundCond == DataSurfaces::Ground) continue;
2495 1552 : if (surf.HeatTransSurf && surf.ExtBoundCond == DataSurfaces::KivaFoundation) {
2496 0 : state.dataSurface->AllHTKivaSurfaceList.push_back(SurfNum);
2497 0 : if (!ErrorsFound) state.dataSurfaceGeometry->kivaManager.foundationInputs[surf.OSCPtr].surfaces.push_back(SurfNum);
2498 0 : continue;
2499 : }
2500 1552 : if (surf.HeatTransSurf && surf.ExtBoundCond == DataSurfaces::OtherSideCoefNoCalcExt) continue;
2501 1552 : if (surf.HeatTransSurf && surf.ExtBoundCond == DataSurfaces::OtherSideCoefCalcExt) continue;
2502 : // Exclude windows and doors, i.e., consider only their base surfaces as possible obstructions
2503 1552 : if (surf.Class == SurfaceClass::Window || surf.Class == SurfaceClass::Door) continue;
2504 : // Exclude duplicate shading surfaces
2505 1354 : if (surf.MirroredSurf) continue;
2506 : // Exclude air boundary surfaces
2507 1312 : if (surf.IsAirBoundarySurf) continue;
2508 :
2509 1274 : surf.IsShadowPossibleObstruction = true;
2510 1274 : state.dataSurface->AllShadowPossObstrSurfaceList.push_back(SurfNum);
2511 : } // for (SurfNum)
2512 :
2513 : // Check for IRT surfaces in invalid places.
2514 224 : if (std::any_of(state.dataConstruction->Construct.begin(),
2515 224 : state.dataConstruction->Construct.end(),
2516 767 : [](Construction::ConstructionProps const &e) { return e.TypeIsIRT; })) {
2517 0 : int iTmp1 = 0;
2518 0 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
2519 0 : auto &surf = state.dataSurface->Surface(SurfNum);
2520 0 : if (!surf.HeatTransSurf) continue; // ignore shading surfaces
2521 0 : if (surf.ExtBoundCond > 0 && surf.ExtBoundCond != SurfNum) continue; // interzone, not adiabatic surface
2522 0 : if (!state.dataConstruction->Construct(surf.Construction).TypeIsIRT) {
2523 0 : continue;
2524 : }
2525 0 : if (!state.dataGlobal->DisplayExtraWarnings) {
2526 0 : ++iTmp1;
2527 : } else {
2528 0 : ShowWarningError(state,
2529 0 : format("{}Surface=\"{}\" uses InfraredTransparent construction in a non-interzone surface. (illegal use)",
2530 : RoutineName,
2531 0 : surf.Name));
2532 : }
2533 : }
2534 0 : if (iTmp1 > 0) {
2535 0 : ShowWarningError(
2536 : state,
2537 0 : format("{}Surfaces use InfraredTransparent constructions {} in non-interzone surfaces. (illegal use)", RoutineName, iTmp1));
2538 0 : ShowContinueError(state, "For explicit details on each use, use Output:Diagnostics,DisplayExtraWarnings;");
2539 : }
2540 : }
2541 :
2542 : // Populate SurfaceFilter lists
2543 2464 : for (int iSurfaceFilter = 1; iSurfaceFilter < static_cast<int>(DataSurfaces::SurfaceFilter::Num); ++iSurfaceFilter)
2544 2240 : state.dataSurface->SurfaceFilterLists[iSurfaceFilter].reserve(state.dataSurface->TotSurfaces);
2545 :
2546 2486 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
2547 2262 : auto const &surf = state.dataSurface->Surface(SurfNum);
2548 2262 : if (!surf.HeatTransSurf) continue;
2549 2136 : if (surf.ExtBoundCond > 0) {
2550 591 : state.dataSurface->SurfaceFilterLists[static_cast<int>(DataSurfaces::SurfaceFilter::AllInteriorSurfaces)].push_back(SurfNum);
2551 591 : if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) {
2552 6 : state.dataSurface->SurfaceFilterLists[static_cast<int>(DataSurfaces::SurfaceFilter::AllInteriorWindows)].push_back(SurfNum);
2553 585 : } else if (surf.Class == SurfaceClass::Wall) {
2554 306 : state.dataSurface->SurfaceFilterLists[static_cast<int>(DataSurfaces::SurfaceFilter::AllInteriorWalls)].push_back(SurfNum);
2555 279 : } else if (surf.Class == SurfaceClass::Floor) {
2556 185 : state.dataSurface->SurfaceFilterLists[static_cast<int>(DataSurfaces::SurfaceFilter::AllInteriorFloors)].push_back(SurfNum);
2557 94 : } else if (surf.Class == SurfaceClass::Roof) {
2558 62 : state.dataSurface->SurfaceFilterLists[static_cast<int>(DataSurfaces::SurfaceFilter::AllInteriorRoofs)].push_back(SurfNum);
2559 62 : state.dataSurface->SurfaceFilterLists[static_cast<int>(DataSurfaces::SurfaceFilter::AllInteriorCeilings)].push_back(SurfNum);
2560 : }
2561 : } else {
2562 1545 : state.dataSurface->SurfaceFilterLists[static_cast<int>(DataSurfaces::SurfaceFilter::AllExteriorSurfaces)].push_back(SurfNum);
2563 1545 : if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) {
2564 196 : state.dataSurface->SurfaceFilterLists[static_cast<int>(DataSurfaces::SurfaceFilter::AllExteriorWindows)].push_back(SurfNum);
2565 1349 : } else if (surf.Class == SurfaceClass::Wall) {
2566 825 : state.dataSurface->SurfaceFilterLists[static_cast<int>(DataSurfaces::SurfaceFilter::AllExteriorWalls)].push_back(SurfNum);
2567 524 : } else if (surf.Class == SurfaceClass::Floor) {
2568 238 : state.dataSurface->SurfaceFilterLists[static_cast<int>(DataSurfaces::SurfaceFilter::AllExteriorFloors)].push_back(SurfNum);
2569 286 : } else if (surf.Class == SurfaceClass::Roof) {
2570 281 : state.dataSurface->SurfaceFilterLists[static_cast<int>(DataSurfaces::SurfaceFilter::AllExteriorRoofs)].push_back(SurfNum);
2571 281 : state.dataSurface->SurfaceFilterLists[static_cast<int>(DataSurfaces::SurfaceFilter::AllInteriorCeilings)].push_back(SurfNum);
2572 : }
2573 : }
2574 : } // for (SurfNum)
2575 :
2576 : // Note, could do same for Window Area and detecting if Interzone Surface in Zone
2577 :
2578 224 : if (state.dataSurfaceGeometry->Warning1Count > 0) {
2579 0 : ShowWarningMessage(state,
2580 0 : format("{}Window dimensions differ from Window 5/6 data file dimensions, {} times.",
2581 : RoutineName,
2582 0 : state.dataSurfaceGeometry->Warning1Count));
2583 0 : ShowContinueError(state, "This will affect the frame heat transfer calculation if the frame in the Data File entry");
2584 0 : ShowContinueError(state, "is not uniform, i.e., has sections with different geometry and/or thermal properties.");
2585 0 : ShowContinueError(state, "For explicit details on each window, use Output:Diagnostics,DisplayExtraWarnings;");
2586 : }
2587 224 : if (state.dataSurfaceGeometry->Warning2Count > 0) {
2588 0 : ShowWarningMessage(state,
2589 0 : format("{}Exterior Windows have been replaced with Window 5/6 two glazing systems, {} times.",
2590 : RoutineName,
2591 0 : state.dataSurfaceGeometry->Warning2Count));
2592 0 : ShowContinueError(state, "Note that originally entered dimensions are overridden.");
2593 0 : ShowContinueError(state, "For explicit details on each window, use Output:Diagnostics,DisplayExtraWarnings;");
2594 : }
2595 224 : if (state.dataSurfaceGeometry->Warning3Count > 0) {
2596 0 : ShowWarningMessage(state,
2597 0 : format("{}Interior Windows have been replaced with Window 5/6 two glazing systems, {} times.",
2598 : RoutineName,
2599 0 : state.dataSurfaceGeometry->Warning3Count));
2600 0 : ShowContinueError(state, "Note that originally entered dimensions are overridden.");
2601 0 : ShowContinueError(state, "For explicit details on each window, use Output:Diagnostics,DisplayExtraWarnings;");
2602 : }
2603 :
2604 224 : if (state.dataErrTracking->TotalMultipliedWindows > 0) {
2605 0 : ShowWarningMessage(state,
2606 0 : format("{}There are {} window/glass door(s) that may cause inaccurate shadowing due to Solar Distribution.",
2607 : RoutineName,
2608 0 : state.dataErrTracking->TotalMultipliedWindows));
2609 0 : ShowContinueError(state, "For explicit details on each window, use Output:Diagnostics,DisplayExtraWarnings;");
2610 0 : state.dataErrTracking->TotalWarningErrors += state.dataErrTracking->TotalMultipliedWindows;
2611 : }
2612 224 : if (state.dataErrTracking->TotalCoincidentVertices > 0) {
2613 0 : ShowWarningMessage(state,
2614 0 : format("{}There are {} coincident/collinear vertices; These have been deleted unless the deletion would bring the "
2615 : "number of surface sides < 3.",
2616 : RoutineName,
2617 0 : state.dataErrTracking->TotalCoincidentVertices));
2618 0 : ShowContinueError(state, "For explicit details on each problem surface, use Output:Diagnostics,DisplayExtraWarnings;");
2619 0 : state.dataErrTracking->TotalWarningErrors += state.dataErrTracking->TotalCoincidentVertices;
2620 : }
2621 224 : if (state.dataErrTracking->TotalDegenerateSurfaces > 0) {
2622 0 : ShowSevereMessage(state,
2623 0 : format("{}There are {} degenerate surfaces; Degenerate surfaces are those with number of sides < 3.",
2624 : RoutineName,
2625 0 : state.dataErrTracking->TotalDegenerateSurfaces));
2626 0 : ShowContinueError(state, "These surfaces should be deleted.");
2627 0 : ShowContinueError(state, "For explicit details on each problem surface, use Output:Diagnostics,DisplayExtraWarnings;");
2628 0 : state.dataErrTracking->TotalSevereErrors += state.dataErrTracking->TotalDegenerateSurfaces;
2629 : }
2630 :
2631 224 : GetHTSurfExtVentedCavityData(state, ErrorsFound);
2632 :
2633 224 : state.dataSurfaceGeometry->exposedFoundationPerimeter.getData(state, ErrorsFound);
2634 :
2635 224 : GetSurfaceHeatTransferAlgorithmOverrides(state, ErrorsFound);
2636 :
2637 : // Set up enclosures, process Air Boundaries if any
2638 224 : SetupEnclosuresAndAirBoundaries(state, state.dataViewFactor->EnclRadInfo, SurfaceGeometry::enclosureType::RadiantEnclosures, ErrorsFound);
2639 :
2640 224 : GetSurfaceGroundSurfsData(state, ErrorsFound);
2641 :
2642 224 : GetSurfaceSrdSurfsData(state, ErrorsFound);
2643 :
2644 224 : GetSurfaceLocalEnvData(state, ErrorsFound);
2645 :
2646 224 : if (SurfError || ErrorsFound) {
2647 0 : ErrorsFound = true;
2648 0 : ShowFatalError(state, format("{}Errors discovered, program terminates.", RoutineName));
2649 : }
2650 :
2651 224 : int TotShadSurf = TotDetachedFixed + TotDetachedBldg + TotRectDetachedFixed + TotRectDetachedBldg + TotShdSubs + TotOverhangs +
2652 224 : TotOverhangsProjection + TotFins + TotFinsProjection;
2653 224 : int NumDElightCmplxFen = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Daylighting:DElight:ComplexFenestration");
2654 224 : if (TotShadSurf > 0 && (NumDElightCmplxFen > 0 || Dayltg::doesDayLightingUseDElight(state))) {
2655 0 : ShowWarningError(state, format("{}When using DElight daylighting the presence of exterior shading surfaces is ignored.", RoutineName));
2656 : }
2657 :
2658 2486 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; SurfNum++) {
2659 2262 : auto &surf = state.dataSurface->Surface(SurfNum);
2660 : // Initialize run time surface arrays
2661 2262 : state.dataSurface->SurfActiveConstruction(SurfNum) = surf.Construction;
2662 2262 : surf.RepresentativeCalcSurfNum = SurfNum;
2663 : }
2664 :
2665 : // Representative surface calculations: Assign representative heat transfer surfaces
2666 224 : if (state.dataSurface->UseRepresentativeSurfaceCalculations &&
2667 224 : state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "ZoneProperty:UserViewFactors:BySurfaceName") == 0) {
2668 0 : for (int zoneNum = 1; zoneNum <= state.dataGlobal->NumOfZones; ++zoneNum) {
2669 0 : for (int spaceNum : state.dataHeatBal->Zone(zoneNum).spaceIndexes) {
2670 0 : auto const &thisSpace = state.dataHeatBal->space(spaceNum);
2671 0 : for (int surfNum = thisSpace.HTSurfaceFirst; surfNum <= thisSpace.HTSurfaceLast; surfNum++) {
2672 0 : auto &surface(state.dataSurface->Surface(surfNum));
2673 : // Conditions where surface always needs to be unique
2674 0 : bool forceUniqueSurface = surface.HasShadeControl ||
2675 0 : state.dataSurface->SurfWinAirflowSource(surfNum) != DataSurfaces::WindowAirFlowSource::Invalid ||
2676 0 : state.dataConstruction->Construct(surface.Construction).SourceSinkPresent ||
2677 0 : surface.Class == SurfaceClass::TDD_Dome ||
2678 0 : (surface.Class == SurfaceClass::Window &&
2679 0 : (surface.OriginalClass == SurfaceClass::TDD_Diffuser ||
2680 0 : state.dataSurface->SurfWinWindowModelType(surfNum) != DataSurfaces::WindowModel::Detailed ||
2681 0 : state.dataWindowManager->inExtWindowModel->isExternalLibraryModel() ||
2682 0 : state.dataConstruction->Construct(surface.Construction).isTCWindow));
2683 0 : if (!forceUniqueSurface) {
2684 0 : state.dataSurface->Surface(surfNum).set_representative_surface(state, surfNum);
2685 : }
2686 : }
2687 : }
2688 : }
2689 : }
2690 :
2691 224 : if (SurfError || ErrorsFound) {
2692 0 : ErrorsFound = true;
2693 0 : ShowFatalError(state, format("{}Errors discovered, program terminates.", RoutineName));
2694 : }
2695 224 : }
2696 :
2697 224 : void CreateMissingSpaces(EnergyPlusData &state, Array1D<SurfaceGeometry::SurfaceData> &Surfaces)
2698 : {
2699 : static constexpr std::string_view RoutineName = "CreateMissingSpaces: ";
2700 : // Scan surfaces to see if Space was assigned in input
2701 224 : EPVector<bool> anySurfacesWithSpace; // True if any surfaces in a zone do not have a space assigned in input
2702 224 : EPVector<bool> anySurfacesWithoutSpace; // True if any surfaces in a zone have a space assigned in input
2703 224 : anySurfacesWithSpace.resize(state.dataGlobal->NumOfZones, false);
2704 224 : anySurfacesWithoutSpace.resize(state.dataGlobal->NumOfZones, false);
2705 :
2706 2486 : for (int surfNum = 1; surfNum <= state.dataSurface->TotSurfaces; ++surfNum) {
2707 2262 : auto &thisSurf = Surfaces(surfNum);
2708 2262 : if (!thisSurf.HeatTransSurf) continue; // ignore shading surfaces
2709 2178 : if (thisSurf.Class == DataSurfaces::SurfaceClass::IntMass) continue; // skip internal mass surfaces for this check
2710 2162 : if (thisSurf.BaseSurf != surfNum) {
2711 : // Set space for subsurfaces
2712 227 : thisSurf.spaceNum = Surfaces(thisSurf.BaseSurf).spaceNum;
2713 : }
2714 2162 : if (thisSurf.spaceNum > 0) {
2715 171 : anySurfacesWithSpace(thisSurf.Zone) = true;
2716 1991 : } else if (thisSurf.ExtBoundCond != unreconciledZoneSurface) {
2717 1443 : anySurfacesWithoutSpace(thisSurf.Zone) = true;
2718 548 : } else if (thisSurf.Name.substr(0, 3) != "iz-") {
2719 : // Only trigger a new space if the spaceless surface is not an autogenerated interzone surface
2720 536 : anySurfacesWithoutSpace(thisSurf.Zone) = true;
2721 : }
2722 : }
2723 :
2724 : // Create any missing Spaces
2725 578 : for (int zoneNum = 1; zoneNum <= state.dataGlobal->NumOfZones; ++zoneNum) {
2726 354 : auto &thisZone = state.dataHeatBal->Zone(zoneNum);
2727 354 : if (anySurfacesWithoutSpace(zoneNum)) {
2728 : // If any surfaces in the zone are not assigned to a space, may need to create a new space
2729 : // Every zone has at least one space, created in HeatBalanceManager::GetSpaceData
2730 : // If no surfaces have a space assigned, then the default space will be used, otherwise, create a new space
2731 299 : if (anySurfacesWithSpace(zoneNum)) {
2732 : // Add new space
2733 0 : ++state.dataGlobal->numSpaces;
2734 0 : assert(state.dataHeatBal->space.size() >= state.dataGlobal->numSpaces);
2735 0 : state.dataHeatBal->space(state.dataGlobal->numSpaces).zoneNum = zoneNum;
2736 : // Add to zone's list of spaces
2737 0 : thisZone.spaceIndexes.emplace_back(state.dataGlobal->numSpaces);
2738 0 : ++state.dataHeatBal->Zone(zoneNum).numSpaces;
2739 0 : assert(state.dataHeatBal->Zone(zoneNum).numSpaces == int(state.dataHeatBal->Zone(zoneNum).spaceIndexes.size()));
2740 : // If some surfaces in the zone are assigned to a space, the new space is the remainder of the zone
2741 0 : state.dataHeatBal->space(state.dataGlobal->numSpaces).Name =
2742 0 : thisZone.Name + "-REMAINDER"; // Make UPPERcase so it can be referenced in input
2743 0 : state.dataHeatBal->space(state.dataGlobal->numSpaces).isRemainderSpace = true;
2744 0 : state.dataHeatBal->space(state.dataGlobal->numSpaces).spaceType = "GENERAL";
2745 0 : state.dataHeatBal->space(state.dataGlobal->numSpaces).spaceTypeNum = HeatBalanceManager::GetGeneralSpaceTypeNum(state);
2746 : }
2747 : }
2748 : }
2749 : // Right-size space vector
2750 224 : state.dataHeatBal->space.resize(state.dataGlobal->numSpaces);
2751 :
2752 : // Assign Spaces to surfaces without one
2753 2486 : for (int surfNum = 1; surfNum <= state.dataSurface->TotSurfaces; ++surfNum) {
2754 2262 : auto &thisSurf = Surfaces(surfNum);
2755 2262 : if (!thisSurf.HeatTransSurf) continue; // ignore shading surfaces
2756 2178 : if (thisSurf.spaceNum == 0) {
2757 2007 : int const numSpaces = state.dataHeatBal->Zone(thisSurf.Zone).numSpaces;
2758 2007 : int const lastSpaceForZone = state.dataHeatBal->Zone(thisSurf.Zone).spaceIndexes(numSpaces);
2759 2007 : thisSurf.spaceNum = lastSpaceForZone;
2760 2007 : if ((thisSurf.ExtBoundCond == unreconciledZoneSurface) && (thisSurf.Name.substr(0, 3) == "iz-")) {
2761 12 : if (state.dataHeatBal->Zone(thisSurf.Zone).numSpaces > 1) {
2762 : // Only trigger warning if the spaceless surface is an autogenerated interzone surface
2763 4 : ShowWarningError(state,
2764 4 : format("{}Surface=\"{}\" has Outside Boundary Condition=Zone, but Zone=\"{}\" has more than 1 Space.",
2765 : RoutineName,
2766 2 : thisSurf.Name.substr(3),
2767 2 : thisSurf.ZoneName));
2768 4 : ShowContinueError(state,
2769 4 : format("Auto-generated surface=\"{}\" will be assigned to Space=\"{}\"",
2770 2 : thisSurf.Name,
2771 2 : state.dataHeatBal->space(thisSurf.spaceNum).Name));
2772 6 : ShowContinueError(state, "Use Outside Boundary Condition = Space to specify the exact Space for the outside boundary.");
2773 : }
2774 : }
2775 : }
2776 : }
2777 224 : }
2778 :
2779 224 : void createSpaceSurfaceLists(EnergyPlusData &state)
2780 : {
2781 : static constexpr std::string_view RoutineName("createSpaceSurfaceLists: ");
2782 : // Build Space surface lists now that all of the surface sorting is complete
2783 2486 : for (int surfNum = 1; surfNum <= state.dataSurface->TotSurfaces; ++surfNum) {
2784 2262 : auto &thisSurf = state.dataSurface->Surface(surfNum);
2785 2262 : if (!thisSurf.HeatTransSurf) continue; // ignore shading surfaces
2786 : // Add to Space's list of surfaces
2787 2178 : state.dataHeatBal->space(thisSurf.spaceNum).surfaces.emplace_back(surfNum);
2788 : }
2789 600 : for (int spaceNum = 1; spaceNum <= state.dataGlobal->numSpaces; ++spaceNum) {
2790 376 : if (int(state.dataHeatBal->space(spaceNum).surfaces.size()) == 0) {
2791 3 : ShowWarningError(state, format("{}Space={} has no surfaces.", RoutineName, state.dataHeatBal->space(spaceNum).Name));
2792 : }
2793 : }
2794 224 : }
2795 :
2796 224 : void setSurfaceFirstLast(EnergyPlusData &state)
2797 : {
2798 : // Set Zone and Space Surface First/Last Pointers
2799 : // Space surface lists have been built earlier in createSpaceSurfaceLists
2800 578 : for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
2801 730 : for (int spaceNum : state.dataHeatBal->Zone(ZoneNum).spaceIndexes) {
2802 376 : auto &thisSpace = state.dataHeatBal->space(spaceNum);
2803 2554 : for (int SurfNum : thisSpace.surfaces) {
2804 2178 : auto &surf = state.dataSurface->Surface(SurfNum);
2805 2178 : if (thisSpace.AllSurfaceFirst == 0) {
2806 373 : thisSpace.AllSurfaceFirst = SurfNum;
2807 : }
2808 2178 : thisSpace.AllSurfaceLast = SurfNum;
2809 :
2810 2178 : if (surf.IsAirBoundarySurf) {
2811 42 : surf.HeatTransSurf = false;
2812 42 : continue;
2813 : }
2814 : // Non window surfaces are grouped next within each space
2815 2136 : if (thisSpace.HTSurfaceFirst == 0) {
2816 372 : thisSpace.HTSurfaceFirst = SurfNum;
2817 372 : thisSpace.OpaqOrIntMassSurfaceFirst = SurfNum;
2818 372 : thisSpace.OpaqOrWinSurfaceFirst = SurfNum;
2819 : }
2820 2136 : thisSpace.HTSurfaceLast = SurfNum;
2821 :
2822 : // Window surfaces are grouped next within each space
2823 2136 : if ((surf.Class == DataSurfaces::SurfaceClass::Window) || (surf.Class == DataSurfaces::SurfaceClass::GlassDoor) ||
2824 1947 : (surf.Class == DataSurfaces::SurfaceClass::TDD_Diffuser)) {
2825 195 : if (thisSpace.WindowSurfaceFirst == 0) {
2826 112 : thisSpace.WindowSurfaceFirst = SurfNum;
2827 : }
2828 195 : thisSpace.WindowSurfaceLast = SurfNum;
2829 1941 : } else if (surf.Class != DataSurfaces::SurfaceClass::TDD_Dome) {
2830 1934 : thisSpace.OpaqOrIntMassSurfaceLast = SurfNum;
2831 : }
2832 :
2833 : // TDDDome surfaces are grouped last within each space
2834 2136 : if (surf.Class == DataSurfaces::SurfaceClass::TDD_Dome) {
2835 7 : if (thisSpace.TDDDomeFirst == 0) {
2836 5 : thisSpace.TDDDomeFirst = SurfNum;
2837 : }
2838 7 : thisSpace.TDDDomeLast = SurfNum;
2839 : } else {
2840 2129 : thisSpace.OpaqOrWinSurfaceLast = SurfNum;
2841 : }
2842 : }
2843 376 : state.dataHeatBal->Zone(ZoneNum).AllSurfaceLast = thisSpace.AllSurfaceLast;
2844 : }
2845 354 : int firstSpaceNum = state.dataHeatBal->Zone(ZoneNum).spaceIndexes(1);
2846 354 : state.dataHeatBal->Zone(ZoneNum).AllSurfaceFirst = state.dataHeatBal->space(firstSpaceNum).AllSurfaceFirst;
2847 : }
2848 224 : }
2849 :
2850 235 : void checkSubSurfAzTiltNorm(EnergyPlusData &state,
2851 : SurfaceData &baseSurface, // Base surface data (in)
2852 : SurfaceData &subSurface, // Subsurface data (in)
2853 : bool &surfaceError // True if surface azimuths or tilts differ by more than error tolerance
2854 : )
2855 : {
2856 235 : bool sameSurfNormal = false; // True if surface has the same surface normal within tolerance
2857 235 : Real64 constexpr warningTolerance = 30.0;
2858 235 : Real64 constexpr errorTolerance = 90.0;
2859 :
2860 235 : surfaceError = false; // True if surface has the same surface normal within tolerance
2861 :
2862 : // Check if base surface and subsurface have the same normal
2863 235 : Vectors::CompareTwoVectors(baseSurface.NewellSurfaceNormalVector, subSurface.NewellSurfaceNormalVector, sameSurfNormal, 0.001);
2864 235 : if (sameSurfNormal) { // copy lcs vectors
2865 : // Prior logic tested for azimuth difference < 30 and then skipped this - this caused large diffs in
2866 : // CmplxGlz_MeasuredDeflectionAndShading Restoring that check here but will require further investigation (MJW Dec 2015)
2867 : // if (std::abs(baseSurface.Azimuth - subSurface.Azimuth) > warningTolerance) {
2868 223 : subSurface.lcsx = baseSurface.lcsx;
2869 223 : subSurface.lcsy = baseSurface.lcsy;
2870 223 : subSurface.lcsz = baseSurface.lcsz;
2871 : // }
2872 : } else {
2873 12 : bool baseSurfHoriz = false; // True if base surface is near horizontal
2874 : // // Not sure what this does, but keeping for now (MJW Dec 2015)
2875 : // if (std::abs(subSurface.Azimuth - 360.0) < 0.01) {
2876 : // subSurface.Azimuth = 360.0 - subSurface.Azimuth;
2877 : // }
2878 : // if (std::abs(baseSurface.Azimuth - 360.0) < 0.01) {
2879 : // baseSurface.Azimuth = 360.0 - baseSurface.Azimuth;
2880 : // }
2881 :
2882 : // Is base surface horizontal? If so, ignore azimuth differences
2883 12 : if (std::abs(baseSurface.Tilt) <= 1.0e-5 || std::abs(baseSurface.Tilt - 180.0) <= 1.0e-5) baseSurfHoriz = true;
2884 :
2885 24 : if (((General::rotAzmDiffDeg(baseSurface.Azimuth, subSurface.Azimuth) > errorTolerance) && !baseSurfHoriz) ||
2886 12 : (std::abs(baseSurface.Tilt - subSurface.Tilt) > errorTolerance)) {
2887 1 : surfaceError = true;
2888 2 : ShowSevereError(
2889 : state,
2890 2 : format("checkSubSurfAzTiltNorm: Outward facing angle of subsurface differs more than {:.1R} degrees from base surface.",
2891 : errorTolerance));
2892 2 : ShowContinueError(state,
2893 2 : format("Subsurface=\"{}\" Tilt = {:.1R} Azimuth = {:.1R}", subSurface.Name, subSurface.Tilt, subSurface.Azimuth));
2894 2 : ShowContinueError(
2895 2 : state, format("Base surface=\"{}\" Tilt = {:.1R} Azimuth = {:.1R}", baseSurface.Name, baseSurface.Tilt, baseSurface.Azimuth));
2896 20 : } else if (((General::rotAzmDiffDeg(baseSurface.Azimuth, subSurface.Azimuth) > warningTolerance) && !baseSurfHoriz) ||
2897 9 : (std::abs(baseSurface.Tilt - subSurface.Tilt) > warningTolerance)) {
2898 5 : ++state.dataSurfaceGeometry->checkSubSurfAzTiltNormErrCount;
2899 5 : if (state.dataSurfaceGeometry->checkSubSurfAzTiltNormErrCount == 1 && !state.dataGlobal->DisplayExtraWarnings) {
2900 10 : ShowWarningError(state,
2901 10 : format("checkSubSurfAzTiltNorm: Some Outward Facing angles of subsurfaces differ more than {:.1R} "
2902 : "degrees from base surface.",
2903 : warningTolerance));
2904 15 : ShowContinueError(state, "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on individual surfaces.");
2905 : }
2906 5 : if (state.dataGlobal->DisplayExtraWarnings) {
2907 0 : ShowWarningError(
2908 : state,
2909 0 : format("checkSubSurfAzTiltNorm: Outward facing angle of subsurface differs more than {:.1R} degrees from base surface.",
2910 : warningTolerance));
2911 0 : ShowContinueError(
2912 0 : state, format("Subsurface=\"{}\" Tilt = {:.1R} Azimuth = {:.1R}", subSurface.Name, subSurface.Tilt, subSurface.Azimuth));
2913 0 : ShowContinueError(
2914 : state,
2915 0 : format("Base surface=\"{}\" Tilt = {:.1R} Azimuth = {:.1R}", baseSurface.Name, baseSurface.Tilt, baseSurface.Azimuth));
2916 : }
2917 : }
2918 : }
2919 235 : }
2920 :
2921 268 : void GetGeometryParameters(EnergyPlusData &state, bool &ErrorsFound) // set to true if errors found during input
2922 : {
2923 :
2924 : // SUBROUTINE INFORMATION:
2925 : // AUTHOR Linda Lawrie
2926 : // DATE WRITTEN May 2000
2927 :
2928 : // PURPOSE OF THIS SUBROUTINE:
2929 : // This subroutine reads in the "Surface Geometry" parameters, verifies them,
2930 : // and sets "global" variables that will tell other routines how the surface
2931 : // vertices are expected in input.
2932 :
2933 : // REFERENCES:
2934 : // GlobalGeometryRules Definition
2935 : // GlobalGeometryRules,
2936 : // \required-object
2937 : // \unique-object
2938 : // A1, \field Starting Vertex Position
2939 : // \required-field
2940 : // \note Specified as entry for a 4 sided surface/rectangle
2941 : // \note Surfaces are specified as viewed from outside the surface
2942 : // \note Shading surfaces as viewed from behind. (towards what they are shading)
2943 : // \type choice
2944 : // \key UpperLeftCorner
2945 : // \key LowerLeftCorner
2946 : // \key UpperRightCorner
2947 : // \key LowerRightCorner
2948 : // A2, \field Vertex Entry Direction
2949 : // \required-field
2950 : // \type choice
2951 : // \key Counterclockwise
2952 : // \key Clockwise
2953 : // A3, \field Coordinate System
2954 : // \required-field
2955 : // \note relative -- coordinates are entered relative to zone origin
2956 : // \note world -- all coordinates entered are "absolute" for this facility
2957 : // \note absolute -- same as world
2958 : // \type choice
2959 : // \key Relative
2960 : // \key World
2961 : // \key Absolute
2962 : // A4, \field Daylighting Reference Point Coordinate System
2963 : // \type choice
2964 : // \key Relative
2965 : // \default Relative
2966 : // \note Relative -- coordinates are entered relative to zone origin
2967 : // \key World
2968 : // \note World -- all coordinates entered are "absolute" for this facility
2969 : // \key Absolute
2970 : // \note absolute -- same as world
2971 : // A5; \field Rectangular Surface Coordinate System
2972 : // \type choice
2973 : // \key Relative
2974 : // \default Relative
2975 : // \note Relative -- Starting corner is entered relative to zone origin
2976 : // \key World
2977 : // \note World -- Starting corner is entered in "absolute"
2978 : // \key Absolute
2979 : // \note absolute -- same as world
2980 :
2981 : // SUBROUTINE PARAMETER DEFINITIONS:
2982 268 : static Array1D_string const FlCorners(4, {"UpperLeftCorner", "LowerLeftCorner", "LowerRightCorner", "UpperRightCorner"});
2983 :
2984 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2985 268 : Array1D_string GAlphas(5);
2986 268 : Array1D<Real64> GNum(1);
2987 :
2988 268 : auto &s_ipsc = state.dataIPShortCut;
2989 :
2990 268 : s_ipsc->cCurrentModuleObject = "GlobalGeometryRules";
2991 268 : int NumStmt = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
2992 268 : std::string OutMsg = " Surface Geometry,";
2993 :
2994 : {
2995 268 : int const SELECT_CASE_var = NumStmt;
2996 :
2997 268 : if (SELECT_CASE_var == 1) {
2998 : int NNum;
2999 : int IOStat;
3000 : int NAlphas;
3001 : // This is the valid case
3002 804 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
3003 268 : s_ipsc->cCurrentModuleObject,
3004 : 1,
3005 : GAlphas,
3006 : NAlphas,
3007 : GNum,
3008 : NNum,
3009 : IOStat,
3010 268 : s_ipsc->lNumericFieldBlanks,
3011 268 : s_ipsc->lAlphaFieldBlanks,
3012 268 : s_ipsc->cAlphaFieldNames,
3013 268 : s_ipsc->cNumericFieldNames);
3014 :
3015 : // Even though these will be validated, set defaults in case error here -- wont
3016 : // cause aborts in later surface gets (hopefully)
3017 268 : state.dataSurface->Corner = DataSurfaces::UpperLeftCorner;
3018 268 : state.dataSurface->WorldCoordSystem = true;
3019 268 : state.dataSurface->CCW = true;
3020 :
3021 268 : int Found = Util::FindItem(GAlphas(1), FlCorners, 4);
3022 268 : if (Found == 0) {
3023 0 : ShowSevereError(state, format("{}: Invalid {}={}", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaFieldNames(1), GAlphas(1)));
3024 0 : ErrorsFound = true;
3025 : } else {
3026 268 : state.dataSurface->Corner = Found;
3027 268 : OutMsg += FlCorners(state.dataSurface->Corner) + ',';
3028 : }
3029 :
3030 268 : bool OK = false;
3031 268 : if (Util::SameString(GAlphas(2), "CCW") || Util::SameString(GAlphas(2), "Counterclockwise")) {
3032 268 : state.dataSurface->CCW = true;
3033 268 : OutMsg += "Counterclockwise,";
3034 268 : OK = true;
3035 : }
3036 268 : if (Util::SameString(GAlphas(2), "CW") || Util::SameString(GAlphas(2), "Clockwise")) {
3037 0 : state.dataSurface->CCW = false;
3038 0 : OutMsg += "Clockwise,";
3039 0 : OK = true;
3040 : }
3041 268 : if (!OK) {
3042 0 : ShowSevereError(state, format("{}: Invalid {}={}", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaFieldNames(2), GAlphas(2)));
3043 0 : ErrorsFound = true;
3044 : }
3045 :
3046 268 : OK = false;
3047 268 : if (Util::SameString(GAlphas(3), "World") || Util::SameString(GAlphas(3), "Absolute")) {
3048 102 : state.dataSurface->WorldCoordSystem = true;
3049 102 : OutMsg += "WorldCoordinateSystem,";
3050 102 : OK = true;
3051 : }
3052 268 : if (Util::SameString(GAlphas(3), "Relative")) {
3053 166 : state.dataSurface->WorldCoordSystem = false;
3054 166 : OutMsg += "RelativeCoordinateSystem,";
3055 166 : OK = true;
3056 : }
3057 268 : if (!OK) {
3058 0 : ShowWarningError(state, format("{}: Invalid {}={}", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaFieldNames(3), GAlphas(3)));
3059 0 : ShowContinueError(state, format("{} defaults to \"WorldCoordinateSystem\"", s_ipsc->cAlphaFieldNames(3)));
3060 0 : state.dataSurface->WorldCoordSystem = true;
3061 0 : OutMsg += "WorldCoordinateSystem,";
3062 : }
3063 :
3064 268 : OK = false;
3065 268 : if (Util::SameString(GAlphas(4), "World") || Util::SameString(GAlphas(4), "Absolute")) {
3066 8 : state.dataSurface->DaylRefWorldCoordSystem = true;
3067 8 : OutMsg += "WorldCoordinateSystem,";
3068 8 : OK = true;
3069 : }
3070 268 : if (Util::SameString(GAlphas(4), "Relative") || GAlphas(4).empty()) {
3071 260 : state.dataSurface->DaylRefWorldCoordSystem = false;
3072 260 : OutMsg += "RelativeCoordinateSystem,";
3073 260 : OK = true;
3074 : }
3075 268 : if (!OK) {
3076 0 : ShowWarningError(state, format("{}: Invalid {}={}", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaFieldNames(4), GAlphas(4)));
3077 0 : ShowContinueError(state, format("{} defaults to \"RelativeToZoneOrigin\"", s_ipsc->cAlphaFieldNames(4)));
3078 0 : state.dataSurface->DaylRefWorldCoordSystem = false;
3079 0 : OutMsg += "RelativeToZoneOrigin,";
3080 : }
3081 :
3082 268 : OK = false;
3083 268 : if (Util::SameString(GAlphas(5), "World") || Util::SameString(GAlphas(5), "Absolute")) {
3084 2 : state.dataSurfaceGeometry->RectSurfRefWorldCoordSystem = true;
3085 2 : OutMsg += "WorldCoordinateSystem";
3086 2 : OK = true;
3087 : }
3088 268 : if (Util::SameString(GAlphas(5), "Relative") || GAlphas(5).empty()) {
3089 266 : state.dataSurfaceGeometry->RectSurfRefWorldCoordSystem = false;
3090 266 : OutMsg += "RelativeToZoneOrigin";
3091 266 : OK = true;
3092 : }
3093 268 : if (!OK) {
3094 0 : ShowWarningError(state, format("{}: Invalid {}={}", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaFieldNames(5), GAlphas(5)));
3095 0 : ShowContinueError(state, format("{} defaults to \"RelativeToZoneOrigin\"", s_ipsc->cAlphaFieldNames(5)));
3096 0 : state.dataSurfaceGeometry->RectSurfRefWorldCoordSystem = false;
3097 0 : OutMsg += "RelativeToZoneOrigin";
3098 : }
3099 :
3100 0 : } else if (SELECT_CASE_var == 0) {
3101 :
3102 0 : ShowSevereError(state, format("{}: Required object not found.", s_ipsc->cCurrentModuleObject));
3103 0 : OutMsg += "None found in input";
3104 0 : ErrorsFound = true;
3105 :
3106 : } else {
3107 :
3108 0 : ShowSevereError(state, format("{}: Too many objects entered. Only one allowed.", s_ipsc->cCurrentModuleObject));
3109 0 : ErrorsFound = true;
3110 : }
3111 : }
3112 :
3113 268 : if (!state.dataSurface->WorldCoordSystem) {
3114 166 : if (state.dataSurface->DaylRefWorldCoordSystem) {
3115 0 : ShowWarningError(state, format("{}: Potential mismatch of coordinate specifications.", s_ipsc->cCurrentModuleObject));
3116 0 : ShowContinueError(state, format("{}=\"{}\"; while ", s_ipsc->cAlphaFieldNames(3), GAlphas(3)));
3117 0 : ShowContinueError(state, format("{}=\"{}\".", s_ipsc->cAlphaFieldNames(4), GAlphas(4)));
3118 : }
3119 166 : if (state.dataSurfaceGeometry->RectSurfRefWorldCoordSystem) {
3120 0 : ShowWarningError(state, format("{}: Potential mismatch of coordinate specifications.", s_ipsc->cCurrentModuleObject));
3121 0 : ShowContinueError(state, format("{}=\"{}\"; while ", s_ipsc->cAlphaFieldNames(3), GAlphas(3)));
3122 0 : ShowContinueError(state, format("{}=\"{}\".", s_ipsc->cAlphaFieldNames(5), GAlphas(5)));
3123 : }
3124 : } else {
3125 102 : bool RelWarning = false;
3126 270 : for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
3127 168 : if (state.dataHeatBal->Zone(ZoneNum).OriginX != 0.0) RelWarning = true;
3128 168 : if (state.dataHeatBal->Zone(ZoneNum).OriginY != 0.0) RelWarning = true;
3129 168 : if (state.dataHeatBal->Zone(ZoneNum).OriginZ != 0.0) RelWarning = true;
3130 : }
3131 102 : if (RelWarning && !state.dataSurfaceGeometry->RectSurfRefWorldCoordSystem) {
3132 4 : ShowWarningError(state,
3133 4 : format("{}: Potential mismatch of coordinate specifications. Note that the rectangular surfaces are relying on the "
3134 : "default SurfaceGeometry for 'Relative to zone' coordinate.",
3135 2 : s_ipsc->cCurrentModuleObject));
3136 2 : ShowContinueError(state, format("{}=\"{}\"; while ", s_ipsc->cAlphaFieldNames(3), GAlphas(3)));
3137 2 : if (GAlphas(5) == "RELATIVE") {
3138 2 : ShowContinueError(state, format("{}=\"{}\".", s_ipsc->cAlphaFieldNames(5), GAlphas(5)));
3139 0 : } else if (GAlphas(5) != "ABSOLUTE") {
3140 0 : ShowContinueError(state, format("{}=\"defaults to RELATIVE\".", s_ipsc->cAlphaFieldNames(5)));
3141 : }
3142 : }
3143 : }
3144 :
3145 268 : print(state.files.eio,
3146 : "! <Surface Geometry>,Starting Corner,Vertex Input Direction,Coordinate System,Daylight Reference "
3147 : "Point Coordinate System,Rectangular (Simple) Surface Coordinate System\n");
3148 268 : print(state.files.eio, "{}\n", OutMsg);
3149 268 : }
3150 :
3151 227 : void GetDetShdSurfaceData(EnergyPlusData &state,
3152 : bool &ErrorsFound, // Error flag indicator (true if errors found)
3153 : int &SurfNum, // Count of Current SurfaceNumber
3154 : int const TotDetachedFixed, // Number of Fixed Detached Shading Surfaces to obtain
3155 : int const TotDetachedBldg // Number of Building Detached Shading Surfaces to obtain
3156 : )
3157 : {
3158 : // SUBROUTINE INFORMATION:
3159 : // AUTHOR Linda Lawrie
3160 : // DATE WRITTEN May 2000
3161 :
3162 : // PURPOSE OF THIS SUBROUTINE:
3163 : // This subroutine gets the Detached Shading Surface Data,
3164 : // checks it for errors, etc.
3165 :
3166 : static constexpr std::string_view routineName = "GetDetShdSurfaceData";
3167 : // SUBROUTINE PARAMETER DEFINITIONS:
3168 227 : static Array1D_string const cModuleObjects(2, {"Shading:Site:Detailed", "Shading:Building:Detailed"});
3169 :
3170 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
3171 : int IOStat; // IO Status when calling get input subroutine
3172 : int NumAlphas; // Number of material alpha names being passed
3173 : int NumNumbers; // Number of material properties being passed
3174 : int Loop;
3175 : int ItemsToGet;
3176 : SurfaceClass ClassItem;
3177 : int numSides;
3178 : Real64 SchedMinValue;
3179 : Real64 SchedMaxValue;
3180 :
3181 227 : auto &s_ipsc = state.dataIPShortCut;
3182 :
3183 227 : if ((TotDetachedFixed + TotDetachedBldg) > 0 && state.dataHeatBal->SolarDistribution == DataHeatBalance::Shadowing::Minimal) {
3184 0 : ShowWarningError(state, "Detached shading effects are ignored when Solar Distribution = MinimalShadowing");
3185 : }
3186 :
3187 227 : if ((TotDetachedFixed + TotDetachedBldg) == 0) return;
3188 :
3189 27 : for (int Item = 1; Item <= 2; ++Item) {
3190 :
3191 18 : s_ipsc->cCurrentModuleObject = cModuleObjects(Item);
3192 18 : if (Item == 1) {
3193 9 : ItemsToGet = TotDetachedFixed;
3194 9 : ClassItem = SurfaceClass::Detached_F;
3195 : } else { // IF (Item == 2) THEN
3196 9 : ItemsToGet = TotDetachedBldg;
3197 9 : ClassItem = SurfaceClass::Detached_B;
3198 : }
3199 :
3200 18 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, s_ipsc->cCurrentModuleObject, Loop, NumAlphas, NumNumbers);
3201 18 : if (NumAlphas != 2) {
3202 0 : ShowSevereError(
3203 : state,
3204 0 : format("{}: Object Definition indicates not = 2 Alpha Objects, Number Indicated={}", s_ipsc->cCurrentModuleObject, NumAlphas));
3205 0 : ErrorsFound = true;
3206 : }
3207 :
3208 35 : for (Loop = 1; Loop <= ItemsToGet; ++Loop) {
3209 34 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
3210 17 : s_ipsc->cCurrentModuleObject,
3211 : Loop,
3212 17 : s_ipsc->cAlphaArgs,
3213 : NumAlphas,
3214 17 : s_ipsc->rNumericArgs,
3215 : NumNumbers,
3216 : IOStat,
3217 17 : s_ipsc->lNumericFieldBlanks,
3218 17 : s_ipsc->lAlphaFieldBlanks,
3219 17 : s_ipsc->cAlphaFieldNames,
3220 17 : s_ipsc->cNumericFieldNames);
3221 :
3222 17 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
3223 :
3224 34 : if (GlobalNames::VerifyUniqueInterObjectName(state,
3225 17 : state.dataSurfaceGeometry->UniqueSurfaceNames,
3226 17 : s_ipsc->cAlphaArgs(1),
3227 17 : s_ipsc->cCurrentModuleObject,
3228 17 : s_ipsc->cAlphaFieldNames(1),
3229 : ErrorsFound)) {
3230 0 : continue;
3231 : }
3232 :
3233 17 : ++SurfNum;
3234 :
3235 17 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
3236 17 : surfTemp.Name = s_ipsc->cAlphaArgs(1); // Set the Surface Name in the Derived Type
3237 17 : surfTemp.Class = ClassItem;
3238 17 : surfTemp.HeatTransSurf = false;
3239 17 : surfTemp.ExtSolar = true;
3240 : // Base transmittance of a shadowing (sub)surface
3241 :
3242 17 : if (s_ipsc->lAlphaFieldBlanks(2)) {
3243 5 : surfTemp.shadowSurfSched =
3244 : nullptr; // Leaving this as nullptr rather than making AlwaysOff because the uses and tests are too varied
3245 12 : } else if ((surfTemp.shadowSurfSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(2))) == nullptr) {
3246 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2));
3247 0 : ErrorsFound = true;
3248 12 : } else if (!surfTemp.shadowSurfSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 1.0)) {
3249 1 : Sched::ShowSevereBadMinMax(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2), Clusive::In, 0.0, Clusive::In, 1.0);
3250 1 : ErrorsFound = true;
3251 : } else {
3252 11 : SchedMinValue = surfTemp.shadowSurfSched->getMinVal(state);
3253 11 : surfTemp.SchedMinValue = SchedMinValue;
3254 11 : SchedMaxValue = surfTemp.shadowSurfSched->getCurrentVal();
3255 11 : if (SchedMinValue == 1.0) {
3256 : // Set transparent for now, check for EMS actuators later in SolarShading::resetShadingSurfaceTransparency
3257 1 : surfTemp.IsTransparent = true;
3258 : }
3259 11 : if (SchedMinValue < 0.0) {
3260 0 : ShowSevereError(state,
3261 0 : format("{}=\"{}\", {}=\"{}\", has schedule values < 0.",
3262 0 : s_ipsc->cCurrentModuleObject,
3263 0 : surfTemp.Name,
3264 0 : s_ipsc->cAlphaFieldNames(2),
3265 0 : s_ipsc->cAlphaArgs(2)));
3266 0 : ShowContinueError(state, "...Schedule values < 0 have no meaning for shading elements.");
3267 : }
3268 11 : if (SchedMaxValue > 0.0) {
3269 2 : state.dataSolarShading->anyScheduledShadingSurface = true;
3270 : }
3271 11 : if (SchedMaxValue > 1.0) {
3272 0 : ShowSevereError(state,
3273 0 : format("{}=\"{}\", {}=\"{}\", has schedule values > 1.",
3274 0 : s_ipsc->cCurrentModuleObject,
3275 0 : surfTemp.Name,
3276 0 : s_ipsc->cAlphaFieldNames(2),
3277 0 : s_ipsc->cAlphaArgs(2)));
3278 0 : ShowContinueError(state, "...Schedule values > 1 have no meaning for shading elements.");
3279 : }
3280 11 : if (std::abs(SchedMinValue - SchedMaxValue) > Constant::OneMillionth) {
3281 0 : state.dataSurface->ShadingTransmittanceVaries = true;
3282 : }
3283 : }
3284 17 : if (s_ipsc->lNumericFieldBlanks(1) || s_ipsc->rNumericArgs(1) == Constant::AutoCalculate) {
3285 0 : numSides = (NumNumbers - 1) / 3;
3286 0 : surfTemp.Sides = numSides;
3287 0 : if (mod(NumNumbers - 1, 3) != 0) {
3288 0 : ShowWarningError(state,
3289 0 : format("{}=\"{}\", {}",
3290 0 : s_ipsc->cCurrentModuleObject,
3291 0 : surfTemp.Name,
3292 0 : format("{} not even multiple of 3. Will read in {}", s_ipsc->cNumericFieldNames(1), surfTemp.Sides)));
3293 : }
3294 0 : if (numSides < 3) {
3295 0 : ShowSevereError(state,
3296 0 : format("{}=\"{}\", {} (autocalculate) must be >= 3. Only {} provided.",
3297 0 : s_ipsc->cCurrentModuleObject,
3298 0 : surfTemp.Name,
3299 0 : s_ipsc->cNumericFieldNames(1),
3300 0 : surfTemp.Sides));
3301 0 : ErrorsFound = true;
3302 0 : continue;
3303 : }
3304 : } else {
3305 17 : numSides = (NumNumbers - 1) / 3;
3306 17 : surfTemp.Sides = s_ipsc->rNumericArgs(1);
3307 17 : if (numSides > surfTemp.Sides) {
3308 0 : ShowWarningError(state,
3309 0 : format("{}=\"{}\", field {}={}",
3310 0 : s_ipsc->cCurrentModuleObject,
3311 0 : surfTemp.Name,
3312 0 : s_ipsc->cNumericFieldNames(1),
3313 0 : fmt::to_string(surfTemp.Sides)));
3314 0 : ShowContinueError(
3315 0 : state, format("...but {} were entered. Only the indicated {} will be used.", numSides, s_ipsc->cNumericFieldNames(1)));
3316 : }
3317 : }
3318 17 : surfTemp.Vertex.allocate(surfTemp.Sides);
3319 68 : GetVertices(state, SurfNum, surfTemp.Sides, s_ipsc->rNumericArgs({2, _}));
3320 17 : CheckConvexity(state, SurfNum, surfTemp.Sides);
3321 17 : if (state.dataReportFlag->MakeMirroredDetachedShading) {
3322 17 : MakeMirrorSurface(state, SurfNum);
3323 : }
3324 : }
3325 :
3326 : } // Item Loop
3327 17 : }
3328 :
3329 227 : void GetRectDetShdSurfaceData(EnergyPlusData &state,
3330 : bool &ErrorsFound, // Error flag indicator (true if errors found)
3331 : int &SurfNum, // Count of Current SurfaceNumber
3332 : int const TotRectDetachedFixed, // Number of Fixed Detached Shading Surfaces to obtain
3333 : int const TotRectDetachedBldg // Number of Building Detached Shading Surfaces to obtain
3334 : )
3335 : {
3336 :
3337 : // SUBROUTINE INFORMATION:
3338 : // AUTHOR Linda Lawrie
3339 : // DATE WRITTEN January 2009
3340 :
3341 : // PURPOSE OF THIS SUBROUTINE:
3342 : // Gets the simple, rectangular detached surfaces.
3343 :
3344 : // SUBROUTINE PARAMETER DEFINITIONS:
3345 227 : static Array1D_string const cModuleObjects(2, {"Shading:Site", "Shading:Building"});
3346 :
3347 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
3348 : int IOStat; // IO Status when calling get input subroutine
3349 : int NumAlphas; // Number of material alpha names being passed
3350 : int NumNumbers; // Number of material properties being passed
3351 : int Loop;
3352 : int ItemsToGet;
3353 : SurfaceClass ClassItem;
3354 :
3355 227 : auto &s_ipsc = state.dataIPShortCut;
3356 :
3357 227 : if ((TotRectDetachedFixed + TotRectDetachedBldg) > 0 && state.dataHeatBal->SolarDistribution == DataHeatBalance::Shadowing::Minimal) {
3358 0 : ShowWarningError(state, "Detached shading effects are ignored when Solar Distribution = MinimalShadowing");
3359 : }
3360 :
3361 227 : if (TotRectDetachedFixed + TotRectDetachedBldg == 0) return;
3362 3 : for (int Item = 1; Item <= 2; ++Item) {
3363 :
3364 2 : s_ipsc->cCurrentModuleObject = cModuleObjects(Item);
3365 2 : if (Item == 1) {
3366 1 : ItemsToGet = TotRectDetachedFixed;
3367 1 : ClassItem = SurfaceClass::Detached_F;
3368 : } else { // IF (Item == 2) THEN
3369 1 : ItemsToGet = TotRectDetachedBldg;
3370 1 : ClassItem = SurfaceClass::Detached_B;
3371 : }
3372 :
3373 2 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, s_ipsc->cCurrentModuleObject, Loop, NumAlphas, NumNumbers);
3374 2 : if (NumAlphas != 1) {
3375 0 : ShowSevereError(
3376 : state,
3377 0 : format("{}: Object Definition indicates not = 1 Alpha Objects, Number Indicated={}", s_ipsc->cCurrentModuleObject, NumAlphas));
3378 0 : ErrorsFound = true;
3379 : }
3380 :
3381 4 : for (Loop = 1; Loop <= ItemsToGet; ++Loop) {
3382 4 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
3383 2 : s_ipsc->cCurrentModuleObject,
3384 : Loop,
3385 2 : s_ipsc->cAlphaArgs,
3386 : NumAlphas,
3387 2 : s_ipsc->rNumericArgs,
3388 : NumNumbers,
3389 : IOStat,
3390 2 : s_ipsc->lNumericFieldBlanks,
3391 2 : s_ipsc->lAlphaFieldBlanks,
3392 2 : s_ipsc->cAlphaFieldNames,
3393 2 : s_ipsc->cNumericFieldNames);
3394 :
3395 4 : if (GlobalNames::VerifyUniqueInterObjectName(state,
3396 2 : state.dataSurfaceGeometry->UniqueSurfaceNames,
3397 2 : s_ipsc->cAlphaArgs(1),
3398 2 : s_ipsc->cCurrentModuleObject,
3399 2 : s_ipsc->cAlphaFieldNames(1),
3400 : ErrorsFound)) {
3401 0 : continue;
3402 : }
3403 :
3404 2 : ++SurfNum;
3405 :
3406 2 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
3407 2 : surfTemp.Name = s_ipsc->cAlphaArgs(1); // Set the Surface Name in the Derived Type
3408 2 : surfTemp.Class = ClassItem;
3409 2 : surfTemp.HeatTransSurf = false;
3410 2 : surfTemp.ExtSolar = true;
3411 :
3412 2 : surfTemp.Azimuth = s_ipsc->rNumericArgs(1);
3413 2 : if (surfTemp.Class == SurfaceClass::Detached_B && !state.dataSurface->WorldCoordSystem) {
3414 0 : surfTemp.Azimuth += state.dataHeatBal->BuildingAzimuth;
3415 : }
3416 2 : if (surfTemp.Class == SurfaceClass::Detached_B) {
3417 1 : surfTemp.Azimuth += state.dataHeatBal->BuildingRotationAppendixG;
3418 : }
3419 2 : surfTemp.Tilt = s_ipsc->rNumericArgs(2);
3420 2 : surfTemp.convOrientation = Convect::GetSurfConvOrientation(surfTemp.Tilt);
3421 :
3422 2 : surfTemp.Sides = 4;
3423 2 : surfTemp.Vertex.allocate(surfTemp.Sides);
3424 :
3425 12 : MakeRectangularVertices(state,
3426 : SurfNum,
3427 2 : s_ipsc->rNumericArgs(3),
3428 2 : s_ipsc->rNumericArgs(4),
3429 2 : s_ipsc->rNumericArgs(5),
3430 2 : s_ipsc->rNumericArgs(6),
3431 2 : s_ipsc->rNumericArgs(7),
3432 2 : state.dataSurfaceGeometry->RectSurfRefWorldCoordSystem);
3433 :
3434 2 : if (surfTemp.Area <= 0.0) {
3435 0 : ShowSevereError(
3436 : state,
3437 0 : format("{}=\"{}\", Surface Area <= 0.0; Entered Area={:.2T}", s_ipsc->cCurrentModuleObject, surfTemp.Name, surfTemp.Area));
3438 0 : ErrorsFound = true;
3439 : }
3440 :
3441 2 : if (state.dataReportFlag->MakeMirroredDetachedShading) {
3442 2 : MakeMirrorSurface(state, SurfNum);
3443 : }
3444 : }
3445 :
3446 : } // Item Loop
3447 : }
3448 :
3449 231 : void GetHTSurfaceData(EnergyPlusData &state,
3450 : bool &ErrorsFound, // Error flag indicator (true if errors found)
3451 : int &SurfNum, // Count of Current SurfaceNumber
3452 : int const TotHTSurfs, // Number of Heat Transfer Base Surfaces to obtain
3453 : int const TotDetailedWalls, // Number of Wall:Detailed items to obtain
3454 : int const TotDetailedRoofs, // Number of RoofCeiling:Detailed items to obtain
3455 : int const TotDetailedFloors, // Number of Floor:Detailed items to obtain
3456 : const Array1D_string &BaseSurfCls, // Valid Classes for Base Surfaces
3457 : const Array1D<SurfaceClass> &BaseSurfIDs,
3458 : int &NeedToAddSurfaces // Number of surfaces to add, based on unentered IZ surfaces
3459 : )
3460 : {
3461 :
3462 : // SUBROUTINE INFORMATION:
3463 : // AUTHOR Linda Lawrie
3464 : // DATE WRITTEN May 2000
3465 :
3466 : // PURPOSE OF THIS SUBROUTINE:
3467 : // This subroutine gets the HeatTransfer Surface Data, checks it for errors, etc.
3468 :
3469 : // REFERENCES:
3470 : // Heat Transfer Surface Definition
3471 : // BuildingSurface:Detailed,
3472 : // \extensible:3 -- duplicate last set of x,y,z coordinates (last 3 fields), remembering to remove ; from "inner" fields.
3473 : // \format vertices
3474 : // A1 , \field Name
3475 : // \required-field
3476 : // \type alpha
3477 : // \reference SurfaceNames
3478 : // \reference SurfAndSubSurfNames
3479 : // \reference AllHeatTranSurfNames
3480 : // \reference HeatTranBaseSurfNames
3481 : // \reference OutFaceEnvNames
3482 : // \reference AllHeatTranAngFacNames
3483 : // \reference RadGroupAndSurfNames
3484 : // \reference SurfGroupAndHTSurfNames
3485 : // \reference AllShadingAndHTSurfNames
3486 : // A2 , \field Surface Type
3487 : // \required-field
3488 : // \type choice
3489 : // \key Floor
3490 : // \key Wall
3491 : // \key Ceiling
3492 : // \key Roof
3493 : // A3 , \field Construction Name
3494 : // \required-field
3495 : // \note To be matched with a construction in this input file
3496 : // \type object-list
3497 : // \object-list ConstructionNames
3498 : // A4 , \field Zone Name
3499 : // \required-field
3500 : // \note Zone the surface is a part of
3501 : // \type object-list
3502 : // \object-list ZoneNames
3503 : // A5 , \field Outside Boundary Condition
3504 : // \required-field
3505 : // \type choice
3506 : // \key Adiabatic
3507 : // \key Surface
3508 : // \key Zone
3509 : // \key Outdoors
3510 : // \key Ground
3511 : // \key GroundFCfactorMethod
3512 : // \key OtherSideCoefficients
3513 : // \key OtherSideConditionsModel
3514 : // \key GroundSlabPreprocessorAverage
3515 : // \key GroundSlabPreprocessorCore
3516 : // \key GroundSlabPreprocessorPerimeter
3517 : // \key GroundBasementPreprocessorAverageWall
3518 : // \key GroundBasementPreprocessorAverageFloor
3519 : // \key GroundBasementPreprocessorUpperWall
3520 : // \key GroundBasementPreprocessorLowerWall
3521 : // A6, \field Outside Boundary Condition Object
3522 : // \type object-list
3523 : // \object-list OutFaceEnvNames
3524 : // \note Non-blank only if the field Outside Boundary Condition is Surface,
3525 : // \note Zone, OtherSideCoefficients or OtherSideConditionsModel
3526 : // \note If Surface, specify name of corresponding surface in adjacent zone or
3527 : // \note specify current surface name for internal partition separating like zones
3528 : // \note If Zone, specify the name of the corresponding zone and
3529 : // \note the program will generate the corresponding interzone surface
3530 : // \note If OtherSideCoefficients, specify name of SurfaceProperty:OtherSideCoefficients
3531 : // \note If OtherSideConditionsModel, specify name of SurfaceProperty:OtherSideConditionsModel
3532 : // A7 , \field Sun Exposure
3533 : // \required-field
3534 : // \type choice
3535 : // \key SunExposed
3536 : // \key NoSun
3537 : // \default SunExposed
3538 : // A8, \field Wind Exposure
3539 : // \required-field
3540 : // \type choice
3541 : // \key WindExposed
3542 : // \key NoWind
3543 : // \default WindExposed
3544 : // N1, \field View Factor to Ground
3545 : // \type real
3546 : // \note From the exterior of the surface
3547 : // \note Unused if one uses the "reflections" options in Solar Distribution in Building input
3548 : // \note unless a DaylightingDevice:Shelf or DaylightingDevice:Tubular object has been specified.
3549 : // \note autocalculate will automatically calculate this value from the tilt of the surface
3550 : // \autocalculatable
3551 : // \minimum 0.0
3552 : // \maximum 1.0
3553 : // \default autocalculate
3554 : // N2 , \field Number of Vertices
3555 : // \note shown with 120 vertex coordinates -- extensible object
3556 : // \note "extensible" -- duplicate last set of x,y,z coordinates (last 3 fields),
3557 : // \note remembering to remove ; from "inner" fields.
3558 : // \note for clarity in any error messages, renumber the fields as well.
3559 : // \note (and changing z terminator to a comma "," for all but last one which needs a semi-colon ";")
3560 : // \autocalculatable
3561 : // \minimum 3
3562 : // \default autocalculate
3563 : // \note vertices are given in GlobalGeometryRules coordinates -- if relative, all surface coordinates
3564 : // \note are "relative" to the Zone Origin. If world, then building and zone origins are used
3565 : // \note for some internal calculations, but all coordinates are given in an "absolute" system.
3566 : // N3-xx as indicated by the N3 value
3567 :
3568 : // Using/Aliasing
3569 :
3570 : // SUBROUTINE PARAMETER DEFINITIONS:
3571 231 : static Array1D_string const cModuleObjects(4, {"BuildingSurface:Detailed", "Wall:Detailed", "Floor:Detailed", "RoofCeiling:Detailed"});
3572 :
3573 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
3574 : int IOStat; // IO Status when calling get input subroutine
3575 : int SurfaceNumAlpha; // Number of material alpha names being passed
3576 : int SurfaceNumProp; // Number of material properties being passed
3577 : int ZoneNum; // DO loop counter (zones)
3578 : int Found; // For matching interzone surfaces
3579 : int Loop;
3580 : int ItemsToGet;
3581 : int ClassItem;
3582 : int ArgPointer;
3583 : int numSides;
3584 :
3585 231 : auto &s_ipsc = state.dataIPShortCut;
3586 :
3587 231 : GetOSCData(state, ErrorsFound);
3588 231 : GetOSCMData(state, ErrorsFound);
3589 231 : GetFoundationData(state, ErrorsFound);
3590 :
3591 231 : NeedToAddSurfaces = 0;
3592 1155 : for (int Item = 1; Item <= 4; ++Item) {
3593 :
3594 924 : s_ipsc->cCurrentModuleObject = cModuleObjects(Item);
3595 924 : if (Item == 1) {
3596 231 : ItemsToGet = TotHTSurfs;
3597 231 : ClassItem = 0;
3598 693 : } else if (Item == 2) {
3599 231 : ItemsToGet = TotDetailedWalls;
3600 231 : ClassItem = 1;
3601 462 : } else if (Item == 3) {
3602 231 : ItemsToGet = TotDetailedFloors;
3603 231 : ClassItem = 2;
3604 : } else { // IF (Item == 4) THEN
3605 231 : ItemsToGet = TotDetailedRoofs;
3606 231 : ClassItem = 3;
3607 : }
3608 :
3609 1848 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(
3610 924 : state, s_ipsc->cCurrentModuleObject, Loop, SurfaceNumAlpha, SurfaceNumProp);
3611 924 : if (Item == 1) {
3612 231 : if (SurfaceNumAlpha != 9) {
3613 0 : ShowSevereError(state,
3614 0 : format("{}: Object Definition indicates not = 9 Alpha Objects, Number Indicated={}",
3615 0 : s_ipsc->cCurrentModuleObject,
3616 : SurfaceNumAlpha));
3617 0 : ErrorsFound = true;
3618 : }
3619 : } else {
3620 693 : if (SurfaceNumAlpha != 8) {
3621 0 : ShowSevereError(state,
3622 0 : format("{}: Object Definition indicates not = 8 Alpha Objects, Number Indicated={}",
3623 0 : s_ipsc->cCurrentModuleObject,
3624 : SurfaceNumAlpha));
3625 0 : ErrorsFound = true;
3626 : }
3627 : }
3628 :
3629 2863 : for (Loop = 1; Loop <= ItemsToGet; ++Loop) {
3630 3878 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
3631 1939 : s_ipsc->cCurrentModuleObject,
3632 : Loop,
3633 1939 : s_ipsc->cAlphaArgs,
3634 : SurfaceNumAlpha,
3635 1939 : s_ipsc->rNumericArgs,
3636 : SurfaceNumProp,
3637 : IOStat,
3638 1939 : s_ipsc->lNumericFieldBlanks,
3639 1939 : s_ipsc->lAlphaFieldBlanks,
3640 1939 : s_ipsc->cAlphaFieldNames,
3641 1939 : s_ipsc->cNumericFieldNames);
3642 :
3643 3878 : if (GlobalNames::VerifyUniqueInterObjectName(state,
3644 1939 : state.dataSurfaceGeometry->UniqueSurfaceNames,
3645 1939 : s_ipsc->cAlphaArgs(1),
3646 1939 : s_ipsc->cCurrentModuleObject,
3647 1939 : s_ipsc->cAlphaFieldNames(1),
3648 : ErrorsFound)) {
3649 0 : continue;
3650 : }
3651 :
3652 1939 : ++SurfNum;
3653 :
3654 1939 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
3655 1939 : surfTemp.Name = s_ipsc->cAlphaArgs(1); // Set the Surface Name in the Derived Type
3656 1939 : ArgPointer = 2;
3657 1939 : if (Item == 1) {
3658 1939 : if (s_ipsc->cAlphaArgs(2) == "CEILING") s_ipsc->cAlphaArgs(2) = "ROOF";
3659 1939 : ClassItem = Util::FindItemInList(s_ipsc->cAlphaArgs(2), BaseSurfCls, 3);
3660 1939 : if (ClassItem == 0) {
3661 0 : ShowSevereError(state,
3662 0 : format("{}=\"{}\", invalid {}=\"{}",
3663 0 : s_ipsc->cCurrentModuleObject,
3664 0 : surfTemp.Name,
3665 0 : s_ipsc->cAlphaFieldNames(2),
3666 0 : s_ipsc->cAlphaArgs(2)));
3667 0 : ErrorsFound = true;
3668 : } else {
3669 1939 : surfTemp.Class = BaseSurfIDs(ClassItem);
3670 : }
3671 1939 : ++ArgPointer;
3672 : } else {
3673 0 : surfTemp.Class = BaseSurfIDs(ClassItem);
3674 : }
3675 :
3676 1939 : surfTemp.Construction =
3677 1939 : Util::FindItemInList(s_ipsc->cAlphaArgs(ArgPointer), state.dataConstruction->Construct, state.dataHeatBal->TotConstructs);
3678 :
3679 1939 : if (surfTemp.Construction == 0) {
3680 2 : ErrorsFound = true;
3681 4 : ShowSevereError(state,
3682 8 : format("{}=\"{}\", invalid {}=\"{}\".",
3683 2 : s_ipsc->cCurrentModuleObject,
3684 2 : surfTemp.Name,
3685 2 : s_ipsc->cAlphaFieldNames(ArgPointer),
3686 2 : s_ipsc->cAlphaArgs(ArgPointer)));
3687 1937 : } else if (state.dataConstruction->Construct(surfTemp.Construction).TypeIsWindow) {
3688 0 : ErrorsFound = true;
3689 0 : ShowSevereError(state,
3690 0 : format("{}=\"{}\", invalid {}=\"{}\" - has Window materials.",
3691 0 : s_ipsc->cCurrentModuleObject,
3692 0 : surfTemp.Name,
3693 0 : s_ipsc->cAlphaFieldNames(ArgPointer),
3694 0 : s_ipsc->cAlphaArgs(ArgPointer)));
3695 0 : if (Item == 1) {
3696 0 : ShowContinueError(state, format("...because {}={}", s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2)));
3697 : } else {
3698 0 : ShowContinueError(state, format("...because Surface Type={}", BaseSurfCls(ClassItem)));
3699 : }
3700 : } else {
3701 1937 : state.dataConstruction->Construct(surfTemp.Construction).IsUsed = true;
3702 1937 : surfTemp.ConstructionStoredInputValue = surfTemp.Construction;
3703 : }
3704 1939 : surfTemp.HeatTransSurf = true;
3705 1939 : surfTemp.BaseSurf = SurfNum;
3706 1939 : surfTemp.BaseSurfName = surfTemp.Name;
3707 :
3708 1939 : ++ArgPointer;
3709 1939 : surfTemp.ZoneName = s_ipsc->cAlphaArgs(ArgPointer);
3710 1939 : ZoneNum = Util::FindItemInList(surfTemp.ZoneName, state.dataHeatBal->Zone, state.dataGlobal->NumOfZones);
3711 :
3712 1939 : if (ZoneNum != 0) {
3713 1939 : surfTemp.Zone = ZoneNum;
3714 : } else {
3715 0 : ShowSevereError(state,
3716 0 : format("{}=\"{}\", invalid {}=\"{}\".",
3717 0 : s_ipsc->cCurrentModuleObject,
3718 0 : surfTemp.Name,
3719 0 : s_ipsc->cAlphaFieldNames(ArgPointer),
3720 0 : s_ipsc->cAlphaArgs(ArgPointer)));
3721 0 : surfTemp.Class = SurfaceClass::Invalid;
3722 0 : surfTemp.ZoneName = "Unknown Zone";
3723 0 : ErrorsFound = true;
3724 : }
3725 :
3726 1939 : ++ArgPointer;
3727 1939 : if (!s_ipsc->lAlphaFieldBlanks(ArgPointer)) {
3728 162 : int spaceNum = Util::FindItemInList(s_ipsc->cAlphaArgs(ArgPointer), state.dataHeatBal->space);
3729 :
3730 162 : if (spaceNum != 0) {
3731 162 : surfTemp.spaceNum = spaceNum;
3732 162 : if (surfTemp.Zone != state.dataHeatBal->space(spaceNum).zoneNum) {
3733 0 : ShowSevereError(state,
3734 0 : format("{}=\"{}\", invalid {}=\"{}\" is not in the same zone as the surface.",
3735 0 : s_ipsc->cCurrentModuleObject,
3736 0 : surfTemp.Name,
3737 0 : s_ipsc->cAlphaFieldNames(ArgPointer),
3738 0 : s_ipsc->cAlphaArgs(ArgPointer)));
3739 0 : surfTemp.Class = SurfaceClass::Invalid;
3740 0 : ErrorsFound = true;
3741 : }
3742 : } else {
3743 0 : ShowSevereError(state,
3744 0 : format("{}=\"{}\", invalid {}=\"{}\" not found.",
3745 0 : s_ipsc->cCurrentModuleObject,
3746 0 : surfTemp.Name,
3747 0 : s_ipsc->cAlphaFieldNames(ArgPointer),
3748 0 : s_ipsc->cAlphaArgs(ArgPointer)));
3749 0 : surfTemp.Class = SurfaceClass::Invalid;
3750 0 : ErrorsFound = true;
3751 : }
3752 : }
3753 : // Get the ExteriorBoundaryCondition flag from input There are 4 conditions that
3754 : // can take place. The conditions are set with a 0, -1, or -2, or all of the
3755 : // zone names have to be looked at and generate the interzone array number
3756 1939 : ++ArgPointer;
3757 1939 : surfTemp.ExtBoundCondName = s_ipsc->cAlphaArgs(ArgPointer + 1);
3758 :
3759 1939 : if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "Outdoors")) {
3760 1228 : surfTemp.ExtBoundCond = DataSurfaces::ExternalEnvironment;
3761 711 : } else if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "Adiabatic")) {
3762 152 : surfTemp.ExtBoundCond = unreconciledZoneSurface;
3763 152 : surfTemp.ExtBoundCondName = surfTemp.Name;
3764 :
3765 559 : } else if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "Ground")) {
3766 119 : surfTemp.ExtBoundCond = DataSurfaces::Ground;
3767 119 : if (state.dataSurfaceGeometry->NoGroundTempObjWarning) {
3768 44 : if (!state.dataEnvrn->GroundTempInputs[(int)DataEnvironment::GroundTempType::BuildingSurface]) {
3769 72 : ShowWarningError(state,
3770 : "GetHTSurfaceData: Surfaces with interface to Ground found but no \"Ground Temperatures\" were input.");
3771 36 : ShowContinueError(state, format("Found first in surface={}", s_ipsc->cAlphaArgs(1)));
3772 72 : ShowContinueError(state,
3773 72 : format("Defaults, constant throughout the year of ({:.1R}) will be used.",
3774 36 : state.dataEnvrn->GroundTemp[(int)DataEnvironment::GroundTempType::BuildingSurface]));
3775 : }
3776 44 : state.dataSurfaceGeometry->NoGroundTempObjWarning = false;
3777 : }
3778 :
3779 : // Added for FCfactor method
3780 440 : } else if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "GroundFCfactorMethod")) {
3781 0 : surfTemp.ExtBoundCond = DataSurfaces::GroundFCfactorMethod;
3782 0 : if (state.dataSurfaceGeometry->NoFCGroundTempObjWarning) {
3783 0 : if (!state.dataEnvrn->GroundTempInputs[(int)DataEnvironment::GroundTempType::FCFactorMethod]) {
3784 0 : ShowSevereError(state,
3785 : "GetHTSurfaceData: Surfaces with interface to GroundFCfactorMethod found but no \"FC Ground "
3786 : "Temperatures\" were input.");
3787 0 : ShowContinueError(state, format("Found first in surface={}", s_ipsc->cAlphaArgs(1)));
3788 0 : ShowContinueError(state,
3789 : "Either add a \"Site:GroundTemperature:FCfactorMethod\" object or use a weather file with "
3790 : "Ground Temperatures.");
3791 0 : ErrorsFound = true;
3792 0 : state.dataSurfaceGeometry->NoFCGroundTempObjWarning = false;
3793 : }
3794 : }
3795 0 : if (surfTemp.Construction > 0) {
3796 0 : if (surfTemp.Class == SurfaceClass::Wall && !state.dataConstruction->Construct(surfTemp.Construction).TypeIsCfactorWall) {
3797 0 : ShowSevereError(
3798 : state,
3799 0 : format("{}=\"{}\", invalid {}", s_ipsc->cCurrentModuleObject, surfTemp.Name, s_ipsc->cAlphaFieldNames(ArgPointer)));
3800 0 : ShowContinueError(state,
3801 0 : format("Construction=\"{}\" is not type Construction:CfactorUndergroundWall.",
3802 0 : state.dataConstruction->Construct(surfTemp.Construction).Name));
3803 0 : ErrorsFound = true;
3804 : }
3805 0 : if (surfTemp.Class == SurfaceClass::Floor && !state.dataConstruction->Construct(surfTemp.Construction).TypeIsFfactorFloor) {
3806 0 : ShowSevereError(
3807 : state,
3808 0 : format("{}=\"{}\", invalid {}", s_ipsc->cCurrentModuleObject, surfTemp.Name, s_ipsc->cAlphaFieldNames(ArgPointer)));
3809 0 : ShowContinueError(state,
3810 0 : format("Construction=\"{}\" is not type Construction:FfactorGroundFloor.",
3811 0 : state.dataConstruction->Construct(surfTemp.Construction).Name));
3812 0 : ErrorsFound = true;
3813 : }
3814 : }
3815 :
3816 440 : } else if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "OtherSideCoefficients")) {
3817 0 : Found = Util::FindItemInList(surfTemp.ExtBoundCondName, state.dataSurface->OSC, state.dataSurface->TotOSC);
3818 0 : if (Found == 0) {
3819 0 : ShowSevereError(state,
3820 0 : format("{}=\"{}\", invalid {}=\"{}\".",
3821 0 : s_ipsc->cCurrentModuleObject,
3822 0 : surfTemp.Name,
3823 0 : s_ipsc->cAlphaFieldNames(ArgPointer + 1),
3824 0 : s_ipsc->cAlphaArgs(ArgPointer + 1)));
3825 0 : ShowContinueError(state, " no OtherSideCoefficients of that name.");
3826 0 : ErrorsFound = true;
3827 : } else {
3828 0 : surfTemp.OSCPtr = Found;
3829 0 : if (state.dataSurface->OSC(Found).SurfFilmCoef > 0.0) {
3830 0 : surfTemp.ExtBoundCond = DataSurfaces::OtherSideCoefCalcExt;
3831 : } else {
3832 0 : surfTemp.ExtBoundCond = DataSurfaces::OtherSideCoefNoCalcExt;
3833 : }
3834 : }
3835 :
3836 440 : } else if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "Surface")) {
3837 : // it has to be another surface which needs to be found
3838 : // this will be found on the second pass through the surface input
3839 : // for flagging, set the value to UnreconciledZoneSurface
3840 : // name (ExtBoundCondName) will be validated later.
3841 427 : surfTemp.ExtBoundCond = unreconciledZoneSurface;
3842 427 : if (s_ipsc->lAlphaFieldBlanks(ArgPointer + 1)) {
3843 0 : surfTemp.ExtBoundCondName = surfTemp.Name;
3844 0 : ShowSevereError(state,
3845 0 : format("{}=\"{}\", invalid {}=<blank>.",
3846 0 : s_ipsc->cCurrentModuleObject,
3847 0 : surfTemp.Name,
3848 0 : s_ipsc->cAlphaFieldNames(ArgPointer + 1)));
3849 0 : ShowContinueError(state, format("..{}=\"Surface\" must be non-blank.", s_ipsc->cAlphaFieldNames(ArgPointer)));
3850 0 : ShowContinueError(state, "..This surface will become an adiabatic surface - no doors/windows allowed.");
3851 : }
3852 :
3853 13 : } else if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "Zone")) {
3854 : // This is the code for an unmatched "other surface"
3855 : // will be set up later.
3856 8 : surfTemp.ExtBoundCond = unenteredAdjacentZoneSurface;
3857 : // check OutsideFaceEnvironment for legal zone
3858 8 : Found = Util::FindItemInList(surfTemp.ExtBoundCondName, state.dataHeatBal->Zone, state.dataGlobal->NumOfZones);
3859 8 : ++NeedToAddSurfaces;
3860 :
3861 8 : if (Found == 0) {
3862 0 : ShowSevereError(state,
3863 0 : format("{}=\"{}\", invalid {}=\"{}\".",
3864 0 : s_ipsc->cCurrentModuleObject,
3865 0 : surfTemp.Name,
3866 0 : s_ipsc->cAlphaFieldNames(ArgPointer),
3867 0 : s_ipsc->cAlphaArgs(ArgPointer)));
3868 0 : ShowContinueError(state, "..Referenced as Zone for this surface.");
3869 0 : ErrorsFound = true;
3870 : }
3871 :
3872 5 : } else if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "Space")) {
3873 : // This is the code for an unmatched "other surface"
3874 : // will be set up later.
3875 2 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond = unenteredAdjacentSpaceSurface;
3876 : // check OutsideFaceEnvironment for legal zone
3877 2 : Found = Util::FindItemInList(
3878 2 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCondName, state.dataHeatBal->space, state.dataGlobal->numSpaces);
3879 2 : ++NeedToAddSurfaces;
3880 :
3881 2 : if (Found == 0) {
3882 0 : ShowSevereError(state,
3883 0 : format("{}=\"{}\", invalid {}=\"{}\".",
3884 0 : s_ipsc->cCurrentModuleObject,
3885 0 : state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
3886 0 : s_ipsc->cAlphaFieldNames(ArgPointer),
3887 0 : s_ipsc->cAlphaArgs(ArgPointer)));
3888 0 : ShowContinueError(state, "..Referenced as Space for this surface.");
3889 0 : ErrorsFound = true;
3890 : }
3891 :
3892 3 : } else if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "Foundation")) {
3893 :
3894 0 : if (!state.dataWeather->WeatherFileExists) {
3895 0 : ShowSevereError(
3896 : state,
3897 0 : format("{}=\"{}\", using \"Foundation\" type Outside Boundary Condition requires specification of a weather file",
3898 0 : s_ipsc->cCurrentModuleObject,
3899 0 : surfTemp.Name));
3900 0 : ShowContinueError(state,
3901 : "Either place in.epw in the working directory or specify a weather file on the command line using -w "
3902 : "/path/to/weather.epw");
3903 0 : ErrorsFound = true;
3904 : }
3905 :
3906 : // Find foundation object, if blank use default
3907 0 : if (s_ipsc->lAlphaFieldBlanks(ArgPointer + 1)) {
3908 :
3909 0 : if (!state.dataSurfaceGeometry->kivaManager.defaultAdded) {
3910 : // Add default foundation if no other foundation object specified
3911 0 : state.dataSurfaceGeometry->kivaManager.addDefaultFoundation();
3912 : }
3913 0 : surfTemp.OSCPtr =
3914 0 : state.dataSurfaceGeometry->kivaManager.defaultIndex; // Reuse OSC pointer...shouldn't be used for non OSC surfaces anyway.
3915 : } else {
3916 0 : Found = state.dataSurfaceGeometry->kivaManager.findFoundation(surfTemp.ExtBoundCondName);
3917 0 : if (Found != (int)state.dataSurfaceGeometry->kivaManager.foundationInputs.size()) {
3918 0 : surfTemp.OSCPtr = Found;
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 + 1),
3925 0 : s_ipsc->cAlphaArgs(ArgPointer + 1)));
3926 0 : ErrorsFound = true;
3927 : }
3928 : }
3929 :
3930 0 : if (state.dataConstruction->Construct(surfTemp.Construction).SourceSinkPresent) {
3931 0 : ShowSevereError(
3932 : state,
3933 0 : format("{}=\"{}\", construction may not have an internal source/sink", s_ipsc->cCurrentModuleObject, surfTemp.Name));
3934 0 : ErrorsFound = true;
3935 : }
3936 0 : surfTemp.ExtBoundCond = DataSurfaces::KivaFoundation;
3937 3 : } else if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "OtherSideConditionsModel")) {
3938 3 : Found = Util::FindItemInList(surfTemp.ExtBoundCondName, state.dataSurface->OSCM, state.dataSurface->TotOSCM);
3939 3 : if (Found == 0) {
3940 0 : ShowSevereError(state,
3941 0 : format("{}=\"{}\", invalid {}=\"{}\".",
3942 0 : s_ipsc->cCurrentModuleObject,
3943 0 : surfTemp.Name,
3944 0 : s_ipsc->cAlphaFieldNames(ArgPointer + 1),
3945 0 : s_ipsc->cAlphaArgs(ArgPointer + 1)));
3946 0 : ErrorsFound = true;
3947 : }
3948 3 : surfTemp.OSCMPtr = Found;
3949 3 : surfTemp.ExtBoundCond = DataSurfaces::OtherSideCondModeledExt;
3950 :
3951 0 : } else if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "GroundSlabPreprocessorAverage") ||
3952 0 : Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "GroundSlabPreprocessorCore") ||
3953 0 : Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "GroundSlabPreprocessorPerimeter") ||
3954 0 : Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "GroundBasementPreprocessorAverageFloor") ||
3955 0 : Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "GroundBasementPreprocessorAverageWall") ||
3956 0 : Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "GroundBasementPreprocessorUpperWall") ||
3957 0 : Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "GroundBasementPreprocessorLowerWall")) {
3958 0 : ShowSevereError(state,
3959 0 : format("{}=\"{}\", invalid {}=\"{}\".",
3960 0 : s_ipsc->cCurrentModuleObject,
3961 0 : surfTemp.Name,
3962 0 : s_ipsc->cAlphaFieldNames(ArgPointer),
3963 0 : s_ipsc->cAlphaArgs(ArgPointer)));
3964 0 : ShowContinueError(state, "The ExpandObjects program has not been run or is not in your EnergyPlus.exe folder.");
3965 0 : ErrorsFound = true;
3966 :
3967 : } else {
3968 0 : ShowSevereError(state,
3969 0 : format("{}=\"{}\", invalid {}=\"{}\".",
3970 0 : s_ipsc->cCurrentModuleObject,
3971 0 : surfTemp.Name,
3972 0 : s_ipsc->cAlphaFieldNames(ArgPointer),
3973 0 : s_ipsc->cAlphaArgs(ArgPointer)));
3974 0 : ShowContinueError(state,
3975 : "Should be one of \"Outdoors\", \"Adiabatic\", Ground\", \"Surface\", \"OtherSideCoefficients\", "
3976 : "\"OtherSideConditionsModel\" or \"Zone\"");
3977 0 : ErrorsFound = true;
3978 : } // ... End of the ExtBoundCond logical IF Block
3979 :
3980 1939 : ArgPointer += 2;
3981 : // Set the logical flag for the exterior solar
3982 1939 : if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "SunExposed")) {
3983 1149 : if ((surfTemp.ExtBoundCond != DataSurfaces::ExternalEnvironment) &&
3984 3 : (surfTemp.ExtBoundCond != DataSurfaces::OtherSideCondModeledExt)) {
3985 0 : ShowWarningError(state,
3986 0 : format("{}=\"{}\", {}=\"{}\".",
3987 0 : s_ipsc->cCurrentModuleObject,
3988 0 : surfTemp.Name,
3989 0 : s_ipsc->cAlphaFieldNames(ArgPointer),
3990 0 : s_ipsc->cAlphaArgs(ArgPointer)));
3991 0 : ShowContinueError(state, "..This surface is not exposed to External Environment. Sun exposure has no effect.");
3992 : } else {
3993 1149 : surfTemp.ExtSolar = true;
3994 : }
3995 790 : } else if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "NoSun")) {
3996 790 : surfTemp.ExtSolar = false;
3997 : } else {
3998 0 : ShowSevereError(state,
3999 0 : format("{}=\"{}\", invalid {}=\"{}\".",
4000 0 : s_ipsc->cCurrentModuleObject,
4001 0 : surfTemp.Name,
4002 0 : s_ipsc->cAlphaFieldNames(ArgPointer),
4003 0 : s_ipsc->cAlphaArgs(ArgPointer)));
4004 0 : ErrorsFound = true;
4005 : }
4006 :
4007 1939 : ++ArgPointer;
4008 : // Set the logical flag for the exterior wind
4009 1939 : if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "WindExposed")) {
4010 1163 : surfTemp.ExtWind = true;
4011 776 : } else if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "NoWind")) {
4012 776 : surfTemp.ExtWind = false;
4013 : } else {
4014 0 : ShowSevereError(state,
4015 0 : format("{}=\"{}\", invalid {}=\"{}\".",
4016 0 : s_ipsc->cCurrentModuleObject,
4017 0 : surfTemp.Name,
4018 0 : s_ipsc->cAlphaFieldNames(ArgPointer),
4019 0 : s_ipsc->cAlphaArgs(ArgPointer)));
4020 0 : ErrorsFound = true;
4021 : }
4022 :
4023 : // Set the logical flag for the EcoRoof presented, this is only based on the flag in the construction type
4024 : // if (surfTemp.Construction > 0)
4025 : // surfTemp.ExtEcoRoof =
4026 : // state.dataConstruction->Construct(surfTemp.Construction).TypeIsEcoRoof;
4027 :
4028 1939 : surfTemp.ViewFactorGround = s_ipsc->rNumericArgs(1);
4029 1939 : if (s_ipsc->lNumericFieldBlanks(1)) surfTemp.ViewFactorGround = Constant::AutoCalculate;
4030 1939 : if (s_ipsc->lNumericFieldBlanks(2) || s_ipsc->rNumericArgs(2) == Constant::AutoCalculate) {
4031 175 : numSides = (SurfaceNumProp - 2) / 3;
4032 175 : surfTemp.Sides = numSides;
4033 175 : if (mod(SurfaceNumProp - 2, 3) != 0) {
4034 0 : ShowWarningError(state,
4035 0 : format("{}=\"{}\", {}",
4036 0 : s_ipsc->cCurrentModuleObject,
4037 0 : surfTemp.Name,
4038 0 : format("{} not even multiple of 3. Will read in {}", s_ipsc->cNumericFieldNames(2), surfTemp.Sides)));
4039 : }
4040 175 : if (numSides < 3) {
4041 0 : ShowSevereError(state,
4042 0 : format("{}=\"{}\", {} (autocalculate) must be >= 3. Only {} provided.",
4043 0 : s_ipsc->cCurrentModuleObject,
4044 0 : surfTemp.Name,
4045 0 : s_ipsc->cNumericFieldNames(2),
4046 0 : surfTemp.Sides));
4047 0 : ErrorsFound = true;
4048 0 : continue;
4049 : }
4050 : } else {
4051 1764 : numSides = (SurfaceNumProp - 2) / 3;
4052 1764 : surfTemp.Sides = s_ipsc->rNumericArgs(2);
4053 1764 : if (numSides > surfTemp.Sides) {
4054 0 : ShowWarningError(state,
4055 0 : format("{}=\"{}\", field {}={}",
4056 0 : s_ipsc->cCurrentModuleObject,
4057 0 : surfTemp.Name,
4058 0 : s_ipsc->cNumericFieldNames(2),
4059 0 : fmt::to_string(surfTemp.Sides)));
4060 0 : ShowContinueError(
4061 0 : state, format("...but {} were entered. Only the indicated {} will be used.", numSides, s_ipsc->cNumericFieldNames(2)));
4062 : }
4063 : }
4064 1939 : surfTemp.Vertex.allocate(surfTemp.Sides);
4065 1939 : surfTemp.NewVertex.allocate(surfTemp.Sides);
4066 7756 : GetVertices(state, SurfNum, surfTemp.Sides, s_ipsc->rNumericArgs({3, _}));
4067 1939 : if (surfTemp.Area <= 0.0) {
4068 0 : ShowSevereError(
4069 : state,
4070 0 : format("{}=\"{}\", Surface Area <= 0.0; Entered Area={:.2T}", s_ipsc->cCurrentModuleObject, surfTemp.Name, surfTemp.Area));
4071 0 : ErrorsFound = true;
4072 : }
4073 :
4074 1939 : CheckConvexity(state, SurfNum, surfTemp.Sides);
4075 1939 : if (Util::SameString(s_ipsc->cAlphaArgs(5), "Surface")) {
4076 0 : if (surfTemp.Sides != static_cast<int>(surfTemp.Vertex.size())) {
4077 0 : ShowSevereError(state,
4078 0 : format("{}=\"{}\", After CheckConvexity, mismatch between Sides ({}) and size of Vertex ({}).",
4079 0 : s_ipsc->cCurrentModuleObject,
4080 0 : surfTemp.Name,
4081 0 : surfTemp.Sides,
4082 0 : surfTemp.Vertex.size()));
4083 0 : ShowContinueError(state, "CheckConvexity is used to verify the convexity of a surface and detect collinear points.");
4084 0 : ErrorsFound = true;
4085 : }
4086 : }
4087 1939 : if (surfTemp.Construction > 0) {
4088 : // Check wall height for the CFactor walls
4089 :
4090 1937 : if (surfTemp.Class == SurfaceClass::Wall && state.dataConstruction->Construct(surfTemp.Construction).TypeIsCfactorWall) {
4091 0 : if (std::abs(surfTemp.Height - state.dataConstruction->Construct(surfTemp.Construction).Height) > 0.05) {
4092 0 : ShowWarningError(
4093 : state,
4094 0 : format("{}=\"{}\", underground Wall Height = {:.2T}", s_ipsc->cCurrentModuleObject, surfTemp.Name, surfTemp.Height));
4095 0 : ShowContinueError(state, "..which does not match its construction height.");
4096 : }
4097 : }
4098 :
4099 : // Check area and perimeter for the FFactor floors
4100 1937 : if (surfTemp.Class == SurfaceClass::Floor && state.dataConstruction->Construct(surfTemp.Construction).TypeIsFfactorFloor) {
4101 0 : if (std::abs(surfTemp.Area - state.dataConstruction->Construct(surfTemp.Construction).Area) > 0.1) {
4102 0 : ShowWarningError(
4103 : state,
4104 0 : format("{}=\"{}\", underground Floor Area = {:.2T}", s_ipsc->cCurrentModuleObject, surfTemp.Name, surfTemp.Area));
4105 0 : ShowContinueError(state, "..which does not match its construction area.");
4106 : }
4107 0 : if (surfTemp.Perimeter < state.dataConstruction->Construct(surfTemp.Construction).PerimeterExposed - 0.1) {
4108 0 : ShowWarningError(state,
4109 0 : format("{}=\"{}\", underground Floor Perimeter = {:.2T}",
4110 0 : s_ipsc->cCurrentModuleObject,
4111 0 : surfTemp.Name,
4112 0 : surfTemp.Perimeter));
4113 0 : ShowContinueError(state, "..which is less than its construction exposed perimeter.");
4114 : }
4115 : }
4116 : }
4117 : // Not sure if it's better to add this or guard in SolarShading.cc
4118 : // surfTemp.shadowSurfSched = nullptr
4119 : }
4120 : } // Item Looop
4121 : // Check number of Vertex between base surface and Outside Boundary surface
4122 : int ExtSurfNum;
4123 2200 : for (int i = 1; i <= SurfNum; i++) {
4124 2548 : if (state.dataSurfaceGeometry->SurfaceTmp(i).ExtBoundCond == unreconciledZoneSurface &&
4125 579 : state.dataSurfaceGeometry->SurfaceTmp(i).ExtBoundCondName != "") {
4126 579 : ExtSurfNum = Util::FindItemInList(state.dataSurfaceGeometry->SurfaceTmp(i).ExtBoundCondName, state.dataSurfaceGeometry->SurfaceTmp);
4127 : // If we cannot find the referenced surface
4128 579 : if (ExtSurfNum == 0) {
4129 2 : ShowSevereError(state,
4130 2 : format("{}=\"{}\" references an outside boundary surface that cannot be found:{}",
4131 1 : s_ipsc->cCurrentModuleObject,
4132 1 : state.dataSurfaceGeometry->SurfaceTmp(i).Name,
4133 1 : state.dataSurfaceGeometry->SurfaceTmp(i).ExtBoundCondName));
4134 1 : ErrorsFound = true;
4135 : // If vertex size mismatch
4136 1156 : } else if (state.dataSurfaceGeometry->SurfaceTmp(i).Vertex.size() !=
4137 578 : state.dataSurfaceGeometry->SurfaceTmp(ExtSurfNum).Vertex.size()) {
4138 4 : ShowSevereError(state,
4139 4 : format("{}=\"{}\", Vertex size mismatch between base surface :{} and outside boundary surface: {}",
4140 2 : s_ipsc->cCurrentModuleObject,
4141 2 : state.dataSurfaceGeometry->SurfaceTmp(i).Name,
4142 2 : state.dataSurfaceGeometry->SurfaceTmp(i).Name,
4143 2 : state.dataSurfaceGeometry->SurfaceTmp(ExtSurfNum).Name));
4144 4 : ShowContinueError(state,
4145 4 : format("The vertex sizes are {} for base surface and {} for outside boundary surface. Please check inputs.",
4146 2 : state.dataSurfaceGeometry->SurfaceTmp(i).Vertex.size(),
4147 2 : state.dataSurfaceGeometry->SurfaceTmp(ExtSurfNum).Vertex.size()));
4148 2 : ErrorsFound = true;
4149 : }
4150 : }
4151 : }
4152 2170 : }
4153 :
4154 226 : void GetRectSurfaces(EnergyPlusData &state,
4155 : bool &ErrorsFound, // Error flag indicator (true if errors found)
4156 : int &SurfNum, // Count of Current SurfaceNumber
4157 : int const TotRectExtWalls, // Number of Exterior Walls to obtain
4158 : int const TotRectIntWalls, // Number of Adiabatic Walls to obtain
4159 : int const TotRectIZWalls, // Number of Interzone Walls to obtain
4160 : int const TotRectUGWalls, // Number of Underground to obtain
4161 : int const TotRectRoofs, // Number of Roofs to obtain
4162 : int const TotRectCeilings, // Number of Adiabatic Ceilings to obtain
4163 : int const TotRectIZCeilings, // Number of Interzone Ceilings to obtain
4164 : int const TotRectGCFloors, // Number of Floors with Ground Contact to obtain
4165 : int const TotRectIntFloors, // Number of Adiabatic Walls to obtain
4166 : int const TotRectIZFloors, // Number of Interzone Floors to obtain
4167 : const Array1D<SurfaceClass> &BaseSurfIDs, // ID Assignments for valid surface classes
4168 : int &NeedToAddSurfaces // Number of surfaces to add, based on unentered IZ surfaces
4169 : )
4170 : {
4171 :
4172 : // SUBROUTINE INFORMATION:
4173 : // AUTHOR Linda Lawrie
4174 : // DATE WRITTEN December 2008
4175 :
4176 : // PURPOSE OF THIS SUBROUTINE:
4177 : // Get simple (rectangular, LLC corner specified) walls
4178 :
4179 : // SUBROUTINE PARAMETER DEFINITIONS:
4180 : static Array1D_string const cModuleObjects(10,
4181 : {"Wall:Exterior",
4182 : "Wall:Adiabatic",
4183 : "Wall:Interzone",
4184 : "Wall:Underground",
4185 : "Roof",
4186 : "Ceiling:Adiabatic",
4187 : "Ceiling:Interzone",
4188 : "Floor:GroundContact",
4189 : "Floor:Adiabatic",
4190 226 : "Floor:Interzone"});
4191 :
4192 : int ItemsToGet;
4193 : int NumAlphas;
4194 : int NumNumbers;
4195 : int IOStat; // IO Status when calling get input subroutine
4196 : int Found; // For matching base surfaces
4197 : bool GettingIZSurfaces;
4198 : int OtherSurfaceField;
4199 : int ExtBoundCondition;
4200 : int ClassItem;
4201 : int ZoneNum;
4202 :
4203 226 : auto &s_ipsc = state.dataIPShortCut;
4204 :
4205 2486 : for (int Item = 1; Item <= 10; ++Item) {
4206 :
4207 2260 : s_ipsc->cCurrentModuleObject = cModuleObjects(Item);
4208 2260 : if (Item == 1) {
4209 226 : ItemsToGet = TotRectExtWalls;
4210 226 : GettingIZSurfaces = false;
4211 226 : OtherSurfaceField = 0;
4212 226 : ExtBoundCondition = DataSurfaces::ExternalEnvironment;
4213 226 : ClassItem = 1;
4214 2034 : } else if (Item == 2) {
4215 226 : ItemsToGet = TotRectIntWalls;
4216 226 : GettingIZSurfaces = false;
4217 226 : OtherSurfaceField = 0;
4218 226 : ExtBoundCondition = unreconciledZoneSurface;
4219 226 : ClassItem = 1;
4220 1808 : } else if (Item == 3) {
4221 226 : ItemsToGet = TotRectIZWalls;
4222 226 : GettingIZSurfaces = true;
4223 226 : OtherSurfaceField = 5;
4224 226 : ExtBoundCondition = unreconciledZoneSurface;
4225 226 : ClassItem = 1;
4226 1582 : } else if (Item == 4) {
4227 226 : ItemsToGet = TotRectUGWalls;
4228 226 : GettingIZSurfaces = false;
4229 226 : OtherSurfaceField = 0;
4230 226 : ExtBoundCondition = DataSurfaces::Ground;
4231 226 : ClassItem = 1;
4232 1356 : } else if (Item == 5) {
4233 226 : ItemsToGet = TotRectRoofs;
4234 226 : GettingIZSurfaces = false;
4235 226 : OtherSurfaceField = 0;
4236 226 : ExtBoundCondition = DataSurfaces::ExternalEnvironment;
4237 226 : ClassItem = 3;
4238 1130 : } else if (Item == 6) {
4239 226 : ItemsToGet = TotRectCeilings;
4240 226 : GettingIZSurfaces = false;
4241 226 : OtherSurfaceField = 0;
4242 226 : ExtBoundCondition = unreconciledZoneSurface;
4243 226 : ClassItem = 3;
4244 904 : } else if (Item == 7) {
4245 226 : ItemsToGet = TotRectIZCeilings;
4246 226 : GettingIZSurfaces = false;
4247 226 : OtherSurfaceField = 5;
4248 226 : ExtBoundCondition = unreconciledZoneSurface;
4249 226 : ClassItem = 3;
4250 678 : } else if (Item == 8) {
4251 226 : ItemsToGet = TotRectGCFloors;
4252 226 : GettingIZSurfaces = false;
4253 226 : OtherSurfaceField = 0;
4254 226 : ExtBoundCondition = DataSurfaces::Ground;
4255 226 : ClassItem = 2;
4256 452 : } else if (Item == 9) {
4257 226 : ItemsToGet = TotRectIntFloors;
4258 226 : GettingIZSurfaces = false;
4259 226 : OtherSurfaceField = 0;
4260 226 : ExtBoundCondition = unreconciledZoneSurface;
4261 226 : ClassItem = 2;
4262 : } else { // IF (Item == 10) THEN
4263 226 : ItemsToGet = TotRectIZFloors;
4264 226 : GettingIZSurfaces = true;
4265 226 : OtherSurfaceField = 5;
4266 226 : ExtBoundCondition = unreconciledZoneSurface;
4267 226 : ClassItem = 2;
4268 : }
4269 :
4270 2261 : for (int Loop = 1; Loop <= ItemsToGet; ++Loop) {
4271 2 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
4272 1 : s_ipsc->cCurrentModuleObject,
4273 : Loop,
4274 1 : s_ipsc->cAlphaArgs,
4275 : NumAlphas,
4276 1 : s_ipsc->rNumericArgs,
4277 : NumNumbers,
4278 : IOStat,
4279 1 : s_ipsc->lNumericFieldBlanks,
4280 1 : s_ipsc->lAlphaFieldBlanks,
4281 1 : s_ipsc->cAlphaFieldNames,
4282 1 : s_ipsc->cNumericFieldNames);
4283 :
4284 2 : if (GlobalNames::VerifyUniqueInterObjectName(state,
4285 1 : state.dataSurfaceGeometry->UniqueSurfaceNames,
4286 1 : s_ipsc->cAlphaArgs(1),
4287 1 : s_ipsc->cCurrentModuleObject,
4288 1 : s_ipsc->cAlphaFieldNames(1),
4289 : ErrorsFound)) {
4290 0 : continue;
4291 : }
4292 :
4293 1 : if (NumNumbers < 7) {
4294 0 : ShowSevereError(
4295 : state,
4296 0 : format("{}=\"{}\", Too few number of numeric args=[{}].", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1), NumNumbers));
4297 0 : ErrorsFound = true;
4298 : }
4299 :
4300 1 : ++SurfNum;
4301 :
4302 1 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
4303 1 : surfTemp.Name = s_ipsc->cAlphaArgs(1); // Set the Surface Name in the Derived Type
4304 1 : surfTemp.Class = BaseSurfIDs(ClassItem); // Set class number
4305 :
4306 1 : surfTemp.Construction =
4307 1 : Util::FindItemInList(s_ipsc->cAlphaArgs(2), state.dataConstruction->Construct, state.dataHeatBal->TotConstructs);
4308 :
4309 1 : if (surfTemp.Construction == 0) {
4310 0 : ErrorsFound = true;
4311 0 : ShowSevereError(state,
4312 0 : format("{}=\"{}\", invalid {}=\"{}\".",
4313 0 : s_ipsc->cCurrentModuleObject,
4314 0 : surfTemp.Name,
4315 0 : s_ipsc->cAlphaFieldNames(2),
4316 0 : s_ipsc->cAlphaArgs(2)));
4317 1 : } else if (state.dataConstruction->Construct(surfTemp.Construction).TypeIsWindow) {
4318 0 : ErrorsFound = true;
4319 0 : ShowSevereError(state,
4320 0 : format("{}=\"{}\", invalid {}=\"{}\" - has Window materials.",
4321 0 : s_ipsc->cCurrentModuleObject,
4322 0 : surfTemp.Name,
4323 0 : s_ipsc->cAlphaFieldNames(3),
4324 0 : s_ipsc->cAlphaArgs(2)));
4325 0 : ShowContinueError(state, format("...because {}={}", s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2)));
4326 : } else {
4327 1 : state.dataConstruction->Construct(surfTemp.Construction).IsUsed = true;
4328 1 : surfTemp.ConstructionStoredInputValue = surfTemp.Construction;
4329 : }
4330 1 : surfTemp.HeatTransSurf = true;
4331 1 : surfTemp.BaseSurf = SurfNum;
4332 1 : surfTemp.BaseSurfName = surfTemp.Name;
4333 :
4334 1 : surfTemp.ZoneName = s_ipsc->cAlphaArgs(3);
4335 1 : ZoneNum = Util::FindItemInList(surfTemp.ZoneName, state.dataHeatBal->Zone, state.dataGlobal->NumOfZones);
4336 :
4337 1 : if (ZoneNum != 0) {
4338 1 : surfTemp.Zone = ZoneNum;
4339 : } else {
4340 0 : ShowSevereError(state,
4341 0 : format("{}=\"{}\", invalid {}=\"{}\".",
4342 0 : s_ipsc->cCurrentModuleObject,
4343 0 : surfTemp.Name,
4344 0 : s_ipsc->cAlphaFieldNames(3),
4345 0 : s_ipsc->cAlphaArgs(3)));
4346 0 : surfTemp.Class = SurfaceClass::Invalid;
4347 0 : surfTemp.ZoneName = "Unknown Zone";
4348 0 : ErrorsFound = true;
4349 : }
4350 :
4351 1 : if (!s_ipsc->lAlphaFieldBlanks(4)) {
4352 0 : int spaceNum = Util::FindItemInList(s_ipsc->cAlphaArgs(4), state.dataHeatBal->space);
4353 :
4354 0 : if (spaceNum != 0) {
4355 0 : surfTemp.spaceNum = spaceNum;
4356 : } else {
4357 0 : ShowSevereError(state,
4358 0 : format("{}=\"{}\", invalid {}=\"{}\".",
4359 0 : s_ipsc->cCurrentModuleObject,
4360 0 : surfTemp.Name,
4361 0 : s_ipsc->cAlphaFieldNames(4),
4362 0 : s_ipsc->cAlphaArgs(4)));
4363 0 : surfTemp.Class = SurfaceClass::Invalid;
4364 0 : ErrorsFound = true;
4365 : }
4366 : }
4367 :
4368 1 : surfTemp.ExtBoundCond = ExtBoundCondition;
4369 1 : if (surfTemp.Construction > 0) {
4370 1 : if (surfTemp.Class == SurfaceClass::Wall && state.dataConstruction->Construct(surfTemp.Construction).TypeIsCfactorWall &&
4371 0 : surfTemp.ExtBoundCond == DataSurfaces::Ground) {
4372 0 : surfTemp.ExtBoundCond = DataSurfaces::GroundFCfactorMethod;
4373 1 : } else if (state.dataConstruction->Construct(surfTemp.Construction).TypeIsCfactorWall) {
4374 0 : ErrorsFound = true;
4375 0 : ShowSevereError(state,
4376 0 : format("{}=\"{}\", Construction type is \"Construction:CfactorUndergroundWall\" but invalid for this object.",
4377 0 : s_ipsc->cCurrentModuleObject,
4378 0 : surfTemp.Name));
4379 : }
4380 :
4381 1 : if (surfTemp.Class == SurfaceClass::Floor && state.dataConstruction->Construct(surfTemp.Construction).TypeIsFfactorFloor &&
4382 0 : surfTemp.ExtBoundCond == DataSurfaces::Ground) {
4383 0 : surfTemp.ExtBoundCond = DataSurfaces::GroundFCfactorMethod;
4384 1 : } else if (state.dataConstruction->Construct(surfTemp.Construction).TypeIsFfactorFloor) {
4385 0 : ErrorsFound = true;
4386 0 : ShowSevereError(state,
4387 0 : format("{}=\"{}\", Construction type is \"Construction:FfactorGroundFloor\" but invalid for this object.",
4388 0 : s_ipsc->cCurrentModuleObject,
4389 0 : surfTemp.Name));
4390 : }
4391 : }
4392 1 : surfTemp.ExtSolar = false;
4393 1 : surfTemp.ExtWind = false;
4394 1 : surfTemp.ViewFactorGround = Constant::AutoCalculate;
4395 :
4396 1 : if (surfTemp.ExtBoundCond == DataSurfaces::ExternalEnvironment) {
4397 0 : surfTemp.ExtSolar = true;
4398 0 : surfTemp.ExtWind = true;
4399 :
4400 : // Set the logical flag for the EcoRoof presented, this is only based on the flag in the construction type
4401 : // if (surfTemp.Construction > 0)
4402 : // surfTemp.ExtEcoRoof =
4403 : // state.dataConstruction->Construct(surfTemp.Construction).TypeIsEcoRoof;
4404 :
4405 1 : } else if (surfTemp.ExtBoundCond == unreconciledZoneSurface) {
4406 1 : if (GettingIZSurfaces) {
4407 0 : surfTemp.ExtBoundCondName = s_ipsc->cAlphaArgs(OtherSurfaceField);
4408 0 : Found = Util::FindItemInList(surfTemp.ExtBoundCondName, state.dataHeatBal->Zone, state.dataGlobal->NumOfZones);
4409 : // see if match to zone, then it's an unentered other surface, else reconciled later
4410 0 : if (Found > 0) {
4411 0 : ++NeedToAddSurfaces;
4412 0 : surfTemp.ExtBoundCond = unenteredAdjacentZoneSurface;
4413 : }
4414 : } else {
4415 1 : surfTemp.ExtBoundCondName = surfTemp.Name;
4416 : }
4417 :
4418 0 : } else if (surfTemp.ExtBoundCond == DataSurfaces::Ground) {
4419 0 : if (state.dataSurfaceGeometry->NoGroundTempObjWarning) {
4420 0 : if (!state.dataEnvrn->GroundTempInputs[(int)DataEnvironment::GroundTempType::BuildingSurface]) {
4421 0 : ShowWarningError(state,
4422 : "GetRectSurfaces: Surfaces with interface to Ground found but no \"Ground Temperatures\" were input.");
4423 0 : ShowContinueError(state, format("Found first in surface={}", s_ipsc->cAlphaArgs(1)));
4424 0 : ShowContinueError(state,
4425 0 : format("Defaults, constant throughout the year of ({:.1R}) will be used.",
4426 0 : state.dataEnvrn->GroundTemp[(int)DataEnvironment::GroundTempType::BuildingSurface]));
4427 : }
4428 0 : state.dataSurfaceGeometry->NoGroundTempObjWarning = false;
4429 : }
4430 :
4431 0 : } else if (surfTemp.ExtBoundCond == DataSurfaces::GroundFCfactorMethod) {
4432 0 : if (state.dataSurfaceGeometry->NoFCGroundTempObjWarning) {
4433 0 : if (!state.dataEnvrn->GroundTempInputs[(int)DataEnvironment::GroundTempType::FCFactorMethod]) {
4434 0 : ShowSevereError(state,
4435 : "GetRectSurfaces: Surfaces with interface to GroundFCfactorMethod found but no \"FC Ground "
4436 : "Temperatures\" were input.");
4437 0 : ShowContinueError(state, format("Found first in surface={}", s_ipsc->cAlphaArgs(1)));
4438 0 : ShowContinueError(state,
4439 : "Either add a \"Site:GroundTemperature:FCfactorMethod\" object or use a weather file with "
4440 : "Ground Temperatures.");
4441 0 : ErrorsFound = true;
4442 0 : state.dataSurfaceGeometry->NoFCGroundTempObjWarning = false;
4443 : }
4444 : }
4445 :
4446 : } // ... End of the ExtBoundCond logical IF Block
4447 :
4448 1 : surfTemp.Azimuth = s_ipsc->rNumericArgs(1);
4449 1 : surfTemp.Tilt = s_ipsc->rNumericArgs(2);
4450 1 : surfTemp.convOrientation = Convect::GetSurfConvOrientation(surfTemp.Tilt);
4451 1 : if (!state.dataSurface->WorldCoordSystem) {
4452 1 : if (ZoneNum != 0) {
4453 1 : surfTemp.Azimuth += state.dataHeatBal->BuildingAzimuth + state.dataHeatBal->Zone(ZoneNum).RelNorth;
4454 : }
4455 : }
4456 1 : if (ZoneNum != 0) {
4457 1 : surfTemp.Azimuth += state.dataHeatBal->BuildingRotationAppendixG;
4458 : }
4459 :
4460 1 : surfTemp.Sides = 4;
4461 1 : surfTemp.Vertex.allocate(surfTemp.Sides);
4462 :
4463 6 : MakeRectangularVertices(state,
4464 : SurfNum,
4465 1 : s_ipsc->rNumericArgs(3),
4466 1 : s_ipsc->rNumericArgs(4),
4467 1 : s_ipsc->rNumericArgs(5),
4468 1 : s_ipsc->rNumericArgs(6),
4469 1 : s_ipsc->rNumericArgs(7),
4470 1 : state.dataSurfaceGeometry->RectSurfRefWorldCoordSystem);
4471 :
4472 1 : if (surfTemp.Area <= 0.0) {
4473 0 : ShowSevereError(
4474 : state,
4475 0 : format("{}=\"{}\", Surface Area <= 0.0; Entered Area={:.2T}", s_ipsc->cCurrentModuleObject, surfTemp.Name, surfTemp.Area));
4476 0 : ErrorsFound = true;
4477 : }
4478 :
4479 : // Check wall height for the CFactor walls
4480 1 : if (surfTemp.Class == SurfaceClass::Wall && surfTemp.ExtBoundCond == DataSurfaces::GroundFCfactorMethod) {
4481 0 : if (std::abs(surfTemp.Height - state.dataConstruction->Construct(surfTemp.Construction).Height) > 0.05) {
4482 0 : ShowWarningError(
4483 : state,
4484 0 : format("{}=\"{}\", underground Wall Height = {:.2T}", s_ipsc->cCurrentModuleObject, surfTemp.Name, surfTemp.Height));
4485 0 : ShowContinueError(state, "..which deos not match its construction height.");
4486 : }
4487 : }
4488 :
4489 : // Check area and perimeter for the FFactor floors
4490 1 : if (surfTemp.Class == SurfaceClass::Floor && surfTemp.ExtBoundCond == DataSurfaces::GroundFCfactorMethod) {
4491 0 : if (std::abs(surfTemp.Area - state.dataConstruction->Construct(surfTemp.Construction).Area) > 0.1) {
4492 0 : ShowWarningError(
4493 0 : state, format("{}=\"{}\", underground Floor Area = {:.2T}", s_ipsc->cCurrentModuleObject, surfTemp.Name, surfTemp.Area));
4494 0 : ShowContinueError(state, "..which does not match its construction area.");
4495 : }
4496 0 : if (surfTemp.Perimeter < state.dataConstruction->Construct(surfTemp.Construction).PerimeterExposed - 0.1) {
4497 0 : ShowWarningError(
4498 : state,
4499 0 : format(
4500 0 : "{}=\"{}\", underground Floor Perimeter = {:.2T}", s_ipsc->cCurrentModuleObject, surfTemp.Name, surfTemp.Perimeter));
4501 0 : ShowContinueError(state, "..which is less than its construction exposed perimeter.");
4502 : }
4503 : }
4504 : } // Getting Items
4505 : }
4506 226 : }
4507 :
4508 7 : void MakeRectangularVertices(EnergyPlusData &state,
4509 : int const SurfNum,
4510 : Real64 const XCoord,
4511 : Real64 const YCoord,
4512 : Real64 const ZCoord,
4513 : Real64 const Length,
4514 : Real64 const Height,
4515 : bool const SurfWorldCoordSystem)
4516 : {
4517 :
4518 : // SUBROUTINE INFORMATION:
4519 : // AUTHOR Linda Lawrie
4520 : // DATE WRITTEN December 2008
4521 :
4522 : // PURPOSE OF THIS SUBROUTINE:
4523 : // This routine creates world/3d coordinates for rectangular surfaces using azimuth, tilt, LLC (X,Y,Z), length & height.
4524 :
4525 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
4526 : Real64 XLLC;
4527 : Real64 YLLC;
4528 : Real64 ZLLC;
4529 7 : Array1D<Real64> XX(4);
4530 7 : Array1D<Real64> YY(4);
4531 : Real64 Xb;
4532 : Real64 Yb;
4533 : Real64 Perimeter;
4534 : int Vrt;
4535 :
4536 7 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
4537 :
4538 7 : if (surfTemp.Zone == 0 && (surfTemp.Class != SurfaceClass::Detached_F && surfTemp.Class != SurfaceClass::Detached_B)) return;
4539 :
4540 7 : surfTemp.Height = Height;
4541 7 : surfTemp.Width = Length;
4542 :
4543 7 : Real64 SurfAzimuth = surfTemp.Azimuth;
4544 7 : Real64 SurfTilt = surfTemp.Tilt;
4545 7 : Real64 CosSurfAzimuth = std::cos(SurfAzimuth * Constant::DegToRad);
4546 7 : Real64 SinSurfAzimuth = std::sin(SurfAzimuth * Constant::DegToRad);
4547 7 : Real64 CosSurfTilt = std::cos(SurfTilt * Constant::DegToRad);
4548 7 : Real64 SinSurfTilt = std::sin(SurfTilt * Constant::DegToRad);
4549 :
4550 7 : if (!SurfWorldCoordSystem) {
4551 7 : if (surfTemp.Zone > 0) {
4552 5 : Xb = XCoord * state.dataSurfaceGeometry->CosZoneRelNorth(surfTemp.Zone) -
4553 5 : YCoord * state.dataSurfaceGeometry->SinZoneRelNorth(surfTemp.Zone) + state.dataHeatBal->Zone(surfTemp.Zone).OriginX;
4554 5 : Yb = XCoord * state.dataSurfaceGeometry->SinZoneRelNorth(surfTemp.Zone) +
4555 5 : YCoord * state.dataSurfaceGeometry->CosZoneRelNorth(surfTemp.Zone) + state.dataHeatBal->Zone(surfTemp.Zone).OriginY;
4556 5 : XLLC = Xb * state.dataSurfaceGeometry->CosBldgRelNorth - Yb * state.dataSurfaceGeometry->SinBldgRelNorth;
4557 5 : YLLC = Xb * state.dataSurfaceGeometry->SinBldgRelNorth + Yb * state.dataSurfaceGeometry->CosBldgRelNorth;
4558 5 : ZLLC = ZCoord + state.dataHeatBal->Zone(surfTemp.Zone).OriginZ;
4559 : } else {
4560 2 : if (surfTemp.Class == SurfaceClass::Detached_B) {
4561 1 : Xb = XCoord;
4562 1 : Yb = YCoord;
4563 1 : XLLC = Xb * state.dataSurfaceGeometry->CosBldgRelNorth - Yb * state.dataSurfaceGeometry->SinBldgRelNorth;
4564 1 : YLLC = Xb * state.dataSurfaceGeometry->SinBldgRelNorth + Yb * state.dataSurfaceGeometry->CosBldgRelNorth;
4565 1 : ZLLC = ZCoord;
4566 : } else {
4567 1 : XLLC = XCoord;
4568 1 : YLLC = YCoord;
4569 1 : ZLLC = ZCoord;
4570 : }
4571 : }
4572 : } else {
4573 : // for world coordinates, only rotate for appendix G
4574 0 : Xb = XCoord;
4575 0 : Yb = YCoord;
4576 0 : ZLLC = ZCoord;
4577 0 : if (surfTemp.Class != SurfaceClass::Detached_F) {
4578 0 : XLLC = Xb * state.dataSurfaceGeometry->CosBldgRotAppGonly - Yb * state.dataSurfaceGeometry->SinBldgRotAppGonly;
4579 0 : YLLC = Xb * state.dataSurfaceGeometry->SinBldgRotAppGonly + Yb * state.dataSurfaceGeometry->CosBldgRotAppGonly;
4580 : } else {
4581 0 : XLLC = Xb;
4582 0 : YLLC = Yb;
4583 : }
4584 : }
4585 :
4586 7 : XX(1) = 0.0;
4587 7 : XX(2) = 0.0;
4588 7 : XX(3) = Length;
4589 7 : XX(4) = Length;
4590 7 : YY(1) = Height;
4591 7 : YY(4) = Height;
4592 7 : YY(3) = 0.0;
4593 7 : YY(2) = 0.0;
4594 :
4595 35 : for (int n = 1; n <= surfTemp.Sides; ++n) {
4596 28 : Vrt = n;
4597 28 : surfTemp.Vertex(Vrt).x = XLLC - XX(n) * CosSurfAzimuth - YY(n) * CosSurfTilt * SinSurfAzimuth;
4598 28 : surfTemp.Vertex(Vrt).y = YLLC + XX(n) * SinSurfAzimuth - YY(n) * CosSurfTilt * CosSurfAzimuth;
4599 28 : surfTemp.Vertex(Vrt).z = ZLLC + YY(n) * SinSurfTilt;
4600 : }
4601 :
4602 7 : Vectors::CreateNewellAreaVector(surfTemp.Vertex, surfTemp.Sides, surfTemp.NewellAreaVector);
4603 7 : surfTemp.GrossArea = Vectors::VecLength(surfTemp.NewellAreaVector);
4604 7 : surfTemp.Area = surfTemp.GrossArea;
4605 7 : surfTemp.NetAreaShadowCalc = surfTemp.Area;
4606 7 : Vectors::CreateNewellSurfaceNormalVector(surfTemp.Vertex, surfTemp.Sides, surfTemp.NewellSurfaceNormalVector);
4607 7 : Vectors::DetermineAzimuthAndTilt(
4608 7 : surfTemp.Vertex, SurfAzimuth, SurfTilt, surfTemp.lcsx, surfTemp.lcsy, surfTemp.lcsz, surfTemp.NewellSurfaceNormalVector);
4609 7 : surfTemp.Azimuth = SurfAzimuth;
4610 7 : surfTemp.Tilt = SurfTilt;
4611 7 : surfTemp.convOrientation = Convect::GetSurfConvOrientation(surfTemp.Tilt);
4612 : // Sine and cosine of azimuth and tilt
4613 7 : surfTemp.SinAzim = SinSurfAzimuth;
4614 7 : surfTemp.CosAzim = CosSurfAzimuth;
4615 7 : surfTemp.SinTilt = SinSurfTilt;
4616 7 : surfTemp.CosTilt = CosSurfTilt;
4617 7 : surfTemp.ViewFactorGround = 0.5 * (1.0 - surfTemp.CosTilt);
4618 : // Outward normal unit vector (pointing away from room)
4619 :
4620 7 : surfTemp.OutNormVec = surfTemp.NewellSurfaceNormalVector;
4621 28 : for (int n = 1; n <= 3; ++n) {
4622 21 : if (std::abs(surfTemp.OutNormVec(n) - 1.0) < 1.e-06) surfTemp.OutNormVec(n) = +1.0;
4623 21 : if (std::abs(surfTemp.OutNormVec(n) + 1.0) < 1.e-06) surfTemp.OutNormVec(n) = -1.0;
4624 21 : if (std::abs(surfTemp.OutNormVec(n)) < 1.e-06) surfTemp.OutNormVec(n) = 0.0;
4625 : }
4626 :
4627 : // Can perform tests on this surface here
4628 7 : surfTemp.ViewFactorSky = 0.5 * (1.0 + surfTemp.CosTilt);
4629 : // The following IR view factors are modified in subr. SkyDifSolarShading if there are shadowing
4630 : // surfaces
4631 7 : surfTemp.ViewFactorSkyIR = surfTemp.ViewFactorSky;
4632 7 : surfTemp.ViewFactorGroundIR = 0.5 * (1.0 - surfTemp.CosTilt);
4633 :
4634 7 : Perimeter = distance(surfTemp.Vertex(surfTemp.Sides), surfTemp.Vertex(1));
4635 28 : for (Vrt = 2; Vrt <= surfTemp.Sides; ++Vrt) {
4636 21 : Perimeter += distance(surfTemp.Vertex(Vrt), surfTemp.Vertex(Vrt - 1));
4637 : }
4638 7 : surfTemp.Perimeter = Perimeter;
4639 :
4640 : // Call to transform vertices
4641 :
4642 7 : TransformVertsByAspect(state, SurfNum, surfTemp.Sides);
4643 7 : }
4644 :
4645 226 : void GetHTSubSurfaceData(EnergyPlusData &state,
4646 : bool &ErrorsFound, // Error flag indicator (true if errors found)
4647 : int &SurfNum, // Count of Current SurfaceNumber
4648 : int const TotHTSubs, // Number of Heat Transfer SubSurfaces to obtain
4649 : const Array1D_string &SubSurfCls, // Valid Classes for Sub Surfaces
4650 : const Array1D<SurfaceClass> &SubSurfIDs, // ID Assignments for valid sub surface classes
4651 : int &AddedSubSurfaces, // Subsurfaces added when windows reference Window5
4652 : int &NeedToAddSurfaces // Number of surfaces to add, based on unentered IZ surfaces
4653 : )
4654 : {
4655 :
4656 : // SUBROUTINE INFORMATION:
4657 : // AUTHOR Linda Lawrie
4658 : // DATE WRITTEN May 2000
4659 : // MODIFIED August 2012 - line up subsurfaces with base surface types
4660 :
4661 : // PURPOSE OF THIS SUBROUTINE:
4662 : // This subroutine gets the HeatTransfer Sub Surface Data, checks it for errors, etc.
4663 :
4664 : // REFERENCES:
4665 : // Heat Transfer Subsurface Definition
4666 : // FenestrationSurface:Detailed,
4667 : // \min-fields 19
4668 : // \memo Used for windows, doors, glass doors, tubular daylighting devices
4669 : // \format vertices
4670 : // A1 , \field Name
4671 : // \required-field
4672 : // \type alpha
4673 : // A2 , \field Surface Type
4674 : // \required-field
4675 : // \type choice
4676 : // \key Window
4677 : // \key Door
4678 : // \key GlassDoor
4679 : // \key TubularDaylightDome
4680 : // \key TubularDaylightDiffuser
4681 : // A3 , \field Construction Name
4682 : // \required-field
4683 : // \note To be matched with a construction in this input file
4684 : // \type object-list
4685 : // \object-list ConstructionNames
4686 : // A4 , \field Building Surface Name
4687 : // \required-field
4688 : // \type object-list
4689 : // \object-list SurfaceNames
4690 : // A5, \field Outside Boundary Condition Object
4691 : // \type object-list
4692 : // \object-list OutFaceEnvNames
4693 : // \note Non-blank only if base surface field Outside Boundary Condition is
4694 : // \note Surface or OtherSideCoefficients
4695 : // \note If Base Surface's Surface, specify name of corresponding subsurface in adjacent zone or
4696 : // \note specify current subsurface name for internal partition separating like zones
4697 : // \note If OtherSideCoefficients, specify name of SurfaceProperty:OtherSideCoefficients
4698 : // \note or leave blank to inherit Base Surface's OtherSide Coefficients
4699 : // N1, \field View Factor to Ground
4700 : // \type real
4701 : // \note From the exterior of the surface
4702 : // \note Unused if one uses the "reflections" options in Solar Distribution in Building input
4703 : // \note unless a DaylightingDevice:Shelf or DaylightingDevice:Tubular object has been specified.
4704 : // \note autocalculate will automatically calculate this value from the tilt of the surface
4705 : // \autocalculatable
4706 : // \minimum 0.0
4707 : // \maximum 1.0
4708 : // \default autocalculate
4709 : // A6, \field Frame and Divider Name
4710 : // \note Enter the name of a WindowProperty:FrameAndDivider object
4711 : // \type object-list
4712 : // \object-list WindowFrameAndDividerNames
4713 : // \note Used only for exterior windows (rectangular) and glass doors.
4714 : // \note Unused for triangular windows.
4715 : // \note If not specified (blank), window or glass door has no frame or divider
4716 : // \note and no beam solar reflection from reveal surfaces.
4717 : // N2 , \field Multiplier
4718 : // \note Used only for Surface Type = WINDOW, GLASSDOOR or DOOR
4719 : // \note Non-integer values will be truncated to integer
4720 : // \default 1.0
4721 : // \minimum 1.0
4722 : // N3 , \field Number of Vertices
4723 : // \minimum 3
4724 : // \maximum 4
4725 : // \autocalculatable
4726 : // \default autocalculate
4727 : // \note vertices are given in GlobalGeometryRules coordinates -- if relative, all surface coordinates
4728 : // \note are "relative" to the Zone Origin. If world, then building and zone origins are used
4729 : // \note for some internal calculations, but all coordinates are given in an "absolute" system.
4730 : // N4-15 as indicated by the N3 value
4731 :
4732 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
4733 : int IOStat; // IO Status when calling get input subroutine
4734 : int SurfaceNumAlpha; // Number of material alpha names being passed
4735 : int SurfaceNumProp; // Number of material properties being passed
4736 : int Found; // For matching interzone surfaces
4737 : int Loop;
4738 : int ValidChk;
4739 : int numSides;
4740 :
4741 226 : auto &s_ipsc = state.dataIPShortCut;
4742 :
4743 226 : GetWindowShadingControlData(state, ErrorsFound);
4744 226 : s_ipsc->cCurrentModuleObject = "FenestrationSurface:Detailed";
4745 226 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, s_ipsc->cCurrentModuleObject, Loop, SurfaceNumAlpha, SurfaceNumProp);
4746 :
4747 226 : if (SurfaceNumAlpha != 6) {
4748 0 : ShowSevereError(
4749 : state,
4750 0 : format("{}: Object Definition indicates not = 6 Alpha Objects, Number Indicated={}", s_ipsc->cCurrentModuleObject, SurfaceNumAlpha));
4751 0 : ErrorsFound = true;
4752 : }
4753 :
4754 226 : if (SurfaceNumProp != 15) {
4755 0 : ShowSevereError(
4756 : state,
4757 0 : format("{}: Object Definition indicates > 15 Numeric Objects, Number Indicated={}", s_ipsc->cCurrentModuleObject, SurfaceNumAlpha));
4758 0 : ErrorsFound = true;
4759 : }
4760 226 : NeedToAddSurfaces = 0;
4761 :
4762 441 : for (Loop = 1; Loop <= TotHTSubs; ++Loop) {
4763 430 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
4764 215 : s_ipsc->cCurrentModuleObject,
4765 : Loop,
4766 215 : s_ipsc->cAlphaArgs,
4767 : SurfaceNumAlpha,
4768 215 : s_ipsc->rNumericArgs,
4769 : SurfaceNumProp,
4770 : IOStat,
4771 215 : s_ipsc->lNumericFieldBlanks,
4772 215 : s_ipsc->lAlphaFieldBlanks,
4773 215 : s_ipsc->cAlphaFieldNames,
4774 215 : s_ipsc->cNumericFieldNames);
4775 :
4776 430 : if (GlobalNames::VerifyUniqueInterObjectName(state,
4777 215 : state.dataSurfaceGeometry->UniqueSurfaceNames,
4778 215 : s_ipsc->cAlphaArgs(1),
4779 215 : s_ipsc->cCurrentModuleObject,
4780 215 : s_ipsc->cAlphaFieldNames(1),
4781 : ErrorsFound)) {
4782 0 : continue;
4783 : }
4784 :
4785 215 : ++SurfNum;
4786 :
4787 215 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
4788 :
4789 215 : if (SurfaceNumProp < 12) {
4790 0 : ShowSevereError(
4791 0 : state, format("{}=\"{}\", Too few number of numeric args=[{}].", s_ipsc->cCurrentModuleObject, surfTemp.Name, SurfaceNumProp));
4792 0 : ErrorsFound = true;
4793 : }
4794 :
4795 215 : surfTemp.Name = s_ipsc->cAlphaArgs(1); // Set the Surface Name in the Derived Type
4796 215 : ValidChk = Util::FindItemInList(s_ipsc->cAlphaArgs(2), SubSurfCls, 6);
4797 215 : if (ValidChk == 0) {
4798 0 : ShowSevereError(state,
4799 0 : format("{}=\"{}\", invalid {}=\"{}",
4800 0 : s_ipsc->cCurrentModuleObject,
4801 0 : surfTemp.Name,
4802 0 : s_ipsc->cAlphaFieldNames(2),
4803 0 : s_ipsc->cAlphaArgs(2)));
4804 0 : ErrorsFound = true;
4805 : } else {
4806 215 : surfTemp.Class = SubSurfIDs(ValidChk); // Set class number
4807 : }
4808 :
4809 215 : surfTemp.Construction = Util::FindItemInList(s_ipsc->cAlphaArgs(3), state.dataConstruction->Construct, state.dataHeatBal->TotConstructs);
4810 :
4811 215 : if (surfTemp.Construction == 0) {
4812 2 : ShowSevereError(state,
4813 4 : format("{}=\"{}\", invalid {}=\"{}\".",
4814 1 : s_ipsc->cCurrentModuleObject,
4815 1 : surfTemp.Name,
4816 1 : s_ipsc->cAlphaFieldNames(3),
4817 1 : s_ipsc->cAlphaArgs(3)));
4818 1 : ErrorsFound = true;
4819 1 : continue;
4820 : } else {
4821 214 : state.dataConstruction->Construct(surfTemp.Construction).IsUsed = true;
4822 214 : surfTemp.ConstructionStoredInputValue = surfTemp.Construction;
4823 : }
4824 :
4825 214 : if (surfTemp.Class == SurfaceClass::Window || surfTemp.Class == SurfaceClass::GlassDoor || surfTemp.Class == SurfaceClass::TDD_Diffuser ||
4826 26 : surfTemp.Class == SurfaceClass::TDD_Dome) {
4827 :
4828 195 : if (surfTemp.Construction != 0) {
4829 195 : auto const &construction = state.dataConstruction->Construct(surfTemp.Construction);
4830 195 : if (!construction.TypeIsWindow && !construction.TypeIsAirBoundary) {
4831 0 : ErrorsFound = true;
4832 0 : ShowSevereError(state,
4833 0 : format("{}=\"{}\" has an opaque surface construction; it should have a window construction.",
4834 0 : s_ipsc->cCurrentModuleObject,
4835 0 : surfTemp.Name));
4836 : }
4837 195 : if (state.dataConstruction->Construct(surfTemp.Construction).SourceSinkPresent) {
4838 0 : ErrorsFound = true;
4839 0 : ShowSevereError(
4840 : state,
4841 0 : format("{}=\"{}\": Windows are not allowed to have embedded sources/sinks", s_ipsc->cCurrentModuleObject, surfTemp.Name));
4842 : }
4843 : }
4844 :
4845 214 : } else if (surfTemp.Construction != 0) {
4846 19 : if (state.dataConstruction->Construct(surfTemp.Construction).TypeIsWindow) {
4847 0 : ErrorsFound = true;
4848 0 : ShowSevereError(state,
4849 0 : format("{}=\"{}\", invalid {}=\"{}\" - has Window materials.",
4850 0 : s_ipsc->cCurrentModuleObject,
4851 0 : surfTemp.Name,
4852 0 : s_ipsc->cAlphaFieldNames(3),
4853 0 : s_ipsc->cAlphaArgs(3)));
4854 0 : ShowContinueError(state, format("...because {}={}", s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2)));
4855 : }
4856 : }
4857 :
4858 214 : surfTemp.HeatTransSurf = true;
4859 :
4860 214 : surfTemp.BaseSurfName = s_ipsc->cAlphaArgs(4);
4861 : // The subsurface inherits properties from the base surface
4862 : // Exterior conditions, Zone, etc.
4863 : // We can figure out the base surface though, because they've all been entered
4864 214 : Found = Util::FindItemInList(surfTemp.BaseSurfName, state.dataSurfaceGeometry->SurfaceTmp, state.dataSurface->TotSurfaces);
4865 214 : if (Found > 0) {
4866 214 : surfTemp.BaseSurf = Found;
4867 214 : surfTemp.ExtBoundCond = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCond;
4868 214 : surfTemp.ExtBoundCondName = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCondName;
4869 214 : surfTemp.ExtSolar = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtSolar;
4870 214 : surfTemp.ExtWind = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtWind;
4871 214 : surfTemp.Zone = state.dataSurfaceGeometry->SurfaceTmp(Found).Zone;
4872 214 : surfTemp.ZoneName = state.dataSurfaceGeometry->SurfaceTmp(Found).ZoneName;
4873 214 : surfTemp.OSCPtr = state.dataSurfaceGeometry->SurfaceTmp(Found).OSCPtr;
4874 234 : if (state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCond == unreconciledZoneSurface &&
4875 20 : state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCondName ==
4876 20 : state.dataSurfaceGeometry->SurfaceTmp(Found).Name) { // Adiabatic surface, no windows or doors allowed
4877 0 : ShowSevereError(state,
4878 0 : format("{}=\"{}\", invalid {}=\"{}\".",
4879 0 : s_ipsc->cCurrentModuleObject,
4880 0 : surfTemp.Name,
4881 0 : s_ipsc->cAlphaFieldNames(4),
4882 0 : s_ipsc->cAlphaArgs(4)));
4883 0 : ShowContinueError(state, "... adiabatic surfaces cannot have windows or doors.");
4884 0 : ShowContinueError(state,
4885 : "... no solar transmission will result for these windows or doors. You must have interior windows or doors on "
4886 : "Interzone surfaces for transmission to result.");
4887 : }
4888 : } else {
4889 0 : ShowSevereError(state,
4890 0 : format("{}=\"{}\", invalid {}=\"{}",
4891 0 : s_ipsc->cCurrentModuleObject,
4892 0 : surfTemp.Name,
4893 0 : s_ipsc->cAlphaFieldNames(4),
4894 0 : s_ipsc->cAlphaArgs(4)));
4895 0 : surfTemp.ZoneName = "Unknown Zone";
4896 0 : ErrorsFound = true;
4897 : }
4898 214 : if (surfTemp.Class == SurfaceClass::TDD_Dome || surfTemp.Class == SurfaceClass::TDD_Diffuser) {
4899 13 : surfTemp.ExtBoundCond = DataSurfaces::ExternalEnvironment;
4900 : }
4901 :
4902 214 : if (surfTemp.ExtBoundCond == DataSurfaces::ExternalEnvironment) {
4903 194 : if (!s_ipsc->lAlphaFieldBlanks(5)) {
4904 0 : ShowWarningError(state,
4905 0 : format("{}=\"{}\", invalid field {}", s_ipsc->cCurrentModuleObject, surfTemp.Name, s_ipsc->cAlphaFieldNames(5)));
4906 0 : ShowContinueError(
4907 : state,
4908 0 : format("...when Base surface uses \"Outdoors\" as {}, subsurfaces need to be blank to inherit the outdoor characteristics.",
4909 0 : s_ipsc->cAlphaFieldNames(5)));
4910 0 : ShowContinueError(state, "...Surface external characteristics changed to reflect base surface.");
4911 : }
4912 : }
4913 :
4914 214 : if (surfTemp.ExtBoundCond == unreconciledZoneSurface) { // "Surface" Base Surface
4915 14 : if (!s_ipsc->lAlphaFieldBlanks(5)) {
4916 14 : surfTemp.ExtBoundCondName = s_ipsc->cAlphaArgs(5);
4917 : } else {
4918 0 : ShowSevereError(state,
4919 0 : format("{}=\"{}\", invalid blank {}", s_ipsc->cCurrentModuleObject, surfTemp.Name, s_ipsc->cAlphaFieldNames(5)));
4920 0 : ShowContinueError(
4921 : state,
4922 0 : format("...when Base surface uses \"Surface\" as {}, subsurfaces must also specify specific surfaces in the adjacent zone.",
4923 0 : s_ipsc->cAlphaFieldNames(5)));
4924 0 : surfTemp.ExtBoundCondName = s_ipsc->cAlphaArgs(5); // putting it as blank will not confuse things later.
4925 0 : ErrorsFound = true;
4926 : }
4927 : }
4928 :
4929 214 : if ((surfTemp.ExtBoundCond == unenteredAdjacentZoneSurface) ||
4930 210 : (surfTemp.ExtBoundCond == unenteredAdjacentSpaceSurface)) { // "Zone" - unmatched interior surface
4931 6 : ++NeedToAddSurfaces;
4932 : // ignoring window5datafiles for now -- will need to add.
4933 : }
4934 :
4935 214 : if (surfTemp.ExtBoundCond == DataSurfaces::OtherSideCoefNoCalcExt || surfTemp.ExtBoundCond == DataSurfaces::OtherSideCoefCalcExt) {
4936 0 : if (!s_ipsc->lAlphaFieldBlanks(5)) { // Otherside Coef special Name
4937 0 : Found = Util::FindItemInList(s_ipsc->cAlphaArgs(5), state.dataSurface->OSC, state.dataSurface->TotOSC);
4938 0 : if (Found == 0) {
4939 0 : ShowSevereError(state,
4940 0 : format("{}=\"{}\", invalid {}=\"{}\".",
4941 0 : s_ipsc->cCurrentModuleObject,
4942 0 : surfTemp.Name,
4943 0 : s_ipsc->cAlphaFieldNames(5),
4944 0 : s_ipsc->cAlphaArgs(5)));
4945 0 : ShowContinueError(state, "...base surface requires that this subsurface have OtherSideCoefficients -- not found.");
4946 0 : ErrorsFound = true;
4947 : } else { // found
4948 : // The following allows for a subsurface that has different characteristics than
4949 : // the base surface with OtherSide Coeff -- do we want that or is it an error?
4950 0 : surfTemp.OSCPtr = Found;
4951 0 : surfTemp.ExtBoundCondName = s_ipsc->cAlphaArgs(5);
4952 0 : if (state.dataSurface->OSC(Found).SurfFilmCoef > 0.0) {
4953 0 : surfTemp.ExtBoundCond = DataSurfaces::OtherSideCoefCalcExt;
4954 : } else {
4955 0 : surfTemp.ExtBoundCond = DataSurfaces::OtherSideCoefNoCalcExt;
4956 : }
4957 : }
4958 : }
4959 : }
4960 :
4961 214 : if (surfTemp.ExtBoundCond == DataSurfaces::OtherSideCondModeledExt) {
4962 0 : surfTemp.ExtBoundCond = DataSurfaces::ExternalEnvironment;
4963 : }
4964 :
4965 214 : if (surfTemp.ExtBoundCondName == BlankString) {
4966 188 : surfTemp.ExtBoundCondName = surfTemp.Name;
4967 : }
4968 214 : surfTemp.ViewFactorGround = s_ipsc->rNumericArgs(1);
4969 214 : if (s_ipsc->lNumericFieldBlanks(1)) surfTemp.ViewFactorGround = Constant::AutoCalculate;
4970 :
4971 214 : if (s_ipsc->lNumericFieldBlanks(3) || s_ipsc->rNumericArgs(3) == Constant::AutoCalculate) {
4972 14 : s_ipsc->rNumericArgs(3) = (SurfaceNumProp - 3) / 3;
4973 14 : surfTemp.Sides = s_ipsc->rNumericArgs(3);
4974 14 : if (mod(SurfaceNumProp - 3, 3) != 0) {
4975 0 : ShowWarningError(state,
4976 0 : format("{}=\"{}\", {}",
4977 0 : s_ipsc->cCurrentModuleObject,
4978 0 : surfTemp.Name,
4979 0 : format("{} not even multiple of 3. Will read in {}", s_ipsc->cNumericFieldNames(3), surfTemp.Sides)));
4980 : }
4981 14 : if (s_ipsc->rNumericArgs(3) < 3) {
4982 0 : ShowSevereError(state,
4983 0 : format("{}=\"{}\", {} (autocalculate) must be >= 3. Only {} provided.",
4984 0 : s_ipsc->cCurrentModuleObject,
4985 0 : surfTemp.Name,
4986 0 : s_ipsc->cNumericFieldNames(3),
4987 0 : surfTemp.Sides));
4988 0 : ErrorsFound = true;
4989 0 : continue;
4990 : }
4991 : } else {
4992 200 : numSides = (SurfaceNumProp - 2) / 3;
4993 200 : surfTemp.Sides = s_ipsc->rNumericArgs(3);
4994 200 : if (numSides > surfTemp.Sides) {
4995 0 : ShowWarningError(state,
4996 0 : format("{}=\"{}\", field {}={}",
4997 0 : s_ipsc->cCurrentModuleObject,
4998 0 : surfTemp.Name,
4999 0 : s_ipsc->cNumericFieldNames(3),
5000 0 : fmt::to_string(surfTemp.Sides)));
5001 0 : ShowContinueError(state,
5002 0 : format("...but {} were entered. Only the indicated {} will be used.", numSides, s_ipsc->cNumericFieldNames(3)));
5003 : }
5004 : }
5005 214 : surfTemp.Vertex.allocate(surfTemp.Sides);
5006 214 : if (surfTemp.Class == SurfaceClass::Window || surfTemp.Class == SurfaceClass::GlassDoor || surfTemp.Class == SurfaceClass::Door)
5007 201 : surfTemp.Multiplier = int(s_ipsc->rNumericArgs(2));
5008 : // Only windows, glass doors and doors can have Multiplier > 1:
5009 227 : if ((surfTemp.Class != SurfaceClass::Window && surfTemp.Class != SurfaceClass::GlassDoor && surfTemp.Class != SurfaceClass::Door) &&
5010 13 : s_ipsc->rNumericArgs(2) > 1.0) {
5011 0 : ShowWarningError(state,
5012 0 : format("{}=\"{}\", invalid {}=[{:.1T}].",
5013 0 : s_ipsc->cCurrentModuleObject,
5014 0 : surfTemp.Name,
5015 0 : s_ipsc->cNumericFieldNames(2),
5016 0 : s_ipsc->rNumericArgs(2)));
5017 0 : ShowContinueError(state,
5018 0 : format("...because {}={} multiplier will be set to 1.0.", s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2)));
5019 0 : surfTemp.Multiplier = 1.0;
5020 : }
5021 :
5022 856 : GetVertices(state, SurfNum, surfTemp.Sides, s_ipsc->rNumericArgs({4, _}));
5023 :
5024 214 : CheckConvexity(state, SurfNum, surfTemp.Sides);
5025 214 : surfTemp.windowShadingControlList.clear();
5026 214 : surfTemp.activeWindowShadingControl = 0;
5027 214 : surfTemp.HasShadeControl = false;
5028 :
5029 214 : surfTemp.shadedConstructionList.clear();
5030 214 : surfTemp.activeShadedConstruction = 0;
5031 214 : surfTemp.shadedStormWinConstructionList.clear();
5032 :
5033 214 : if (surfTemp.Class == SurfaceClass::Window || surfTemp.Class == SurfaceClass::GlassDoor || surfTemp.Class == SurfaceClass::TDD_Diffuser ||
5034 26 : surfTemp.Class == SurfaceClass::TDD_Dome) {
5035 :
5036 195 : if (surfTemp.ExtBoundCond == DataSurfaces::OtherSideCoefNoCalcExt || surfTemp.ExtBoundCond == DataSurfaces::OtherSideCoefCalcExt) {
5037 0 : ShowSevereError(
5038 : state,
5039 0 : format("{}=\"{}\", Other side coefficients are not allowed with windows.", s_ipsc->cCurrentModuleObject, surfTemp.Name));
5040 0 : ErrorsFound = true;
5041 : }
5042 :
5043 195 : if (surfTemp.ExtBoundCond == DataSurfaces::Ground) {
5044 0 : ShowSevereError(state,
5045 0 : format("{}=\"{}\", Exterior boundary condition = Ground is not allowed with windows.",
5046 0 : s_ipsc->cCurrentModuleObject,
5047 0 : surfTemp.Name));
5048 0 : ErrorsFound = true;
5049 : }
5050 :
5051 195 : if (surfTemp.ExtBoundCond == DataSurfaces::KivaFoundation) {
5052 0 : ShowSevereError(state,
5053 0 : format("{}=\"{}\", Exterior boundary condition = Foundation is not allowed with windows.",
5054 0 : s_ipsc->cCurrentModuleObject,
5055 0 : surfTemp.Name));
5056 0 : ErrorsFound = true;
5057 : }
5058 :
5059 195 : InitialAssociateWindowShadingControlFenestration(state, ErrorsFound, SurfNum);
5060 :
5061 195 : CheckWindowShadingControlFrameDivider(state, "GetHTSubSurfaceData", ErrorsFound, SurfNum, 6);
5062 :
5063 195 : if (surfTemp.Sides == 3) { // Triangular window
5064 1 : if (!s_ipsc->cAlphaArgs(6).empty()) {
5065 0 : ShowWarningError(state,
5066 0 : format("{}=\"{}\", invalid {}=\"{}\".",
5067 0 : s_ipsc->cCurrentModuleObject,
5068 0 : surfTemp.Name,
5069 0 : s_ipsc->cAlphaFieldNames(6),
5070 0 : s_ipsc->cAlphaArgs(6)));
5071 0 : ShowContinueError(state, ".. because it is a triangular window and cannot have a frame or divider or reveal reflection.");
5072 0 : ShowContinueError(state, "Frame, divider and reveal reflection will be ignored for this window.");
5073 : }
5074 1 : surfTemp.FrameDivider = 0;
5075 : } // End of check if window is triangular or rectangular
5076 :
5077 : } // check on non-opaquedoor subsurfaces
5078 :
5079 214 : CheckSubSurfaceMiscellaneous(
5080 214 : state, "GetHTSubSurfaceData", ErrorsFound, SurfNum, s_ipsc->cAlphaArgs(1), s_ipsc->cAlphaArgs(3), AddedSubSurfaces);
5081 :
5082 : } // End of main loop over subsurfaces
5083 440 : }
5084 :
5085 226 : void GetRectSubSurfaces(EnergyPlusData &state,
5086 : bool &ErrorsFound, // Error flag indicator (true if errors found)
5087 : int &SurfNum, // Count of Current SurfaceNumber
5088 : int const TotWindows, // Number of Window SubSurfaces to obtain
5089 : int const TotDoors, // Number of Door SubSurfaces to obtain
5090 : int const TotGlazedDoors, // Number of Glass Door SubSurfaces to obtain
5091 : int const TotIZWindows, // Number of Interzone Window SubSurfaces to obtain
5092 : int const TotIZDoors, // Number of Interzone Door SubSurfaces to obtain
5093 : int const TotIZGlazedDoors, // Number of Interzone Glass Door SubSurfaces to obtain
5094 : const Array1D<SurfaceClass> &SubSurfIDs, // ID Assignments for valid sub surface classes
5095 : int &AddedSubSurfaces, // Subsurfaces added when windows reference Window5
5096 : int &NeedToAddSubSurfaces // Number of surfaces to add, based on unentered IZ surfaces
5097 : )
5098 : {
5099 :
5100 : // SUBROUTINE INFORMATION:
5101 : // AUTHOR Linda Lawrie
5102 : // DATE WRITTEN December 2008
5103 :
5104 : // PURPOSE OF THIS SUBROUTINE:
5105 : // Get simple (rectangular, relative origin to base surface) windows, doors, glazed doors.
5106 :
5107 : // SUBROUTINE PARAMETER DEFINITIONS:
5108 226 : static Array1D_string const cModuleObjects(6, {"Window", "Door", "GlazedDoor", "Window:Interzone", "Door:Interzone", "GlazedDoor:Interzone"});
5109 :
5110 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
5111 : int ItemsToGet;
5112 : int Loop;
5113 : int NumAlphas;
5114 : int NumNumbers;
5115 : int IOStat; // IO Status when calling get input subroutine
5116 : int Found; // For matching base surfaces
5117 : bool GettingIZSurfaces;
5118 : int FrameField;
5119 : int OtherSurfaceField;
5120 : int ClassItem;
5121 : int IZFound;
5122 :
5123 226 : auto &s_ipsc = state.dataIPShortCut;
5124 1582 : for (int Item = 1; Item <= 6; ++Item) {
5125 :
5126 1356 : s_ipsc->cCurrentModuleObject = cModuleObjects(Item);
5127 1356 : if (Item == 1) {
5128 226 : ItemsToGet = TotWindows;
5129 226 : GettingIZSurfaces = false;
5130 226 : FrameField = 5;
5131 226 : OtherSurfaceField = 0;
5132 226 : ClassItem = 1;
5133 1130 : } else if (Item == 2) {
5134 226 : ItemsToGet = TotDoors;
5135 226 : GettingIZSurfaces = false;
5136 226 : FrameField = 0;
5137 226 : OtherSurfaceField = 0;
5138 226 : ClassItem = 2;
5139 904 : } else if (Item == 3) {
5140 226 : ItemsToGet = TotGlazedDoors;
5141 226 : GettingIZSurfaces = false;
5142 226 : FrameField = 5;
5143 226 : OtherSurfaceField = 0;
5144 226 : ClassItem = 3;
5145 678 : } else if (Item == 4) {
5146 226 : ItemsToGet = TotIZWindows;
5147 226 : GettingIZSurfaces = true;
5148 226 : FrameField = 0;
5149 226 : OtherSurfaceField = 4;
5150 226 : ClassItem = 1;
5151 452 : } else if (Item == 5) {
5152 226 : ItemsToGet = TotIZDoors;
5153 226 : GettingIZSurfaces = true;
5154 226 : FrameField = 0;
5155 226 : OtherSurfaceField = 4;
5156 226 : ClassItem = 2;
5157 : } else { // Item = 6
5158 226 : ItemsToGet = TotIZGlazedDoors;
5159 226 : GettingIZSurfaces = true;
5160 226 : FrameField = 0;
5161 226 : OtherSurfaceField = 4;
5162 226 : ClassItem = 3;
5163 : }
5164 :
5165 1365 : for (Loop = 1; Loop <= ItemsToGet; ++Loop) {
5166 18 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
5167 9 : s_ipsc->cCurrentModuleObject,
5168 : Loop,
5169 9 : s_ipsc->cAlphaArgs,
5170 : NumAlphas,
5171 9 : s_ipsc->rNumericArgs,
5172 : NumNumbers,
5173 : IOStat,
5174 9 : s_ipsc->lNumericFieldBlanks,
5175 9 : s_ipsc->lAlphaFieldBlanks,
5176 9 : s_ipsc->cAlphaFieldNames,
5177 9 : s_ipsc->cNumericFieldNames);
5178 :
5179 18 : if (GlobalNames::VerifyUniqueInterObjectName(state,
5180 9 : state.dataSurfaceGeometry->UniqueSurfaceNames,
5181 9 : s_ipsc->cAlphaArgs(1),
5182 9 : s_ipsc->cCurrentModuleObject,
5183 9 : s_ipsc->cAlphaFieldNames(1),
5184 : ErrorsFound)) {
5185 0 : continue;
5186 : }
5187 :
5188 9 : if (NumNumbers < 5) {
5189 0 : ShowSevereError(
5190 : state,
5191 0 : format("{}=\"{}\", Too few number of numeric args=[{}].", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1), NumNumbers));
5192 0 : ErrorsFound = true;
5193 : }
5194 :
5195 9 : ++SurfNum;
5196 9 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
5197 :
5198 9 : surfTemp.Name = s_ipsc->cAlphaArgs(1); // Set the Surface Name in the Derived Type
5199 9 : surfTemp.Class = SubSurfIDs(ClassItem); // Set class number
5200 :
5201 9 : surfTemp.Construction =
5202 9 : Util::FindItemInList(s_ipsc->cAlphaArgs(2), state.dataConstruction->Construct, state.dataHeatBal->TotConstructs);
5203 :
5204 9 : if (surfTemp.Construction == 0) {
5205 0 : ErrorsFound = true;
5206 0 : ShowSevereError(state,
5207 0 : format("{}=\"{}\", invalid {}=\"{}\".",
5208 0 : s_ipsc->cCurrentModuleObject,
5209 0 : surfTemp.Name,
5210 0 : s_ipsc->cAlphaFieldNames(2),
5211 0 : s_ipsc->cAlphaArgs(2)));
5212 : } else {
5213 9 : state.dataConstruction->Construct(surfTemp.Construction).IsUsed = true;
5214 9 : surfTemp.ConstructionStoredInputValue = surfTemp.Construction;
5215 : }
5216 :
5217 9 : if (surfTemp.Class == SurfaceClass::Window || surfTemp.Class == SurfaceClass::GlassDoor) {
5218 :
5219 8 : if (surfTemp.Construction != 0) {
5220 8 : auto const &construction = state.dataConstruction->Construct(surfTemp.Construction);
5221 :
5222 8 : if (!construction.TypeIsWindow && !construction.TypeIsAirBoundary) {
5223 0 : ErrorsFound = true;
5224 0 : ShowSevereError(state,
5225 0 : format("{}=\"{}\" has an opaque surface construction; it should have a window construction.",
5226 0 : s_ipsc->cCurrentModuleObject,
5227 0 : surfTemp.Name));
5228 : }
5229 8 : if (state.dataConstruction->Construct(surfTemp.Construction).SourceSinkPresent) {
5230 0 : ErrorsFound = true;
5231 0 : ShowSevereError(state,
5232 0 : format("{}=\"{}\": Windows are not allowed to have embedded sources/sinks",
5233 0 : s_ipsc->cCurrentModuleObject,
5234 0 : surfTemp.Name));
5235 : }
5236 : }
5237 :
5238 9 : } else if (surfTemp.Construction != 0) {
5239 1 : if (state.dataConstruction->Construct(surfTemp.Construction).TypeIsWindow) {
5240 0 : ErrorsFound = true;
5241 0 : ShowSevereError(state,
5242 0 : format("{}=\"{}\", invalid {}=\"{}\" - has Window materials.",
5243 0 : s_ipsc->cCurrentModuleObject,
5244 0 : surfTemp.Name,
5245 0 : s_ipsc->cAlphaFieldNames(2),
5246 0 : s_ipsc->cAlphaArgs(2)));
5247 : }
5248 : }
5249 :
5250 9 : surfTemp.HeatTransSurf = true;
5251 :
5252 9 : surfTemp.BaseSurfName = s_ipsc->cAlphaArgs(3);
5253 : // The subsurface inherits properties from the base surface
5254 : // Exterior conditions, Zone, etc.
5255 : // We can figure out the base surface though, because they've all been entered
5256 9 : Found = Util::FindItemInList(surfTemp.BaseSurfName, state.dataSurfaceGeometry->SurfaceTmp, state.dataSurface->TotSurfaces);
5257 9 : if (Found > 0) {
5258 9 : surfTemp.BaseSurf = Found;
5259 9 : surfTemp.ExtBoundCond = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCond;
5260 9 : surfTemp.ExtBoundCondName = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCondName;
5261 9 : surfTemp.ExtSolar = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtSolar;
5262 9 : surfTemp.ExtWind = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtWind;
5263 9 : surfTemp.Tilt = state.dataSurfaceGeometry->SurfaceTmp(Found).Tilt;
5264 9 : surfTemp.convOrientation = Convect::GetSurfConvOrientation(surfTemp.Tilt);
5265 9 : surfTemp.Azimuth = state.dataSurfaceGeometry->SurfaceTmp(Found).Azimuth;
5266 9 : surfTemp.Zone = state.dataSurfaceGeometry->SurfaceTmp(Found).Zone;
5267 9 : surfTemp.ZoneName = state.dataSurfaceGeometry->SurfaceTmp(Found).ZoneName;
5268 9 : surfTemp.OSCPtr = state.dataSurfaceGeometry->SurfaceTmp(Found).OSCPtr;
5269 9 : surfTemp.ViewFactorGround = state.dataSurfaceGeometry->SurfaceTmp(Found).ViewFactorGround;
5270 9 : surfTemp.ViewFactorSky = state.dataSurfaceGeometry->SurfaceTmp(Found).ViewFactorSky;
5271 : } else {
5272 0 : ShowSevereError(state,
5273 0 : format("{}=\"{}\", invalid {}=\"{}",
5274 0 : s_ipsc->cCurrentModuleObject,
5275 0 : surfTemp.Name,
5276 0 : s_ipsc->cAlphaFieldNames(3),
5277 0 : s_ipsc->cAlphaArgs(3)));
5278 0 : surfTemp.ZoneName = "Unknown Zone";
5279 0 : ErrorsFound = true;
5280 0 : continue;
5281 : }
5282 9 : if (state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCond == unreconciledZoneSurface &&
5283 0 : state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCondName ==
5284 0 : state.dataSurfaceGeometry->SurfaceTmp(Found).Name) { // Adiabatic surface, no windows or doors allowed
5285 0 : ShowSevereError(state,
5286 0 : format("{}=\"{}\", invalid {}=\"{}\".",
5287 0 : s_ipsc->cCurrentModuleObject,
5288 0 : surfTemp.Name,
5289 0 : s_ipsc->cAlphaFieldNames(3),
5290 0 : s_ipsc->cAlphaArgs(3)));
5291 0 : ShowContinueError(state, "... adiabatic surfaces cannot have windows or doors.");
5292 0 : ShowContinueError(state,
5293 : "... no solar transmission will result for these windows or doors. You must have interior windows or doors on "
5294 : "Interzone surfaces for transmission to result.");
5295 : }
5296 :
5297 9 : if (surfTemp.ExtBoundCond == unreconciledZoneSurface) { // "Surface" Base Surface
5298 0 : if (!GettingIZSurfaces) {
5299 0 : ShowSevereError(state, format("{}=\"{}\", invalid use of object", s_ipsc->cCurrentModuleObject, surfTemp.Name));
5300 0 : ShowContinueError(
5301 : state,
5302 0 : format(
5303 : "...when Base surface uses \"Surface\" as {}, subsurfaces must also specify specific surfaces in the adjacent zone.",
5304 0 : s_ipsc->cAlphaFieldNames(5)));
5305 0 : ShowContinueError(state, format("...Please use {}:Interzone to enter this surface.", s_ipsc->cCurrentModuleObject));
5306 0 : surfTemp.ExtBoundCondName = BlankString; // putting it as blank will not confuse things later.
5307 0 : ErrorsFound = true;
5308 : }
5309 : }
5310 :
5311 9 : if (surfTemp.ExtBoundCond == unreconciledZoneSurface) { // "Surface" Base Surface
5312 0 : if (GettingIZSurfaces) {
5313 0 : surfTemp.ExtBoundCondName = s_ipsc->cAlphaArgs(OtherSurfaceField);
5314 0 : IZFound = Util::FindItemInList(surfTemp.ExtBoundCondName, state.dataHeatBal->Zone, state.dataGlobal->NumOfZones);
5315 0 : if (IZFound > 0) surfTemp.ExtBoundCond = unenteredAdjacentZoneSurface;
5316 : } else { // Interior Window
5317 0 : surfTemp.ExtBoundCondName = surfTemp.Name;
5318 : }
5319 : }
5320 :
5321 : // This is the parent's property:
5322 9 : if (surfTemp.ExtBoundCond == unenteredAdjacentZoneSurface) { // OtherZone - unmatched interior surface
5323 0 : if (GettingIZSurfaces) {
5324 0 : ++NeedToAddSubSurfaces;
5325 : } else { // Interior Window
5326 0 : ShowSevereError(state,
5327 0 : format("{}=\"{}\", invalid Interzone Surface, specify {}:InterZone",
5328 0 : s_ipsc->cCurrentModuleObject,
5329 0 : surfTemp.Name,
5330 0 : s_ipsc->cCurrentModuleObject));
5331 0 : ShowContinueError(state, "...when base surface is an interzone surface, subsurface must also be an interzone surface.");
5332 0 : ++NeedToAddSubSurfaces;
5333 0 : ErrorsFound = true;
5334 : }
5335 : }
5336 :
5337 9 : if (GettingIZSurfaces) {
5338 0 : if (s_ipsc->lAlphaFieldBlanks(OtherSurfaceField)) {
5339 : // blank -- set it up for unentered adjacent zone
5340 0 : if (surfTemp.ExtBoundCond == unenteredAdjacentZoneSurface) { // already set but need Zone
5341 0 : surfTemp.ExtBoundCondName = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCondName; // base surface has it
5342 0 : } else if (surfTemp.ExtBoundCond == unreconciledZoneSurface) {
5343 0 : surfTemp.ExtBoundCondName = state.dataSurfaceGeometry->SurfaceTmp(Found).ZoneName; // base surface has it
5344 0 : surfTemp.ExtBoundCond = unenteredAdjacentZoneSurface;
5345 : } else { // not correct boundary condition for interzone subsurface
5346 0 : ShowSevereError(
5347 : state,
5348 0 : format("{}=\"{}\", invalid Base Surface type for Interzone Surface", s_ipsc->cCurrentModuleObject, surfTemp.Name));
5349 0 : ShowContinueError(state,
5350 : "...when base surface is not an interzone surface, subsurface must also not be an interzone surface.");
5351 0 : ErrorsFound = true;
5352 : }
5353 : }
5354 : }
5355 :
5356 9 : if (surfTemp.ExtBoundCond == DataSurfaces::OtherSideCondModeledExt) {
5357 0 : surfTemp.ExtBoundCond = DataSurfaces::ExternalEnvironment;
5358 : }
5359 :
5360 : // SurfaceTmp(SurfNum)%ViewFactorGround = AutoCalculate
5361 :
5362 9 : surfTemp.Sides = 4;
5363 9 : surfTemp.Vertex.allocate(surfTemp.Sides);
5364 9 : if (surfTemp.Class == SurfaceClass::Window || surfTemp.Class == SurfaceClass::GlassDoor || surfTemp.Class == SurfaceClass::Door) {
5365 9 : surfTemp.Multiplier = int(s_ipsc->rNumericArgs(1));
5366 0 : } else if (s_ipsc->rNumericArgs(1) > 1.0) {
5367 0 : ShowWarningError(state,
5368 0 : format("{}=\"{}\", invalid {}=[{:.1T}].",
5369 0 : s_ipsc->cCurrentModuleObject,
5370 0 : surfTemp.Name,
5371 0 : s_ipsc->cNumericFieldNames(1),
5372 0 : s_ipsc->rNumericArgs(1)));
5373 0 : ShowContinueError(state,
5374 0 : format("...because {}={} multiplier will be set to 1.0.", s_ipsc->cAlphaFieldNames(1), s_ipsc->cAlphaArgs(1)));
5375 0 : surfTemp.Multiplier = 1.0;
5376 : }
5377 :
5378 36 : MakeRelativeRectangularVertices(state,
5379 : surfTemp.BaseSurf,
5380 : SurfNum,
5381 9 : s_ipsc->rNumericArgs(2),
5382 9 : s_ipsc->rNumericArgs(3),
5383 9 : s_ipsc->rNumericArgs(4),
5384 9 : s_ipsc->rNumericArgs(5));
5385 :
5386 9 : if (surfTemp.Area <= 0.0) {
5387 0 : ShowSevereError(
5388 : state,
5389 0 : format("{}=\"{}\", Surface Area <= 0.0; Entered Area={:.2T}", s_ipsc->cCurrentModuleObject, surfTemp.Name, surfTemp.Area));
5390 0 : ErrorsFound = true;
5391 : }
5392 :
5393 9 : surfTemp.windowShadingControlList.clear();
5394 9 : surfTemp.activeWindowShadingControl = 0;
5395 9 : surfTemp.HasShadeControl = false;
5396 :
5397 9 : surfTemp.shadedConstructionList.clear();
5398 9 : surfTemp.activeShadedConstruction = 0;
5399 9 : surfTemp.shadedStormWinConstructionList.clear();
5400 :
5401 9 : InitialAssociateWindowShadingControlFenestration(state, ErrorsFound, SurfNum);
5402 :
5403 9 : if (!GettingIZSurfaces && (surfTemp.Class == SurfaceClass::Window || surfTemp.Class == SurfaceClass::GlassDoor)) {
5404 :
5405 8 : if (surfTemp.ExtBoundCond == DataSurfaces::OtherSideCoefNoCalcExt ||
5406 8 : surfTemp.ExtBoundCond == DataSurfaces::OtherSideCoefCalcExt) {
5407 0 : ShowSevereError(
5408 : state,
5409 0 : format("{}=\"{}\", Other side coefficients are not allowed with windows.", s_ipsc->cCurrentModuleObject, surfTemp.Name));
5410 0 : ErrorsFound = true;
5411 : }
5412 :
5413 8 : if (surfTemp.ExtBoundCond == DataSurfaces::Ground) {
5414 0 : ShowSevereError(state,
5415 0 : format("{}=\"{}\", Exterior boundary condition = Ground is not allowed with windows.",
5416 0 : s_ipsc->cCurrentModuleObject,
5417 0 : surfTemp.Name));
5418 0 : ErrorsFound = true;
5419 : }
5420 :
5421 8 : CheckWindowShadingControlFrameDivider(state, "GetRectSubSurfaces", ErrorsFound, SurfNum, FrameField);
5422 :
5423 : } // check on non-opaquedoor subsurfaces
5424 :
5425 9 : CheckSubSurfaceMiscellaneous(
5426 9 : state, "GetRectSubSurfaces", ErrorsFound, SurfNum, s_ipsc->cAlphaArgs(1), s_ipsc->cAlphaArgs(2), AddedSubSurfaces);
5427 :
5428 : } // Getting Items
5429 : }
5430 226 : }
5431 :
5432 203 : void CheckWindowShadingControlFrameDivider(EnergyPlusData &state,
5433 : std::string_view const cRoutineName, // routine name calling this one (for error messages)
5434 : bool &ErrorsFound, // true if errors have been found or are found here
5435 : int const SurfNum, // current surface number
5436 : int const FrameField // field number for frame/divider
5437 : )
5438 : {
5439 :
5440 : // SUBROUTINE INFORMATION:
5441 : // AUTHOR Linda Lawrie
5442 : // DATE WRITTEN December 2008
5443 :
5444 : // PURPOSE OF THIS SUBROUTINE:
5445 : // This routine performs checks on WindowShadingControl settings and Frame/Divider Settings.
5446 :
5447 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
5448 : int ConstrNumSh; // Construction number with Shade
5449 : int ShDevNum; // Shading Device number
5450 : int Lay; // Layer number
5451 : int TotGlassLayers; // Number of glass layers in window construction
5452 : int TotLayers; // Number of layers in unshaded construction
5453 : int TotShLayers; // Number of layers in shaded construction
5454 : int MatGap; // Gap material number
5455 : int MatGap1; // Material number of gap to left (outer side) of between-glass shade/blind
5456 : int MatGap2; // Material number of gap to right (inner side) of between-glass shade/blind
5457 : int MatSh; // Between-glass shade/blind material number
5458 : Real64 MatGapCalc; // Calculated MatGap diff for shaded vs non-shaded constructions
5459 :
5460 : // If WindowShadingControl has been specified for this window --
5461 : // Set shaded construction number if shaded construction was specified in WindowShadingControl.
5462 : // Otherwise, create shaded construction if WindowShadingControl for this window has
5463 : // interior or exterior shade/blind (but not between-glass shade/blind) specified.
5464 :
5465 203 : auto &s_ipsc = state.dataIPShortCut;
5466 203 : auto &s_mat = state.dataMaterial;
5467 :
5468 203 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
5469 :
5470 214 : for (std::size_t shadeControlIndex = 0; shadeControlIndex < surfTemp.windowShadingControlList.size(); ++shadeControlIndex) {
5471 11 : int WSCPtr = surfTemp.windowShadingControlList[shadeControlIndex];
5472 11 : ConstrNumSh = 0;
5473 11 : if (!ErrorsFound && surfTemp.HasShadeControl) {
5474 11 : ConstrNumSh = surfTemp.shadedConstructionList[shadeControlIndex];
5475 11 : if (ConstrNumSh > 0) {
5476 11 : surfTemp.activeShadedConstruction = ConstrNumSh;
5477 0 : } else if (ANY_INTERIOR_SHADE_BLIND(state.dataSurface->WindowShadingControl(WSCPtr).ShadingType) ||
5478 0 : ANY_EXTERIOR_SHADE_BLIND_SCREEN(state.dataSurface->WindowShadingControl(WSCPtr).ShadingType)) {
5479 0 : ShDevNum = state.dataSurface->WindowShadingControl(WSCPtr).ShadingDevice;
5480 0 : if (ShDevNum > 0) {
5481 0 : CreateShadedWindowConstruction(state, SurfNum, WSCPtr, ShDevNum, shadeControlIndex);
5482 0 : ConstrNumSh = surfTemp.activeShadedConstruction;
5483 : }
5484 : }
5485 : }
5486 :
5487 : // Error checks for shades and blinds
5488 :
5489 11 : int ConstrNum = surfTemp.Construction;
5490 11 : if (!ErrorsFound && WSCPtr > 0 && ConstrNum > 0 && ConstrNumSh > 0) {
5491 :
5492 11 : if (ANY_INTERIOR_SHADE_BLIND(state.dataSurface->WindowShadingControl(WSCPtr).ShadingType)) {
5493 9 : TotLayers = state.dataConstruction->Construct(ConstrNum).TotLayers;
5494 9 : TotShLayers = state.dataConstruction->Construct(ConstrNumSh).TotLayers;
5495 9 : if (TotShLayers - 1 != TotLayers) {
5496 0 : ShowWarningError(
5497 : state,
5498 : "WindowShadingControl: Interior shade or blind: Potential problem in match of unshaded/shaded constructions, "
5499 : "shaded should have 1 more layers than unshaded.");
5500 0 : ShowContinueError(state, format("Unshaded construction={}", state.dataConstruction->Construct(ConstrNum).Name));
5501 0 : ShowContinueError(state, format("Shaded construction={}", state.dataConstruction->Construct(ConstrNumSh).Name));
5502 0 : ShowContinueError(state,
5503 : "If preceding two constructions are same name, you have likely specified a WindowShadingControl (Field #3) "
5504 : "with the Window Construction rather than a shaded construction.");
5505 : }
5506 18 : for (Lay = 1; Lay <= state.dataConstruction->Construct(ConstrNum).TotLayers; ++Lay) {
5507 9 : if (state.dataConstruction->Construct(ConstrNum).LayerPoint(Lay) !=
5508 9 : state.dataConstruction->Construct(ConstrNumSh).LayerPoint(Lay)) {
5509 0 : ErrorsFound = true;
5510 0 : ShowSevereError(state,
5511 0 : format(" The glass and gas layers in the shaded and unshaded constructions do not match for window={}",
5512 0 : surfTemp.Name));
5513 0 : ShowContinueError(state, format("Unshaded construction={}", state.dataConstruction->Construct(ConstrNum).Name));
5514 0 : ShowContinueError(state, format("Shaded construction={}", state.dataConstruction->Construct(ConstrNumSh).Name));
5515 0 : break;
5516 : }
5517 : }
5518 : }
5519 :
5520 11 : if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(state.dataSurface->WindowShadingControl(WSCPtr).ShadingType)) {
5521 0 : TotLayers = state.dataConstruction->Construct(ConstrNum).TotLayers;
5522 0 : TotShLayers = state.dataConstruction->Construct(ConstrNumSh).TotLayers;
5523 0 : if (TotShLayers - 1 != TotLayers) {
5524 0 : ShowWarningError(state,
5525 : "WindowShadingControl: Exterior shade, screen or blind: Potential problem in match of unshaded/shaded "
5526 : "constructions, shaded should have 1 more layer than unshaded.");
5527 0 : ShowContinueError(state, format("Unshaded construction={}", state.dataConstruction->Construct(ConstrNum).Name));
5528 0 : ShowContinueError(state, format("Shaded construction={}", state.dataConstruction->Construct(ConstrNumSh).Name));
5529 0 : ShowContinueError(
5530 : state,
5531 : "If preceding two constructions have the same name, you have likely specified a WindowShadingControl (Field "
5532 : "#3) with the Window Construction rather than a shaded construction.");
5533 : }
5534 0 : for (Lay = 1; Lay <= state.dataConstruction->Construct(ConstrNum).TotLayers; ++Lay) {
5535 0 : if (state.dataConstruction->Construct(ConstrNum).LayerPoint(Lay) !=
5536 0 : state.dataConstruction->Construct(ConstrNumSh).LayerPoint(Lay + 1)) {
5537 0 : ErrorsFound = true;
5538 0 : ShowSevereError(state,
5539 0 : format(" The glass and gas layers in the shaded and unshaded constructions do not match for window={}",
5540 0 : surfTemp.Name));
5541 0 : ShowContinueError(state, format("Unshaded construction={}", state.dataConstruction->Construct(ConstrNum).Name));
5542 0 : ShowContinueError(state, format("Shaded construction={}", state.dataConstruction->Construct(ConstrNumSh).Name));
5543 0 : break;
5544 : }
5545 : }
5546 : }
5547 :
5548 11 : if (ANY_BETWEENGLASS_SHADE_BLIND(state.dataSurface->WindowShadingControl(WSCPtr).ShadingType)) {
5549 : // Divider not allowed with between-glass shade or blind
5550 0 : if (surfTemp.FrameDivider > 0) {
5551 0 : if (state.dataSurface->FrameDivider(surfTemp.FrameDivider).DividerWidth > 0.0) {
5552 0 : ShowWarningError(state, format("A divider cannot be specified for window {}", surfTemp.Name));
5553 0 : ShowContinueError(state, ", which has a between-glass shade or blind.");
5554 0 : ShowContinueError(state, "Calculation will proceed without the divider for this window.");
5555 0 : state.dataSurface->FrameDivider(surfTemp.FrameDivider).DividerWidth = 0.0;
5556 : }
5557 : }
5558 : // Check consistency of gap widths between unshaded and shaded constructions
5559 0 : TotGlassLayers = state.dataConstruction->Construct(ConstrNum).TotGlassLayers;
5560 0 : TotLayers = state.dataConstruction->Construct(ConstrNum).TotLayers;
5561 0 : TotShLayers = state.dataConstruction->Construct(ConstrNumSh).TotLayers;
5562 0 : if (TotShLayers - 2 != TotLayers) {
5563 0 : ShowWarningError(
5564 : state,
5565 : "WindowShadingControl: Between Glass Shade/Blind: Potential problem in match of unshaded/shaded constructions, "
5566 : "shaded should have 2 more layers than unshaded.");
5567 0 : ShowContinueError(state, format("Unshaded construction={}", state.dataConstruction->Construct(ConstrNum).Name));
5568 0 : ShowContinueError(state, format("Shaded construction={}", state.dataConstruction->Construct(ConstrNumSh).Name));
5569 0 : ShowContinueError(state,
5570 : "If preceding two constructions are same name, you have likely specified a WindowShadingControl (Field #3) "
5571 : "with the Window Construction rather than a shaded construction.");
5572 : }
5573 0 : if (state.dataConstruction->Construct(ConstrNum).LayerPoint(TotLayers) !=
5574 0 : state.dataConstruction->Construct(ConstrNumSh).LayerPoint(TotShLayers)) {
5575 0 : ShowSevereError(state, format("{}: Mis-match in unshaded/shaded inside layer materials. These should match.", cRoutineName));
5576 0 : ShowContinueError(state,
5577 0 : format("Unshaded construction={}, Material={}",
5578 0 : state.dataConstruction->Construct(ConstrNum).Name,
5579 0 : s_mat->materials(state.dataConstruction->Construct(ConstrNum).LayerPoint(TotLayers))->Name));
5580 0 : ShowContinueError(state,
5581 0 : format("Shaded construction={}, Material={}",
5582 0 : state.dataConstruction->Construct(ConstrNumSh).Name,
5583 0 : s_mat->materials(state.dataConstruction->Construct(ConstrNumSh).LayerPoint(TotShLayers))->Name));
5584 0 : ErrorsFound = true;
5585 : }
5586 0 : if (state.dataConstruction->Construct(ConstrNum).LayerPoint(1) != state.dataConstruction->Construct(ConstrNumSh).LayerPoint(1)) {
5587 0 : ShowSevereError(state, format("{}: Mis-match in unshaded/shaded inside layer materials. These should match.", cRoutineName));
5588 0 : ShowContinueError(state,
5589 0 : format("Unshaded construction={}, Material={}",
5590 0 : state.dataConstruction->Construct(ConstrNum).Name,
5591 0 : s_mat->materials(state.dataConstruction->Construct(ConstrNum).LayerPoint(1))->Name));
5592 0 : ShowContinueError(state,
5593 0 : format("Shaded construction={}, Material={}",
5594 0 : state.dataConstruction->Construct(ConstrNumSh).Name,
5595 0 : s_mat->materials(state.dataConstruction->Construct(ConstrNumSh).LayerPoint(1))->Name));
5596 0 : ErrorsFound = true;
5597 : }
5598 0 : if (TotGlassLayers == 2 || TotGlassLayers == 3) {
5599 0 : MatGap = state.dataConstruction->Construct(ConstrNum).LayerPoint(2 * TotGlassLayers - 2);
5600 0 : MatGap1 = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(2 * TotGlassLayers - 2);
5601 0 : MatGap2 = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(2 * TotGlassLayers);
5602 0 : MatSh = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(2 * TotGlassLayers - 1);
5603 0 : if (state.dataSurface->WindowShadingControl(WSCPtr).ShadingType == DataSurfaces::WinShadingType::BGBlind) {
5604 0 : MatGapCalc = std::abs(s_mat->materials(MatGap)->Thickness -
5605 0 : (s_mat->materials(MatGap1)->Thickness + s_mat->materials(MatGap2)->Thickness));
5606 0 : if (MatGapCalc > 0.001) {
5607 0 : ShowSevereError(state,
5608 0 : format("{}: The gap width(s) for the unshaded window construction {}",
5609 : cRoutineName,
5610 0 : state.dataConstruction->Construct(ConstrNum).Name));
5611 0 : ShowContinueError(state,
5612 0 : "are inconsistent with the gap widths for shaded window construction " +
5613 0 : state.dataConstruction->Construct(ConstrNumSh).Name);
5614 0 : ShowContinueError(state, "for window " + surfTemp.Name + ", which has a between-glass blind.");
5615 0 : ShowContinueError(
5616 : state,
5617 0 : format("..Material={} thickness={:.3R} -", s_mat->materials(MatGap)->Name, s_mat->materials(MatGap)->Thickness));
5618 0 : ShowContinueError(state,
5619 0 : format("..( Material={} thickness={:.3R} +",
5620 0 : s_mat->materials(MatGap1)->Name,
5621 0 : s_mat->materials(MatGap1)->Thickness));
5622 0 : ShowContinueError(state,
5623 0 : format("..Material={} thickness={:.3R} )=[{:.3R}] >.001",
5624 0 : s_mat->materials(MatGap2)->Name,
5625 0 : s_mat->materials(MatGap2)->Thickness,
5626 : MatGapCalc));
5627 0 : ErrorsFound = true;
5628 : }
5629 : } else { // Between-glass shade
5630 0 : MatGapCalc = std::abs(
5631 0 : s_mat->materials(MatGap)->Thickness -
5632 0 : (s_mat->materials(MatGap1)->Thickness + s_mat->materials(MatGap2)->Thickness + s_mat->materials(MatSh)->Thickness));
5633 0 : if (MatGapCalc > 0.001) {
5634 0 : ShowSevereError(state,
5635 0 : format("{}: The gap width(s) for the unshaded window construction {}",
5636 : cRoutineName,
5637 0 : state.dataConstruction->Construct(ConstrNum).Name));
5638 0 : ShowContinueError(state,
5639 0 : "are inconsistent with the gap widths for shaded window construction " +
5640 0 : state.dataConstruction->Construct(ConstrNumSh).Name);
5641 0 : ShowContinueError(state, "for window " + surfTemp.Name + ", which has a between-glass shade.");
5642 0 : ShowContinueError(
5643 : state,
5644 0 : format("..Material={} thickness={:.3R} -", s_mat->materials(MatGap)->Name, s_mat->materials(MatGap)->Thickness));
5645 0 : ShowContinueError(state,
5646 0 : format("...( Material={} thickness={:.3R} +",
5647 0 : s_mat->materials(MatGap1)->Name,
5648 0 : s_mat->materials(MatGap1)->Thickness));
5649 0 : ShowContinueError(state,
5650 0 : format("..Material={} thickness={:.3R} +",
5651 0 : s_mat->materials(MatGap2)->Name,
5652 0 : s_mat->materials(MatGap2)->Thickness));
5653 0 : ShowContinueError(state,
5654 0 : format("..Material={} thickness={:.3R} )=[{:.3R}] >.001",
5655 0 : s_mat->materials(MatSh)->Name,
5656 0 : s_mat->materials(MatSh)->Thickness,
5657 : MatGapCalc));
5658 0 : ErrorsFound = true;
5659 : }
5660 : }
5661 : }
5662 : }
5663 : }
5664 : }
5665 :
5666 203 : if (surfTemp.Sides != 3) { // Rectangular Window
5667 : // Initialize the FrameDivider number for this window. W5FrameDivider will be positive if
5668 : // this window's construction came from the Window5 data file and that construction had an
5669 : // associated frame or divider. It will be zero if the window's construction is not from the
5670 : // Window5 data file, or the construction is from the data file, but the construction has no
5671 : // associated frame or divider. Note that if there is a FrameDivider candidate for this
5672 : // window from the Window5 data file it is used instead of the window's input FrameDivider.
5673 :
5674 202 : if (surfTemp.Construction != 0) {
5675 202 : surfTemp.FrameDivider = state.dataConstruction->Construct(surfTemp.Construction).W5FrameDivider;
5676 :
5677 : // Warning if FrameAndDivider for this window is over-ridden by one from Window5 Data File
5678 202 : if (surfTemp.FrameDivider > 0 && !s_ipsc->lAlphaFieldBlanks(FrameField)) {
5679 0 : ShowSevereError(state,
5680 0 : format("{}=\"{}\", {}=\"{}\"",
5681 0 : s_ipsc->cCurrentModuleObject,
5682 0 : surfTemp.Name,
5683 0 : s_ipsc->cAlphaFieldNames(FrameField),
5684 0 : s_ipsc->cAlphaArgs(FrameField)));
5685 0 : ShowContinueError(state,
5686 0 : format("will be replaced with FrameAndDivider from Window5 Data File entry {}",
5687 0 : state.dataConstruction->Construct(surfTemp.Construction).Name));
5688 : }
5689 :
5690 202 : if (!s_ipsc->lAlphaFieldBlanks(FrameField) && surfTemp.FrameDivider == 0) {
5691 24 : surfTemp.FrameDivider = Util::FindItemInList(s_ipsc->cAlphaArgs(FrameField), state.dataSurface->FrameDivider);
5692 24 : if (surfTemp.FrameDivider == 0) {
5693 0 : if (!state.dataConstruction->Construct(surfTemp.Construction).WindowTypeEQL) {
5694 0 : ShowSevereError(state,
5695 0 : format("{}=\"{}\", invalid {}=\"{}\"",
5696 0 : s_ipsc->cCurrentModuleObject,
5697 0 : surfTemp.Name,
5698 0 : s_ipsc->cAlphaFieldNames(FrameField),
5699 0 : s_ipsc->cAlphaArgs(FrameField)));
5700 0 : ErrorsFound = true;
5701 : } else {
5702 0 : ShowSevereError(state,
5703 0 : format("{}=\"{}\", invalid {}=\"{}\"",
5704 0 : s_ipsc->cCurrentModuleObject,
5705 0 : surfTemp.Name,
5706 0 : s_ipsc->cAlphaFieldNames(FrameField),
5707 0 : s_ipsc->cAlphaArgs(FrameField)));
5708 0 : ShowContinueError(state, "...Frame/Divider is not supported in Equivalent Layer Window model.");
5709 : }
5710 : }
5711 : // Divider not allowed with between-glass shade or blind
5712 26 : for (int WSCPtr : surfTemp.windowShadingControlList) {
5713 2 : if (!ErrorsFound && WSCPtr > 0 && ConstrNumSh > 0) {
5714 2 : if (ANY_BETWEENGLASS_SHADE_BLIND(state.dataSurface->WindowShadingControl(WSCPtr).ShadingType)) {
5715 0 : if (surfTemp.FrameDivider > 0) {
5716 0 : if (state.dataSurface->FrameDivider(surfTemp.FrameDivider).DividerWidth > 0.0) {
5717 0 : ShowSevereError(state,
5718 0 : format("{}=\"{}\", invalid {}=\"{}\"",
5719 0 : s_ipsc->cCurrentModuleObject,
5720 0 : surfTemp.Name,
5721 0 : s_ipsc->cAlphaFieldNames(FrameField),
5722 0 : s_ipsc->cAlphaArgs(FrameField)));
5723 0 : ShowContinueError(state,
5724 : "Divider cannot be specified because the construction has a between-glass shade or blind.");
5725 0 : ShowContinueError(state, "Calculation will proceed without the divider for this window.");
5726 0 : ShowContinueError(
5727 : state,
5728 0 : format("Divider width = [{:.2R}].", state.dataSurface->FrameDivider(surfTemp.FrameDivider).DividerWidth));
5729 0 : state.dataSurface->FrameDivider(surfTemp.FrameDivider).DividerWidth = 0.0;
5730 : }
5731 : } // End of check if window has divider
5732 : } // End of check if window has a between-glass shade or blind
5733 : } // End of check if window has a shaded construction
5734 : } // end of looping through window shading controls of window
5735 : } // End of check if window has an associated FrameAndDivider
5736 : } // End of check if window has a construction
5737 : }
5738 :
5739 203 : if (state.dataConstruction->Construct(surfTemp.Construction).WindowTypeEQL) {
5740 7 : if (surfTemp.FrameDivider > 0) {
5741 : // Equivalent Layer window does not have frame/divider model
5742 4 : ShowSevereError(state,
5743 8 : format("{}=\"{}\", invalid {}=\"{}\"",
5744 2 : s_ipsc->cCurrentModuleObject,
5745 2 : surfTemp.Name,
5746 2 : s_ipsc->cAlphaFieldNames(FrameField),
5747 2 : s_ipsc->cAlphaArgs(FrameField)));
5748 4 : ShowContinueError(state, "Frame/Divider is not supported in Equivalent Layer Window model.");
5749 2 : surfTemp.FrameDivider = 0;
5750 : }
5751 : }
5752 203 : }
5753 :
5754 223 : void CheckSubSurfaceMiscellaneous(EnergyPlusData &state,
5755 : std::string_view const cRoutineName, // routine name calling this one (for error messages)
5756 : bool &ErrorsFound, // true if errors have been found or are found here
5757 : int const SurfNum, // current surface number
5758 : std::string const &SubSurfaceName, // name of the surface
5759 : std::string const &SubSurfaceConstruction, // name of the construction
5760 : int &AddedSubSurfaces)
5761 : {
5762 :
5763 : // SUBROUTINE INFORMATION:
5764 : // AUTHOR Linda Lawrie
5765 : // DATE WRITTEN December 2008
5766 :
5767 : // PURPOSE OF THIS SUBROUTINE:
5768 : // This routine performs miscellaneous checks on subsurfaces: Windows, GlassDoors, Doors, Tubular Devices.
5769 :
5770 223 : auto &s_mat = state.dataMaterial;
5771 : // Warning if window has multiplier > 1 and SolarDistribution = FullExterior or FullInteriorExterior
5772 :
5773 223 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
5774 43 : if ((surfTemp.Class == SurfaceClass::Window || surfTemp.Class == SurfaceClass::GlassDoor) &&
5775 449 : static_cast<int>(state.dataHeatBal->SolarDistribution) > static_cast<int>(DataHeatBalance::Shadowing::Minimal) &&
5776 183 : surfTemp.Multiplier > 1.0) {
5777 0 : if (state.dataGlobal->DisplayExtraWarnings) {
5778 0 : ShowWarningError(state, format("{}: A Multiplier > 1.0 for window/glass door {}", cRoutineName, surfTemp.Name));
5779 0 : ShowContinueError(state, "in conjunction with SolarDistribution = FullExterior or FullInteriorExterior");
5780 0 : ShowContinueError(state, "can cause inaccurate shadowing on the window and/or");
5781 0 : ShowContinueError(state, "inaccurate interior solar distribution from the window.");
5782 : }
5783 0 : ++state.dataErrTracking->TotalMultipliedWindows;
5784 : }
5785 :
5786 : // Require that a construction referenced by a surface that is a window
5787 : // NOT have a shading device layer; use WindowShadingControl to specify a shading device.
5788 :
5789 223 : int ConstrNum = surfTemp.Construction;
5790 223 : if (ConstrNum > 0) {
5791 223 : int NumShades = 0;
5792 595 : for (int Lay = 1; Lay <= state.dataConstruction->Construct(ConstrNum).TotLayers; ++Lay) {
5793 372 : int LayerPtr = state.dataConstruction->Construct(ConstrNum).LayerPoint(Lay);
5794 372 : if (LayerPtr == 0) continue; // Error is caught already, will terminate later
5795 744 : if (s_mat->materials(LayerPtr)->group == Material::Group::Shade || s_mat->materials(LayerPtr)->group == Material::Group::Blind ||
5796 372 : s_mat->materials(LayerPtr)->group == Material::Group::Screen)
5797 0 : ++NumShades;
5798 : }
5799 223 : if (NumShades != 0) {
5800 0 : ShowSevereError(state, format("{}: Window \"{}\" must not directly reference", cRoutineName, SubSurfaceName));
5801 0 : ShowContinueError(state, format("a Construction (i.e, \"{}\") with a shading device.", SubSurfaceConstruction));
5802 0 : ShowContinueError(state, "Use WindowShadingControl to specify a shading device for a window.");
5803 0 : ErrorsFound = true;
5804 : }
5805 : }
5806 :
5807 : // Disallow glass transmittance dirt factor for interior windows and glass doors
5808 :
5809 223 : if (surfTemp.ExtBoundCond != DataSurfaces::ExternalEnvironment &&
5810 20 : (surfTemp.Class == SurfaceClass::Window || surfTemp.Class == SurfaceClass::GlassDoor)) {
5811 5 : ConstrNum = surfTemp.Construction;
5812 5 : if (ConstrNum > 0) {
5813 8 : for (int Lay = 1; Lay <= state.dataConstruction->Construct(ConstrNum).TotLayers; ++Lay) {
5814 3 : int LayerPtr = state.dataConstruction->Construct(ConstrNum).LayerPoint(Lay);
5815 3 : auto const *mat = s_mat->materials(LayerPtr);
5816 3 : if (mat->group != Material::Group::Glass) continue;
5817 :
5818 3 : if (dynamic_cast<Material::MaterialGlass const *>(mat)->GlassTransDirtFactor < 1.0) {
5819 0 : ShowSevereError(state, format("{}: Interior Window or GlassDoor {} has a glass layer with", cRoutineName, SubSurfaceName));
5820 0 : ShowContinueError(state, "Dirt Correction Factor for Solar and Visible Transmittance < 1.0");
5821 0 : ShowContinueError(state, "A value less than 1.0 for this factor is only allowed for exterior windows and glass doors.");
5822 0 : ErrorsFound = true;
5823 : }
5824 : }
5825 : }
5826 : }
5827 :
5828 : // If this is a window with a construction from the Window5DataFile, call routine that will
5829 : // (1) if one glazing system on Data File, give warning message if window height or width
5830 : // differ by more than 10% from those of the glazing system on the Data File;
5831 : // (2) if two glazing systems (separated by a mullion) on Data File, create a second window
5832 : // and adjust the dimensions of the original and second windows to those on the Data File
5833 :
5834 223 : if (surfTemp.Construction != 0) {
5835 :
5836 223 : if (state.dataConstruction->Construct(surfTemp.Construction).FromWindow5DataFile) {
5837 :
5838 0 : ModifyWindow(state, SurfNum, ErrorsFound, AddedSubSurfaces);
5839 :
5840 : } else {
5841 : // Calculate net area for base surface (note that ModifyWindow, above, adjusts net area of
5842 : // base surface for case where window construction is from Window5 Data File
5843 : // In case there is in error in this window's base surface (i.e. none)..
5844 223 : if (surfTemp.BaseSurf > 0) {
5845 223 : state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).Area -= surfTemp.Area;
5846 :
5847 : // Subtract TDD:DIFFUSER area from other side interzone surface
5848 229 : if ((surfTemp.Class == SurfaceClass::TDD_Diffuser) &&
5849 6 : not_blank(
5850 6 : state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).ExtBoundCondName)) { // Base surface is an interzone surface
5851 : // Lookup interzone surface of the base surface
5852 : // (Interzone surfaces have not been assigned yet, but all base surfaces should already be loaded.)
5853 6 : int Found = Util::FindItemInList(state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).ExtBoundCondName,
5854 6 : state.dataSurfaceGeometry->SurfaceTmp,
5855 : SurfNum);
5856 6 : if (Found != 0) state.dataSurfaceGeometry->SurfaceTmp(Found).Area -= surfTemp.Area;
5857 : }
5858 223 : if (state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).Area <= 0.0) {
5859 0 : ShowSevereError(state,
5860 0 : format("{}: Surface Openings have too much area for base surface={}",
5861 : cRoutineName,
5862 0 : state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).Name));
5863 0 : ShowContinueError(state, format("Opening Surface creating error={}", surfTemp.Name));
5864 0 : ErrorsFound = true;
5865 : }
5866 : // Net area of base surface with unity window multipliers (used in shadowing checks)
5867 : // For Windows, Glass Doors and Doors, just one area is subtracted. For the rest, should be
5868 : // full area.
5869 223 : if (surfTemp.Class == SurfaceClass::Window || surfTemp.Class == SurfaceClass::GlassDoor) {
5870 190 : state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).NetAreaShadowCalc -= surfTemp.Area / surfTemp.Multiplier;
5871 33 : } else if (surfTemp.Class == SurfaceClass::Door) { // Door, TDD:Diffuser, TDD:DOME
5872 20 : state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).NetAreaShadowCalc -= surfTemp.Area / surfTemp.Multiplier;
5873 : } else {
5874 13 : state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).NetAreaShadowCalc -= surfTemp.Area;
5875 : }
5876 : }
5877 : }
5878 : }
5879 223 : }
5880 :
5881 14 : void MakeRelativeRectangularVertices(EnergyPlusData &state,
5882 : int const BaseSurfNum, // Base surface
5883 : int const SurfNum,
5884 : Real64 const XCoord,
5885 : Real64 const ZCoord,
5886 : Real64 const Length,
5887 : Real64 const Height)
5888 : {
5889 :
5890 : // SUBROUTINE INFORMATION:
5891 : // AUTHOR Linda Lawrie
5892 : // DATE WRITTEN December 2008
5893 :
5894 : // PURPOSE OF THIS SUBROUTINE:
5895 : // This routine creates world/3d coordinates for rectangular surfaces using relative X and Z, length & height.
5896 :
5897 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
5898 14 : Array1D<Real64> XX(4);
5899 14 : Array1D<Real64> YY(4);
5900 : Real64 Perimeter;
5901 : int Vrt;
5902 :
5903 14 : if (BaseSurfNum == 0) return; // invalid base surface, don't bother
5904 :
5905 : // Tilt and Facing (Azimuth) will be same as the Base Surface
5906 :
5907 14 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
5908 14 : surfTemp.Height = Height;
5909 14 : surfTemp.Width = Length;
5910 :
5911 14 : Real64 SurfAzimuth = surfTemp.Azimuth;
5912 14 : Real64 SurfTilt = surfTemp.Tilt;
5913 14 : Real64 CosSurfAzimuth = std::cos(SurfAzimuth * Constant::DegToRad);
5914 14 : Real64 SinSurfAzimuth = std::sin(SurfAzimuth * Constant::DegToRad);
5915 14 : Real64 CosSurfTilt = std::cos(SurfTilt * Constant::DegToRad);
5916 14 : Real64 SinSurfTilt = std::sin(SurfTilt * Constant::DegToRad);
5917 14 : Real64 BaseCosSurfAzimuth = state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosAzim;
5918 14 : Real64 BaseSinSurfAzimuth = state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).SinAzim;
5919 14 : Real64 BaseCosSurfTilt = state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosTilt;
5920 14 : Real64 BaseSinSurfTilt = state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).SinTilt;
5921 :
5922 14 : Real64 XLLC = state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).x - XCoord * BaseCosSurfAzimuth -
5923 14 : ZCoord * BaseCosSurfTilt * BaseSinSurfAzimuth;
5924 14 : Real64 YLLC = state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).y + XCoord * BaseSinSurfAzimuth -
5925 14 : ZCoord * BaseCosSurfTilt * BaseCosSurfAzimuth;
5926 14 : Real64 ZLLC = state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).z + ZCoord * BaseSinSurfTilt;
5927 :
5928 14 : XX(1) = 0.0;
5929 14 : XX(2) = 0.0;
5930 14 : XX(3) = Length;
5931 14 : XX(4) = Length;
5932 14 : YY(1) = Height;
5933 14 : YY(4) = Height;
5934 14 : YY(3) = 0.0;
5935 14 : YY(2) = 0.0;
5936 :
5937 70 : for (int n = 1; n <= surfTemp.Sides; ++n) {
5938 56 : Vrt = n;
5939 56 : surfTemp.Vertex(Vrt).x = XLLC - XX(n) * CosSurfAzimuth - YY(n) * CosSurfTilt * SinSurfAzimuth;
5940 56 : surfTemp.Vertex(Vrt).y = YLLC + XX(n) * SinSurfAzimuth - YY(n) * CosSurfTilt * CosSurfAzimuth;
5941 56 : surfTemp.Vertex(Vrt).z = ZLLC + YY(n) * SinSurfTilt;
5942 : }
5943 :
5944 14 : Vectors::CreateNewellAreaVector(surfTemp.Vertex, surfTemp.Sides, surfTemp.NewellAreaVector);
5945 14 : surfTemp.GrossArea = Vectors::VecLength(surfTemp.NewellAreaVector);
5946 14 : surfTemp.Area = surfTemp.GrossArea;
5947 14 : surfTemp.NetAreaShadowCalc = surfTemp.Area;
5948 14 : Vectors::CreateNewellSurfaceNormalVector(surfTemp.Vertex, surfTemp.Sides, surfTemp.NewellSurfaceNormalVector);
5949 14 : Vectors::DetermineAzimuthAndTilt(
5950 14 : surfTemp.Vertex, SurfAzimuth, SurfTilt, surfTemp.lcsx, surfTemp.lcsy, surfTemp.lcsz, surfTemp.NewellSurfaceNormalVector);
5951 14 : surfTemp.Azimuth = SurfAzimuth;
5952 14 : surfTemp.Tilt = SurfTilt;
5953 14 : surfTemp.convOrientation = Convect::GetSurfConvOrientation(surfTemp.Tilt);
5954 : // Sine and cosine of azimuth and tilt
5955 14 : surfTemp.SinAzim = SinSurfAzimuth;
5956 14 : surfTemp.CosAzim = CosSurfAzimuth;
5957 14 : surfTemp.SinTilt = SinSurfTilt;
5958 14 : surfTemp.CosTilt = CosSurfTilt;
5959 14 : if (surfTemp.Class != SurfaceClass::Window && surfTemp.Class != SurfaceClass::GlassDoor && surfTemp.Class != SurfaceClass::Door)
5960 5 : surfTemp.ViewFactorGround = 0.5 * (1.0 - surfTemp.CosTilt);
5961 : // Outward normal unit vector (pointing away from room)
5962 14 : surfTemp.OutNormVec = surfTemp.NewellSurfaceNormalVector;
5963 56 : for (int n = 1; n <= 3; ++n) {
5964 42 : if (std::abs(surfTemp.OutNormVec(n) - 1.0) < 1.e-06) surfTemp.OutNormVec(n) = +1.0;
5965 42 : if (std::abs(surfTemp.OutNormVec(n) + 1.0) < 1.e-06) surfTemp.OutNormVec(n) = -1.0;
5966 42 : if (std::abs(surfTemp.OutNormVec(n)) < 1.e-06) surfTemp.OutNormVec(n) = 0.0;
5967 : }
5968 :
5969 : // IF (SurfaceTmp(SurfNum)%Class == SurfaceClass::Roof .and. SurfTilt > 80.) THEN
5970 : // WRITE(TiltString,'(F5.1)') SurfTilt
5971 : // TiltString=ADJUSTL(TiltString)
5972 : // CALL ShowWarningError(state, format("Roof/Ceiling Tilt={}{}{}{}{}{}{}{}{}{} for Surface={}{}{}, in
5973 : // Zone={}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}", //TRIM(TiltString)//',,
5974 : // much, greater, than, expected, tilt, of, 0,'//, &, //, //TRIM(SurfaceTmp(SurfNum)%Name)//, &, //, //TRIM(SurfaceTmp(SurfNum)%ZoneName)),
5975 : // //, ENDIF, //, IF, (SurfaceTmp(SurfNum)%Class, ==, SurfaceClass::Floor, .and., SurfTilt, <, 170.), THEN, //, WRITE(TiltString,'(F5.1)'),
5976 : // SurfTilt, //, TiltString=ADJUSTL(TiltString), //, CALL, ShowWarningError(state, 'Floor Tilt='//TRIM(TiltString)//', much less than
5977 : // expected tilt of 180,'// &
5978 : // ' for Surface='//TRIM(SurfaceTmp(SurfNum)%Name)// &
5979 : // ', in Zone='//TRIM(SurfaceTmp(SurfNum)%ZoneName)), //, ENDIF, if,
5980 : // (surfTemp.Class, ==, SurfaceClass::Window, ||,
5981 : // surfTemp.Class, ==, SurfaceClass::GlassDoor, ||,
5982 : // surfTemp.Class, ==, SurfaceClass::Door),
5983 : // surfTemp.Area, *=,
5984 : // surfTemp.Multiplier;, //, Can, perform, tests, on, this, surface, here,
5985 : // surfTemp.ViewFactorSky, =, 0.5, *, (1.0,
5986 : // surfTemp.CosTilt));
5987 : // The following IR view factors are modified in subr. SkyDifSolarShading if there are shadowing
5988 : // surfaces
5989 14 : surfTemp.ViewFactorSkyIR = surfTemp.ViewFactorSky;
5990 14 : surfTemp.ViewFactorGroundIR = 0.5 * (1.0 - surfTemp.CosTilt);
5991 :
5992 14 : Perimeter = distance(surfTemp.Vertex(surfTemp.Sides), surfTemp.Vertex(1));
5993 56 : for (Vrt = 2; Vrt <= surfTemp.Sides; ++Vrt) {
5994 42 : Perimeter += distance(surfTemp.Vertex(Vrt), surfTemp.Vertex(Vrt - 1));
5995 : }
5996 14 : surfTemp.Perimeter = Perimeter;
5997 :
5998 : // Call to transform vertices
5999 :
6000 14 : TransformVertsByAspect(state, SurfNum, surfTemp.Sides);
6001 14 : }
6002 :
6003 226 : void GetAttShdSurfaceData(EnergyPlusData &state,
6004 : bool &ErrorsFound, // Error flag indicator (true if errors found)
6005 : int &SurfNum, // Count of Current SurfaceNumber
6006 : int const TotShdSubs // Number of Attached Shading SubSurfaces to obtain
6007 : )
6008 : {
6009 : // SUBROUTINE INFORMATION:
6010 : // AUTHOR Linda Lawrie
6011 : // DATE WRITTEN May 2000
6012 :
6013 : // PURPOSE OF THIS SUBROUTINE:
6014 : // This subroutine gets the HeatTransfer Surface Data,
6015 : // checks it for errors, etc.
6016 :
6017 : static constexpr std::string_view routineName = "GetAttShdSurfaceData";
6018 :
6019 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
6020 : int IOStat; // IO Status when calling get input subroutine
6021 : int NumAlphas; // Number of alpha names being passed
6022 : int NumNumbers; // Number of properties being passed
6023 : int Found; // For matching interzone surfaces
6024 : int Loop;
6025 : Real64 SchedMinValue;
6026 : Real64 SchedMaxValue;
6027 :
6028 226 : auto &s_ipsc = state.dataIPShortCut;
6029 :
6030 226 : if (TotShdSubs > 0 && state.dataHeatBal->SolarDistribution == DataHeatBalance::Shadowing::Minimal) {
6031 0 : ShowWarningError(state, "Shading effects of Fins and Overhangs are ignored when Solar Distribution = MinimalShadowing");
6032 : }
6033 226 : s_ipsc->cCurrentModuleObject = "Shading:Zone:Detailed";
6034 226 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, s_ipsc->cCurrentModuleObject, Loop, NumAlphas, NumNumbers);
6035 226 : if (NumAlphas != 3) {
6036 0 : ShowSevereError(
6037 0 : state, format("{}: Object Definition indicates not = 3 Alpha Objects, Number Indicated={}", s_ipsc->cCurrentModuleObject, NumAlphas));
6038 0 : ErrorsFound = true;
6039 : }
6040 :
6041 250 : for (Loop = 1; Loop <= TotShdSubs; ++Loop) {
6042 48 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
6043 24 : s_ipsc->cCurrentModuleObject,
6044 : Loop,
6045 24 : s_ipsc->cAlphaArgs,
6046 : NumAlphas,
6047 24 : s_ipsc->rNumericArgs,
6048 : NumNumbers,
6049 : IOStat,
6050 24 : s_ipsc->lNumericFieldBlanks,
6051 24 : s_ipsc->lAlphaFieldBlanks,
6052 24 : s_ipsc->cAlphaFieldNames,
6053 24 : s_ipsc->cNumericFieldNames);
6054 :
6055 24 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
6056 :
6057 48 : if (GlobalNames::VerifyUniqueInterObjectName(state,
6058 24 : state.dataSurfaceGeometry->UniqueSurfaceNames,
6059 24 : s_ipsc->cAlphaArgs(1),
6060 24 : s_ipsc->cCurrentModuleObject,
6061 24 : s_ipsc->cAlphaFieldNames(1),
6062 : ErrorsFound)) {
6063 0 : continue;
6064 : }
6065 :
6066 24 : ++SurfNum;
6067 24 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
6068 :
6069 24 : surfTemp.Name = s_ipsc->cAlphaArgs(1); // Set the Surface Name in the Derived Type
6070 24 : surfTemp.Class = SurfaceClass::Shading;
6071 24 : surfTemp.HeatTransSurf = false;
6072 24 : surfTemp.BaseSurfName = s_ipsc->cAlphaArgs(2);
6073 : // The subsurface inherits properties from the base surface
6074 : // Exterior conditions, Zone, etc.
6075 : // We can figure out the base surface though, because they've all been entered
6076 24 : Found = Util::FindItemInList(surfTemp.BaseSurfName, state.dataSurfaceGeometry->SurfaceTmp, state.dataSurface->TotSurfaces);
6077 24 : if (Found > 0) {
6078 : // SurfaceTmp(SurfNum)%BaseSurf=Found
6079 24 : surfTemp.ExtBoundCond = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCond;
6080 24 : surfTemp.ExtSolar = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtSolar;
6081 24 : surfTemp.ExtWind = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtWind;
6082 24 : surfTemp.Zone = state.dataSurfaceGeometry->SurfaceTmp(Found).Zone; // Necessary to do relative coordinates in GetVertices below
6083 24 : surfTemp.ZoneName = state.dataSurfaceGeometry->SurfaceTmp(Found).ZoneName; // Necessary to have surface drawn in OutputReports
6084 : } else {
6085 0 : ShowSevereError(state,
6086 0 : format("{}=\"{}\", invalid {}=\"{}",
6087 0 : s_ipsc->cCurrentModuleObject,
6088 0 : surfTemp.Name,
6089 0 : s_ipsc->cAlphaFieldNames(2),
6090 0 : s_ipsc->cAlphaArgs(2)));
6091 0 : ErrorsFound = true;
6092 : }
6093 24 : if (surfTemp.ExtBoundCond == unenteredAdjacentZoneSurface) {
6094 0 : ShowSevereError(state,
6095 0 : format("{}=\"{}\", invalid {}=\"{}",
6096 0 : s_ipsc->cCurrentModuleObject,
6097 0 : surfTemp.Name,
6098 0 : s_ipsc->cAlphaFieldNames(2),
6099 0 : s_ipsc->cAlphaArgs(2)));
6100 0 : ShowContinueError(state, "...trying to attach a shading device to an interzone surface.");
6101 0 : ErrorsFound = true;
6102 :
6103 0 : surfTemp.ExtBoundCond = DataSurfaces::ExternalEnvironment; // reset so program won't crash during "add surfaces"
6104 : }
6105 24 : if (surfTemp.ExtBoundCond == unreconciledZoneSurface) {
6106 0 : ShowSevereError(state,
6107 0 : format("{}=\"{}\", invalid {}=\"{}",
6108 0 : s_ipsc->cCurrentModuleObject,
6109 0 : surfTemp.Name,
6110 0 : s_ipsc->cAlphaFieldNames(2),
6111 0 : s_ipsc->cAlphaArgs(2)));
6112 0 : ShowContinueError(state, "...trying to attach a shading device to an interior surface.");
6113 0 : ErrorsFound = true;
6114 :
6115 0 : surfTemp.ExtBoundCond = DataSurfaces::ExternalEnvironment; // reset so program won't crash during "add surfaces"
6116 : }
6117 :
6118 24 : if (s_ipsc->lAlphaFieldBlanks(3)) {
6119 : // Defaults to constant-0.0, but leave this as nullptr for now
6120 23 : } else if ((surfTemp.shadowSurfSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(3))) == nullptr) {
6121 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3));
6122 0 : ErrorsFound = true;
6123 23 : } else if (!surfTemp.shadowSurfSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 1.0)) {
6124 1 : Sched::ShowSevereBadMinMax(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3), Clusive::In, 0.0, Clusive::In, 1.0);
6125 1 : ErrorsFound = true;
6126 : } else {
6127 :
6128 22 : SchedMinValue = surfTemp.shadowSurfSched->getMinVal(state);
6129 22 : surfTemp.SchedMinValue = SchedMinValue;
6130 22 : SchedMaxValue = surfTemp.shadowSurfSched->getMaxVal(state);
6131 22 : if (SchedMinValue == 1.0) {
6132 : // Set transparent for now, check for EMS actuators later in SolarShading::resetShadingSurfaceTransparency
6133 1 : surfTemp.IsTransparent = true;
6134 : }
6135 22 : if (SchedMaxValue > 0.0) {
6136 13 : state.dataSolarShading->anyScheduledShadingSurface = true;
6137 : }
6138 22 : if (SchedMaxValue - SchedMinValue > Constant::OneMillionth) {
6139 11 : state.dataSurface->ShadingTransmittanceVaries = true;
6140 : }
6141 : }
6142 :
6143 24 : if (s_ipsc->lNumericFieldBlanks(1) || s_ipsc->rNumericArgs(1) == Constant::AutoCalculate) {
6144 0 : s_ipsc->rNumericArgs(1) = (NumNumbers - 1) / 3;
6145 0 : surfTemp.Sides = s_ipsc->rNumericArgs(1);
6146 0 : if (mod(NumNumbers - 1, 3) != 0) {
6147 0 : ShowWarningError(state,
6148 0 : format("{}=\"{}\", {}",
6149 0 : s_ipsc->cCurrentModuleObject,
6150 0 : surfTemp.Name,
6151 0 : format("{} not even multiple of 3. Will read in {}", s_ipsc->cNumericFieldNames(1), surfTemp.Sides)));
6152 : }
6153 0 : if (s_ipsc->rNumericArgs(1) < 3) {
6154 0 : ShowSevereError(state,
6155 0 : format("{}=\"{}\", {} (autocalculate) must be >= 3. Only {} provided.",
6156 0 : s_ipsc->cCurrentModuleObject,
6157 0 : surfTemp.Name,
6158 0 : s_ipsc->cNumericFieldNames(1),
6159 0 : surfTemp.Sides));
6160 0 : ErrorsFound = true;
6161 0 : continue;
6162 : }
6163 : } else {
6164 24 : surfTemp.Sides = s_ipsc->rNumericArgs(1);
6165 : }
6166 24 : surfTemp.Vertex.allocate(surfTemp.Sides);
6167 96 : GetVertices(state, SurfNum, surfTemp.Sides, s_ipsc->rNumericArgs({2, _}));
6168 24 : CheckConvexity(state, SurfNum, surfTemp.Sides);
6169 : // IF (SurfaceTmp(SurfNum)%Sides == 3) THEN
6170 : // CALL ShowWarningError(state, TRIM(s_ipsc->cCurrentModuleObject)//'="'//TRIM(SurfaceTmp(SurfNum)%Name)// &
6171 : // ' should not be triangular.')
6172 : // CALL ShowContinueError(state, '...Check results carefully.')
6173 : // ErrorsFound=.TRUE.
6174 : // ENDIF
6175 : // Reset surface to be "detached"
6176 24 : surfTemp.BaseSurf = 0;
6177 : // SurfaceTmp(SurfNum)%BaseSurfName=' '
6178 24 : surfTemp.Zone = 0;
6179 : // SurfaceTmp(SurfNum)%ZoneName=' '
6180 24 : if (state.dataReportFlag->MakeMirroredAttachedShading) {
6181 24 : MakeMirrorSurface(state, SurfNum);
6182 : }
6183 : }
6184 250 : }
6185 :
6186 226 : void GetSimpleShdSurfaceData(EnergyPlusData &state,
6187 : bool &ErrorsFound, // Error flag indicator (true if errors found)
6188 : int &SurfNum, // Count of Current SurfaceNumber
6189 : int const TotOverhangs, // Number of Overhangs to obtain
6190 : int const TotOverhangsProjection, // Number of Overhangs (projection) to obtain
6191 : int const TotFins, // Number of Fins to obtain
6192 : int const TotFinsProjection // Number of Fins (projection) to obtain
6193 : )
6194 : {
6195 :
6196 : // SUBROUTINE INFORMATION:
6197 : // AUTHOR Linda Lawrie
6198 : // DATE WRITTEN January 2009
6199 :
6200 : // PURPOSE OF THIS SUBROUTINE:
6201 : // Get simple overhang and fin descriptions.
6202 :
6203 : // SUBROUTINE PARAMETER DEFINITIONS:
6204 226 : static Array1D_string const cModuleObjects(4, {"Shading:Overhang", "Shading:Overhang:Projection", "Shading:Fin", "Shading:Fin:Projection"});
6205 :
6206 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
6207 : int ItemsToGet;
6208 : int NumAlphas;
6209 : int NumNumbers;
6210 : int IOStat; // IO Status when calling get input subroutine
6211 : Real64 Depth;
6212 : Real64 Length;
6213 : Real64 Xp;
6214 : Real64 Yp;
6215 : Real64 Zp;
6216 : Real64 XLLC;
6217 : Real64 YLLC;
6218 : int BaseSurfNum;
6219 : Real64 TiltAngle;
6220 : bool MakeFin;
6221 :
6222 226 : auto &s_ipsc = state.dataIPShortCut;
6223 :
6224 228 : if ((TotOverhangs + TotOverhangsProjection + TotFins + TotFinsProjection) > 0 &&
6225 2 : state.dataHeatBal->SolarDistribution == DataHeatBalance::Shadowing::Minimal) {
6226 0 : ShowWarningError(state, "Shading effects of Fins and Overhangs are ignored when Solar Distribution = MinimalShadowing");
6227 : }
6228 1130 : for (int Item = 1; Item <= 4; ++Item) {
6229 :
6230 904 : s_ipsc->cCurrentModuleObject = cModuleObjects(Item);
6231 904 : if (Item == 1) {
6232 226 : ItemsToGet = TotOverhangs;
6233 678 : } else if (Item == 2) {
6234 226 : ItemsToGet = TotOverhangsProjection;
6235 452 : } else if (Item == 3) {
6236 226 : ItemsToGet = TotFins;
6237 : } else { // ! (Item == 4) THEN
6238 226 : ItemsToGet = TotFinsProjection;
6239 : }
6240 :
6241 909 : for (int Loop = 1; Loop <= ItemsToGet; ++Loop) {
6242 10 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
6243 5 : s_ipsc->cCurrentModuleObject,
6244 : Loop,
6245 5 : s_ipsc->cAlphaArgs,
6246 : NumAlphas,
6247 5 : s_ipsc->rNumericArgs,
6248 : NumNumbers,
6249 : IOStat,
6250 5 : s_ipsc->lNumericFieldBlanks,
6251 5 : s_ipsc->lAlphaFieldBlanks,
6252 5 : s_ipsc->cAlphaFieldNames,
6253 5 : s_ipsc->cNumericFieldNames);
6254 :
6255 10 : if (GlobalNames::VerifyUniqueInterObjectName(state,
6256 5 : state.dataSurfaceGeometry->UniqueSurfaceNames,
6257 5 : s_ipsc->cAlphaArgs(1),
6258 5 : s_ipsc->cCurrentModuleObject,
6259 5 : s_ipsc->cAlphaFieldNames(1),
6260 : ErrorsFound)) {
6261 0 : continue;
6262 : }
6263 :
6264 5 : ++SurfNum;
6265 5 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
6266 :
6267 5 : surfTemp.Name = s_ipsc->cAlphaArgs(1); // Set the Surface Name in the Derived Type
6268 5 : surfTemp.Class = SurfaceClass::Shading;
6269 5 : surfTemp.HeatTransSurf = false;
6270 : // this object references a window or door....
6271 5 : int Found = Util::FindItemInList(s_ipsc->cAlphaArgs(2), state.dataSurfaceGeometry->SurfaceTmp, state.dataSurface->TotSurfaces);
6272 5 : if (Found > 0) {
6273 5 : BaseSurfNum = state.dataSurfaceGeometry->SurfaceTmp(Found).BaseSurf;
6274 5 : surfTemp.BaseSurfName = state.dataSurfaceGeometry->SurfaceTmp(Found).BaseSurfName;
6275 5 : surfTemp.ExtBoundCond = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCond;
6276 5 : surfTemp.ExtSolar = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtSolar;
6277 5 : surfTemp.ExtWind = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtWind;
6278 5 : surfTemp.Zone = state.dataSurfaceGeometry->SurfaceTmp(Found).Zone; // Necessary to do relative coordinates in GetVertices below
6279 5 : surfTemp.ZoneName = state.dataSurfaceGeometry->SurfaceTmp(Found).ZoneName; // Necessary to have surface drawn in OutputReports
6280 : } else {
6281 0 : ShowSevereError(state,
6282 0 : format("{}=\"{}\", invalid {}=\"{}",
6283 0 : s_ipsc->cCurrentModuleObject,
6284 0 : surfTemp.Name,
6285 0 : s_ipsc->cAlphaFieldNames(2),
6286 0 : s_ipsc->cAlphaArgs(2)));
6287 0 : ErrorsFound = true;
6288 0 : continue;
6289 : }
6290 5 : if (surfTemp.ExtBoundCond == unenteredAdjacentZoneSurface) {
6291 0 : ShowSevereError(state,
6292 0 : format("{}=\"{}\", invalid {}=\"{}",
6293 0 : s_ipsc->cCurrentModuleObject,
6294 0 : surfTemp.Name,
6295 0 : s_ipsc->cAlphaFieldNames(2),
6296 0 : s_ipsc->cAlphaArgs(2)));
6297 0 : ShowContinueError(state, "...trying to attach a shading device to an interzone surface.");
6298 0 : ErrorsFound = true;
6299 0 : surfTemp.ExtBoundCond = DataSurfaces::ExternalEnvironment; // reset so program won't crash during "add surfaces"
6300 : }
6301 5 : if (surfTemp.ExtBoundCond == unreconciledZoneSurface) {
6302 0 : ShowSevereError(state,
6303 0 : format("{}=\"{}\", invalid {}=\"{}",
6304 0 : s_ipsc->cCurrentModuleObject,
6305 0 : surfTemp.Name,
6306 0 : s_ipsc->cAlphaFieldNames(2),
6307 0 : s_ipsc->cAlphaArgs(2)));
6308 0 : ShowContinueError(state, "...trying to attach a shading device to an interior surface.");
6309 0 : ErrorsFound = true;
6310 0 : surfTemp.ExtBoundCond = DataSurfaces::ExternalEnvironment; // reset so program won't crash during "add surfaces"
6311 : }
6312 :
6313 5 : surfTemp.shadowSurfSched = nullptr;
6314 :
6315 : //===== Overhang =====
6316 :
6317 5 : if (Item < 3) {
6318 : // Found is the surface window or door.
6319 : // N1, \field Height above Window or Door
6320 : // \units m
6321 : // N2, \field Tilt Angle from Window/Door
6322 : // \units deg
6323 : // \default 90
6324 : // \minimum 0
6325 : // \maximum 180
6326 : // N3, \field Left extension from Window/Door Width
6327 : // \units m
6328 : // N4, \field Right extension from Window/Door Width
6329 : // \note N3 + N4 + Window/Door Width is Overhang Length
6330 : // \units m
6331 : // N5; \field Depth
6332 : // \units m
6333 : // for projection option:
6334 : // N5; \field Depth as Fraction of Window/Door Height
6335 : // \units m
6336 3 : Length = s_ipsc->rNumericArgs(3) + s_ipsc->rNumericArgs(4) + state.dataSurfaceGeometry->SurfaceTmp(Found).Width;
6337 3 : if (Item == 1) {
6338 2 : Depth = s_ipsc->rNumericArgs(5);
6339 1 : } else if (Item == 2) {
6340 1 : Depth = s_ipsc->rNumericArgs(5) * state.dataSurfaceGeometry->SurfaceTmp(Found).Height;
6341 : }
6342 :
6343 3 : if (Length * Depth <= 0.0) {
6344 0 : ShowSevereError(state,
6345 0 : format("{}=\"{}\", illegal surface area=[{:.2R}]. Surface will NOT be entered.",
6346 0 : s_ipsc->cCurrentModuleObject,
6347 0 : s_ipsc->cAlphaArgs(1),
6348 0 : Length * Depth));
6349 0 : continue;
6350 : }
6351 :
6352 3 : TiltAngle = state.dataSurfaceGeometry->SurfaceTmp(Found).Tilt + s_ipsc->rNumericArgs(2);
6353 3 : surfTemp.Tilt = TiltAngle;
6354 3 : surfTemp.convOrientation = Convect::GetSurfConvOrientation(surfTemp.Tilt);
6355 3 : surfTemp.Azimuth = state.dataSurfaceGeometry->SurfaceTmp(Found).Azimuth;
6356 :
6357 : // Make it relative to surface origin.....
6358 3 : Xp = state.dataSurfaceGeometry->SurfaceTmp(Found).Vertex(2).x - state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).x;
6359 3 : Yp = state.dataSurfaceGeometry->SurfaceTmp(Found).Vertex(2).y - state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).y;
6360 3 : Zp = state.dataSurfaceGeometry->SurfaceTmp(Found).Vertex(2).z - state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).z;
6361 :
6362 3 : XLLC = -Xp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosAzim +
6363 3 : Yp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).SinAzim;
6364 :
6365 3 : YLLC =
6366 3 : -Xp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).SinAzim *
6367 3 : state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosTilt -
6368 3 : Yp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosAzim * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosTilt +
6369 3 : Zp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).SinTilt;
6370 :
6371 3 : surfTemp.Sides = 4;
6372 3 : surfTemp.Vertex.allocate(surfTemp.Sides);
6373 :
6374 6 : MakeRelativeRectangularVertices(state,
6375 : BaseSurfNum,
6376 : SurfNum,
6377 3 : XLLC - s_ipsc->rNumericArgs(3),
6378 3 : YLLC + state.dataSurfaceGeometry->SurfaceTmp(Found).Height + s_ipsc->rNumericArgs(1),
6379 : Length,
6380 : Depth);
6381 :
6382 : // Reset surface to be "detached"
6383 : // SurfaceTmp(SurfNum)%BaseSurfName=' '
6384 : // SurfaceTmp(SurfNum)%ZoneName=' '
6385 :
6386 3 : surfTemp.BaseSurf = 0;
6387 3 : surfTemp.Zone = 0;
6388 :
6389 : // and mirror
6390 3 : if (state.dataReportFlag->MakeMirroredAttachedShading) {
6391 3 : MakeMirrorSurface(state, SurfNum);
6392 : }
6393 :
6394 : } else { // Fins
6395 :
6396 : //===== Fins =====
6397 :
6398 : //===== Left Fin =====
6399 :
6400 : // N1, \field Left Extension from Window/Door
6401 : // \units m
6402 : // N2, \field Left Distance Above Top of Window
6403 : // \units m
6404 : // N3, \field Left Distance Below Bottom of Window
6405 : // \units m
6406 : // \note N2 + N3 + height of Window/Door is height of Fin
6407 : // N4, \field Left Tilt Angle from Window/Door
6408 : // \units deg
6409 : // \default 90
6410 : // \minimum 0
6411 : // \maximum 180
6412 : // N5, \field Left Depth
6413 : // \units m
6414 : // for projection option:
6415 : // N5, \field Left Depth as Fraction of Window/Door Width
6416 : // \units m
6417 2 : surfTemp.Name = surfTemp.Name + " Left";
6418 2 : Length = s_ipsc->rNumericArgs(2) + s_ipsc->rNumericArgs(3) + state.dataSurfaceGeometry->SurfaceTmp(Found).Height;
6419 2 : if (Item == 3) {
6420 0 : Depth = s_ipsc->rNumericArgs(5);
6421 2 : } else if (Item == 4) {
6422 2 : Depth = s_ipsc->rNumericArgs(5) * state.dataSurfaceGeometry->SurfaceTmp(Found).Width;
6423 : }
6424 :
6425 2 : MakeFin = true;
6426 2 : if (Length * Depth <= 0.0) {
6427 2 : ShowWarningError(state,
6428 3 : format("{}=Left Fin of \"{}\", illegal surface area=[{:.2R}]. Surface will NOT be entered.",
6429 1 : s_ipsc->cCurrentModuleObject,
6430 1 : s_ipsc->cAlphaArgs(1),
6431 1 : Length * Depth));
6432 1 : MakeFin = false;
6433 : }
6434 :
6435 2 : if (MakeFin) {
6436 1 : TiltAngle = state.dataSurfaceGeometry->SurfaceTmp(Found).Tilt;
6437 1 : surfTemp.Tilt = TiltAngle;
6438 1 : surfTemp.convOrientation = Convect::GetSurfConvOrientation(surfTemp.Tilt);
6439 1 : surfTemp.Azimuth = state.dataSurfaceGeometry->SurfaceTmp(Found).Azimuth - (180.0 - s_ipsc->rNumericArgs(4));
6440 :
6441 : // Make it relative to surface origin.....
6442 :
6443 1 : Xp =
6444 1 : state.dataSurfaceGeometry->SurfaceTmp(Found).Vertex(2).x - state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).x;
6445 1 : Yp =
6446 1 : state.dataSurfaceGeometry->SurfaceTmp(Found).Vertex(2).y - state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).y;
6447 1 : Zp =
6448 1 : state.dataSurfaceGeometry->SurfaceTmp(Found).Vertex(2).z - state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).z;
6449 :
6450 1 : XLLC = -Xp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosAzim +
6451 1 : Yp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).SinAzim;
6452 :
6453 1 : YLLC = -Xp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).SinAzim *
6454 1 : state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosTilt -
6455 1 : Yp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosAzim *
6456 1 : state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosTilt +
6457 1 : Zp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).SinTilt;
6458 :
6459 1 : surfTemp.CosAzim = std::cos(surfTemp.Azimuth * Constant::DegToRad);
6460 1 : surfTemp.SinAzim = std::sin(surfTemp.Azimuth * Constant::DegToRad);
6461 1 : surfTemp.CosTilt = std::cos(surfTemp.Tilt * Constant::DegToRad);
6462 1 : surfTemp.SinTilt = std::sin(surfTemp.Tilt * Constant::DegToRad);
6463 :
6464 1 : surfTemp.Sides = 4;
6465 1 : surfTemp.Vertex.allocate(surfTemp.Sides);
6466 :
6467 3 : MakeRelativeRectangularVertices(
6468 1 : state, BaseSurfNum, SurfNum, XLLC - s_ipsc->rNumericArgs(1), YLLC - s_ipsc->rNumericArgs(3), -Depth, Length);
6469 :
6470 : // Reset surface to be "detached"
6471 : // SurfaceTmp(SurfNum)%BaseSurfName=' '
6472 : // SurfaceTmp(SurfNum)%ZoneName=' '
6473 :
6474 1 : surfTemp.BaseSurf = 0;
6475 1 : surfTemp.Zone = 0;
6476 :
6477 : // and mirror
6478 1 : if (state.dataReportFlag->MakeMirroredAttachedShading) {
6479 1 : MakeMirrorSurface(state, SurfNum);
6480 : }
6481 : } else {
6482 1 : --SurfNum;
6483 : }
6484 :
6485 : //===== Right Fin =====
6486 :
6487 : // N6, \field Right Extension from Window/Door
6488 : // \units m
6489 : // N7, \field Right Distance Above Top of Window
6490 : // \units m
6491 : // N8, \field Right Distance Below Bottom of Window
6492 : // \note N7 + N8 + height of Window/Door is height of Fin
6493 : // \units m
6494 : // N9, \field Right Tilt Angle from Window/Door
6495 : // \units deg
6496 : // \default 90
6497 : // \minimum 0
6498 : // \maximum 180
6499 : // N10; \field Right Depth
6500 : // \units m
6501 : // for projection option:
6502 : // N10; \field Right Depth as Fraction of Window/Door Width
6503 : // \units m
6504 :
6505 2 : ++SurfNum;
6506 2 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
6507 2 : surfTemp.Name = s_ipsc->cAlphaArgs(1) + " Right"; // Set the Surface Name in the Derived Type
6508 2 : surfTemp.Class = SurfaceClass::Shading;
6509 2 : surfTemp.HeatTransSurf = false;
6510 2 : BaseSurfNum = state.dataSurfaceGeometry->SurfaceTmp(Found).BaseSurf;
6511 2 : surfTemp.BaseSurfName = state.dataSurfaceGeometry->SurfaceTmp(Found).BaseSurfName;
6512 2 : surfTemp.ExtBoundCond = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCond;
6513 2 : surfTemp.ExtSolar = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtSolar;
6514 2 : surfTemp.ExtWind = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtWind;
6515 2 : surfTemp.Zone = state.dataSurfaceGeometry->SurfaceTmp(Found).Zone; // Necessary to do relative coordinates in GetVertices below
6516 2 : surfTemp.ZoneName = state.dataSurfaceGeometry->SurfaceTmp(Found).ZoneName; // Necessary to have surface drawn in OutputReports
6517 :
6518 2 : surfTemp.shadowSurfSched = nullptr;
6519 2 : Length = s_ipsc->rNumericArgs(7) + s_ipsc->rNumericArgs(8) + state.dataSurfaceGeometry->SurfaceTmp(Found).Height;
6520 2 : if (Item == 3) {
6521 0 : Depth = s_ipsc->rNumericArgs(10);
6522 2 : } else if (Item == 4) {
6523 2 : Depth = s_ipsc->rNumericArgs(10) * state.dataSurfaceGeometry->SurfaceTmp(Found).Width;
6524 : }
6525 :
6526 2 : MakeFin = true;
6527 2 : if (Length * Depth <= 0.0) {
6528 2 : ShowWarningError(state,
6529 3 : format("{}=Right Fin of \"{}\", illegal surface area=[{:.2R}]. Surface will NOT be entered.",
6530 1 : s_ipsc->cCurrentModuleObject,
6531 1 : s_ipsc->cAlphaArgs(1),
6532 1 : Length * Depth));
6533 1 : MakeFin = false;
6534 : }
6535 :
6536 2 : if (MakeFin) {
6537 : // Make it relative to surface origin.....
6538 :
6539 1 : Xp =
6540 1 : state.dataSurfaceGeometry->SurfaceTmp(Found).Vertex(2).x - state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).x;
6541 1 : Yp =
6542 1 : state.dataSurfaceGeometry->SurfaceTmp(Found).Vertex(2).y - state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).y;
6543 1 : Zp =
6544 1 : state.dataSurfaceGeometry->SurfaceTmp(Found).Vertex(2).z - state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).z;
6545 :
6546 1 : XLLC = -Xp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosAzim +
6547 1 : Yp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).SinAzim;
6548 :
6549 1 : YLLC = -Xp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).SinAzim *
6550 1 : state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosTilt -
6551 1 : Yp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosAzim *
6552 1 : state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosTilt +
6553 1 : Zp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).SinTilt;
6554 :
6555 1 : TiltAngle = state.dataSurfaceGeometry->SurfaceTmp(Found).Tilt;
6556 1 : surfTemp.Tilt = TiltAngle;
6557 1 : surfTemp.convOrientation = Convect::GetSurfConvOrientation(surfTemp.Tilt);
6558 1 : surfTemp.Azimuth = state.dataSurfaceGeometry->SurfaceTmp(Found).Azimuth - (180.0 - s_ipsc->rNumericArgs(9));
6559 1 : surfTemp.CosAzim = std::cos(surfTemp.Azimuth * Constant::DegToRad);
6560 1 : surfTemp.SinAzim = std::sin(surfTemp.Azimuth * Constant::DegToRad);
6561 1 : surfTemp.CosTilt = std::cos(surfTemp.Tilt * Constant::DegToRad);
6562 1 : surfTemp.SinTilt = std::sin(surfTemp.Tilt * Constant::DegToRad);
6563 :
6564 1 : surfTemp.Sides = 4;
6565 1 : surfTemp.Vertex.allocate(surfTemp.Sides);
6566 :
6567 3 : MakeRelativeRectangularVertices(state,
6568 : BaseSurfNum,
6569 : SurfNum,
6570 1 : XLLC + state.dataSurfaceGeometry->SurfaceTmp(Found).Width + s_ipsc->rNumericArgs(6),
6571 1 : YLLC - s_ipsc->rNumericArgs(8),
6572 : -Depth,
6573 : Length);
6574 :
6575 : // Reset surface to be "detached"
6576 : // SurfaceTmp(SurfNum)%BaseSurfName=' '
6577 : // SurfaceTmp(SurfNum)%ZoneName=' '
6578 :
6579 1 : surfTemp.BaseSurf = 0;
6580 1 : surfTemp.Zone = 0;
6581 :
6582 : // and mirror
6583 1 : if (state.dataReportFlag->MakeMirroredAttachedShading) {
6584 1 : MakeMirrorSurface(state, SurfNum);
6585 : }
6586 : } else {
6587 1 : --SurfNum;
6588 : }
6589 : }
6590 : }
6591 : }
6592 226 : }
6593 :
6594 227 : void GetIntMassSurfaceData(EnergyPlusData &state,
6595 : bool &ErrorsFound, // Error flag indicator (true if errors found)
6596 : int &SurfNum // Count of Current SurfaceNumber
6597 : )
6598 : {
6599 :
6600 : // SUBROUTINE INFORMATION:
6601 : // AUTHOR Linda Lawrie
6602 : // DATE WRITTEN May 2000
6603 :
6604 : // PURPOSE OF THIS SUBROUTINE:
6605 : // This subroutine gets the Internal Surface Data,
6606 : // checks it for errors, etc.
6607 :
6608 : // REFERENCES:
6609 : // Internal Mass Surface Definition
6610 : // Surface:HeatTransfer:InternalMass,
6611 : // \note used to describe internal zone surface area that does not need to be part of geometric representation
6612 : // A1 , \field User Supplied Surface Name
6613 : // \type alpha
6614 : // \reference SurfaceNames
6615 : // A2 , \field Construction Name of the Surface
6616 : // \note To be matched with a construction in this input file
6617 : // \type object-list
6618 : // \object-list ConstructionNames
6619 : // A3 , \field Interior Environment
6620 : // \note Zone the surface is a part of
6621 : // \type object-list
6622 : // \object-list ZoneNames
6623 : // N1, \field View factor to Person (to people?)
6624 : // \type real
6625 : // \note from the interior of the surface
6626 : // N2 ; \field Surface area
6627 : // \units m2
6628 :
6629 : // SUBROUTINE PARAMETER DEFINITIONS:
6630 : static constexpr std::string_view RoutineName("GetIntMassSurfaceData: ");
6631 :
6632 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
6633 : int IOStat; // IO Status when calling get input subroutine
6634 : int SurfaceNumAlpha; // Number of material alpha names being passed
6635 : int SurfaceNumArg; // Number of material properties being passed
6636 :
6637 227 : auto &s_ipsc = state.dataIPShortCut;
6638 227 : s_ipsc->cCurrentModuleObject = "InternalMass";
6639 227 : int TotIntMass = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
6640 227 : if (TotIntMass == 0) return;
6641 :
6642 9 : state.dataSurface->IntMassObjects.allocate(TotIntMass);
6643 :
6644 : // scan for use of Zone lists in InternalMass objects
6645 9 : bool errFlag = false;
6646 9 : int NumIntMassSurfaces = 0;
6647 28 : for (int Item = 1; Item <= TotIntMass; ++Item) {
6648 38 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
6649 19 : s_ipsc->cCurrentModuleObject,
6650 : Item,
6651 19 : s_ipsc->cAlphaArgs,
6652 : SurfaceNumAlpha,
6653 19 : s_ipsc->rNumericArgs,
6654 : SurfaceNumArg,
6655 : IOStat,
6656 19 : s_ipsc->lNumericFieldBlanks,
6657 19 : s_ipsc->lAlphaFieldBlanks,
6658 19 : s_ipsc->cAlphaFieldNames,
6659 19 : s_ipsc->cNumericFieldNames);
6660 :
6661 38 : if (GlobalNames::VerifyUniqueInterObjectName(state,
6662 19 : state.dataSurfaceGeometry->UniqueSurfaceNames,
6663 19 : s_ipsc->cAlphaArgs(1),
6664 19 : s_ipsc->cCurrentModuleObject,
6665 19 : s_ipsc->cAlphaFieldNames(1),
6666 : ErrorsFound)) {
6667 0 : continue;
6668 : }
6669 :
6670 19 : state.dataSurface->IntMassObjects(Item).Name = s_ipsc->cAlphaArgs(1);
6671 19 : state.dataSurface->IntMassObjects(Item).GrossArea = s_ipsc->rNumericArgs(1);
6672 19 : state.dataSurface->IntMassObjects(Item).Construction =
6673 19 : Util::FindItemInList(s_ipsc->cAlphaArgs(2), state.dataConstruction->Construct, state.dataHeatBal->TotConstructs);
6674 19 : state.dataSurface->IntMassObjects(Item).ZoneOrZoneListName = s_ipsc->cAlphaArgs(3);
6675 19 : int Item1 = Util::FindItemInList(s_ipsc->cAlphaArgs(3), state.dataHeatBal->Zone, state.dataGlobal->NumOfZones);
6676 19 : int ZLItem = 0;
6677 19 : if (Item1 == 0 && state.dataHeatBal->NumOfZoneLists > 0)
6678 3 : ZLItem = Util::FindItemInList(s_ipsc->cAlphaArgs(3), state.dataHeatBal->ZoneList);
6679 19 : if (Item1 > 0) {
6680 16 : if (s_ipsc->lAlphaFieldBlanks(4)) {
6681 16 : ++NumIntMassSurfaces;
6682 : }
6683 16 : state.dataSurface->IntMassObjects(Item).NumOfZones = 1;
6684 16 : state.dataSurface->IntMassObjects(Item).ZoneListActive = false;
6685 16 : state.dataSurface->IntMassObjects(Item).ZoneOrZoneListPtr = Item1;
6686 3 : } else if (ZLItem > 0) {
6687 3 : NumIntMassSurfaces += state.dataHeatBal->ZoneList(ZLItem).NumOfZones;
6688 3 : state.dataSurface->IntMassObjects(Item).NumOfZones = state.dataHeatBal->ZoneList(ZLItem).NumOfZones;
6689 3 : state.dataSurface->IntMassObjects(Item).ZoneListActive = true;
6690 3 : state.dataSurface->IntMassObjects(Item).ZoneOrZoneListPtr = ZLItem;
6691 0 : } else if (state.dataIPShortCut->lAlphaFieldBlanks(4)) {
6692 : // If Space or SpaceList Name is blank, then throw error.
6693 0 : ShowSevereError(state,
6694 0 : format("{}=\"{}\" invalid {}=\"{}\" not found.",
6695 0 : s_ipsc->cCurrentModuleObject,
6696 0 : s_ipsc->cAlphaArgs(1),
6697 0 : s_ipsc->cAlphaFieldNames(3),
6698 0 : s_ipsc->cAlphaArgs(3)));
6699 0 : ++SurfNum;
6700 0 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
6701 0 : surfTemp.Class = SurfaceClass::Invalid;
6702 0 : surfTemp.ZoneName = "Unknown Zone";
6703 0 : ErrorsFound = true;
6704 0 : errFlag = true;
6705 : }
6706 :
6707 19 : if (!s_ipsc->lAlphaFieldBlanks(4)) {
6708 0 : state.dataSurface->IntMassObjects(Item).spaceOrSpaceListName = s_ipsc->cAlphaArgs(4);
6709 0 : Item1 = Util::FindItemInList(s_ipsc->cAlphaArgs(4), state.dataHeatBal->space);
6710 0 : int SLItem = 0;
6711 0 : if (Item1 == 0 && int(state.dataHeatBal->spaceList.size()) > 0)
6712 0 : SLItem = Util::FindItemInList(s_ipsc->cAlphaArgs(4), state.dataHeatBal->spaceList);
6713 0 : if (Item1 > 0) {
6714 0 : ++NumIntMassSurfaces;
6715 0 : state.dataSurface->IntMassObjects(Item).numOfSpaces = 1;
6716 0 : state.dataSurface->IntMassObjects(Item).spaceListActive = false;
6717 0 : state.dataSurface->IntMassObjects(Item).spaceOrSpaceListPtr = Item1;
6718 0 : state.dataSurface->IntMassObjects(Item).NumOfZones = 1;
6719 0 : state.dataSurface->IntMassObjects(Item).ZoneListActive = false;
6720 0 : state.dataSurface->IntMassObjects(Item).ZoneOrZoneListPtr = state.dataHeatBal->space(Item1).zoneNum;
6721 0 : } else if (SLItem > 0) {
6722 0 : int numOfSpaces = int(state.dataHeatBal->spaceList(SLItem).numListSpaces);
6723 0 : NumIntMassSurfaces += numOfSpaces;
6724 0 : state.dataSurface->IntMassObjects(Item).numOfSpaces = numOfSpaces;
6725 0 : state.dataSurface->IntMassObjects(Item).spaceListActive = true;
6726 0 : state.dataSurface->IntMassObjects(Item).spaceOrSpaceListPtr = SLItem;
6727 : } else {
6728 0 : ShowSevereError(state,
6729 0 : format("{}=\"{}\" invalid {}=\"{}\" not found.",
6730 0 : s_ipsc->cCurrentModuleObject,
6731 0 : s_ipsc->cAlphaArgs(1),
6732 0 : s_ipsc->cAlphaFieldNames(4),
6733 0 : s_ipsc->cAlphaArgs(4)));
6734 0 : ++SurfNum;
6735 0 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
6736 0 : surfTemp.Class = SurfaceClass::Invalid;
6737 0 : ErrorsFound = true;
6738 0 : errFlag = true;
6739 : }
6740 : }
6741 :
6742 19 : if (errFlag) {
6743 0 : ShowSevereError(state, format("{}Errors with invalid names in {} objects.", RoutineName, s_ipsc->cCurrentModuleObject));
6744 0 : ShowContinueError(state, "...These will not be read in. Other errors may occur.");
6745 0 : NumIntMassSurfaces = 0;
6746 : }
6747 :
6748 19 : if (state.dataSurface->IntMassObjects(Item).Construction == 0) {
6749 0 : ErrorsFound = true;
6750 0 : ShowSevereError(state,
6751 0 : format("{}=\"{}\", {} not found={}",
6752 0 : s_ipsc->cCurrentModuleObject,
6753 0 : s_ipsc->cAlphaArgs(1),
6754 0 : s_ipsc->cAlphaFieldNames(2),
6755 0 : s_ipsc->cAlphaArgs(2)));
6756 19 : } else if (state.dataConstruction->Construct(state.dataSurface->IntMassObjects(Item).Construction).TypeIsWindow) {
6757 0 : ErrorsFound = true;
6758 0 : ShowSevereError(state,
6759 0 : format("{}=\"{}\", invalid {}=\"{}\" - has Window materials.",
6760 0 : s_ipsc->cCurrentModuleObject,
6761 0 : s_ipsc->cAlphaArgs(1),
6762 0 : s_ipsc->cAlphaFieldNames(2),
6763 0 : s_ipsc->cAlphaArgs(2)));
6764 : } else {
6765 19 : state.dataConstruction->Construct(state.dataSurface->IntMassObjects(Item).Construction).IsUsed = true;
6766 : }
6767 : }
6768 :
6769 9 : if (NumIntMassSurfaces > 0) {
6770 28 : for (int Loop = 1; Loop <= TotIntMass; ++Loop) {
6771 19 : int numberOfZonesOrSpaces = 1;
6772 19 : if (state.dataSurface->IntMassObjects(Loop).ZoneListActive) {
6773 3 : numberOfZonesOrSpaces = state.dataSurface->IntMassObjects(Loop).NumOfZones;
6774 16 : } else if (state.dataSurface->IntMassObjects(Loop).spaceListActive) {
6775 0 : numberOfZonesOrSpaces = state.dataSurface->IntMassObjects(Loop).numOfSpaces;
6776 : }
6777 :
6778 59 : for (int Item1 = 1; Item1 <= numberOfZonesOrSpaces; ++Item1) {
6779 :
6780 40 : ++SurfNum;
6781 :
6782 40 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
6783 40 : surfTemp.Construction = state.dataSurface->IntMassObjects(Loop).Construction;
6784 40 : if (!state.dataSurface->IntMassObjects(Loop).ZoneListActive && !state.dataSurface->IntMassObjects(Loop).spaceListActive) {
6785 16 : surfTemp.Zone = state.dataSurface->IntMassObjects(Loop).ZoneOrZoneListPtr;
6786 16 : surfTemp.spaceNum = state.dataSurface->IntMassObjects(Loop).spaceOrSpaceListPtr;
6787 16 : surfTemp.Name = state.dataSurface->IntMassObjects(Loop).Name;
6788 16 : surfTemp.Class = SurfaceClass::IntMass;
6789 16 : surfTemp.ZoneName = state.dataSurface->IntMassObjects(Loop).ZoneOrZoneListName;
6790 16 : surfTemp.HeatTransSurf = true;
6791 : } else {
6792 24 : int ZoneNum = 0; // index to a zone
6793 24 : if (state.dataSurface->IntMassObjects(Loop).ZoneListActive) {
6794 72 : General::CheckCreatedZoneItemName(
6795 : state,
6796 : RoutineName,
6797 24 : s_ipsc->cCurrentModuleObject,
6798 : state.dataHeatBal
6799 24 : ->Zone(state.dataHeatBal->ZoneList(state.dataSurface->IntMassObjects(Loop).ZoneOrZoneListPtr).Zone(Item1))
6800 24 : .Name,
6801 24 : state.dataHeatBal->ZoneList(state.dataSurface->IntMassObjects(Loop).ZoneOrZoneListPtr).MaxZoneNameLength,
6802 24 : state.dataSurface->IntMassObjects(Loop).Name,
6803 24 : state.dataSurfaceGeometry->SurfaceTmp,
6804 24 : SurfNum - 1,
6805 24 : surfTemp.Name,
6806 : errFlag);
6807 :
6808 24 : ZoneNum = state.dataHeatBal->ZoneList(state.dataSurface->IntMassObjects(Loop).ZoneOrZoneListPtr).Zone(Item1);
6809 0 : } else if (state.dataSurface->IntMassObjects(Loop).spaceListActive) {
6810 0 : int spaceNum = state.dataHeatBal->spaceList(state.dataSurface->IntMassObjects(Loop).spaceOrSpaceListPtr).spaces(Item1);
6811 0 : ZoneNum = state.dataHeatBal->space(spaceNum).zoneNum;
6812 0 : const std::string spaceName = state.dataHeatBal->space(spaceNum).Name;
6813 0 : surfTemp.Name = spaceName + ' ' + state.dataSurface->IntMassObjects(Loop).Name;
6814 0 : surfTemp.spaceNum = spaceNum;
6815 0 : }
6816 24 : surfTemp.Zone = ZoneNum;
6817 24 : surfTemp.Class = SurfaceClass::IntMass;
6818 24 : surfTemp.ZoneName = state.dataHeatBal->Zone(ZoneNum).Name;
6819 24 : surfTemp.HeatTransSurf = true;
6820 24 : if (errFlag) ErrorsFound = true;
6821 : }
6822 :
6823 40 : if (state.dataSurface->IntMassObjects(Loop).Construction > 0) {
6824 40 : if (state.dataConstruction->Construct(state.dataSurface->IntMassObjects(Loop).Construction).IsUsed) {
6825 40 : surfTemp.ConstructionStoredInputValue = state.dataSurface->IntMassObjects(Loop).Construction;
6826 : }
6827 : }
6828 40 : surfTemp.GrossArea = state.dataSurface->IntMassObjects(Loop).GrossArea;
6829 40 : surfTemp.Area = surfTemp.GrossArea;
6830 40 : surfTemp.NetAreaShadowCalc = surfTemp.Area;
6831 40 : surfTemp.Width = surfTemp.Area;
6832 40 : surfTemp.Height = 1.0;
6833 40 : surfTemp.Tilt = 90.0;
6834 40 : surfTemp.convOrientation = Convect::GetSurfConvOrientation(surfTemp.Tilt);
6835 40 : surfTemp.CosTilt = 0.0; // Tuned Was std::cos( 90.0 * DegToRadians )
6836 40 : surfTemp.SinTilt = 1.0; // Tuned Was std::sin( 90.0 * DegToRadians )
6837 40 : surfTemp.Azimuth = 0.0;
6838 40 : surfTemp.CosAzim = 1.0; // Tuned Was std::cos( 0.0 )
6839 40 : surfTemp.SinAzim = 0.0; // Tuned Was std::sin( 0.0 )
6840 : // Outward normal unit vector (pointing away from room)
6841 40 : surfTemp.OutNormVec = surfTemp.lcsz;
6842 40 : surfTemp.ViewFactorSky = 0.5;
6843 40 : surfTemp.ExtSolar = false;
6844 40 : surfTemp.ExtWind = false;
6845 40 : surfTemp.BaseSurf = SurfNum;
6846 40 : surfTemp.BaseSurfName = surfTemp.Name;
6847 40 : surfTemp.ExtBoundCondName = surfTemp.Name;
6848 40 : surfTemp.ExtBoundCond = unreconciledZoneSurface;
6849 : }
6850 : }
6851 : }
6852 : }
6853 :
6854 228 : int GetNumIntMassSurfaces(EnergyPlusData &state) // Number of Internal Mass Surfaces to obtain
6855 :
6856 : {
6857 : // Counts internal mass surfaces applied to zones and zone lists
6858 :
6859 : int IOStat; // IO Status when calling get input subroutine
6860 : int SurfaceNumAlpha; // Number of material alpha names being passed
6861 : int SurfaceNumArg; // Number of material properties being passed
6862 :
6863 228 : auto &s_ipsc = state.dataIPShortCut;
6864 228 : s_ipsc->cCurrentModuleObject = "InternalMass";
6865 :
6866 228 : int NumIntMassSurf = 0;
6867 228 : int TotIntMass = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "InternalMass");
6868 :
6869 228 : if (TotIntMass == 0) return NumIntMassSurf;
6870 : // scan for zones and zone lists in InternalMass objects
6871 32 : for (int Item = 1; Item <= TotIntMass; ++Item) {
6872 44 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
6873 22 : s_ipsc->cCurrentModuleObject,
6874 : Item,
6875 22 : s_ipsc->cAlphaArgs,
6876 : SurfaceNumAlpha,
6877 22 : s_ipsc->rNumericArgs,
6878 : SurfaceNumArg,
6879 : IOStat,
6880 22 : s_ipsc->lNumericFieldBlanks,
6881 22 : s_ipsc->lAlphaFieldBlanks,
6882 22 : s_ipsc->cAlphaFieldNames,
6883 22 : s_ipsc->cNumericFieldNames);
6884 :
6885 22 : int Item1 = Util::FindItemInList(s_ipsc->cAlphaArgs(3), state.dataHeatBal->Zone, state.dataGlobal->NumOfZones);
6886 22 : int ZLItem = 0;
6887 22 : if (Item1 == 0 && state.dataHeatBal->NumOfZoneLists > 0)
6888 6 : ZLItem = Util::FindItemInList(s_ipsc->cAlphaArgs(3), state.dataHeatBal->ZoneList);
6889 22 : if (Item1 > 0) {
6890 16 : if (s_ipsc->lAlphaFieldBlanks(4)) {
6891 16 : ++NumIntMassSurf;
6892 : }
6893 6 : } else if (ZLItem > 0) {
6894 6 : NumIntMassSurf += state.dataHeatBal->ZoneList(ZLItem).NumOfZones;
6895 : }
6896 :
6897 22 : if (!s_ipsc->lAlphaFieldBlanks(4)) {
6898 0 : Item1 = Util::FindItemInList(s_ipsc->cAlphaArgs(4), state.dataHeatBal->space);
6899 0 : int SLItem = 0;
6900 0 : if (Item1 == 0 && int(state.dataHeatBal->spaceList.size()) > 0)
6901 0 : SLItem = Util::FindItemInList(s_ipsc->cAlphaArgs(4), state.dataHeatBal->spaceList);
6902 0 : if (Item1 > 0) {
6903 0 : ++NumIntMassSurf;
6904 0 : } else if (SLItem > 0) {
6905 0 : int numOfSpaces = int(state.dataHeatBal->spaceList(SLItem).numListSpaces);
6906 0 : NumIntMassSurf += numOfSpaces;
6907 : }
6908 : }
6909 : }
6910 10 : NumIntMassSurf = max(NumIntMassSurf, TotIntMass);
6911 10 : return NumIntMassSurf;
6912 : }
6913 :
6914 0 : void GetShadingSurfReflectanceData(EnergyPlusData &state, bool &ErrorsFound) // If errors found in input
6915 : {
6916 :
6917 : // SUBROUTINE INFORMATION:
6918 : // AUTHOR Fred Winkelmann
6919 : // DATE WRITTEN Sept 2003
6920 :
6921 : // PURPOSE OF THIS SUBROUTINE:
6922 : // Gets data for a Shading Surface Reflectance object. This is only called when the
6923 : // Solar Distribution is to be calculated for reflectances.
6924 :
6925 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
6926 : int IOStat; // IO Status when calling get input subroutine
6927 : int NumAlpha; // Number of alpha names being passed
6928 : int NumProp; // Number of properties being passed
6929 : int TotShadingSurfaceReflectance; // Total Shading Surface Reflectance statements
6930 : int Loop; // DO loop index
6931 : int SurfNum; // Surface number
6932 : int GlConstrNum; // Glazing construction number
6933 : bool WrongSurfaceType;
6934 :
6935 0 : auto &s_ipsc = state.dataIPShortCut;
6936 : // For shading surfaces, initialize value of reflectance values to default values. These values
6937 : // may be overridden below for shading surfaces with an associated Shading Surface Reflectance object.
6938 0 : for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
6939 0 : auto const &surf = state.dataSurface->Surface(SurfNum);
6940 0 : if (!(surf.Class == SurfaceClass::Shading || surf.Class == SurfaceClass::Detached_F || surf.Class == SurfaceClass::Detached_B ||
6941 0 : surf.Class == SurfaceClass::Overhang || surf.Class == SurfaceClass::Fin))
6942 0 : continue;
6943 0 : state.dataSurface->SurfShadowDiffuseSolRefl(SurfNum) = 0.2;
6944 0 : state.dataSurface->SurfShadowDiffuseVisRefl(SurfNum) = 0.2;
6945 0 : state.dataSurface->SurfShadowGlazingFrac(SurfNum) = 0.0;
6946 0 : state.dataSurface->SurfShadowGlazingConstruct(SurfNum) = 0;
6947 : }
6948 :
6949 : // Get the total number of Shading Surface Reflectance objects
6950 0 : s_ipsc->cCurrentModuleObject = "ShadingProperty:Reflectance";
6951 0 : TotShadingSurfaceReflectance = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
6952 : // IF(TotShadingSurfaceReflectance.EQ.0) RETURN
6953 :
6954 0 : for (Loop = 1; Loop <= TotShadingSurfaceReflectance; ++Loop) {
6955 :
6956 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
6957 0 : s_ipsc->cCurrentModuleObject,
6958 : Loop,
6959 0 : s_ipsc->cAlphaArgs,
6960 : NumAlpha,
6961 0 : s_ipsc->rNumericArgs,
6962 : NumProp,
6963 : IOStat,
6964 0 : s_ipsc->lNumericFieldBlanks,
6965 0 : s_ipsc->lAlphaFieldBlanks,
6966 0 : s_ipsc->cAlphaFieldNames,
6967 0 : s_ipsc->cNumericFieldNames);
6968 0 : SurfNum = Util::FindItemInList(s_ipsc->cAlphaArgs(1), state.dataSurface->Surface, state.dataSurface->TotSurfaces);
6969 0 : if (SurfNum == 0) {
6970 0 : ShowWarningError(state, format("{}=\"{}\", invalid specification", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
6971 0 : ShowContinueError(state, format(".. not found {}=\"{}\".", s_ipsc->cAlphaFieldNames(1), s_ipsc->cAlphaArgs(1)));
6972 : // ErrorsFound =.TRUE.
6973 0 : continue;
6974 : }
6975 :
6976 : // Check that associated surface is a shading surface
6977 0 : WrongSurfaceType = false;
6978 0 : auto const &surf = state.dataSurface->Surface(SurfNum);
6979 0 : if (!(surf.Class == SurfaceClass::Shading || surf.Class == SurfaceClass::Detached_F || surf.Class == SurfaceClass::Detached_B ||
6980 0 : surf.Class == SurfaceClass::Overhang || surf.Class == SurfaceClass::Fin))
6981 0 : WrongSurfaceType = true;
6982 0 : if (WrongSurfaceType) {
6983 0 : ShowSevereError(
6984 : state,
6985 0 : format("GetShadingSurfReflectanceData: {}=\"{}\", surface is not a shading surface.", s_ipsc->cCurrentModuleObject, surf.Name));
6986 0 : ErrorsFound = true;
6987 0 : continue;
6988 : }
6989 :
6990 : // If associated surface is a shading surface, set reflectance values
6991 0 : state.dataSurface->SurfShadowGlazingFrac(SurfNum) = s_ipsc->rNumericArgs(3);
6992 0 : state.dataSurface->SurfShadowDiffuseSolRefl(SurfNum) = (1.0 - s_ipsc->rNumericArgs(3)) * s_ipsc->rNumericArgs(1);
6993 0 : state.dataSurface->SurfShadowDiffuseVisRefl(SurfNum) = (1.0 - s_ipsc->rNumericArgs(3)) * s_ipsc->rNumericArgs(2);
6994 0 : if (s_ipsc->rNumericArgs(3) > 0.0) {
6995 0 : GlConstrNum = Util::FindItemInList(s_ipsc->cAlphaArgs(2), state.dataConstruction->Construct, state.dataHeatBal->TotConstructs);
6996 0 : if (GlConstrNum == 0) {
6997 0 : ShowSevereError(state,
6998 0 : format("{}=\"{}\", {} not found={}",
6999 0 : s_ipsc->cCurrentModuleObject,
7000 0 : state.dataSurface->Surface(SurfNum).Name,
7001 0 : s_ipsc->cAlphaFieldNames(2),
7002 0 : s_ipsc->cAlphaArgs(2)));
7003 0 : ErrorsFound = true;
7004 : } else {
7005 0 : state.dataConstruction->Construct(GlConstrNum).IsUsed = true;
7006 : }
7007 0 : state.dataSurface->SurfShadowGlazingConstruct(SurfNum) = GlConstrNum;
7008 : }
7009 0 : SurfNum = Util::FindItemInList("Mir-" + s_ipsc->cAlphaArgs(1), state.dataSurface->Surface, state.dataSurface->TotSurfaces);
7010 0 : if (SurfNum == 0) continue;
7011 0 : state.dataSurface->SurfShadowGlazingFrac(SurfNum) = s_ipsc->rNumericArgs(3);
7012 0 : state.dataSurface->SurfShadowDiffuseSolRefl(SurfNum) = (1.0 - s_ipsc->rNumericArgs(3)) * s_ipsc->rNumericArgs(1);
7013 0 : state.dataSurface->SurfShadowDiffuseVisRefl(SurfNum) = (1.0 - s_ipsc->rNumericArgs(3)) * s_ipsc->rNumericArgs(2);
7014 0 : if (s_ipsc->rNumericArgs(3) > 0.0) {
7015 0 : GlConstrNum = Util::FindItemInList(s_ipsc->cAlphaArgs(2), state.dataConstruction->Construct, state.dataHeatBal->TotConstructs);
7016 0 : if (GlConstrNum != 0) {
7017 0 : state.dataConstruction->Construct(GlConstrNum).IsUsed = true;
7018 : }
7019 0 : state.dataSurface->SurfShadowGlazingConstruct(SurfNum) = GlConstrNum;
7020 : }
7021 :
7022 : } // End of loop over Shading Surface Reflectance objects
7023 :
7024 : // Write reflectance values to .eio file.
7025 0 : print(state.files.eio,
7026 : "! <ShadingProperty Reflectance>,Shading Surface Name,Shading Type,Diffuse Solar Reflectance, Diffuse "
7027 : "Visible Reflectance,Surface Glazing Fraction,Surface Glazing Construction\n");
7028 :
7029 0 : for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
7030 0 : auto const &surf = state.dataSurface->Surface(SurfNum);
7031 0 : if (!(surf.Class == SurfaceClass::Shading || surf.Class == SurfaceClass::Detached_F || surf.Class == SurfaceClass::Detached_B ||
7032 0 : surf.Class == SurfaceClass::Overhang || surf.Class == SurfaceClass::Fin))
7033 0 : continue;
7034 :
7035 0 : constexpr std::string_view fmt = "ShadingProperty Reflectance,{},{},{:.2R},{:.2R},{:.2R}, {}\n";
7036 0 : if (state.dataSurface->SurfShadowGlazingConstruct(SurfNum) != 0) {
7037 0 : print(state.files.eio,
7038 : fmt,
7039 0 : surf.Name,
7040 0 : cSurfaceClass(surf.Class),
7041 0 : state.dataSurface->SurfShadowDiffuseSolRefl(SurfNum),
7042 0 : state.dataSurface->SurfShadowDiffuseVisRefl(SurfNum),
7043 0 : state.dataSurface->SurfShadowGlazingFrac(SurfNum),
7044 0 : state.dataConstruction->Construct(state.dataSurface->SurfShadowGlazingConstruct(SurfNum)).Name);
7045 : } else {
7046 0 : print(state.files.eio,
7047 : fmt,
7048 0 : surf.Name,
7049 0 : cSurfaceClass(surf.Class),
7050 0 : state.dataSurface->SurfShadowDiffuseSolRefl(SurfNum),
7051 0 : state.dataSurface->SurfShadowDiffuseVisRefl(SurfNum),
7052 0 : state.dataSurface->SurfShadowGlazingFrac(SurfNum),
7053 : "N/A");
7054 : }
7055 : }
7056 0 : }
7057 :
7058 224 : void GetHTSurfExtVentedCavityData(EnergyPlusData &state, bool &ErrorsFound) // Error flag indicator (true if errors found)
7059 : {
7060 :
7061 : // SUBROUTINE INFORMATION:
7062 : // AUTHOR BGriffith
7063 : // DATE WRITTEN January 2005
7064 :
7065 : // PURPOSE OF THIS SUBROUTINE:
7066 : // load input data for Exterior Vented Cavity Special case for heat transfer surfaces
7067 :
7068 : // METHODOLOGY EMPLOYED:
7069 : // usual E+ input processes
7070 :
7071 : // REFERENCES:
7072 : // derived from SUBROUTINE GetTranspiredCollectorInput
7073 :
7074 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
7075 : int Item; // Item to be "gotten"
7076 : int NumAlphas; // Number of Alphas for each GetObjectItem call
7077 : int NumNumbers; // Number of Numbers for each GetObjectItem call
7078 : int MaxNumAlphas; // argument for call to GetObjectDefMaxArgs
7079 : int MaxNumNumbers; // argument for call to GetObjectDefMaxArgs
7080 : int Dummy; // argument for call to GetObjectDefMaxArgs
7081 : int IOStatus; // Used in GetObjectItem
7082 : int Found;
7083 : int AlphaOffset; // local temp var
7084 224 : std::string Roughness;
7085 : int ThisSurf; // do loop counter
7086 : Real64 AvgAzimuth; // temp for error checking
7087 : Real64 AvgTilt; // temp for error checking
7088 224 : constexpr Real64 AZITOL = 15.0; // Degree Azimuth Angle Tolerance
7089 224 : constexpr Real64 TILTOL = 10.0; // Degree Tilt Angle Tolerance
7090 : int SurfID; // local surface "pointer"
7091 :
7092 224 : auto &s_ipsc = state.dataIPShortCut;
7093 224 : s_ipsc->cCurrentModuleObject = "SurfaceProperty:ExteriorNaturalVentedCavity";
7094 224 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, s_ipsc->cCurrentModuleObject, Dummy, MaxNumAlphas, MaxNumNumbers);
7095 :
7096 224 : if (MaxNumNumbers != 8) {
7097 0 : ShowSevereError(
7098 : state,
7099 0 : format("{}: Object Definition indicates not = 8 Number Objects, Number Indicated={}", s_ipsc->cCurrentModuleObject, MaxNumNumbers));
7100 0 : ErrorsFound = true;
7101 : }
7102 :
7103 224 : state.dataSurface->TotExtVentCav = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
7104 :
7105 224 : state.dataHeatBal->ExtVentedCavity.allocate(state.dataSurface->TotExtVentCav);
7106 :
7107 224 : for (Item = 1; Item <= state.dataSurface->TotExtVentCav; ++Item) {
7108 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
7109 0 : s_ipsc->cCurrentModuleObject,
7110 : Item,
7111 0 : s_ipsc->cAlphaArgs,
7112 : NumAlphas,
7113 0 : s_ipsc->rNumericArgs,
7114 : NumNumbers,
7115 : IOStatus,
7116 0 : s_ipsc->lNumericFieldBlanks,
7117 0 : s_ipsc->lAlphaFieldBlanks,
7118 0 : s_ipsc->cAlphaFieldNames,
7119 0 : s_ipsc->cNumericFieldNames);
7120 : // first handle cAlphaArgs
7121 0 : bool ErrorInName = false;
7122 0 : bool IsBlank = false;
7123 :
7124 0 : Util::VerifyName(state,
7125 0 : s_ipsc->cAlphaArgs(1),
7126 0 : state.dataHeatBal->ExtVentedCavity,
7127 : Item - 1,
7128 : ErrorInName,
7129 : IsBlank,
7130 0 : s_ipsc->cCurrentModuleObject + " Name");
7131 0 : if (ErrorInName) {
7132 0 : ShowContinueError(state, "...cannot not duplicate other names");
7133 0 : ErrorsFound = true;
7134 0 : continue;
7135 : }
7136 0 : state.dataHeatBal->ExtVentedCavity(Item).Name = s_ipsc->cAlphaArgs(1);
7137 :
7138 0 : state.dataHeatBal->ExtVentedCavity(Item).OSCMName = s_ipsc->cAlphaArgs(2);
7139 0 : if (!s_ipsc->lAlphaFieldBlanks(2)) {
7140 0 : Found = Util::FindItemInList(state.dataHeatBal->ExtVentedCavity(Item).OSCMName, state.dataSurface->OSCM, state.dataSurface->TotOSCM);
7141 0 : if (Found == 0) {
7142 0 : ShowSevereError(state,
7143 0 : format("{}=\"{}\", invalid {}=\"{}\".",
7144 0 : s_ipsc->cCurrentModuleObject,
7145 0 : state.dataHeatBal->ExtVentedCavity(Item).Name,
7146 0 : s_ipsc->cAlphaFieldNames(2),
7147 0 : s_ipsc->cAlphaArgs(2)));
7148 0 : ErrorsFound = true;
7149 : }
7150 : } else {
7151 0 : Found = 0;
7152 0 : ShowSevereError(state,
7153 0 : format("{}=\"{}\", invalid {} cannot be blank.",
7154 0 : s_ipsc->cCurrentModuleObject,
7155 0 : state.dataHeatBal->ExtVentedCavity(Item).Name,
7156 0 : s_ipsc->cAlphaFieldNames(2)));
7157 0 : ErrorsFound = true;
7158 : }
7159 0 : state.dataHeatBal->ExtVentedCavity(Item).OSCMPtr = Found;
7160 :
7161 0 : Roughness = s_ipsc->cAlphaArgs(3);
7162 : // Select the correct Number for the associated ascii name for the roughness type
7163 0 : if (Util::SameString(Roughness, "VerySmooth")) {
7164 0 : state.dataHeatBal->ExtVentedCavity(Item).BaffleRoughness = Material::SurfaceRoughness::VerySmooth;
7165 0 : } else if (Util::SameString(Roughness, "Smooth")) {
7166 0 : state.dataHeatBal->ExtVentedCavity(Item).BaffleRoughness = Material::SurfaceRoughness::Smooth;
7167 0 : } else if (Util::SameString(Roughness, "MediumSmooth")) {
7168 0 : state.dataHeatBal->ExtVentedCavity(Item).BaffleRoughness = Material::SurfaceRoughness::MediumSmooth;
7169 0 : } else if (Util::SameString(Roughness, "MediumRough")) {
7170 0 : state.dataHeatBal->ExtVentedCavity(Item).BaffleRoughness = Material::SurfaceRoughness::MediumRough;
7171 0 : } else if (Util::SameString(Roughness, "Rough")) {
7172 0 : state.dataHeatBal->ExtVentedCavity(Item).BaffleRoughness = Material::SurfaceRoughness::Rough;
7173 0 : } else if (Util::SameString(Roughness, "VeryRough")) {
7174 0 : state.dataHeatBal->ExtVentedCavity(Item).BaffleRoughness = Material::SurfaceRoughness::VeryRough;
7175 : } // TODO: fix this after creating FindEnumeratedValueIndex()
7176 :
7177 : // Was it set?
7178 0 : if (state.dataHeatBal->ExtVentedCavity(Item).BaffleRoughness == Material::SurfaceRoughness::Invalid) {
7179 0 : ShowSevereError(state,
7180 0 : format("{}=\"{}\", invalid {}=\"{}",
7181 0 : s_ipsc->cCurrentModuleObject,
7182 0 : state.dataHeatBal->ExtVentedCavity(Item).Name,
7183 0 : s_ipsc->cAlphaFieldNames(3),
7184 0 : s_ipsc->cAlphaArgs(3)));
7185 0 : ErrorsFound = true;
7186 : }
7187 :
7188 0 : AlphaOffset = 3;
7189 0 : state.dataHeatBal->ExtVentedCavity(Item).NumSurfs = NumAlphas - AlphaOffset;
7190 0 : if (state.dataHeatBal->ExtVentedCavity(Item).NumSurfs == 0) {
7191 0 : ShowSevereError(state,
7192 0 : format("{}=\"{}\", no underlying surfaces specified. Must have at least one.",
7193 0 : s_ipsc->cCurrentModuleObject,
7194 0 : state.dataHeatBal->ExtVentedCavity(Item).Name));
7195 0 : ErrorsFound = true;
7196 0 : continue;
7197 : }
7198 0 : state.dataHeatBal->ExtVentedCavity(Item).SurfPtrs.allocate(state.dataHeatBal->ExtVentedCavity(Item).NumSurfs);
7199 0 : state.dataHeatBal->ExtVentedCavity(Item).SurfPtrs = 0;
7200 0 : for (ThisSurf = 1; ThisSurf <= state.dataHeatBal->ExtVentedCavity(Item).NumSurfs; ++ThisSurf) {
7201 0 : Found = Util::FindItemInList(s_ipsc->cAlphaArgs(ThisSurf + AlphaOffset), state.dataSurface->Surface, state.dataSurface->TotSurfaces);
7202 0 : if (Found == 0) {
7203 0 : ShowSevereError(state,
7204 0 : format("{}=\"{}\", invalid {}=\"{}",
7205 0 : s_ipsc->cCurrentModuleObject,
7206 0 : state.dataHeatBal->ExtVentedCavity(Item).Name,
7207 0 : s_ipsc->cAlphaFieldNames(ThisSurf + AlphaOffset),
7208 0 : s_ipsc->cAlphaArgs(ThisSurf + AlphaOffset)));
7209 0 : ErrorsFound = true;
7210 0 : continue;
7211 : }
7212 : // check that surface is appropriate, Heat transfer, Sun, Wind,
7213 0 : if (!state.dataSurface->Surface(Found).HeatTransSurf) {
7214 0 : ShowSevereError(state,
7215 0 : format("{}=\"{}\", invalid {}=\"{}",
7216 0 : s_ipsc->cCurrentModuleObject,
7217 0 : state.dataHeatBal->ExtVentedCavity(Item).Name,
7218 0 : s_ipsc->cAlphaFieldNames(ThisSurf + AlphaOffset),
7219 0 : s_ipsc->cAlphaArgs(ThisSurf + AlphaOffset)));
7220 0 : ShowContinueError(state, "...because it is not a Heat Transfer Surface.");
7221 0 : ErrorsFound = true;
7222 0 : continue;
7223 : }
7224 0 : if (!state.dataSurface->Surface(Found).ExtSolar) {
7225 0 : ShowSevereError(state,
7226 0 : format("{}=\"{}\", invalid {}=\"{}",
7227 0 : s_ipsc->cCurrentModuleObject,
7228 0 : state.dataHeatBal->ExtVentedCavity(Item).Name,
7229 0 : s_ipsc->cAlphaFieldNames(ThisSurf + AlphaOffset),
7230 0 : s_ipsc->cAlphaArgs(ThisSurf + AlphaOffset)));
7231 0 : ShowContinueError(state, "...because it is not exposed to Sun.");
7232 0 : ErrorsFound = true;
7233 0 : continue;
7234 : }
7235 0 : if (!state.dataSurface->Surface(Found).ExtWind) {
7236 0 : ShowSevereError(state,
7237 0 : format("{}=\"{}\", invalid {}=\"{}",
7238 0 : s_ipsc->cCurrentModuleObject,
7239 0 : state.dataHeatBal->ExtVentedCavity(Item).Name,
7240 0 : s_ipsc->cAlphaFieldNames(ThisSurf + AlphaOffset),
7241 0 : s_ipsc->cAlphaArgs(ThisSurf + AlphaOffset)));
7242 0 : ShowContinueError(state, "...because it is not exposed to Wind.");
7243 0 : ErrorsFound = true;
7244 0 : continue;
7245 : }
7246 0 : if (state.dataSurface->Surface(Found).ExtBoundCond != DataSurfaces::OtherSideCondModeledExt) {
7247 0 : ShowSevereError(state,
7248 0 : format("{}=\"{}\", is invalid", s_ipsc->cCurrentModuleObject, state.dataHeatBal->ExtVentedCavity(Item).Name));
7249 0 : ShowContinueError(state,
7250 0 : format("...because {}=\"{}\".",
7251 0 : s_ipsc->cAlphaFieldNames(ThisSurf + AlphaOffset),
7252 0 : s_ipsc->cAlphaArgs(ThisSurf + AlphaOffset)));
7253 0 : ShowContinueError(state, "...is not an OtherSideConditionedModel surface.");
7254 0 : ErrorsFound = true;
7255 0 : continue;
7256 : }
7257 0 : state.dataHeatBal->ExtVentedCavity(Item).SurfPtrs(ThisSurf) = Found;
7258 :
7259 : // now set info in Surface structure
7260 0 : state.dataSurface->SurfExtCavNum(Found) = Item;
7261 0 : state.dataSurface->SurfExtCavityPresent(Found) = true;
7262 : }
7263 :
7264 0 : if (ErrorsFound) continue; // previous inner do loop may have detected problems that need to be cycle'd again to avoid crash
7265 :
7266 : // now that we should have all the surfaces, do some preparations and checks.
7267 :
7268 : // are they all similar tilt and azimuth? Issue warnings so people can do it if they really want
7269 0 : Real64 const surfaceArea(sum_sub(state.dataSurface->Surface, &SurfaceData::Area, state.dataHeatBal->ExtVentedCavity(Item).SurfPtrs));
7270 : // AvgAzimuth = sum( Surface( ExtVentedCavity( Item ).SurfPtrs ).Azimuth * Surface( ExtVentedCavity( Item ).SurfPtrs
7271 : //).Area
7272 : //)
7273 : /// sum( Surface( ExtVentedCavity( Item ).SurfPtrs ).Area ); //Autodesk:F2C++ Array subscript usage: Replaced by below
7274 0 : AvgAzimuth = sum_product_sub(state.dataSurface->Surface,
7275 : &SurfaceData::Azimuth,
7276 : &SurfaceData::Area,
7277 0 : state.dataHeatBal->ExtVentedCavity(Item).SurfPtrs) /
7278 : surfaceArea; // Autodesk:F2C++ Functions handle array subscript usage
7279 : // AvgTilt = sum( Surface( ExtVentedCavity( Item ).SurfPtrs ).Tilt * Surface( ExtVentedCavity( Item ).SurfPtrs ).Area )
7280 : // /
7281 : // sum( Surface( ExtVentedCavity( Item ).SurfPtrs ).Area ); //Autodesk:F2C++ Array subscript usage: Replaced by below
7282 0 : AvgTilt = sum_product_sub(
7283 0 : state.dataSurface->Surface, &SurfaceData::Tilt, &SurfaceData::Area, state.dataHeatBal->ExtVentedCavity(Item).SurfPtrs) /
7284 : surfaceArea; // Autodesk:F2C++ Functions handle array subscript usage
7285 0 : for (ThisSurf = 1; ThisSurf <= state.dataHeatBal->ExtVentedCavity(Item).NumSurfs; ++ThisSurf) {
7286 0 : SurfID = state.dataHeatBal->ExtVentedCavity(Item).SurfPtrs(ThisSurf);
7287 0 : if (General::rotAzmDiffDeg(state.dataSurface->Surface(SurfID).Azimuth, AvgAzimuth) > AZITOL) {
7288 0 : ShowWarningError(state,
7289 0 : format("{}=\"{}, Surface {} has Azimuth different from others in the associated group.",
7290 0 : s_ipsc->cCurrentModuleObject,
7291 0 : state.dataHeatBal->ExtVentedCavity(Item).Name,
7292 0 : state.dataSurface->Surface(SurfID).Name));
7293 : }
7294 0 : if (std::abs(state.dataSurface->Surface(SurfID).Tilt - AvgTilt) > TILTOL) {
7295 0 : ShowWarningError(state,
7296 0 : format("{}=\"{}, Surface {} has Tilt different from others in the associated group.",
7297 0 : s_ipsc->cCurrentModuleObject,
7298 0 : state.dataHeatBal->ExtVentedCavity(Item).Name,
7299 0 : state.dataSurface->Surface(SurfID).Name));
7300 : }
7301 :
7302 : // test that there are no windows. Now allow windows
7303 : // If (Surface(SurfID)%GrossArea > Surface(SurfID)%Area) Then
7304 : // Call ShowWarningError(state, 'Surface '//TRIM(Surface(SurfID)%name)//' has a subsurface whose area is not being ' &
7305 : // //'subtracted in the group of surfaces associated with '//TRIM(ExtVentedCavity(Item)%Name))
7306 : // endif
7307 : }
7308 0 : state.dataHeatBal->ExtVentedCavity(Item).Tilt = AvgTilt;
7309 0 : state.dataHeatBal->ExtVentedCavity(Item).Azimuth = AvgAzimuth;
7310 :
7311 : // find area weighted centroid.
7312 : // ExtVentedCavity( Item ).Centroid.z = sum( Surface( ExtVentedCavity( Item ).SurfPtrs ).Centroid.z * Surface(
7313 : // ExtVentedCavity( Item
7314 : //).SurfPtrs ).Area ) / sum( Surface( ExtVentedCavity( Item ).SurfPtrs ).Area ); //Autodesk:F2C++ Array subscript usage: Replaced
7315 : // by below
7316 0 : state.dataHeatBal->ExtVentedCavity(Item).Centroid.z = sum_product_sub(state.dataSurface->Surface,
7317 : &SurfaceData::Centroid,
7318 : &Vector::z,
7319 0 : state.dataSurface->Surface,
7320 : &SurfaceData::Area,
7321 0 : state.dataHeatBal->ExtVentedCavity(Item).SurfPtrs) /
7322 : surfaceArea; // Autodesk:F2C++ Functions handle array subscript usage
7323 :
7324 : // now handle rNumericArgs from input object
7325 0 : state.dataHeatBal->ExtVentedCavity(Item).Porosity = s_ipsc->rNumericArgs(1);
7326 0 : state.dataHeatBal->ExtVentedCavity(Item).LWEmitt = s_ipsc->rNumericArgs(2);
7327 0 : state.dataHeatBal->ExtVentedCavity(Item).SolAbsorp = s_ipsc->rNumericArgs(3);
7328 0 : state.dataHeatBal->ExtVentedCavity(Item).HdeltaNPL = s_ipsc->rNumericArgs(4);
7329 0 : state.dataHeatBal->ExtVentedCavity(Item).PlenGapThick = s_ipsc->rNumericArgs(5);
7330 0 : if (state.dataHeatBal->ExtVentedCavity(Item).PlenGapThick <= 0.0) {
7331 0 : ShowSevereError(state, format("{}=\"{}\", invalid .", s_ipsc->cCurrentModuleObject, state.dataHeatBal->ExtVentedCavity(Item).Name));
7332 0 : ErrorsFound = true;
7333 0 : ShowContinueError(
7334 : state,
7335 0 : format("...because field \"{}\" must be greater than Zero=[{:.2T}].", s_ipsc->cNumericFieldNames(5), s_ipsc->rNumericArgs(5)));
7336 0 : continue;
7337 : }
7338 0 : state.dataHeatBal->ExtVentedCavity(Item).AreaRatio = s_ipsc->rNumericArgs(6);
7339 0 : state.dataHeatBal->ExtVentedCavity(Item).Cv = s_ipsc->rNumericArgs(7);
7340 0 : state.dataHeatBal->ExtVentedCavity(Item).Cd = s_ipsc->rNumericArgs(8);
7341 :
7342 : // Fill out data we now know
7343 : // sum areas of HT surface areas
7344 : // ExtVentedCavity( Item ).ProjArea = sum( Surface( ExtVentedCavity( Item ).SurfPtrs ).Area ); //Autodesk:F2C++ Array
7345 : // subscript usage: Replaced by below
7346 0 : state.dataHeatBal->ExtVentedCavity(Item).ProjArea = surfaceArea;
7347 0 : if (state.dataHeatBal->ExtVentedCavity(Item).ProjArea <= 0.0) {
7348 0 : ShowSevereError(state, format("{}=\"{}\", invalid .", s_ipsc->cCurrentModuleObject, state.dataHeatBal->ExtVentedCavity(Item).Name));
7349 0 : ErrorsFound = true;
7350 0 : ShowContinueError(state,
7351 0 : format("...because gross area of underlying surfaces must be greater than Zero=[{:.2T}].",
7352 0 : state.dataHeatBal->ExtVentedCavity(Item).ProjArea));
7353 0 : continue;
7354 : }
7355 0 : state.dataHeatBal->ExtVentedCavity(Item).ActualArea =
7356 0 : state.dataHeatBal->ExtVentedCavity(Item).ProjArea * state.dataHeatBal->ExtVentedCavity(Item).AreaRatio;
7357 :
7358 0 : SetupOutputVariable(state,
7359 : "Surface Exterior Cavity Baffle Surface Temperature",
7360 : Constant::Units::C,
7361 0 : state.dataHeatBal->ExtVentedCavity(Item).Tbaffle,
7362 : OutputProcessor::TimeStepType::System,
7363 : OutputProcessor::StoreType::Average,
7364 0 : state.dataHeatBal->ExtVentedCavity(Item).Name);
7365 0 : SetupOutputVariable(state,
7366 : "Surface Exterior Cavity Air Drybulb Temperature",
7367 : Constant::Units::C,
7368 0 : state.dataHeatBal->ExtVentedCavity(Item).TAirCav,
7369 : OutputProcessor::TimeStepType::System,
7370 : OutputProcessor::StoreType::Average,
7371 0 : state.dataHeatBal->ExtVentedCavity(Item).Name);
7372 0 : SetupOutputVariable(state,
7373 : "Surface Exterior Cavity Total Natural Ventilation Air Change Rate",
7374 : Constant::Units::ach,
7375 0 : state.dataHeatBal->ExtVentedCavity(Item).PassiveACH,
7376 : OutputProcessor::TimeStepType::System,
7377 : OutputProcessor::StoreType::Average,
7378 0 : state.dataHeatBal->ExtVentedCavity(Item).Name);
7379 0 : SetupOutputVariable(state,
7380 : "Surface Exterior Cavity Total Natural Ventilation Mass Flow Rate",
7381 : Constant::Units::kg_s,
7382 0 : state.dataHeatBal->ExtVentedCavity(Item).PassiveMdotVent,
7383 : OutputProcessor::TimeStepType::System,
7384 : OutputProcessor::StoreType::Average,
7385 0 : state.dataHeatBal->ExtVentedCavity(Item).Name);
7386 0 : SetupOutputVariable(state,
7387 : "Surface Exterior Cavity Natural Ventilation from Wind Mass Flow Rate",
7388 : Constant::Units::kg_s,
7389 0 : state.dataHeatBal->ExtVentedCavity(Item).PassiveMdotWind,
7390 : OutputProcessor::TimeStepType::System,
7391 : OutputProcessor::StoreType::Average,
7392 0 : state.dataHeatBal->ExtVentedCavity(Item).Name);
7393 0 : SetupOutputVariable(state,
7394 : "Surface Exterior Cavity Natural Ventilation from Buoyancy Mass Flow Rate",
7395 : Constant::Units::kg_s,
7396 0 : state.dataHeatBal->ExtVentedCavity(Item).PassiveMdotTherm,
7397 : OutputProcessor::TimeStepType::System,
7398 : OutputProcessor::StoreType::Average,
7399 0 : state.dataHeatBal->ExtVentedCavity(Item).Name);
7400 : }
7401 224 : }
7402 :
7403 224 : void ExposedFoundationPerimeter::getData(EnergyPlusData &state, bool &ErrorsFound)
7404 : {
7405 :
7406 : static constexpr std::string_view routineName = "ExposedFoundationPerimeter::getData";
7407 : int IOStatus; // Used in GetObjectItem
7408 : int NumAlphas;
7409 : int NumNumbers;
7410 :
7411 224 : Real64 constexpr tolerance = 1e-6;
7412 :
7413 224 : auto &s_ipsc = state.dataIPShortCut;
7414 :
7415 224 : s_ipsc->cCurrentModuleObject = "SurfaceProperty:ExposedFoundationPerimeter";
7416 224 : int numObjects = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
7417 :
7418 224 : for (int obj = 1; obj <= numObjects; ++obj) {
7419 0 : int alpF = 1;
7420 0 : int numF = 1;
7421 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
7422 0 : s_ipsc->cCurrentModuleObject,
7423 : obj,
7424 0 : s_ipsc->cAlphaArgs,
7425 : NumAlphas,
7426 0 : s_ipsc->rNumericArgs,
7427 : NumNumbers,
7428 : IOStatus,
7429 0 : s_ipsc->lNumericFieldBlanks,
7430 0 : s_ipsc->lAlphaFieldBlanks,
7431 0 : s_ipsc->cAlphaFieldNames,
7432 0 : s_ipsc->cNumericFieldNames);
7433 :
7434 0 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(alpF)};
7435 :
7436 0 : int Found = Util::FindItemInList(s_ipsc->cAlphaArgs(alpF), state.dataSurface->Surface, state.dataSurface->TotSurfaces);
7437 0 : if (Found == 0) {
7438 0 : ShowSevereError(state, format("{}=\"{}\", did not find matching surface", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
7439 0 : ErrorsFound = true;
7440 : }
7441 0 : alpF++;
7442 0 : if (state.dataSurface->Surface(Found).Class != SurfaceClass::Floor) {
7443 0 : ShowWarningError(
7444 0 : state, format("{}: {}, surface is not a floor surface", s_ipsc->cCurrentModuleObject, state.dataSurface->Surface(Found).Name));
7445 0 : ShowContinueError(state, format("{} will not be used", s_ipsc->cCurrentModuleObject));
7446 0 : continue;
7447 : }
7448 :
7449 : // Choose calculation method
7450 :
7451 : enum class CalculationMethod
7452 : {
7453 : Invalid = -1,
7454 : TotalExposedPerimeter,
7455 : ExposedPerimeterFraction,
7456 : Bysegment,
7457 : Num
7458 : };
7459 :
7460 0 : constexpr std::array<std::string_view, static_cast<int>(CalculationMethod::Num)> CalculationMethodUC = {
7461 : "TOTALEXPOSEDPERIMETER", "EXPOSEDPERIMETERFRACTION", "BYSEGMENT"};
7462 0 : CalculationMethod calculationMethod = static_cast<CalculationMethod>(getEnumValue(CalculationMethodUC, s_ipsc->cAlphaArgs(alpF)));
7463 0 : if (calculationMethod != CalculationMethod::TotalExposedPerimeter && calculationMethod != CalculationMethod::ExposedPerimeterFraction &&
7464 0 : calculationMethod != CalculationMethod::Bysegment) {
7465 0 : ShowSevereError(state,
7466 0 : format("{}=\"{}\", {} is not a valid choice for {}",
7467 0 : s_ipsc->cCurrentModuleObject,
7468 0 : s_ipsc->cAlphaArgs(1),
7469 : calculationMethod,
7470 0 : s_ipsc->cAlphaFieldNames(alpF)));
7471 0 : ErrorsFound = true;
7472 : }
7473 0 : alpF++;
7474 :
7475 0 : Data data;
7476 0 : data.useDetailedExposedPerimeter = true;
7477 :
7478 0 : if (!s_ipsc->lNumericFieldBlanks(numF)) {
7479 0 : if (calculationMethod == CalculationMethod::TotalExposedPerimeter) {
7480 0 : data.exposedFraction = s_ipsc->rNumericArgs(numF) / state.dataSurface->Surface(Found).Perimeter;
7481 0 : if (data.exposedFraction > 1 + tolerance) {
7482 0 : ShowWarningError(state,
7483 0 : format("{}: {}, {} is greater than the perimeter of {}",
7484 0 : s_ipsc->cCurrentModuleObject,
7485 0 : state.dataSurface->Surface(Found).Name,
7486 0 : s_ipsc->cNumericFieldNames(numF),
7487 0 : state.dataSurface->Surface(Found).Name));
7488 0 : ShowContinueError(state,
7489 0 : format("{} perimeter = {}, {} exposed perimeter = {}",
7490 0 : state.dataSurface->Surface(Found).Name,
7491 0 : state.dataSurface->Surface(Found).Perimeter,
7492 0 : s_ipsc->cCurrentModuleObject,
7493 0 : s_ipsc->rNumericArgs(numF)));
7494 0 : ShowContinueError(
7495 : state,
7496 0 : format("{} will be set equal to {} perimeter", s_ipsc->cNumericFieldNames(numF), state.dataSurface->Surface(Found).Name));
7497 0 : data.exposedFraction = 1.0;
7498 : }
7499 :
7500 0 : data.useDetailedExposedPerimeter = false;
7501 : } else {
7502 0 : ShowWarningError(state,
7503 0 : format("{}: {}, {} set as calculation method, but a value has been set for {}. This value will be ignored.",
7504 0 : s_ipsc->cCurrentModuleObject,
7505 0 : state.dataSurface->Surface(Found).Name,
7506 : calculationMethod,
7507 0 : s_ipsc->cNumericFieldNames(numF)));
7508 : }
7509 : } else {
7510 0 : if (calculationMethod == CalculationMethod::TotalExposedPerimeter) {
7511 0 : ShowSevereError(state,
7512 0 : format("{}: {}, {} set as calculation method, but no value has been set for {}",
7513 0 : s_ipsc->cCurrentModuleObject,
7514 0 : state.dataSurface->Surface(Found).Name,
7515 : calculationMethod,
7516 0 : s_ipsc->cNumericFieldNames(numF)));
7517 0 : ErrorsFound = true;
7518 : }
7519 : }
7520 0 : numF++;
7521 :
7522 0 : if (!s_ipsc->lNumericFieldBlanks(numF)) {
7523 0 : if (calculationMethod == CalculationMethod::ExposedPerimeterFraction) {
7524 0 : data.exposedFraction = s_ipsc->rNumericArgs(numF);
7525 0 : data.useDetailedExposedPerimeter = false;
7526 : } else {
7527 0 : ShowWarningError(state,
7528 0 : format("{}: {}, {} set as calculation method, but a value has been set for {}. This value will be ignored.",
7529 0 : s_ipsc->cCurrentModuleObject,
7530 0 : state.dataSurface->Surface(Found).Name,
7531 : calculationMethod,
7532 0 : s_ipsc->cNumericFieldNames(numF)));
7533 : }
7534 : } else {
7535 0 : if (calculationMethod == CalculationMethod::ExposedPerimeterFraction) {
7536 0 : ShowSevereError(state,
7537 0 : format("{}: {}, {} set as calculation method, but no value has been set for {}",
7538 0 : s_ipsc->cCurrentModuleObject,
7539 0 : state.dataSurface->Surface(Found).Name,
7540 : calculationMethod,
7541 0 : s_ipsc->cNumericFieldNames(numF)));
7542 0 : ErrorsFound = true;
7543 : }
7544 : }
7545 0 : numF++;
7546 :
7547 0 : int numRemainingFields = NumAlphas - (alpF - 1) + NumNumbers - (numF - 1);
7548 0 : if (numRemainingFields > 0) {
7549 0 : if (calculationMethod == CalculationMethod::Bysegment) {
7550 0 : if (numRemainingFields != (int)state.dataSurface->Surface(Found).Vertex.size()) {
7551 0 : ShowSevereError(state,
7552 0 : format("{}: {}, must have equal number of segments as the floor has vertices.{}\" and \"{}\"",
7553 0 : s_ipsc->cCurrentModuleObject,
7554 0 : state.dataSurface->Surface(Found).Name,
7555 0 : s_ipsc->cAlphaFieldNames(alpF),
7556 0 : s_ipsc->cNumericFieldNames(numF - 1)));
7557 0 : ShowContinueError(state,
7558 0 : format("{} number of vertices = {}, {} number of segments = {}",
7559 0 : state.dataSurface->Surface(Found).Name,
7560 0 : state.dataSurface->Surface(Found).Vertex.size(),
7561 0 : s_ipsc->cCurrentModuleObject,
7562 : numRemainingFields));
7563 0 : ErrorsFound = true;
7564 : }
7565 0 : for (int segNum = 0; segNum < numRemainingFields; segNum++) {
7566 0 : if (s_ipsc->lAlphaFieldBlanks(alpF)) {
7567 0 : ShowSevereEmptyField(
7568 0 : state, eoh, s_ipsc->cAlphaFieldNames(alpF), "Calculation Method", CalculationMethodUC[(int)calculationMethod]);
7569 0 : ErrorsFound = true;
7570 0 : } else if (BooleanSwitch bs = getYesNoValue(s_ipsc->cAlphaArgs(alpF)); bs != BooleanSwitch::Invalid) {
7571 0 : data.isExposedPerimeter.push_back(static_cast<bool>(bs));
7572 : } else {
7573 0 : ShowSevereInvalidBool(state, eoh, s_ipsc->cAlphaFieldNames(alpF), s_ipsc->cAlphaArgs(alpF));
7574 0 : ErrorsFound = true;
7575 : }
7576 0 : alpF++;
7577 : }
7578 : }
7579 : } else {
7580 0 : if (calculationMethod == CalculationMethod::Bysegment) {
7581 0 : ShowSevereError(state,
7582 0 : format("{}: {}, {} set as calculation method, but no values have been set for Surface Segments Exposed",
7583 0 : s_ipsc->cCurrentModuleObject,
7584 0 : state.dataSurface->Surface(Found).Name,
7585 : calculationMethod));
7586 0 : ErrorsFound = true;
7587 : }
7588 : }
7589 0 : surfaceMap[Found] = data;
7590 0 : }
7591 224 : }
7592 :
7593 224 : void GetSurfaceLocalEnvData(EnergyPlusData &state, bool &ErrorsFound) // Error flag indicator (true if errors found)
7594 : {
7595 : // SUBROUTINE INFORMATION:
7596 : // AUTHOR X LUO
7597 : // DATE WRITTEN July 2017
7598 :
7599 : // PURPOSE OF THIS SUBROUTINE:
7600 : // load input data for Outdoor Air Node for exterior surfaces
7601 :
7602 : // SUBROUTINE PARAMETER DEFINITIONS:
7603 : static constexpr std::string_view RoutineName("GetSurfaceLocalEnvData: ");
7604 : static constexpr std::string_view routineName = "GetSurfaceLocalEnvData";
7605 :
7606 224 : auto &s_ipsc = state.dataIPShortCut;
7607 :
7608 224 : s_ipsc->cCurrentModuleObject = "SurfaceProperty:LocalEnvironment";
7609 224 : state.dataSurface->TotSurfLocalEnv = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
7610 :
7611 224 : if (state.dataSurface->TotSurfLocalEnv > 0) {
7612 : int NumAlpha;
7613 : int NumNumeric;
7614 : int IOStat;
7615 :
7616 13 : state.dataGlobal->AnyLocalEnvironmentsInModel = true;
7617 :
7618 13 : if (!allocated(state.dataSurface->SurfLocalEnvironment)) {
7619 13 : state.dataSurface->SurfLocalEnvironment.allocate(state.dataSurface->TotSurfLocalEnv);
7620 : }
7621 :
7622 36 : for (int Loop = 1; Loop <= state.dataSurface->TotSurfLocalEnv; ++Loop) {
7623 :
7624 23 : auto &SurfLocalEnv = state.dataSurface->SurfLocalEnvironment(Loop);
7625 :
7626 46 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
7627 23 : s_ipsc->cCurrentModuleObject,
7628 : Loop,
7629 23 : s_ipsc->cAlphaArgs,
7630 : NumAlpha,
7631 23 : s_ipsc->rNumericArgs,
7632 : NumNumeric,
7633 : IOStat,
7634 23 : s_ipsc->lNumericFieldBlanks,
7635 23 : s_ipsc->lAlphaFieldBlanks,
7636 23 : s_ipsc->cAlphaFieldNames,
7637 23 : s_ipsc->cNumericFieldNames);
7638 :
7639 23 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
7640 :
7641 23 : Util::IsNameEmpty(state, s_ipsc->cAlphaArgs(1), s_ipsc->cCurrentModuleObject, ErrorsFound);
7642 :
7643 23 : SurfLocalEnv.Name = s_ipsc->cAlphaArgs(1);
7644 :
7645 : // Assign surface number
7646 23 : int SurfNum = Util::FindItemInList(s_ipsc->cAlphaArgs(2), state.dataSurface->Surface);
7647 23 : if (SurfNum == 0) {
7648 0 : ShowSevereError(state,
7649 0 : format("{} {} = \"{}\", object. Illegal value for \"{}\" has been found.",
7650 : RoutineName,
7651 0 : s_ipsc->cCurrentModuleObject,
7652 0 : SurfLocalEnv.Name,
7653 0 : s_ipsc->cAlphaFieldNames(2)));
7654 0 : ShowContinueError(state,
7655 0 : format("{} entered value = \"{}\", no corresponding surface (ref BuildingSurface:Detailed) has been "
7656 : "found in the input file.",
7657 0 : s_ipsc->cAlphaFieldNames(2),
7658 0 : s_ipsc->cAlphaArgs(2)));
7659 0 : ErrorsFound = true;
7660 : } else {
7661 23 : SurfLocalEnv.SurfPtr = SurfNum;
7662 : }
7663 :
7664 : // Assign Sunlit Fraction Schedule number
7665 23 : if (s_ipsc->lAlphaFieldBlanks(3)) {
7666 1 : } else if ((SurfLocalEnv.sunlitFracSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(3))) == nullptr) {
7667 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3));
7668 0 : ErrorsFound = true;
7669 : }
7670 :
7671 : // Assign surrounding surfaces object number;
7672 23 : if (!s_ipsc->lAlphaFieldBlanks(4)) {
7673 21 : int SurroundingSurfsNum = Util::FindItemInList(s_ipsc->cAlphaArgs(4), state.dataSurface->SurroundingSurfsProperty);
7674 21 : if (SurroundingSurfsNum == 0) {
7675 0 : ShowSevereError(state,
7676 0 : format("{} {} = \"{}\", object. Illegal value for \"{}\" has been found.",
7677 : RoutineName,
7678 0 : s_ipsc->cCurrentModuleObject,
7679 0 : SurfLocalEnv.Name,
7680 0 : s_ipsc->cAlphaFieldNames(4)));
7681 0 : ShowContinueError(state,
7682 0 : format("{} entered value = \"{}\", no corresponding surrounding surfaces properties has been found "
7683 : "in the input file.",
7684 0 : s_ipsc->cAlphaFieldNames(4),
7685 0 : s_ipsc->cAlphaArgs(4)));
7686 0 : ErrorsFound = true;
7687 : } else {
7688 21 : SurfLocalEnv.SurroundingSurfsPtr = SurroundingSurfsNum;
7689 : }
7690 : }
7691 :
7692 : // Assign outdoor air node number;
7693 23 : if (!s_ipsc->lAlphaFieldBlanks(5)) {
7694 1 : int NodeNum = GetOnlySingleNode(state,
7695 1 : s_ipsc->cAlphaArgs(5),
7696 : ErrorsFound,
7697 : DataLoopNode::ConnectionObjectType::SurfacePropertyLocalEnvironment,
7698 1 : SurfLocalEnv.Name,
7699 : DataLoopNode::NodeFluidType::Air,
7700 : DataLoopNode::ConnectionType::Inlet,
7701 : NodeInputManager::CompFluidStream::Primary,
7702 : DataLoopNode::ObjectIsParent);
7703 1 : if (NodeNum == 0 && OutAirNodeManager::CheckOutAirNodeNumber(state, NodeNum)) {
7704 0 : ShowSevereError(state,
7705 0 : format("{} {} = \"{}\", object. Illegal value for \"{}\" has been found.",
7706 : RoutineName,
7707 0 : s_ipsc->cCurrentModuleObject,
7708 0 : SurfLocalEnv.Name,
7709 0 : s_ipsc->cAlphaFieldNames(5)));
7710 0 : ShowContinueError(state,
7711 0 : format("{} entered value = \"{}\", no corresponding outdoor air node has been found in the input file.",
7712 0 : s_ipsc->cAlphaFieldNames(5),
7713 0 : s_ipsc->cAlphaArgs(5)));
7714 0 : ErrorsFound = true;
7715 : } else {
7716 1 : SurfLocalEnv.OutdoorAirNodePtr = NodeNum;
7717 : }
7718 : }
7719 :
7720 : // get ground surfaces object number;
7721 23 : if (!s_ipsc->lAlphaFieldBlanks(6)) {
7722 12 : int GndSurfsNum = Util::FindItemInList(s_ipsc->cAlphaArgs(6), state.dataSurface->GroundSurfsProperty);
7723 12 : if (GndSurfsNum == 0) {
7724 0 : ShowSevereError(state,
7725 0 : format("{} {} = \"{}\", object. Illegal value for \"{}\" has been found.",
7726 : RoutineName,
7727 0 : s_ipsc->cCurrentModuleObject,
7728 0 : SurfLocalEnv.Name,
7729 0 : s_ipsc->cAlphaFieldNames(6)));
7730 0 : ShowContinueError(
7731 : state,
7732 0 : format("{} entered value = \"{}\", no corresponding ground surfaces object has been found in the input file.",
7733 0 : s_ipsc->cAlphaFieldNames(6),
7734 0 : s_ipsc->cAlphaArgs(6)));
7735 0 : ErrorsFound = true;
7736 : } else {
7737 12 : SurfLocalEnv.GroundSurfsPtr = GndSurfsNum;
7738 : }
7739 : }
7740 : }
7741 : }
7742 : // Link surface properties to surface object
7743 2486 : for (int SurfLoop = 1; SurfLoop <= state.dataSurface->TotSurfaces; ++SurfLoop) {
7744 2376 : for (int Loop = 1; Loop <= state.dataSurface->TotSurfLocalEnv; ++Loop) {
7745 114 : auto const &SurfLocalEnv = state.dataSurface->SurfLocalEnvironment(Loop);
7746 114 : if (SurfLocalEnv.SurfPtr == SurfLoop) {
7747 23 : auto &surface = state.dataSurface->Surface(SurfLoop);
7748 23 : if (SurfLocalEnv.OutdoorAirNodePtr != 0) {
7749 1 : surface.SurfLinkedOutAirNode = SurfLocalEnv.OutdoorAirNodePtr;
7750 : }
7751 23 : if (SurfLocalEnv.sunlitFracSched != nullptr) {
7752 1 : surface.SurfSchedExternalShadingFrac = true;
7753 1 : surface.surfExternalShadingSched = SurfLocalEnv.sunlitFracSched;
7754 : }
7755 23 : if (SurfLocalEnv.SurroundingSurfsPtr != 0) {
7756 21 : surface.SurfHasSurroundingSurfProperty = true;
7757 21 : surface.SurfSurroundingSurfacesNum = SurfLocalEnv.SurroundingSurfsPtr;
7758 21 : surface.ViewFactorSrdSurfs =
7759 21 : state.dataSurface->SurroundingSurfsProperty(surface.SurfSurroundingSurfacesNum).SurfsViewFactorSum;
7760 21 : if (surface.ViewFactorSrdSurfs == 0.0) {
7761 0 : surface.SurfHasSurroundingSurfProperty = false;
7762 : }
7763 : }
7764 23 : if (SurfLocalEnv.GroundSurfsPtr != 0) {
7765 12 : surface.IsSurfPropertyGndSurfacesDefined = true;
7766 12 : surface.UseSurfPropertyGndSurfTemp = true;
7767 12 : surface.UseSurfPropertyGndSurfRefl = true;
7768 12 : surface.SurfPropertyGndSurfIndex = SurfLocalEnv.GroundSurfsPtr;
7769 : }
7770 : }
7771 : }
7772 : }
7773 224 : }
7774 :
7775 224 : void GetSurfaceSrdSurfsData(EnergyPlusData &state, bool &ErrorsFound) // Error flag indicator (true if errors found)
7776 : {
7777 : // SUBROUTINE INFORMATION:
7778 : // AUTHOR X LUO
7779 : // DATE WRITTEN July 2017
7780 :
7781 : // PURPOSE OF THIS SUBROUTINE:
7782 : // load input data for surrounding surfaces properties for exterior surfaces
7783 224 : constexpr std::string_view routineName = "GetSurfaceSrdSurfsData";
7784 :
7785 224 : auto &s_ipsc = state.dataIPShortCut;
7786 :
7787 224 : s_ipsc->cCurrentModuleObject = "SurfaceProperty:SurroundingSurfaces";
7788 224 : int TotSrdSurfProperties = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
7789 :
7790 224 : if (TotSrdSurfProperties > 0) {
7791 : int NumAlpha;
7792 : int NumNumeric;
7793 : int IOStat;
7794 :
7795 11 : if (!allocated(state.dataSurface->SurroundingSurfsProperty)) {
7796 11 : state.dataSurface->SurroundingSurfsProperty.allocate(TotSrdSurfProperties);
7797 : }
7798 :
7799 32 : for (int Loop = 1; Loop <= TotSrdSurfProperties; ++Loop) {
7800 :
7801 21 : auto &SrdSurfsProp = state.dataSurface->SurroundingSurfsProperty(Loop);
7802 :
7803 42 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
7804 21 : s_ipsc->cCurrentModuleObject,
7805 : Loop,
7806 21 : s_ipsc->cAlphaArgs,
7807 : NumAlpha,
7808 21 : s_ipsc->rNumericArgs,
7809 : NumNumeric,
7810 : IOStat,
7811 21 : s_ipsc->lNumericFieldBlanks,
7812 21 : s_ipsc->lAlphaFieldBlanks,
7813 21 : s_ipsc->cAlphaFieldNames,
7814 21 : s_ipsc->cNumericFieldNames);
7815 :
7816 21 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
7817 :
7818 21 : Util::IsNameEmpty(state, s_ipsc->cAlphaArgs(1), s_ipsc->cCurrentModuleObject, ErrorsFound);
7819 :
7820 : // A1: Name
7821 21 : SrdSurfsProp.Name = s_ipsc->cAlphaArgs(1);
7822 :
7823 : // N1: sky view factor
7824 21 : if (!s_ipsc->lNumericFieldBlanks(1)) {
7825 16 : SrdSurfsProp.SkyViewFactor = s_ipsc->rNumericArgs(1);
7826 16 : SrdSurfsProp.IsSkyViewFactorSet = true;
7827 : }
7828 :
7829 : // A2: sky temp sch name
7830 21 : if (s_ipsc->lAlphaFieldBlanks(2)) {
7831 15 : } else if ((SrdSurfsProp.skyTempSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(2))) == nullptr) {
7832 5 : ShowWarningItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2));
7833 : }
7834 :
7835 : // N2: ground view factor
7836 21 : if (!s_ipsc->lNumericFieldBlanks(2)) {
7837 4 : SrdSurfsProp.GroundViewFactor = s_ipsc->rNumericArgs(2);
7838 4 : SrdSurfsProp.IsGroundViewFactorSet = true;
7839 : }
7840 :
7841 : // A3: ground temp sch name
7842 21 : if (s_ipsc->lAlphaFieldBlanks(3)) {
7843 2 : } else if ((SrdSurfsProp.groundTempSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(3))) == nullptr) {
7844 1 : ShowWarningItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3));
7845 : }
7846 :
7847 : // The object requires at least one srd surface input, each surface requires a set of 3 fields (2 Alpha fields Name and Temp
7848 : // Sch Name and 1 Num fields View Factor)
7849 21 : if (NumAlpha < 5) {
7850 0 : ShowSevereError(state, format("{} = \"{}\" is not defined correctly.", s_ipsc->cCurrentModuleObject, SrdSurfsProp.Name));
7851 0 : ShowContinueError(state, "At lease one set of surrounding surface properties should be defined.");
7852 0 : ErrorsFound = true;
7853 0 : continue;
7854 : }
7855 21 : if ((NumAlpha - 3) / 2 != (NumNumeric - 2)) {
7856 0 : ShowSevereError(state, format("{} = \"{}\" is not defined correctly.", s_ipsc->cCurrentModuleObject, SrdSurfsProp.Name));
7857 0 : ShowContinueError(state, "Check number of input fields for each surrounding surface.");
7858 0 : ErrorsFound = true;
7859 0 : continue;
7860 : }
7861 : // Read surrounding surfaces properties
7862 21 : SrdSurfsProp.TotSurroundingSurface = NumNumeric - 2;
7863 21 : SrdSurfsProp.SurroundingSurfs.allocate(SrdSurfsProp.TotSurroundingSurface);
7864 54 : for (int SurfLoop = 1; SurfLoop <= SrdSurfsProp.TotSurroundingSurface; ++SurfLoop) {
7865 33 : auto &surroundSurf = SrdSurfsProp.SurroundingSurfs(SurfLoop);
7866 33 : surroundSurf.Name = s_ipsc->cAlphaArgs(SurfLoop * 2 + 2);
7867 33 : surroundSurf.ViewFactor = s_ipsc->rNumericArgs(SurfLoop + 2);
7868 :
7869 : // Added checking
7870 33 : if (s_ipsc->lAlphaFieldBlanks(SurfLoop * 2 + 3)) {
7871 0 : ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(SurfLoop * 2 + 3));
7872 0 : ErrorsFound = true;
7873 33 : } else if ((surroundSurf.tempSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(SurfLoop * 2 + 3))) == nullptr) {
7874 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(SurfLoop * 2 + 3), s_ipsc->cAlphaArgs(SurfLoop * 2 + 3));
7875 0 : ErrorsFound = true;
7876 : }
7877 33 : SrdSurfsProp.SurfsViewFactorSum += SrdSurfsProp.SurroundingSurfs(SurfLoop).ViewFactor;
7878 : }
7879 : }
7880 : }
7881 224 : }
7882 :
7883 224 : void GetSurfaceGroundSurfsData(EnergyPlusData &state, bool &ErrorsFound)
7884 : {
7885 : static constexpr std::string_view routineName = "GetSurfaceGroundSurfsData";
7886 :
7887 224 : auto &s_ipsc = state.dataIPShortCut;
7888 224 : s_ipsc->cCurrentModuleObject = "SurfaceProperty:GroundSurfaces";
7889 224 : state.dataSurface->TotSurfPropGndSurfs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
7890 224 : auto const instances = state.dataInputProcessing->inputProcessor->epJSON.find(s_ipsc->cCurrentModuleObject);
7891 224 : if (instances == state.dataInputProcessing->inputProcessor->epJSON.end()) {
7892 218 : if (state.dataSurface->TotSurfPropGndSurfs > 0) ErrorsFound = true;
7893 218 : return;
7894 : }
7895 :
7896 6 : auto &instancesValue = instances.value();
7897 18 : for (auto instance = instancesValue.begin(); instance != instancesValue.end(); ++instance) {
7898 12 : auto const &fields = instance.value();
7899 12 : std::string const &thisObjectName = instance.key();
7900 :
7901 12 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, thisObjectName};
7902 :
7903 12 : DataSurfaces::GroundSurfacesProperty thisGndSurfsObj;
7904 12 : thisGndSurfsObj.Name = Util::makeUPPER(thisObjectName);
7905 12 : state.dataInputProcessing->inputProcessor->markObjectAsUsed(s_ipsc->cCurrentModuleObject, thisObjectName);
7906 12 : auto groundSurfaces = fields.find("ground_surfaces");
7907 12 : if (groundSurfaces != fields.end()) {
7908 12 : auto &groundSurfacesArray = groundSurfaces.value();
7909 12 : thisGndSurfsObj.NumGndSurfs = groundSurfacesArray.size();
7910 32 : for (auto &groundSurface : groundSurfacesArray) {
7911 20 : DataSurfaces::GroundSurfacesData thisGndSurf;
7912 20 : auto GndSurfName = groundSurface.find("ground_surface_name");
7913 20 : if (GndSurfName != groundSurface.end()) {
7914 20 : std::string ground_surf_name = GndSurfName.value().get<std::string>();
7915 20 : if (!ground_surf_name.empty()) {
7916 20 : thisGndSurf.Name = Util::makeUPPER(ground_surf_name);
7917 : }
7918 20 : }
7919 20 : auto groundSurfViewFactor = groundSurface.find("ground_surface_view_factor");
7920 20 : if (groundSurfViewFactor != groundSurface.end()) {
7921 15 : thisGndSurf.ViewFactor = groundSurfViewFactor.value().get<Real64>();
7922 15 : thisGndSurfsObj.IsGroundViewFactorSet = true;
7923 : }
7924 20 : auto TempSchName = groundSurface.find("ground_surface_temperature_schedule_name");
7925 20 : if (TempSchName != groundSurface.end()) {
7926 20 : std::string schedName = TempSchName.value().get<std::string>();
7927 20 : if (schedName.empty()) {
7928 20 : } else if ((thisGndSurf.tempSched = Sched::GetSchedule(state, Util::makeUPPER(schedName))) == nullptr) {
7929 0 : ShowSevereItemNotFound(state, eoh, "Ground Surface Temperature Schedule Name", schedName);
7930 0 : ErrorsFound = true;
7931 : }
7932 20 : }
7933 :
7934 20 : auto ReflSchName = groundSurface.find("ground_surface_reflectance_schedule_name");
7935 20 : if (ReflSchName != groundSurface.end()) {
7936 3 : std::string schedName = ReflSchName.value().get<std::string>();
7937 3 : if (schedName.empty()) {
7938 3 : } else if ((thisGndSurf.reflSched = Sched::GetSchedule(state, Util::makeUPPER(schedName))) == nullptr) {
7939 0 : ShowSevereItemNotFound(state, eoh, "Ground Surface Reflectance Schedule Name", schedName);
7940 0 : ErrorsFound = true;
7941 : }
7942 3 : }
7943 20 : thisGndSurfsObj.GndSurfs.push_back(thisGndSurf);
7944 20 : }
7945 : }
7946 32 : for (int gSurfNum = 1; gSurfNum <= thisGndSurfsObj.NumGndSurfs; gSurfNum++) {
7947 20 : thisGndSurfsObj.SurfsViewFactorSum += thisGndSurfsObj.GndSurfs(gSurfNum).ViewFactor;
7948 : }
7949 12 : state.dataSurface->GroundSurfsProperty.push_back(thisGndSurfsObj);
7950 12 : } // for (instance)
7951 :
7952 : // set report variables
7953 6 : if (state.dataSurface->TotSurfPropGndSurfs > 0) {
7954 18 : for (int Loop = 1; Loop <= state.dataSurface->TotSurfPropGndSurfs; Loop++) {
7955 12 : bool SetTempSchReportVar = true;
7956 12 : bool SetReflSchReportVar = true;
7957 12 : auto &thisGndSurfsObj = state.dataSurface->GroundSurfsProperty(Loop);
7958 32 : for (int gSurfNum = 1; gSurfNum <= thisGndSurfsObj.NumGndSurfs; gSurfNum++) {
7959 20 : if (thisGndSurfsObj.GndSurfs(gSurfNum).tempSched != nullptr && SetTempSchReportVar) {
7960 24 : SetupOutputVariable(state,
7961 : "Surfaces Property Ground Surfaces Average Temperature",
7962 : Constant::Units::C,
7963 12 : thisGndSurfsObj.SurfsTempAvg,
7964 : OutputProcessor::TimeStepType::Zone,
7965 : OutputProcessor::StoreType::Average,
7966 12 : thisGndSurfsObj.Name);
7967 12 : SetTempSchReportVar = false;
7968 : }
7969 20 : if (thisGndSurfsObj.GndSurfs(gSurfNum).reflSched != nullptr && SetReflSchReportVar) {
7970 2 : SetupOutputVariable(state,
7971 : "Surfaces Property Ground Surfaces Average Reflectance",
7972 : Constant::Units::None,
7973 1 : thisGndSurfsObj.SurfsReflAvg,
7974 : OutputProcessor::TimeStepType::Zone,
7975 : OutputProcessor::StoreType::Average,
7976 1 : thisGndSurfsObj.Name);
7977 1 : SetReflSchReportVar = false;
7978 : }
7979 : }
7980 : }
7981 : }
7982 : }
7983 :
7984 224 : void GetSurfaceHeatTransferAlgorithmOverrides(EnergyPlusData &state, bool &ErrorsFound)
7985 : {
7986 :
7987 : // SUBROUTINE INFORMATION:
7988 : // AUTHOR B. Griffith, portions from ApplyConvectionValue by Linda Lawrie
7989 : // DATE WRITTEN July 2012
7990 : static constexpr std::string_view routineName = "GetSurfaceHeatTransferAlgorithmOverrides";
7991 :
7992 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
7993 : int CountHTAlgoObjectsSingleSurf;
7994 : int CountHTAlgoObjectsMultiSurf;
7995 : int CountHTAlgoObjectsSurfList;
7996 : int IOStatus; // Used in GetObjectItem
7997 : DataSurfaces::HeatTransferModel tmpAlgoInput;
7998 : int Item;
7999 : int Item1;
8000 : int NumAlphas;
8001 : int NumNumbers;
8002 : int Found;
8003 : bool SurfacesOfType;
8004 : int SurfNum;
8005 : // INTEGER :: Index
8006 : int NumEMPDMat;
8007 : int NumPCMat;
8008 : int NumVTCMat;
8009 : int NumHAMTMat1;
8010 : int NumHAMTMat2;
8011 : int NumHAMTMat3;
8012 : int NumHAMTMat4;
8013 : int NumHAMTMat5;
8014 : int NumHAMTMat6;
8015 : int SumHAMTMat;
8016 : bool msgneeded;
8017 :
8018 224 : auto &s_ipsc = state.dataIPShortCut;
8019 224 : s_ipsc->cCurrentModuleObject = "SurfaceProperty:HeatBalanceSourceTerm";
8020 224 : int CountAddHeatSourceSurf = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
8021 :
8022 226 : for (Item = 1; Item <= CountAddHeatSourceSurf; ++Item) {
8023 4 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
8024 2 : s_ipsc->cCurrentModuleObject,
8025 : Item,
8026 2 : s_ipsc->cAlphaArgs,
8027 : NumAlphas,
8028 2 : s_ipsc->rNumericArgs,
8029 : NumNumbers,
8030 : IOStatus,
8031 2 : s_ipsc->lNumericFieldBlanks,
8032 2 : s_ipsc->lAlphaFieldBlanks,
8033 2 : s_ipsc->cAlphaFieldNames,
8034 2 : s_ipsc->cNumericFieldNames);
8035 :
8036 2 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
8037 2 : Found = Util::FindItemInList(s_ipsc->cAlphaArgs(1), state.dataSurface->Surface, state.dataSurface->TotSurfaces);
8038 :
8039 2 : if (Found == 0) {
8040 0 : ShowSevereError(state, format("{}=\"{}\", did not find matching surface.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
8041 0 : ErrorsFound = true;
8042 4 : } else if (state.dataSurface->Surface(Found).insideHeatSourceTermSched != nullptr ||
8043 2 : state.dataSurface->Surface(Found).outsideHeatSourceTermSched != nullptr) {
8044 0 : ShowSevereError(state,
8045 0 : format("{}=\"{}\", multiple SurfaceProperty:HeatBalanceSourceTerm objects applied to the same surface.",
8046 0 : s_ipsc->cCurrentModuleObject,
8047 0 : s_ipsc->cAlphaArgs(1)));
8048 0 : ErrorsFound = true;
8049 : }
8050 :
8051 2 : if (s_ipsc->lAlphaFieldBlanks(2)) {
8052 1 : } else if ((state.dataSurface->Surface(Found).insideHeatSourceTermSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(2))) == nullptr) {
8053 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2));
8054 0 : ErrorsFound = true;
8055 : } else {
8056 1 : state.dataSurface->allInsideSourceSurfaceList.emplace_back(Found);
8057 : }
8058 :
8059 2 : if (s_ipsc->lAlphaFieldBlanks(3)) {
8060 1 : } else if ((state.dataSurface->Surface(Found).outsideHeatSourceTermSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(3))) == nullptr) {
8061 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3));
8062 0 : ErrorsFound = true;
8063 1 : } else if (state.dataSurface->Surface(Found).OSCPtr > 0) {
8064 0 : ShowSevereError(state,
8065 0 : format("{}=\"SurfaceProperty:HeatBalanceSourceTerm\", cannot be specified for OtherSideCoefficient Surface={}",
8066 0 : s_ipsc->cCurrentModuleObject,
8067 0 : s_ipsc->cAlphaArgs(1)));
8068 0 : ErrorsFound = true;
8069 : } else {
8070 1 : state.dataSurface->allOutsideSourceSurfaceList.emplace_back(Found);
8071 : }
8072 :
8073 3 : if (state.dataSurface->Surface(Found).outsideHeatSourceTermSched == nullptr &&
8074 1 : state.dataSurface->Surface(Found).insideHeatSourceTermSched == nullptr) {
8075 0 : ShowSevereError(
8076 0 : state, format("{}=\"{}\", no schedule defined for additional heat source.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
8077 0 : ErrorsFound = true;
8078 : }
8079 : }
8080 :
8081 : // first initialize each heat transfer surface with the overall model type, array assignment
8082 2486 : for (auto &e : state.dataSurface->Surface)
8083 2262 : e.HeatTransferAlgorithm = state.dataHeatBal->OverallHeatTransferSolutionAlgo;
8084 :
8085 224 : s_ipsc->cCurrentModuleObject = "SurfaceProperty:HeatTransferAlgorithm";
8086 224 : CountHTAlgoObjectsSingleSurf = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
8087 :
8088 224 : s_ipsc->cCurrentModuleObject = "SurfaceProperty:HeatTransferAlgorithm";
8089 226 : for (Item = 1; Item <= CountHTAlgoObjectsSingleSurf; ++Item) {
8090 4 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
8091 2 : s_ipsc->cCurrentModuleObject,
8092 : Item,
8093 2 : s_ipsc->cAlphaArgs,
8094 : NumAlphas,
8095 2 : s_ipsc->rNumericArgs,
8096 : NumNumbers,
8097 : IOStatus,
8098 2 : s_ipsc->lNumericFieldBlanks,
8099 2 : s_ipsc->lAlphaFieldBlanks,
8100 2 : s_ipsc->cAlphaFieldNames,
8101 2 : s_ipsc->cNumericFieldNames);
8102 2 : bool ErrorsFoundSingleSurf = false;
8103 2 : Found = Util::FindItemInList(s_ipsc->cAlphaArgs(1), state.dataSurface->Surface, state.dataSurface->TotSurfaces);
8104 :
8105 2 : if (Found == 0) {
8106 0 : ShowSevereError(state, format("{}=\"{}\", did not find matching surface.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
8107 0 : ErrorsFoundSingleSurf = true;
8108 : }
8109 :
8110 : {
8111 2 : std::string const &SELECT_CASE_var = s_ipsc->cAlphaArgs(2);
8112 :
8113 2 : if (SELECT_CASE_var == "CONDUCTIONTRANSFERFUNCTION") {
8114 1 : tmpAlgoInput = DataSurfaces::HeatTransferModel::CTF;
8115 1 : state.dataHeatBal->AnyCTF = true;
8116 1 : } else if (SELECT_CASE_var == "MOISTUREPENETRATIONDEPTHCONDUCTIONTRANSFERFUNCTION") {
8117 0 : tmpAlgoInput = DataSurfaces::HeatTransferModel::EMPD;
8118 0 : state.dataHeatBal->AnyEMPD = true;
8119 1 : } else if (SELECT_CASE_var == "COMBINEDHEATANDMOISTUREFINITEELEMENT") {
8120 1 : tmpAlgoInput = DataSurfaces::HeatTransferModel::HAMT;
8121 1 : state.dataHeatBal->AnyHAMT = true;
8122 0 : } else if (SELECT_CASE_var == "CONDUCTIONFINITEDIFFERENCE") {
8123 0 : tmpAlgoInput = DataSurfaces::HeatTransferModel::CondFD;
8124 0 : state.dataHeatBal->AnyCondFD = true;
8125 : } else {
8126 0 : ShowSevereError(state,
8127 0 : format("{}=\"{}\", invalid {}=\"{}",
8128 0 : s_ipsc->cCurrentModuleObject,
8129 0 : s_ipsc->cAlphaArgs(1),
8130 0 : s_ipsc->cAlphaFieldNames(2),
8131 0 : s_ipsc->cAlphaArgs(2)));
8132 0 : ErrorsFoundSingleSurf = true;
8133 : }
8134 : }
8135 :
8136 2 : if (!ErrorsFoundSingleSurf) {
8137 2 : state.dataSurface->Surface(Found).HeatTransferAlgorithm = tmpAlgoInput;
8138 : } else {
8139 0 : ErrorsFound = true;
8140 : }
8141 : } // single surface heat transfer algorithm override
8142 :
8143 224 : s_ipsc->cCurrentModuleObject = "SurfaceProperty:HeatTransferAlgorithm:MultipleSurface";
8144 224 : CountHTAlgoObjectsMultiSurf = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
8145 :
8146 224 : for (Item = 1; Item <= CountHTAlgoObjectsMultiSurf; ++Item) {
8147 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
8148 0 : s_ipsc->cCurrentModuleObject,
8149 : Item,
8150 0 : s_ipsc->cAlphaArgs,
8151 : NumAlphas,
8152 0 : s_ipsc->rNumericArgs,
8153 : NumNumbers,
8154 : IOStatus,
8155 0 : s_ipsc->lNumericFieldBlanks,
8156 0 : s_ipsc->lAlphaFieldBlanks,
8157 0 : s_ipsc->cAlphaFieldNames,
8158 0 : s_ipsc->cNumericFieldNames);
8159 0 : bool ErrorsFoundMultiSurf = false;
8160 : {
8161 0 : std::string const &SELECT_CASE_var = s_ipsc->cAlphaArgs(3);
8162 :
8163 0 : if (SELECT_CASE_var == "CONDUCTIONTRANSFERFUNCTION") {
8164 0 : tmpAlgoInput = DataSurfaces::HeatTransferModel::CTF;
8165 0 : state.dataHeatBal->AnyCTF = true;
8166 0 : } else if (SELECT_CASE_var == "MOISTUREPENETRATIONDEPTHCONDUCTIONTRANSFERFUNCTION") {
8167 0 : tmpAlgoInput = DataSurfaces::HeatTransferModel::EMPD;
8168 0 : state.dataHeatBal->AnyEMPD = true;
8169 0 : } else if (SELECT_CASE_var == "COMBINEDHEATANDMOISTUREFINITEELEMENT") {
8170 0 : tmpAlgoInput = DataSurfaces::HeatTransferModel::HAMT;
8171 0 : state.dataHeatBal->AnyHAMT = true;
8172 0 : } else if (SELECT_CASE_var == "CONDUCTIONFINITEDIFFERENCE") {
8173 0 : tmpAlgoInput = DataSurfaces::HeatTransferModel::CondFD;
8174 0 : state.dataHeatBal->AnyCondFD = true;
8175 : } else {
8176 0 : ShowSevereError(state,
8177 0 : format("{}=\"{}\", invalid {}=\"{}",
8178 0 : s_ipsc->cCurrentModuleObject,
8179 0 : s_ipsc->cAlphaArgs(1),
8180 0 : s_ipsc->cAlphaFieldNames(3),
8181 0 : s_ipsc->cAlphaArgs(3)));
8182 0 : ErrorsFoundMultiSurf = true;
8183 : }
8184 : }
8185 :
8186 : {
8187 0 : std::string const &SELECT_CASE_var = s_ipsc->cAlphaArgs(2);
8188 :
8189 0 : if (SELECT_CASE_var == "ALLEXTERIORSURFACES") {
8190 0 : SurfacesOfType = false;
8191 0 : for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
8192 0 : auto &surf = state.dataSurface->Surface(SurfNum);
8193 0 : if (!surf.HeatTransSurf) continue;
8194 0 : if (surf.ExtBoundCond > 0) continue; // Interior surfaces
8195 0 : if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) continue;
8196 0 : SurfacesOfType = true;
8197 0 : surf.HeatTransferAlgorithm = tmpAlgoInput;
8198 : }
8199 :
8200 0 : } else if (SELECT_CASE_var == "ALLEXTERIORWALLS") {
8201 0 : SurfacesOfType = false;
8202 0 : for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
8203 0 : auto &surf = state.dataSurface->Surface(SurfNum);
8204 0 : if (!surf.HeatTransSurf) continue;
8205 0 : if (surf.ExtBoundCond > 0) continue; // Interior surfaces
8206 :
8207 0 : if (surf.Class != SurfaceClass::Wall) continue;
8208 0 : if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) continue;
8209 0 : SurfacesOfType = true;
8210 0 : surf.HeatTransferAlgorithm = tmpAlgoInput;
8211 : }
8212 :
8213 0 : } else if (SELECT_CASE_var == "ALLEXTERIORROOFS") {
8214 0 : SurfacesOfType = false;
8215 0 : for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
8216 0 : auto &surf = state.dataSurface->Surface(SurfNum);
8217 0 : if (!surf.HeatTransSurf) continue;
8218 0 : if (surf.ExtBoundCond > 0) continue; // Interior surfaces
8219 0 : if (surf.Class != SurfaceClass::Roof) continue;
8220 0 : if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) continue;
8221 0 : SurfacesOfType = true;
8222 0 : surf.HeatTransferAlgorithm = tmpAlgoInput;
8223 : }
8224 :
8225 0 : } else if (SELECT_CASE_var == "ALLEXTERIORFLOORS") {
8226 0 : SurfacesOfType = false;
8227 0 : for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
8228 0 : auto &surf = state.dataSurface->Surface(SurfNum);
8229 0 : if (!surf.HeatTransSurf) continue;
8230 0 : if (surf.ExtBoundCond > 0) continue; // Interior surfaces
8231 0 : if (surf.Class != SurfaceClass::Floor) continue;
8232 0 : if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) continue;
8233 0 : SurfacesOfType = true;
8234 0 : surf.HeatTransferAlgorithm = tmpAlgoInput;
8235 : }
8236 :
8237 0 : } else if (SELECT_CASE_var == "ALLGROUNDCONTACTSURFACES") {
8238 0 : SurfacesOfType = false;
8239 0 : for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
8240 0 : auto &surf = state.dataSurface->Surface(SurfNum);
8241 0 : if (!surf.HeatTransSurf) continue;
8242 0 : if (surf.ExtBoundCond != DataSurfaces::Ground) continue; // ground BC
8243 0 : if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) continue;
8244 0 : SurfacesOfType = true;
8245 0 : surf.HeatTransferAlgorithm = tmpAlgoInput;
8246 : }
8247 0 : } else if (SELECT_CASE_var == "ALLINTERIORSURFACES") {
8248 0 : SurfacesOfType = false;
8249 0 : for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
8250 0 : auto &surf = state.dataSurface->Surface(SurfNum);
8251 0 : if (!surf.HeatTransSurf) continue;
8252 0 : if (surf.ExtBoundCond <= 0) continue; // Exterior surfaces
8253 0 : if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) continue;
8254 0 : SurfacesOfType = true;
8255 0 : surf.HeatTransferAlgorithm = tmpAlgoInput;
8256 : }
8257 :
8258 0 : } else if (SELECT_CASE_var == "ALLINTERIORWALLS") {
8259 0 : SurfacesOfType = false;
8260 0 : for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
8261 0 : auto &surf = state.dataSurface->Surface(SurfNum);
8262 0 : if (!surf.HeatTransSurf) continue;
8263 0 : if (surf.ExtBoundCond <= 0) continue; // Exterior surfaces
8264 0 : if (surf.Class != SurfaceClass::Wall) continue;
8265 0 : if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) continue;
8266 0 : SurfacesOfType = true;
8267 0 : surf.HeatTransferAlgorithm = tmpAlgoInput;
8268 : }
8269 :
8270 0 : } else if ((SELECT_CASE_var == "ALLINTERIORROOFS") || (SELECT_CASE_var == "ALLINTERIORCEILINGS")) {
8271 0 : SurfacesOfType = false;
8272 0 : for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
8273 0 : auto &surf = state.dataSurface->Surface(SurfNum);
8274 0 : if (!surf.HeatTransSurf) continue;
8275 0 : if (surf.ExtBoundCond <= 0) continue; // Exterior surfaces
8276 0 : if (surf.Class != SurfaceClass::Roof) continue;
8277 0 : if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) continue;
8278 0 : SurfacesOfType = true;
8279 0 : surf.HeatTransferAlgorithm = tmpAlgoInput;
8280 : }
8281 :
8282 0 : } else if (SELECT_CASE_var == "ALLINTERIORFLOORS") {
8283 0 : SurfacesOfType = false;
8284 0 : for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
8285 0 : auto &surf = state.dataSurface->Surface(SurfNum);
8286 0 : if (!surf.HeatTransSurf) continue;
8287 0 : if (surf.ExtBoundCond <= 0) continue; // Exterior surfaces
8288 0 : if (surf.Class != SurfaceClass::Floor) continue;
8289 0 : if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) continue;
8290 0 : SurfacesOfType = true;
8291 0 : surf.HeatTransferAlgorithm = tmpAlgoInput;
8292 : }
8293 : } else {
8294 0 : SurfacesOfType = false;
8295 0 : ShowSevereError(state,
8296 0 : format("{}=\"{}\", invalid {}=\"{}",
8297 0 : s_ipsc->cCurrentModuleObject,
8298 0 : s_ipsc->cAlphaArgs(1),
8299 0 : s_ipsc->cAlphaFieldNames(2),
8300 0 : s_ipsc->cAlphaArgs(2)));
8301 0 : ErrorsFoundMultiSurf = true;
8302 : }
8303 : }
8304 :
8305 0 : if (!SurfacesOfType) {
8306 0 : ShowWarningError(
8307 : state,
8308 0 : format("In {}=\"{}\", for Multiple Surface Assignment=\"{}\", there were no surfaces of that type found for assignment.",
8309 0 : s_ipsc->cCurrentModuleObject,
8310 0 : s_ipsc->cAlphaArgs(1),
8311 0 : s_ipsc->cAlphaArgs(2)));
8312 : }
8313 0 : if (ErrorsFoundMultiSurf) ErrorsFound = true;
8314 :
8315 : } // multi surface heat transfer algo override
8316 :
8317 224 : s_ipsc->cCurrentModuleObject = "SurfaceProperty:HeatTransferAlgorithm:SurfaceList";
8318 224 : CountHTAlgoObjectsSurfList = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
8319 224 : for (Item = 1; Item <= CountHTAlgoObjectsSurfList; ++Item) {
8320 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
8321 0 : s_ipsc->cCurrentModuleObject,
8322 : Item,
8323 0 : s_ipsc->cAlphaArgs,
8324 : NumAlphas,
8325 0 : s_ipsc->rNumericArgs,
8326 : NumNumbers,
8327 : IOStatus,
8328 0 : s_ipsc->lNumericFieldBlanks,
8329 0 : s_ipsc->lAlphaFieldBlanks,
8330 0 : s_ipsc->cAlphaFieldNames,
8331 0 : s_ipsc->cNumericFieldNames);
8332 0 : bool ErrorsFoundSurfList = false;
8333 : {
8334 0 : std::string const &SELECT_CASE_var = s_ipsc->cAlphaArgs(2);
8335 :
8336 0 : if (SELECT_CASE_var == "CONDUCTIONTRANSFERFUNCTION") {
8337 0 : tmpAlgoInput = DataSurfaces::HeatTransferModel::CTF;
8338 0 : state.dataHeatBal->AnyCTF = true;
8339 0 : } else if (SELECT_CASE_var == "MOISTUREPENETRATIONDEPTHCONDUCTIONTRANSFERFUNCTION") {
8340 0 : tmpAlgoInput = DataSurfaces::HeatTransferModel::EMPD;
8341 0 : state.dataHeatBal->AnyEMPD = true;
8342 0 : } else if (SELECT_CASE_var == "COMBINEDHEATANDMOISTUREFINITEELEMENT") {
8343 0 : tmpAlgoInput = DataSurfaces::HeatTransferModel::HAMT;
8344 0 : state.dataHeatBal->AnyHAMT = true;
8345 0 : } else if (SELECT_CASE_var == "CONDUCTIONFINITEDIFFERENCE") {
8346 0 : tmpAlgoInput = DataSurfaces::HeatTransferModel::CondFD;
8347 0 : state.dataHeatBal->AnyCondFD = true;
8348 : } else {
8349 0 : ShowSevereError(state,
8350 0 : format("{}=\"{}\", invalid {}=\"{}",
8351 0 : s_ipsc->cCurrentModuleObject,
8352 0 : s_ipsc->cAlphaArgs(1),
8353 0 : s_ipsc->cAlphaFieldNames(2),
8354 0 : s_ipsc->cAlphaArgs(2)));
8355 0 : ErrorsFoundSurfList = true;
8356 : }
8357 : }
8358 :
8359 0 : for (Item1 = 3; Item1 <= NumAlphas; ++Item1) {
8360 :
8361 0 : Found = Util::FindItemInList(s_ipsc->cAlphaArgs(Item1), state.dataSurface->Surface, state.dataSurface->TotSurfaces);
8362 :
8363 0 : if (Found == 0) {
8364 0 : ShowSevereError(state, format("{}=\"{}\", did not find matching surface.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
8365 0 : ShowContinueError(state, format("Name of surface not found = \"{}\"", s_ipsc->cAlphaArgs(Item1)));
8366 0 : ErrorsFoundSurfList = true;
8367 : }
8368 :
8369 0 : if (!ErrorsFoundSurfList) {
8370 0 : state.dataSurface->Surface(Found).HeatTransferAlgorithm = tmpAlgoInput;
8371 : } else {
8372 0 : ErrorsFound = true;
8373 : }
8374 : }
8375 : }
8376 :
8377 224 : s_ipsc->cCurrentModuleObject = "SurfaceProperty:HeatTransferAlgorithm:Construction";
8378 224 : CountHTAlgoObjectsSurfList = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
8379 225 : for (Item = 1; Item <= CountHTAlgoObjectsSurfList; ++Item) {
8380 2 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
8381 1 : s_ipsc->cCurrentModuleObject,
8382 : Item,
8383 1 : s_ipsc->cAlphaArgs,
8384 : NumAlphas,
8385 1 : s_ipsc->rNumericArgs,
8386 : NumNumbers,
8387 : IOStatus,
8388 1 : s_ipsc->lNumericFieldBlanks,
8389 1 : s_ipsc->lAlphaFieldBlanks,
8390 1 : s_ipsc->cAlphaFieldNames,
8391 1 : s_ipsc->cNumericFieldNames);
8392 1 : bool ErrorsFoundByConstruct = false;
8393 : {
8394 1 : std::string const &SELECT_CASE_var = s_ipsc->cAlphaArgs(2);
8395 :
8396 1 : if (SELECT_CASE_var == "CONDUCTIONTRANSFERFUNCTION") {
8397 0 : tmpAlgoInput = DataSurfaces::HeatTransferModel::CTF;
8398 0 : state.dataHeatBal->AnyCTF = true;
8399 1 : } else if (SELECT_CASE_var == "MOISTUREPENETRATIONDEPTHCONDUCTIONTRANSFERFUNCTION") {
8400 0 : tmpAlgoInput = DataSurfaces::HeatTransferModel::EMPD;
8401 0 : state.dataHeatBal->AnyEMPD = true;
8402 1 : } else if (SELECT_CASE_var == "COMBINEDHEATANDMOISTUREFINITEELEMENT") {
8403 0 : tmpAlgoInput = DataSurfaces::HeatTransferModel::HAMT;
8404 0 : state.dataHeatBal->AnyHAMT = true;
8405 1 : } else if (SELECT_CASE_var == "CONDUCTIONFINITEDIFFERENCE") {
8406 1 : tmpAlgoInput = DataSurfaces::HeatTransferModel::CondFD;
8407 1 : state.dataHeatBal->AnyCondFD = true;
8408 : } else {
8409 0 : ShowSevereError(state,
8410 0 : format("{}=\"{}\", invalid {}=\"{}",
8411 0 : s_ipsc->cCurrentModuleObject,
8412 0 : s_ipsc->cAlphaArgs(1),
8413 0 : s_ipsc->cAlphaFieldNames(2),
8414 0 : s_ipsc->cAlphaArgs(2)));
8415 0 : ErrorsFoundByConstruct = true;
8416 : }
8417 : }
8418 :
8419 1 : Found = Util::FindItemInList(s_ipsc->cAlphaArgs(3), state.dataConstruction->Construct, state.dataHeatBal->TotConstructs);
8420 1 : if (Found == 0) {
8421 0 : ShowSevereError(state,
8422 0 : format("{}=\"{}\", invalid {}=\"{}",
8423 0 : s_ipsc->cCurrentModuleObject,
8424 0 : s_ipsc->cAlphaArgs(1),
8425 0 : s_ipsc->cAlphaFieldNames(3),
8426 0 : s_ipsc->cAlphaArgs(3)));
8427 0 : ErrorsFoundByConstruct = true;
8428 : }
8429 :
8430 1 : if (!ErrorsFoundByConstruct) {
8431 5 : for (Item1 = 1; Item1 <= state.dataSurface->TotSurfaces; ++Item1) {
8432 4 : if (state.dataSurface->Surface(Item1).Construction == Found) {
8433 1 : state.dataSurface->Surface(Item1).HeatTransferAlgorithm = tmpAlgoInput;
8434 : }
8435 : }
8436 : }
8437 : }
8438 :
8439 : // Change algorithm for Kiva and air boundary foundation surfaces
8440 2486 : for (auto &surf : state.dataSurface->Surface) {
8441 2262 : if (surf.ExtBoundCond == DataSurfaces::KivaFoundation) {
8442 0 : surf.HeatTransferAlgorithm = DataSurfaces::HeatTransferModel::Kiva;
8443 0 : state.dataHeatBal->AnyKiva = true;
8444 : }
8445 : }
8446 :
8447 : // test for missing materials for algorithms selected
8448 224 : NumEMPDMat = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "MaterialProperty:MoisturePenetrationDepth:Settings");
8449 224 : NumPCMat = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "MaterialProperty:PhaseChange") +
8450 224 : state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "MaterialProperty:PhaseChangeHysteresis");
8451 224 : NumVTCMat = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "MaterialProperty:VariableThermalConductivity");
8452 224 : NumHAMTMat1 = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "MaterialProperty:HeatAndMoistureTransfer:Settings");
8453 : NumHAMTMat2 =
8454 224 : state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "MaterialProperty:HeatAndMoistureTransfer:SorptionIsotherm");
8455 224 : NumHAMTMat3 = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "MaterialProperty:HeatAndMoistureTransfer:Suction");
8456 224 : NumHAMTMat4 = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "MaterialProperty:HeatAndMoistureTransfer:Redistribution");
8457 224 : NumHAMTMat5 = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "MaterialProperty:HeatAndMoistureTransfer:Diffusion");
8458 : NumHAMTMat6 =
8459 224 : state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "MaterialProperty:HeatAndMoistureTransfer:ThermalConductivity");
8460 224 : SumHAMTMat = NumHAMTMat1 + NumHAMTMat2 + NumHAMTMat3 + NumHAMTMat4 + NumHAMTMat5 + NumHAMTMat6;
8461 224 : msgneeded = false;
8462 :
8463 224 : if (NumEMPDMat > 0 && !state.dataHeatBal->AnyEMPD) {
8464 0 : ShowWarningError(state,
8465 0 : format("The input file includes {} MaterialProperty:MoisturePenetrationDepth:Settings objects but the moisture "
8466 : "penetration depth algorithm is not used anywhere.",
8467 : NumEMPDMat));
8468 0 : msgneeded = true;
8469 : }
8470 224 : if (NumPCMat > 0 && !state.dataHeatBal->AnyCondFD) {
8471 0 : ShowWarningError(state,
8472 0 : format("The input file includes {} MaterialProperty:PhaseChange objects but the conduction finite difference algorithm "
8473 : "is not used anywhere.",
8474 : NumPCMat));
8475 0 : msgneeded = true;
8476 : }
8477 224 : if (NumVTCMat > 0 && !state.dataHeatBal->AnyCondFD) {
8478 0 : ShowWarningError(state,
8479 0 : format("The input file includes {} MaterialProperty:VariableThermalConductivity objects but the conduction finite "
8480 : "difference algorithm is not used anywhere.",
8481 : NumVTCMat));
8482 0 : msgneeded = true;
8483 : }
8484 224 : if (SumHAMTMat > 0 && !state.dataHeatBal->AnyHAMT) {
8485 0 : ShowWarningError(state,
8486 0 : format("The input file includes {} MaterialProperty:HeatAndMoistureTransfer:* objects but the combined heat and "
8487 : "moisture finite difference algorithm is not used anywhere.",
8488 : SumHAMTMat));
8489 0 : msgneeded = true;
8490 : }
8491 224 : if (msgneeded) {
8492 0 : ShowContinueError(state, "Previous materials will be ignored due to HeatBalanceAlgorithm choice.");
8493 : }
8494 224 : msgneeded = false;
8495 224 : if (NumEMPDMat == 0 && state.dataHeatBal->AnyEMPD) {
8496 2 : ShowWarningError(state,
8497 : "The moisture penetration depth conduction transfer function algorithm is used but the input file includes no "
8498 : "MaterialProperty:MoisturePenetrationDepth:Settings objects.");
8499 1 : msgneeded = true;
8500 : }
8501 224 : if (SumHAMTMat == 0 && state.dataHeatBal->AnyHAMT) {
8502 2 : ShowWarningError(state,
8503 : "The combined heat and moisture finite element algorithm is used but the input file includes no "
8504 : "MaterialProperty:HeatAndMoistureTransfer:* objects.");
8505 1 : msgneeded = true;
8506 : }
8507 224 : if (msgneeded) {
8508 3 : ShowContinueError(state,
8509 : "Certain materials objects are necessary to achieve proper results with the heat transfer algorithm(s) selected.");
8510 : }
8511 :
8512 : // Write Solution Algorithm to the initialization output file for User Verification
8513 224 : print(state.files.eio,
8514 : "{}\n",
8515 : "! <Surface Heat Transfer Algorithm>, Value {CTF - ConductionTransferFunction | EMPD - "
8516 : "MoisturePenetrationDepthConductionTransferFunction | CondFD - ConductionFiniteDifference | HAMT - "
8517 : "CombinedHeatAndMoistureFiniteElement} - Description,Inside Surface Max Temperature Limit{C}, Surface "
8518 : "Convection Coefficient Lower Limit {W/m2-K}, Surface Convection Coefficient Upper Limit {W/m2-K}");
8519 :
8520 224 : int numberOfHeatTransferAlgosUsed = 0;
8521 : // Formats
8522 : static constexpr std::string_view Format_725("Surface Heat Transfer Algorithm, {},{:.0R},{:.2R},{:.1R}\n");
8523 :
8524 224 : if (state.dataHeatBal->AnyCTF) {
8525 183 : constexpr std::string_view AlgoName = "CTF - ConductionTransferFunction";
8526 183 : ++numberOfHeatTransferAlgosUsed;
8527 183 : print(state.files.eio,
8528 : Format_725,
8529 : AlgoName,
8530 183 : state.dataHeatBalSurf->MaxSurfaceTempLimit,
8531 183 : state.dataHeatBal->LowHConvLimit,
8532 183 : state.dataHeatBal->HighHConvLimit);
8533 : }
8534 224 : if (state.dataHeatBal->AnyEMPD) {
8535 1 : state.dataHeatBal->AllCTF = false;
8536 1 : constexpr std::string_view AlgoName = "EMPD - MoisturePenetrationDepthConductionTransferFunction";
8537 1 : ++numberOfHeatTransferAlgosUsed;
8538 1 : print(state.files.eio,
8539 : Format_725,
8540 : AlgoName,
8541 1 : state.dataHeatBalSurf->MaxSurfaceTempLimit,
8542 1 : state.dataHeatBal->LowHConvLimit,
8543 1 : state.dataHeatBal->HighHConvLimit);
8544 1 : if (state.dataHeatBal->doSpaceHeatBalanceSimulation || state.dataHeatBal->doSpaceHeatBalanceSizing) {
8545 0 : ShowSevereError(
8546 : state,
8547 : "MoisturePenetrationDepthConductionTransferFunction is not supported with ZoneAirHeatBalanceAlgorithm Space Heat Balance.");
8548 0 : ErrorsFound = true;
8549 : }
8550 : }
8551 224 : if (state.dataHeatBal->AnyCondFD) {
8552 3 : state.dataHeatBal->AllCTF = false;
8553 3 : constexpr std::string_view AlgoName = "CondFD - ConductionFiniteDifference";
8554 3 : ++numberOfHeatTransferAlgosUsed;
8555 3 : print(state.files.eio,
8556 : Format_725,
8557 : AlgoName,
8558 3 : state.dataHeatBalSurf->MaxSurfaceTempLimit,
8559 3 : state.dataHeatBal->LowHConvLimit,
8560 3 : state.dataHeatBal->HighHConvLimit);
8561 : }
8562 224 : if (state.dataHeatBal->AnyHAMT) {
8563 1 : state.dataHeatBal->AllCTF = false;
8564 1 : constexpr std::string_view AlgoName = "HAMT - CombinedHeatAndMoistureFiniteElement";
8565 1 : ++numberOfHeatTransferAlgosUsed;
8566 1 : print(state.files.eio,
8567 : Format_725,
8568 : AlgoName,
8569 1 : state.dataHeatBalSurf->MaxSurfaceTempLimit,
8570 1 : state.dataHeatBal->LowHConvLimit,
8571 1 : state.dataHeatBal->HighHConvLimit);
8572 1 : if (state.dataHeatBal->doSpaceHeatBalanceSimulation || state.dataHeatBal->doSpaceHeatBalanceSizing) {
8573 0 : ShowSevereError(state, "CombinedHeatAndMoistureFiniteElement is not supported with ZoneAirHeatBalanceAlgorithm Space Heat Balance.");
8574 0 : ErrorsFound = true;
8575 : }
8576 : }
8577 224 : if (state.dataHeatBal->AnyKiva) {
8578 0 : state.dataHeatBal->AllCTF = false;
8579 0 : constexpr std::string_view AlgoName = "KivaFoundation - TwoDimensionalFiniteDifference";
8580 0 : ++numberOfHeatTransferAlgosUsed;
8581 0 : print(state.files.eio,
8582 : Format_725,
8583 : AlgoName,
8584 0 : state.dataHeatBalSurf->MaxSurfaceTempLimit,
8585 0 : state.dataHeatBal->LowHConvLimit,
8586 0 : state.dataHeatBal->HighHConvLimit);
8587 : }
8588 :
8589 : // Check HeatTransferAlgorithm for interior surfaces
8590 224 : if (numberOfHeatTransferAlgosUsed > 1) {
8591 : int ExtSurfNum;
8592 5 : for (Item = 1; Item <= state.dataSurface->TotSurfaces; ++Item) {
8593 4 : auto &surf = state.dataSurface->Surface(Item);
8594 4 : if (surf.ExtBoundCond > 0) {
8595 2 : if ((surf.HeatTransferAlgorithm == DataSurfaces::HeatTransferModel::Invalid) ||
8596 2 : (surf.HeatTransferAlgorithm == DataSurfaces::HeatTransferModel::None))
8597 0 : continue;
8598 2 : ExtSurfNum = surf.ExtBoundCond;
8599 2 : auto &extSurf = state.dataSurface->Surface(ExtSurfNum);
8600 2 : if (surf.HeatTransferAlgorithm != extSurf.HeatTransferAlgorithm) {
8601 2 : ShowWarningError(state,
8602 : "An interior surface is defined as two surfaces with reverse constructions. The HeatTransferAlgorithm in "
8603 : "both constructions should be same.");
8604 2 : ShowContinueError(state,
8605 2 : format("The HeatTransferAlgorithm of Surface: {}, is {}",
8606 1 : surf.Name,
8607 1 : DataSurfaces::HeatTransAlgoStrs[static_cast<int>(surf.HeatTransferAlgorithm)]));
8608 2 : ShowContinueError(state,
8609 2 : format("The HeatTransferAlgorithm of Surface: {}, is {}",
8610 1 : extSurf.Name,
8611 1 : DataSurfaces::HeatTransAlgoStrs[static_cast<int>(extSurf.HeatTransferAlgorithm)]));
8612 1 : if (surf.HeatTransferAlgorithm > extSurf.HeatTransferAlgorithm) {
8613 2 : ShowContinueError(state,
8614 2 : format("The HeatTransferAlgorithm of Surface: {}, is assigned to {}. Simulation continues.",
8615 1 : extSurf.Name,
8616 1 : DataSurfaces::HeatTransAlgoStrs[static_cast<int>(surf.HeatTransferAlgorithm)]));
8617 1 : extSurf.HeatTransferAlgorithm = surf.HeatTransferAlgorithm;
8618 : } else {
8619 0 : ShowContinueError(state,
8620 0 : format("The HeatTransferAlgorithm of Surface: {}, is assigned to {}. Simulation continues.",
8621 0 : surf.Name,
8622 0 : DataSurfaces::HeatTransAlgoStrs[static_cast<int>(extSurf.HeatTransferAlgorithm)]));
8623 0 : surf.HeatTransferAlgorithm = extSurf.HeatTransferAlgorithm;
8624 : }
8625 : }
8626 : }
8627 : }
8628 : }
8629 :
8630 : // Assign model type to windows, shading surfaces, and TDDs
8631 2486 : for (Item = 1; Item <= state.dataSurface->TotSurfaces; ++Item) {
8632 2262 : if (state.dataSurface->Surface(Item).Class == SurfaceClass::Window || state.dataSurface->Surface(Item).Class == SurfaceClass::GlassDoor) {
8633 : // todo, add complex fenestration switch HeatTransferModel_ComplexFenestration
8634 197 : if (state.dataSurface->SurfWinWindowModelType(Item) == DataSurfaces::WindowModel::BSDF) {
8635 0 : state.dataSurface->Surface(Item).HeatTransferAlgorithm = DataSurfaces::HeatTransferModel::ComplexFenestration;
8636 : } else {
8637 197 : state.dataSurface->Surface(Item).HeatTransferAlgorithm = DataSurfaces::HeatTransferModel::Window5;
8638 : }
8639 : }
8640 2262 : if (state.dataSurface->Surface(Item).Class == SurfaceClass::Detached_B ||
8641 2242 : state.dataSurface->Surface(Item).Class == SurfaceClass::Detached_F ||
8642 6682 : state.dataSurface->Surface(Item).Class == SurfaceClass::Shading || state.dataSurface->Surface(Item).Class == SurfaceClass::Overhang ||
8643 2178 : state.dataSurface->Surface(Item).Class == SurfaceClass::Fin) {
8644 84 : state.dataSurface->Surface(Item).HeatTransferAlgorithm = DataSurfaces::HeatTransferModel::None;
8645 : }
8646 4524 : if (state.dataSurface->Surface(Item).Class == SurfaceClass::TDD_Diffuser ||
8647 2262 : state.dataSurface->Surface(Item).Class == SurfaceClass::TDD_Dome) {
8648 7 : state.dataSurface->Surface(Item).HeatTransferAlgorithm = DataSurfaces::HeatTransferModel::TDD;
8649 : }
8650 :
8651 2565 : if (state.dataSurface->Surface(Item).HeatTransferAlgorithm == DataSurfaces::HeatTransferModel::CTF ||
8652 303 : state.dataSurface->Surface(Item).HeatTransferAlgorithm == DataSurfaces::HeatTransferModel::EMPD) {
8653 1959 : state.dataConstruction->Construct(state.dataSurface->Surface(Item).Construction).IsUsedCTF = true;
8654 : }
8655 : }
8656 224 : }
8657 :
8658 : struct PopCoincidentVertexReturn
8659 : {
8660 : double perimeter;
8661 : int poppedVertexPos = -1; // This is a STL vector position, 0-indexed
8662 : int keptVertexPos = -1;
8663 : };
8664 :
8665 2201 : PopCoincidentVertexReturn checkPopCoincidentVertex(const Array1D<Vector> &vertices)
8666 : {
8667 :
8668 2201 : size_t const nSides = vertices.size();
8669 :
8670 : // Pass one: Vector of distance from this vertex to the next one
8671 2201 : std::vector<Real64> distances(nSides);
8672 2201 : size_t index = 0;
8673 2201 : double min_distance = std::numeric_limits<Real64>::max();
8674 2201 : double perimeter = 0.0;
8675 11009 : for (auto it = vertices.begin(); it != vertices.end(); ++it) {
8676 8808 : auto itnext = std::next(it);
8677 8808 : if (itnext == std::end(vertices)) {
8678 2201 : itnext = std::begin(vertices);
8679 : }
8680 8808 : const auto dist = distance(*it, *itnext);
8681 8808 : distances[index++] = dist;
8682 8808 : min_distance = std::min(min_distance, dist);
8683 8808 : perimeter += dist;
8684 : }
8685 : // Return early if nothing to be popped
8686 2201 : if (min_distance >= Constant::OneCentimeter) {
8687 2193 : return {perimeter};
8688 : }
8689 :
8690 : // Pass two: figure out the vertex that is coincident with its previous and/or next vertex and
8691 : // that minimizes the (distanceThisToNext + distanceThisToPrev).
8692 8 : Real64 min_weight = std::numeric_limits<Real64>::max();
8693 8 : int poppedVertexPos = -1;
8694 8 : int keptVertexPos = -1;
8695 :
8696 49 : for (index = 0; index < nSides; ++index) {
8697 41 : size_t const prevIndex = (index == 0) ? nSides - 1 : index - 1;
8698 41 : Real64 const &distanceThisToNext = distances[index];
8699 41 : Real64 const &distanceThisToPrev = distances[prevIndex];
8700 41 : if ((distanceThisToNext >= Constant::OneCentimeter) && (distanceThisToPrev >= Constant::OneCentimeter)) {
8701 19 : continue;
8702 : }
8703 22 : Real64 const weight = distanceThisToNext + distanceThisToPrev;
8704 22 : if (weight < min_weight) {
8705 13 : min_weight = weight;
8706 13 : poppedVertexPos = static_cast<int>(index);
8707 13 : if (distanceThisToPrev < distanceThisToNext) {
8708 4 : keptVertexPos = prevIndex;
8709 : } else {
8710 9 : keptVertexPos = static_cast<int>((index == nSides - 1) ? 0 : index + 1);
8711 : }
8712 : }
8713 : }
8714 :
8715 : // Return the keptVertexPos (which can be the previous or the next), so we can print the displayExtraWarning correctly
8716 8 : return {perimeter, poppedVertexPos, keptVertexPos};
8717 2201 : }
8718 :
8719 2194 : void GetVertices(EnergyPlusData &state,
8720 : int const SurfNum, // Current surface number
8721 : int const NSides, // Number of sides to figure
8722 : Array1S<Real64> const Vertices // Vertices, in specified order
8723 : )
8724 : {
8725 :
8726 : // SUBROUTINE INFORMATION:
8727 : // AUTHOR Linda Lawrie
8728 : // DATE WRITTEN May 2000
8729 :
8730 : // PURPOSE OF THIS SUBROUTINE:
8731 : // This subroutine gets the surface vertices from the arrays
8732 : // passed by the calling routine. These had previously been obtained
8733 : // from the InputProcessor (GetObjectItem). This routine will provide
8734 : // a standard place for determining various properties of the surface
8735 : // from the vertices.
8736 :
8737 : // SUBROUTINE PARAMETER DEFINITIONS:
8738 : static constexpr std::string_view RoutineName("GetVertices: ");
8739 :
8740 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
8741 : int n; // Loop counter
8742 : int NSrc; // Used for CW -> CCW transformation
8743 : int NTar; // Used for CW -> CCW transformation
8744 : Real64 SurfWorldAz;
8745 : Real64 SurfTilt;
8746 : Real64 Perimeter; // Perimeter length of the surface
8747 : Real64 Xb; // Intermediate calculation
8748 : Real64 Yb; // Intermediate calculation
8749 : int ZoneNum;
8750 : int ThisCorner;
8751 : Real64 ThisWidth;
8752 : Real64 ThisHeight;
8753 : // unused REAL(r64) :: ccwtest
8754 : // unused LOGICAL :: SurfaceCCW
8755 : Real64 dotp;
8756 :
8757 : // Object Data
8758 2194 : Vector const TestVector(0.0, 0.0, 1.0);
8759 2194 : Vector temp;
8760 :
8761 2194 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
8762 :
8763 2194 : if (NSides > state.dataSurface->MaxVerticesPerSurface) state.dataSurface->MaxVerticesPerSurface = NSides;
8764 2194 : int Ptr = 1;
8765 10971 : for (n = 1; n <= NSides; ++n) {
8766 8777 : surfTemp.Vertex(n).x = Vertices(Ptr);
8767 8777 : ++Ptr;
8768 8777 : surfTemp.Vertex(n).y = Vertices(Ptr);
8769 8777 : ++Ptr;
8770 8777 : surfTemp.Vertex(n).z = Vertices(Ptr);
8771 8777 : ++Ptr;
8772 : }
8773 :
8774 : // Address changing vertices if they were put in in CW order rather than CCW
8775 2194 : if (!state.dataSurface->CCW) {
8776 : // If even number of sides, this will transfer appropriately
8777 : // If odd number, will leave the "odd" one, which is what you want.
8778 2 : NSrc = NSides;
8779 2 : NTar = 2;
8780 4 : for (n = 1; n <= (NSides - 1) / 2; ++n) {
8781 2 : temp = surfTemp.Vertex(NSrc);
8782 2 : surfTemp.Vertex(NSrc) = surfTemp.Vertex(NTar);
8783 2 : surfTemp.Vertex(NTar) = temp;
8784 2 : --NSrc;
8785 2 : ++NTar;
8786 : }
8787 : }
8788 : // Now address which "Corner" has been put in first. Note: the azimuth and tilt and area
8789 : // calculations do not care which corner is put in first.
8790 : // 2/2011 - don't think the shading calculations have a corner preference. Will keep this for
8791 : // consistency (for now)
8792 2194 : ThisCorner = state.dataSurface->Corner;
8793 2648 : while (ThisCorner != DataSurfaces::UpperLeftCorner) {
8794 454 : if (NSides < 4) {
8795 4 : if (ThisCorner == DataSurfaces::UpperRightCorner) {
8796 0 : break;
8797 : }
8798 : }
8799 454 : NTar = ThisCorner;
8800 454 : NSrc = ThisCorner + 1;
8801 454 : if (NSrc > NSides) NSrc = 1;
8802 1812 : for (n = 1; n <= NSides - 1; ++n) {
8803 1358 : temp = surfTemp.Vertex(NTar);
8804 1358 : surfTemp.Vertex(NTar) = surfTemp.Vertex(NSrc);
8805 1358 : surfTemp.Vertex(NSrc) = temp;
8806 1358 : ++NTar;
8807 1358 : ++NSrc;
8808 1358 : if (NTar > NSides) NTar = 1;
8809 1358 : if (NSrc > NSides) NSrc = 1;
8810 : }
8811 454 : ++ThisCorner;
8812 454 : if (ThisCorner > NSides) ThisCorner = 1;
8813 : } // Corners
8814 2194 : if (!state.dataSurface->WorldCoordSystem) {
8815 : // Input in "relative" coordinates, use Building and Zone North Axes and Origins
8816 : // to translate each point (including rotation for Appendix G)
8817 1225 : ZoneNum = surfTemp.Zone;
8818 1225 : if (ZoneNum > 0) {
8819 6077 : for (n = 1; n <= NSides; ++n) {
8820 4865 : Xb = surfTemp.Vertex(n).x * state.dataSurfaceGeometry->CosZoneRelNorth(ZoneNum) -
8821 4865 : surfTemp.Vertex(n).y * state.dataSurfaceGeometry->SinZoneRelNorth(ZoneNum) + state.dataHeatBal->Zone(ZoneNum).OriginX;
8822 4865 : Yb = surfTemp.Vertex(n).x * state.dataSurfaceGeometry->SinZoneRelNorth(ZoneNum) +
8823 4865 : surfTemp.Vertex(n).y * state.dataSurfaceGeometry->CosZoneRelNorth(ZoneNum) + state.dataHeatBal->Zone(ZoneNum).OriginY;
8824 4865 : surfTemp.Vertex(n).x = Xb * state.dataSurfaceGeometry->CosBldgRelNorth - Yb * state.dataSurfaceGeometry->SinBldgRelNorth;
8825 4865 : surfTemp.Vertex(n).y = Xb * state.dataSurfaceGeometry->SinBldgRelNorth + Yb * state.dataSurfaceGeometry->CosBldgRelNorth;
8826 4865 : surfTemp.Vertex(n).z += state.dataHeatBal->Zone(ZoneNum).OriginZ;
8827 : }
8828 13 : } else if (surfTemp.Class == SurfaceClass::Detached_B) {
8829 50 : for (n = 1; n <= NSides; ++n) {
8830 40 : Xb = surfTemp.Vertex(n).x;
8831 40 : Yb = surfTemp.Vertex(n).y;
8832 40 : surfTemp.Vertex(n).x = Xb * state.dataSurfaceGeometry->CosBldgRelNorth - Yb * state.dataSurfaceGeometry->SinBldgRelNorth;
8833 40 : surfTemp.Vertex(n).y = Xb * state.dataSurfaceGeometry->SinBldgRelNorth + Yb * state.dataSurfaceGeometry->CosBldgRelNorth;
8834 : }
8835 : }
8836 : } else {
8837 : // if world coordinate only need to rotate for Appendix G
8838 969 : ZoneNum = surfTemp.Zone;
8839 969 : if (ZoneNum > 0) {
8840 4809 : for (n = 1; n <= NSides; ++n) {
8841 3844 : Xb = surfTemp.Vertex(n).x;
8842 3844 : Yb = surfTemp.Vertex(n).y;
8843 3844 : surfTemp.Vertex(n).x = Xb * state.dataSurfaceGeometry->CosBldgRotAppGonly - Yb * state.dataSurfaceGeometry->SinBldgRotAppGonly;
8844 3844 : surfTemp.Vertex(n).y = Xb * state.dataSurfaceGeometry->SinBldgRotAppGonly + Yb * state.dataSurfaceGeometry->CosBldgRotAppGonly;
8845 : }
8846 4 : } else if (surfTemp.Class == SurfaceClass::Detached_B) {
8847 10 : for (n = 1; n <= NSides; ++n) {
8848 8 : Xb = surfTemp.Vertex(n).x;
8849 8 : Yb = surfTemp.Vertex(n).y;
8850 8 : surfTemp.Vertex(n).x = Xb * state.dataSurfaceGeometry->CosBldgRotAppGonly - Yb * state.dataSurfaceGeometry->SinBldgRotAppGonly;
8851 8 : surfTemp.Vertex(n).y = Xb * state.dataSurfaceGeometry->SinBldgRotAppGonly + Yb * state.dataSurfaceGeometry->CosBldgRotAppGonly;
8852 : }
8853 : }
8854 : }
8855 :
8856 2194 : if (NSides > 2) {
8857 2194 : auto &surface = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
8858 2194 : auto &vertices = surface.Vertex;
8859 2194 : auto &nSides = surface.Sides;
8860 2194 : std::string TiltString;
8861 :
8862 : while (true) {
8863 2201 : PopCoincidentVertexReturn const popResult = checkPopCoincidentVertex(vertices);
8864 2201 : Perimeter = popResult.perimeter;
8865 2201 : if (popResult.poppedVertexPos < 0) {
8866 : // No pop needed, we're done
8867 2193 : break;
8868 : }
8869 :
8870 : // Grab the popped one, and the kept one (regardless of whether it's previous or next)
8871 8 : auto it = vertices.begin();
8872 8 : std::advance(it, popResult.poppedVertexPos);
8873 8 : int const poppedVertexIndex = popResult.poppedVertexPos + 1;
8874 :
8875 8 : auto itKept = vertices.begin();
8876 8 : std::advance(itKept, popResult.keptVertexPos);
8877 8 : int const keptVertexIndex = popResult.keptVertexPos + 1;
8878 :
8879 8 : if (state.dataGlobal->DisplayExtraWarnings) {
8880 12 : ShowWarningError(state,
8881 12 : format("{}Distance between two vertices < .01, possibly coincident. for Surface={}, in Zone={}",
8882 : RoutineName,
8883 6 : surfTemp.Name,
8884 6 : surfTemp.ZoneName));
8885 :
8886 9 : bool const printPoppedFirst = (poppedVertexIndex < keptVertexIndex) ? !(poppedVertexIndex == 1 && keptVertexIndex == nSides)
8887 3 : : (poppedVertexIndex == nSides && keptVertexIndex == 1);
8888 :
8889 6 : if (printPoppedFirst) {
8890 5 : ShowContinueError(state, format("Vertex [{}]=({:.2R},{:.2R},{:.2R})", poppedVertexIndex, it->x, it->y, it->z));
8891 5 : ShowContinueError(state, format("Vertex [{}]=({:.2R},{:.2R},{:.2R})", keptVertexIndex, itKept->x, itKept->y, itKept->z));
8892 : } else {
8893 1 : ShowContinueError(state, format("Vertex [{}]=({:.2R},{:.2R},{:.2R})", keptVertexIndex, itKept->x, itKept->y, itKept->z));
8894 1 : ShowContinueError(state, format("Vertex [{}]=({:.2R},{:.2R},{:.2R})", poppedVertexIndex, it->x, it->y, it->z));
8895 : }
8896 : }
8897 8 : ++state.dataErrTracking->TotalCoincidentVertices;
8898 8 : if (nSides <= 3) {
8899 1 : if (state.dataGlobal->DisplayExtraWarnings) {
8900 0 : ShowContinueError(state,
8901 0 : format("Cannot Drop Vertex [{}]; Number of Surface Sides at minimum. This surface is now a "
8902 : "degenerate surface.",
8903 : poppedVertexIndex));
8904 : }
8905 1 : ++state.dataErrTracking->TotalDegenerateSurfaces;
8906 : // If degenerate, we won't be able to pop now nor later, so exit
8907 : // mark degenerate surface?
8908 1 : break;
8909 : }
8910 :
8911 7 : if (state.dataGlobal->DisplayExtraWarnings) {
8912 6 : ShowContinueError(state, format("Dropping Vertex [{}].", poppedVertexIndex));
8913 : }
8914 7 : --nSides;
8915 7 : vertices.erase(it);
8916 : // No need to recompute perimeter, because it'll be done in the next iteration, until no popping or degenerate happens
8917 7 : }
8918 :
8919 2194 : surfTemp.Perimeter = Perimeter;
8920 :
8921 2194 : Vectors::CreateNewellSurfaceNormalVector(surfTemp.Vertex, surfTemp.Sides, surfTemp.NewellSurfaceNormalVector);
8922 2194 : Vectors::CreateNewellAreaVector(surfTemp.Vertex, surfTemp.Sides, surfTemp.NewellAreaVector);
8923 : // For surfaces with subsurfaces, the following two areas are turned into net areas later by
8924 : // subtracting subsurface areas
8925 2194 : surfTemp.GrossArea = Vectors::VecLength(surfTemp.NewellAreaVector);
8926 2194 : surfTemp.Area = surfTemp.GrossArea;
8927 2194 : surfTemp.NetAreaShadowCalc = surfTemp.Area;
8928 2194 : Vectors::DetermineAzimuthAndTilt(
8929 2194 : surfTemp.Vertex, SurfWorldAz, SurfTilt, surfTemp.lcsx, surfTemp.lcsy, surfTemp.lcsz, surfTemp.NewellSurfaceNormalVector);
8930 2194 : dotp = dot(surfTemp.NewellSurfaceNormalVector, TestVector);
8931 2194 : if (surfTemp.Class == SurfaceClass::Roof && dotp < -0.000001) {
8932 16 : TiltString = format("{:.1R}", SurfTilt);
8933 32 : ShowWarningError(state,
8934 32 : format("{}Roof/Ceiling is upside down! Tilt angle=[{}], should be near 0, Surface=\"{}\", in Zone=\"{}\".",
8935 : RoutineName,
8936 : TiltString,
8937 16 : surfTemp.Name,
8938 16 : surfTemp.ZoneName));
8939 32 : ShowContinueError(state, "Automatic fix is attempted.");
8940 16 : ReverseAndRecalculate(state, SurfNum, surfTemp.Sides, SurfWorldAz, SurfTilt);
8941 2178 : } else if (surfTemp.Class == SurfaceClass::Roof && SurfTilt > 80.0) {
8942 8 : TiltString = format("{:.1R}", SurfTilt);
8943 16 : ShowWarningError(
8944 : state,
8945 16 : format("{}Roof/Ceiling is not oriented correctly! Tilt angle=[{}], should be near 0, Surface=\"{}\", in Zone=\"{}\".",
8946 : RoutineName,
8947 : TiltString,
8948 8 : surfTemp.Name,
8949 8 : surfTemp.ZoneName));
8950 : }
8951 2194 : if (surfTemp.Class == SurfaceClass::Floor && dotp > 0.000001) {
8952 41 : TiltString = format("{:.1R}", SurfTilt);
8953 82 : ShowWarningError(state,
8954 82 : format("{}Floor is upside down! Tilt angle=[{}], should be near 180, Surface=\"{}\", in Zone=\"{}\".",
8955 : RoutineName,
8956 : TiltString,
8957 41 : surfTemp.Name,
8958 41 : surfTemp.ZoneName));
8959 82 : ShowContinueError(state, "Automatic fix is attempted.");
8960 41 : ReverseAndRecalculate(state, SurfNum, surfTemp.Sides, SurfWorldAz, SurfTilt);
8961 2153 : } else if (surfTemp.Class == SurfaceClass::Floor && SurfTilt < 158.2) { // slope/grade = 40%!
8962 16 : TiltString = format("{:.1R}", SurfTilt);
8963 32 : ShowWarningError(state,
8964 32 : format("{}Floor is not oriented correctly! Tilt angle=[{}], should be near 180, Surface=\"{}\", in Zone=\"{}\".",
8965 : RoutineName,
8966 : TiltString,
8967 16 : surfTemp.Name,
8968 16 : surfTemp.ZoneName));
8969 : }
8970 2194 : surfTemp.Azimuth = SurfWorldAz;
8971 2194 : surfTemp.Tilt = SurfTilt;
8972 2194 : surfTemp.convOrientation = Convect::GetSurfConvOrientation(surfTemp.Tilt);
8973 :
8974 : // Sine and cosine of azimuth and tilt
8975 2194 : surfTemp.SinAzim = std::sin(SurfWorldAz * Constant::DegToRad);
8976 2194 : surfTemp.CosAzim = std::cos(SurfWorldAz * Constant::DegToRad);
8977 2194 : surfTemp.SinTilt = std::sin(SurfTilt * Constant::DegToRad);
8978 2194 : surfTemp.CosTilt = std::cos(SurfTilt * Constant::DegToRad);
8979 2194 : if (surfTemp.ViewFactorGround == Constant::AutoCalculate) {
8980 477 : surfTemp.ViewFactorGround = 0.5 * (1.0 - surfTemp.CosTilt);
8981 : }
8982 : // Outward normal unit vector (pointing away from room)
8983 2194 : surfTemp.OutNormVec = surfTemp.NewellSurfaceNormalVector;
8984 8776 : for (n = 1; n <= 3; ++n) {
8985 6582 : if (std::abs(surfTemp.OutNormVec(n) - 1.0) < 1.e-06) surfTemp.OutNormVec(n) = +1.0;
8986 6582 : if (std::abs(surfTemp.OutNormVec(n) + 1.0) < 1.e-06) surfTemp.OutNormVec(n) = -1.0;
8987 6582 : if (std::abs(surfTemp.OutNormVec(n)) < 1.e-06) surfTemp.OutNormVec(n) = 0.0;
8988 : }
8989 :
8990 2194 : if (surfTemp.Class == SurfaceClass::Window || surfTemp.Class == SurfaceClass::GlassDoor || surfTemp.Class == SurfaceClass::Door)
8991 201 : surfTemp.Area *= surfTemp.Multiplier;
8992 : // Can perform tests on this surface here
8993 2194 : surfTemp.ViewFactorSky = 0.5 * (1.0 + surfTemp.CosTilt);
8994 : // The following IR view factors are modified in subr. SkyDifSolarShading if there are shadowing
8995 : // surfaces
8996 2194 : surfTemp.ViewFactorSkyIR = surfTemp.ViewFactorSky;
8997 2194 : surfTemp.ViewFactorGroundIR = 0.5 * (1.0 - surfTemp.CosTilt);
8998 :
8999 : // Call to transform vertices
9000 :
9001 2194 : TransformVertsByAspect(state, SurfNum, surfTemp.Sides);
9002 :
9003 2194 : } else {
9004 0 : ShowFatalError(state, format("{}Called with less than 2 sides, Surface={}", RoutineName, surfTemp.Name));
9005 : }
9006 :
9007 : // Preliminary Height/Width
9008 2194 : temp = surfTemp.Vertex(3) - surfTemp.Vertex(2);
9009 2194 : ThisWidth = Vectors::VecLength(temp);
9010 2194 : temp = surfTemp.Vertex(2) - surfTemp.Vertex(1);
9011 2194 : ThisHeight = Vectors::VecLength(temp);
9012 2194 : surfTemp.Height = ThisHeight;
9013 2194 : surfTemp.Width = ThisWidth;
9014 2194 : }
9015 :
9016 57 : void ReverseAndRecalculate(EnergyPlusData &state,
9017 : int const SurfNum, // Surface number for the surface
9018 : int const NSides, // number of sides to surface
9019 : Real64 &SurfAzimuth, // Surface Facing angle (will be 0 for roofs/floors)
9020 : Real64 &SurfTilt // Surface tilt (
9021 : )
9022 : {
9023 :
9024 : // SUBROUTINE INFORMATION:
9025 : // AUTHOR Linda Lawrie
9026 : // DATE WRITTEN February 2011
9027 :
9028 : // PURPOSE OF THIS SUBROUTINE:
9029 : // This routine reverses the vertices for a surface (needed when roof/floor is upside down)
9030 : // and recalculates the azimuth, etc for the surface.
9031 :
9032 : // SUBROUTINE PARAMETER DEFINITIONS:
9033 : static constexpr std::string_view RoutineName("ReverseAndRecalculate: ");
9034 :
9035 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
9036 : int n; // Loop Control
9037 : int RevPtr; // pointer for reversing vertices
9038 57 : std::string TiltString;
9039 :
9040 : // Object Data
9041 57 : Array1D<Vector> Vertices(NSides); // Vertices, in specified order
9042 :
9043 57 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
9044 :
9045 284 : for (n = 1; n <= NSides; ++n) {
9046 227 : Vertices(n) = surfTemp.Vertex(n);
9047 : }
9048 57 : RevPtr = NSides;
9049 284 : for (n = 1; n <= NSides; ++n) {
9050 227 : surfTemp.Vertex(n) = Vertices(RevPtr);
9051 227 : --RevPtr;
9052 : }
9053 :
9054 57 : print(state.files.debug, "Reversing Surface Name={}\n", surfTemp.Name);
9055 284 : for (n = 1; n <= NSides; ++n) {
9056 227 : print(state.files.debug,
9057 : "side={:5} abs coord vertex= {:18.13F} {:18.13F} {:18.13F}\n",
9058 : n,
9059 227 : surfTemp.Vertex(n).x,
9060 227 : surfTemp.Vertex(n).y,
9061 227 : surfTemp.Vertex(n).z);
9062 : }
9063 :
9064 57 : Vectors::CreateNewellSurfaceNormalVector(surfTemp.Vertex, surfTemp.Sides, surfTemp.NewellSurfaceNormalVector);
9065 57 : Vectors::DetermineAzimuthAndTilt(
9066 57 : surfTemp.Vertex, SurfAzimuth, SurfTilt, surfTemp.lcsx, surfTemp.lcsy, surfTemp.lcsz, surfTemp.NewellSurfaceNormalVector);
9067 57 : if (surfTemp.Class == SurfaceClass::Roof && SurfTilt > 80.0) {
9068 0 : TiltString = format("{:.1R}", SurfTilt);
9069 0 : ShowWarningError(
9070 : state,
9071 0 : format("{}Roof/Ceiling is still upside down! Tilt angle=[{}], should be near 0, please fix manually.", RoutineName, TiltString));
9072 : }
9073 57 : if (surfTemp.Class == SurfaceClass::Floor && SurfTilt < 158.2) { // 40% grade!
9074 16 : ShowWarningError(
9075 16 : state, format("{}Floor is still upside down! Tilt angle=[{}], should be near 180, please fix manually.", RoutineName, TiltString));
9076 : }
9077 57 : }
9078 :
9079 49 : void MakeMirrorSurface(EnergyPlusData &state, int &SurfNum) // In=>Surface to Mirror, Out=>new Surface index // This is not good
9080 : {
9081 :
9082 : // SUBROUTINE INFORMATION:
9083 : // AUTHOR Linda Lawrie
9084 : // DATE WRITTEN June 2002
9085 :
9086 : // PURPOSE OF THIS SUBROUTINE:
9087 : // This subroutine creates a "mirror" surface using the indicated surface.
9088 : // This is the simple approach for bi-directional shading devices. If, perchance,
9089 : // the user has already taken care of this (e.g. fins in middle of wall), there will
9090 : // be extra shading devices shown.
9091 :
9092 49 : auto &origSurface = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
9093 49 : auto &newSurface = state.dataSurfaceGeometry->SurfaceTmp(SurfNum + 1);
9094 49 : newSurface = origSurface;
9095 :
9096 49 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
9097 :
9098 49 : int nVert = origSurface.Sides;
9099 : // Reverse the vertices in the original surface. Add "MIR-" to name.
9100 244 : for (int Vert = 1; Vert <= surfTemp.Sides; ++Vert) {
9101 195 : newSurface.Vertex(Vert) = origSurface.Vertex(nVert);
9102 195 : --nVert;
9103 : }
9104 49 : newSurface.Name = "Mir-" + origSurface.Name;
9105 49 : newSurface.MirroredSurf = true;
9106 :
9107 49 : if (newSurface.Sides > 2) {
9108 49 : Vectors::CreateNewellAreaVector(newSurface.Vertex, newSurface.Sides, newSurface.NewellAreaVector);
9109 49 : newSurface.GrossArea = Vectors::VecLength(newSurface.NewellAreaVector);
9110 49 : newSurface.Area = newSurface.GrossArea;
9111 49 : newSurface.NetAreaShadowCalc = newSurface.Area;
9112 49 : Vectors::CreateNewellSurfaceNormalVector(newSurface.Vertex, newSurface.Sides, newSurface.NewellSurfaceNormalVector);
9113 49 : Real64 SurfWorldAz = 0.0;
9114 49 : Real64 SurfTilt = 0.0;
9115 49 : Vectors::DetermineAzimuthAndTilt(
9116 49 : newSurface.Vertex, SurfWorldAz, SurfTilt, newSurface.lcsx, newSurface.lcsy, newSurface.lcsz, newSurface.NewellSurfaceNormalVector);
9117 49 : newSurface.Azimuth = SurfWorldAz;
9118 49 : newSurface.Tilt = SurfTilt;
9119 49 : newSurface.convOrientation = Convect::GetSurfConvOrientation(newSurface.Tilt);
9120 :
9121 : // Sine and cosine of azimuth and tilt
9122 49 : newSurface.SinAzim = std::sin(SurfWorldAz * Constant::DegToRad);
9123 49 : newSurface.CosAzim = std::cos(SurfWorldAz * Constant::DegToRad);
9124 49 : newSurface.SinTilt = std::sin(SurfTilt * Constant::DegToRad);
9125 49 : newSurface.CosTilt = std::cos(SurfTilt * Constant::DegToRad);
9126 : // Outward normal unit vector (pointing away from room)
9127 49 : newSurface.OutNormVec = newSurface.NewellSurfaceNormalVector;
9128 196 : for (int n = 1; n <= 3; ++n) {
9129 147 : if (std::abs(newSurface.OutNormVec(n) - 1.0) < 1.e-06) newSurface.OutNormVec(n) = +1.0;
9130 147 : if (std::abs(newSurface.OutNormVec(n) + 1.0) < 1.e-06) newSurface.OutNormVec(n) = -1.0;
9131 147 : if (std::abs(newSurface.OutNormVec(n)) < 1.e-06) newSurface.OutNormVec(n) = 0.0;
9132 : }
9133 :
9134 : // Can perform tests on this surface here
9135 49 : newSurface.ViewFactorSky = 0.5 * (1.0 + newSurface.CosTilt);
9136 : // The following IR view factors are modified in subr. SkyDifSolarShading if there are shadowing surfaces
9137 49 : newSurface.ViewFactorSkyIR = newSurface.ViewFactorSky;
9138 49 : newSurface.ViewFactorGroundIR = 0.5 * (1.0 - newSurface.CosTilt);
9139 49 : ++SurfNum; // Calling function expects incremented argument on return
9140 : }
9141 49 : }
9142 :
9143 226 : void GetWindowShadingControlData(EnergyPlusData &state, bool &ErrorsFound) // If errors found in input
9144 : {
9145 :
9146 : // SUBROUTINE INFORMATION:
9147 : // AUTHOR Fred Winkelmann
9148 : // DATE WRITTEN November 1998
9149 : // MODIFIED Aug 2001 (FW): add handling of new ShadingControlIsScheduled
9150 : // and GlareControlIsActive fields
9151 : // Nov 2001 (FW): add ShadingDevice as alternative to ShadedConstruction
9152 : // Dec 2001 (FW): add slat angle controls for blinds
9153 : // Aug 2002 (FW): add Setpoint2; check that specified control type is legal
9154 : // Feb 2003 (FW): add error if Material Name of Shading Device is used with
9155 : // Shading Type = BetweenGlassShade or BetweenGlassBlind
9156 : // Dec 2003 (FW): improve BetweenGlassBlind error messages
9157 : // Feb 2009 (BG): improve error checking for OnIfScheduleAllows
9158 :
9159 : // PURPOSE OF THIS SUBROUTINE:
9160 : // Reads in the window shading control information
9161 : // from the input data file, interprets it and puts it in the derived type
9162 :
9163 : // SUBROUTINE PARAMETER DEFINITIONS:
9164 : static constexpr std::string_view routineName = "GetWindowShadingControlData";
9165 :
9166 226 : int constexpr NumValidShadingTypes(9);
9167 : static Array1D_string const cValidShadingTypes(NumValidShadingTypes,
9168 : {
9169 : "SHADEOFF", // 1
9170 : "INTERIORSHADE", // 2
9171 : "SWITCHABLEGLAZING", // 3
9172 : "EXTERIORSHADE", // 4
9173 : "EXTERIORSCREEN", // 5
9174 : "INTERIORBLIND", // 6
9175 : "EXTERIORBLIND", // 7
9176 : "BETWEENGLASSSHADE", // 8
9177 : "BETWEENGLASSBLIND" // 9
9178 226 : });
9179 :
9180 226 : constexpr std::array<std::string_view, static_cast<int>(DataSurfaces::WindowShadingControlType::Num)> WindowShadingControlTypeNamesUC{
9181 : "ALWAYSON",
9182 : "ALWAYSOFF",
9183 : "ONIFSCHEDULEALLOWS",
9184 : "ONIFHIGHSOLARONWINDOW",
9185 : "ONIFHIGHHORIZONTALSOLAR",
9186 : "ONIFHIGHOUTDOORAIRTEMPERATURE",
9187 : "ONIFHIGHZONEAIRTEMPERATURE",
9188 : "ONIFHIGHZONECOOLING",
9189 : "ONIFHIGHGLARE",
9190 : "MEETDAYLIGHTILLUMINANCESETPOINT",
9191 : "ONNIGHTIFLOWOUTDOORTEMPANDOFFDAY",
9192 : "ONNIGHTIFLOWINSIDETEMPANDOFFDAY",
9193 : "ONNIGHTIFHEATINGANDOFFDAY",
9194 : "ONNIGHTIFLOWOUTDOORTEMPANDONDAYIFCOOLING",
9195 : "ONNIGHTIFHEATINGANDONDAYIFCOOLING",
9196 : "OFFNIGHTANDONDAYIFCOOLINGANDHIGHSOLARONWINDOW",
9197 : "ONNIGHTANDONDAYIFCOOLINGANDHIGHSOLARONWINDOW",
9198 : "ONIFHIGHOUTDOORAIRTEMPANDHIGHSOLARONWINDOW",
9199 : "ONIFHIGHOUTDOORAIRTEMPANDHIGHHORIZONTALSOLAR",
9200 : "ONIFHIGHZONEAIRTEMPANDHIGHSOLARONWINDOW",
9201 : "ONIFHIGHZONEAIRTEMPANDHIGHHORIZONTALSOLAR",
9202 : "ONIFHIGHSOLARORHIGHLUMINANCETILLMIDNIGHT",
9203 : "ONIFHIGHSOLARORHIGHLUMINANCETILLSUNSET",
9204 : "ONIFHIGHSOLARORHIGHLUMINANCETILLNEXTMORNING"};
9205 :
9206 226 : constexpr std::array<std::string_view, static_cast<int>(DataSurfaces::SlatAngleControl::Num)> SlatAngleNamesUC{
9207 : "FIXEDSLATANGLE", "SCHEDULEDSLATANGLE", "BLOCKBEAMSOLAR"};
9208 :
9209 226 : constexpr std::array<std::string_view, static_cast<int>(DataSurfaces::MultiSurfaceControl::Num)> MultiSurfaceControlNamesUC = {"SEQUENTIAL",
9210 : "GROUP"};
9211 :
9212 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
9213 : int IOStat; // IO Status when calling get input subroutine
9214 : int ControlNumAlpha; // Number of control alpha names being passed
9215 : int ControlNumProp; // Number of control properties being passed
9216 : int ControlNum; // DO loop counter/index for window shading control number
9217 : int IShadedConst; // Construction number of shaded construction
9218 : int IShadingDevice; // Material number of shading device
9219 : int NLayers; // Layers in shaded construction
9220 : int Loop;
9221 : bool BGShadeBlindError; // True if problem with construction that is supposed to have between-glass
9222 : // shade or blind
9223 : int Found;
9224 :
9225 226 : auto &s_mat = state.dataMaterial;
9226 226 : auto &s_ipsc = state.dataIPShortCut;
9227 : // Get the total number of window shading control blocks
9228 226 : s_ipsc->cCurrentModuleObject = "WindowShadingControl";
9229 226 : state.dataSurface->TotWinShadingControl = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
9230 226 : if (state.dataSurface->TotWinShadingControl == 0) return;
9231 :
9232 4 : state.dataSurface->WindowShadingControl.allocate(state.dataSurface->TotWinShadingControl);
9233 :
9234 4 : ControlNum = 0;
9235 8 : for (Loop = 1; Loop <= state.dataSurface->TotWinShadingControl; ++Loop) {
9236 :
9237 8 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
9238 4 : s_ipsc->cCurrentModuleObject,
9239 : Loop,
9240 4 : s_ipsc->cAlphaArgs,
9241 : ControlNumAlpha,
9242 4 : s_ipsc->rNumericArgs,
9243 : ControlNumProp,
9244 : IOStat,
9245 4 : s_ipsc->lNumericFieldBlanks,
9246 4 : s_ipsc->lAlphaFieldBlanks,
9247 4 : s_ipsc->cAlphaFieldNames,
9248 4 : s_ipsc->cNumericFieldNames);
9249 :
9250 4 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
9251 :
9252 4 : bool ErrorInName = false;
9253 4 : bool IsBlank = false;
9254 :
9255 4 : Util::VerifyName(state,
9256 4 : s_ipsc->cAlphaArgs(1),
9257 4 : state.dataSurface->WindowShadingControl,
9258 : ControlNum,
9259 : ErrorInName,
9260 : IsBlank,
9261 8 : s_ipsc->cCurrentModuleObject + " Name");
9262 4 : if (ErrorInName) {
9263 0 : ErrorsFound = true;
9264 0 : continue;
9265 : }
9266 :
9267 4 : ++ControlNum;
9268 :
9269 4 : auto &windowShadingControl = state.dataSurface->WindowShadingControl(ControlNum);
9270 :
9271 4 : windowShadingControl.Name = s_ipsc->cAlphaArgs(1); // Set the Control Name in the Derived Type
9272 :
9273 4 : windowShadingControl.ZoneIndex = Util::FindItemInList(s_ipsc->cAlphaArgs(2), state.dataHeatBal->Zone);
9274 4 : if (windowShadingControl.ZoneIndex == 0) {
9275 0 : ShowSevereError(state,
9276 0 : format("{}=\"{}\" invalid {}=\"{}\" not found.",
9277 0 : s_ipsc->cCurrentModuleObject,
9278 0 : s_ipsc->cAlphaArgs(1),
9279 0 : s_ipsc->cAlphaFieldNames(2),
9280 0 : s_ipsc->cAlphaArgs(2)));
9281 0 : ErrorsFound = true;
9282 : }
9283 :
9284 4 : windowShadingControl.SequenceNumber = int(s_ipsc->rNumericArgs(1));
9285 :
9286 : // For upward compatibility change old "noninsulating" and "insulating" shade types to
9287 : // INTERIORSHADE or EXTERIORSHADE
9288 4 : if (s_ipsc->cAlphaArgs(3) == "INTERIORNONINSULATINGSHADE" || s_ipsc->cAlphaArgs(3) == "INTERIORINSULATINGSHADE") {
9289 0 : ShowWarningError(state,
9290 0 : format("{}=\"{}\" is using obsolete {}=\"{}\", changing to \"InteriorShade\"",
9291 0 : s_ipsc->cCurrentModuleObject,
9292 0 : windowShadingControl.Name,
9293 0 : s_ipsc->cAlphaFieldNames(3),
9294 0 : s_ipsc->cAlphaArgs(3)));
9295 0 : windowShadingControl.ShadingType = DataSurfaces::WinShadingType::IntShade;
9296 0 : s_ipsc->cAlphaArgs(3) = "INTERIORSHADE";
9297 : }
9298 4 : if (s_ipsc->cAlphaArgs(3) == "EXTERIORNONINSULATINGSHADE" || s_ipsc->cAlphaArgs(3) == "EXTERIORINSULATINGSHADE") {
9299 0 : ShowWarningError(state,
9300 0 : format("{}=\"{}\" is using obsolete {}=\"{}\", changing to \"ExteriorShade\"",
9301 0 : s_ipsc->cCurrentModuleObject,
9302 0 : windowShadingControl.Name,
9303 0 : s_ipsc->cAlphaFieldNames(3),
9304 0 : s_ipsc->cAlphaArgs(3)));
9305 0 : windowShadingControl.ShadingType = DataSurfaces::WinShadingType::ExtShade;
9306 0 : s_ipsc->cAlphaArgs(3) = "EXTERIORSHADE";
9307 : }
9308 :
9309 : // Check for illegal shading type name
9310 4 : Found = Util::FindItemInList(s_ipsc->cAlphaArgs(3), cValidShadingTypes, NumValidShadingTypes);
9311 4 : if (Found <= 1) {
9312 0 : ErrorsFound = true;
9313 0 : ShowSevereError(state,
9314 0 : format("{}=\"{}\" invalid {}=\"{}\".",
9315 0 : s_ipsc->cCurrentModuleObject,
9316 0 : windowShadingControl.Name,
9317 0 : s_ipsc->cAlphaFieldNames(3),
9318 0 : s_ipsc->cAlphaArgs(3)));
9319 : } else {
9320 4 : windowShadingControl.ShadingType = DataSurfaces::WinShadingType(Found);
9321 : }
9322 :
9323 : // WindowShadingControl().getInputShadedConstruction is only used during GetInput process and is ultimately stored in
9324 : // Surface().shadedConstructionList
9325 4 : windowShadingControl.getInputShadedConstruction =
9326 4 : Util::FindItemInList(s_ipsc->cAlphaArgs(4), state.dataConstruction->Construct, state.dataHeatBal->TotConstructs);
9327 4 : windowShadingControl.ShadingDevice = Material::GetMaterialNum(state, s_ipsc->cAlphaArgs(9));
9328 :
9329 4 : if (s_ipsc->lAlphaFieldBlanks(6)) {
9330 3 : windowShadingControl.sched = Sched::GetScheduleAlwaysOn(state); // Not an availability schedule, but the default is constant-1.0
9331 1 : } else if ((windowShadingControl.sched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(6))) == nullptr) {
9332 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(6), s_ipsc->cAlphaArgs(6));
9333 0 : ErrorsFound = true;
9334 : }
9335 :
9336 4 : windowShadingControl.SetPoint = s_ipsc->rNumericArgs(2);
9337 4 : windowShadingControl.SetPoint2 = s_ipsc->rNumericArgs(3);
9338 4 : windowShadingControl.ShadingControlIsScheduled = getYesNoValue(s_ipsc->cAlphaArgs(7)) == BooleanSwitch::Yes;
9339 4 : windowShadingControl.GlareControlIsActive = getYesNoValue(s_ipsc->cAlphaArgs(8)) == BooleanSwitch::Yes;
9340 :
9341 4 : if (windowShadingControl.ShadingType != DataSurfaces::WinShadingType::IntBlind &&
9342 3 : windowShadingControl.ShadingType != DataSurfaces::WinShadingType::ExtBlind &&
9343 3 : windowShadingControl.ShadingType != DataSurfaces::WinShadingType::BGBlind) {
9344 1 : } else if (s_ipsc->cAlphaArgs(10).empty()) {
9345 0 : ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(10), s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3));
9346 0 : ErrorsFound = true;
9347 1 : } else if ((windowShadingControl.slatAngleControl = static_cast<DataSurfaces::SlatAngleControl>(
9348 1 : getEnumValue(SlatAngleNamesUC, s_ipsc->cAlphaArgs(10)))) == DataSurfaces::SlatAngleControl::Invalid) {
9349 0 : ShowSevereInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(10), s_ipsc->cAlphaArgs(10));
9350 0 : ErrorsFound = true;
9351 1 : } else if (windowShadingControl.slatAngleControl != DataSurfaces::SlatAngleControl::Scheduled) {
9352 0 : } else if (s_ipsc->lAlphaFieldBlanks(11)) {
9353 0 : ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(11), s_ipsc->cAlphaFieldNames(10), s_ipsc->cAlphaArgs(10));
9354 0 : ErrorsFound = true;
9355 0 : } else if ((windowShadingControl.slatAngleSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(11))) == nullptr) {
9356 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(11), s_ipsc->cAlphaArgs(11));
9357 0 : ErrorsFound = true;
9358 : }
9359 :
9360 : // store the string for now and associate it after daylighting control objects are read
9361 4 : windowShadingControl.DaylightingControlName = s_ipsc->cAlphaArgs(12);
9362 :
9363 4 : windowShadingControl.multiSurfaceControl =
9364 4 : static_cast<DataSurfaces::MultiSurfaceControl>(getEnumValue(MultiSurfaceControlNamesUC, s_ipsc->cAlphaArgs(13)));
9365 :
9366 4 : if (windowShadingControl.multiSurfaceControl == DataSurfaces::MultiSurfaceControl::Invalid) {
9367 0 : windowShadingControl.multiSurfaceControl = DataSurfaces::MultiSurfaceControl::Sequential;
9368 0 : ShowWarningError(state,
9369 0 : format("{}=\"{}\" should be either SEQUENTIAL or GROUP {}=\"{}\", defaulting to \"SEQUENTIAL\"",
9370 0 : s_ipsc->cCurrentModuleObject,
9371 0 : windowShadingControl.Name,
9372 0 : s_ipsc->cAlphaFieldNames(13),
9373 0 : s_ipsc->cAlphaArgs(13)));
9374 : }
9375 :
9376 4 : if (ControlNumAlpha >= 14) {
9377 4 : windowShadingControl.FenestrationCount = ControlNumAlpha - 13;
9378 4 : windowShadingControl.FenestrationName.allocate(windowShadingControl.FenestrationCount);
9379 4 : windowShadingControl.FenestrationIndex.allocate(windowShadingControl.FenestrationCount);
9380 15 : for (int i = 1; i <= windowShadingControl.FenestrationCount; i++) {
9381 11 : windowShadingControl.FenestrationName(i) = s_ipsc->cAlphaArgs(i + 13);
9382 : }
9383 : } else {
9384 0 : ShowSevereError(state,
9385 0 : format("{}=\"{}\" invalid. Must reference at least one Fenestration Surface object name.",
9386 0 : s_ipsc->cCurrentModuleObject,
9387 0 : s_ipsc->cAlphaArgs(1)));
9388 : }
9389 :
9390 4 : windowShadingControl.shadingControlType = static_cast<DataSurfaces::WindowShadingControlType>(
9391 4 : getEnumValue(WindowShadingControlTypeNamesUC, Util::makeUPPER(s_ipsc->cAlphaArgs(5))));
9392 :
9393 4 : if (windowShadingControl.ShadingDevice > 0) {
9394 0 : if (s_mat->materials(windowShadingControl.ShadingDevice)->group == Material::Group::Screen &&
9395 0 : !(windowShadingControl.shadingControlType == DataSurfaces::WindowShadingControlType::AlwaysOn ||
9396 0 : windowShadingControl.shadingControlType == DataSurfaces::WindowShadingControlType::AlwaysOff ||
9397 0 : windowShadingControl.shadingControlType == DataSurfaces::WindowShadingControlType::OnIfScheduled)) {
9398 0 : ErrorsFound = true;
9399 0 : ShowSevereError(state,
9400 0 : format("{}=\"{}\" invalid {}=\"{}\" for exterior screens.",
9401 0 : s_ipsc->cCurrentModuleObject,
9402 0 : windowShadingControl.Name,
9403 0 : s_ipsc->cAlphaFieldNames(5),
9404 0 : s_ipsc->cAlphaArgs(5)));
9405 0 : ShowContinueError(state,
9406 : "Valid shading control types for exterior window screens are ALWAYSON, ALWAYSOFF, or ONIFSCHEDULEALLOWS.");
9407 : }
9408 : } else {
9409 4 : if (windowShadingControl.getInputShadedConstruction > 0) {
9410 4 : state.dataConstruction->Construct(windowShadingControl.getInputShadedConstruction).IsUsed = true;
9411 4 : if (s_mat->materials(state.dataConstruction->Construct(windowShadingControl.getInputShadedConstruction).LayerPoint(1))->group ==
9412 4 : Material::Group::Screen &&
9413 0 : !(windowShadingControl.shadingControlType == DataSurfaces::WindowShadingControlType::AlwaysOn ||
9414 0 : windowShadingControl.shadingControlType == DataSurfaces::WindowShadingControlType::AlwaysOff ||
9415 0 : windowShadingControl.shadingControlType == DataSurfaces::WindowShadingControlType::OnIfScheduled)) {
9416 0 : ErrorsFound = true;
9417 0 : ShowSevereError(state,
9418 0 : format("{}=\"{}\" invalid {}=\"{}\" for exterior screens.",
9419 0 : s_ipsc->cCurrentModuleObject,
9420 0 : windowShadingControl.Name,
9421 0 : s_ipsc->cAlphaFieldNames(5),
9422 0 : s_ipsc->cAlphaArgs(5)));
9423 0 : ShowContinueError(state,
9424 : "Valid shading control types for exterior window screens are ALWAYSON, ALWAYSOFF, or ONIFSCHEDULEALLOWS.");
9425 : }
9426 0 : } else if (s_ipsc->lAlphaFieldBlanks(4)) {
9427 0 : ShowSevereError(
9428 : state,
9429 0 : format("{}=\"{}\", {} is blank.", s_ipsc->cCurrentModuleObject, windowShadingControl.Name, s_ipsc->cAlphaFieldNames(4)));
9430 0 : ShowContinueError(state, "A valid construction is required.");
9431 0 : ErrorsFound = true;
9432 : } else {
9433 0 : ShowSevereError(
9434 : state,
9435 0 : format("{}=\"{}\", {} is invalid.", s_ipsc->cCurrentModuleObject, windowShadingControl.Name, s_ipsc->cAlphaFieldNames(4)));
9436 0 : ShowContinueError(state, format("Construction=\"{}\" was used. A valid construction is required.", s_ipsc->cAlphaArgs(4)));
9437 0 : ErrorsFound = true;
9438 : }
9439 : }
9440 :
9441 : // Warning if setpoint is unintentionally zero
9442 4 : if (windowShadingControl.SetPoint == 0 && windowShadingControl.shadingControlType != DataSurfaces::WindowShadingControlType::AlwaysOn &&
9443 2 : windowShadingControl.shadingControlType != DataSurfaces::WindowShadingControlType::AlwaysOff &&
9444 2 : windowShadingControl.shadingControlType != DataSurfaces::WindowShadingControlType::OnIfScheduled &&
9445 1 : windowShadingControl.shadingControlType != DataSurfaces::WindowShadingControlType::HiGlare) {
9446 0 : ShowWarningError(state, format("{}=\"{}\", The first SetPoint is zero.", s_ipsc->cCurrentModuleObject, windowShadingControl.Name));
9447 0 : ShowContinueError(state, "..You may have forgotten to specify that setpoint.");
9448 : }
9449 :
9450 : // Error checks
9451 4 : if (BooleanSwitch bs = getYesNoValue(s_ipsc->cAlphaArgs(7)); bs == BooleanSwitch::Invalid) { // Shading Control is Schedule field
9452 0 : ShowSevereInvalidBool(state, eoh, s_ipsc->cAlphaFieldNames(7), s_ipsc->cAlphaArgs(7));
9453 0 : ErrorsFound = true;
9454 : }
9455 :
9456 4 : if (BooleanSwitch bs = getYesNoValue(s_ipsc->cAlphaArgs(8)); bs == BooleanSwitch::Invalid) { // Shading Control is Schedule field
9457 0 : ShowSevereInvalidBool(state, eoh, s_ipsc->cAlphaFieldNames(8), s_ipsc->cAlphaArgs(8));
9458 0 : ErrorsFound = true;
9459 : }
9460 :
9461 4 : if ((windowShadingControl.shadingControlType == DataSurfaces::WindowShadingControlType::OnIfScheduled) &&
9462 1 : (!windowShadingControl.ShadingControlIsScheduled)) { // CR 7709 BG
9463 0 : ErrorsFound = true;
9464 0 : ShowSevereError(state,
9465 0 : format("{} = \"{}\" invalid, {} must be set to \"Yes\" for {} = OnIfScheduleAllows",
9466 0 : s_ipsc->cCurrentModuleObject,
9467 0 : windowShadingControl.Name,
9468 0 : s_ipsc->cAlphaFieldNames(7),
9469 0 : s_ipsc->cAlphaFieldNames(5)));
9470 : }
9471 :
9472 4 : if (windowShadingControl.shadingControlType == DataSurfaces::WindowShadingControlType::MeetDaylIlumSetp &&
9473 0 : windowShadingControl.ShadingType != DataSurfaces::WinShadingType::SwitchableGlazing) {
9474 0 : ErrorsFound = true;
9475 0 : ShowSevereError(state,
9476 0 : format("{}=\"{}\" invalid {}=\"{}\".",
9477 0 : s_ipsc->cCurrentModuleObject,
9478 0 : windowShadingControl.Name,
9479 0 : s_ipsc->cAlphaFieldNames(3),
9480 0 : s_ipsc->cAlphaArgs(3)));
9481 0 : ShowContinueError(state,
9482 0 : format("...{} must be SwitchableGlazing for this control, but entered type=\"{}\".",
9483 0 : s_ipsc->cAlphaFieldNames(3),
9484 0 : s_ipsc->cAlphaArgs(3)));
9485 : }
9486 :
9487 4 : DataSurfaces::WinShadingType ShTyp = windowShadingControl.ShadingType;
9488 4 : IShadedConst = windowShadingControl.getInputShadedConstruction;
9489 4 : IShadingDevice = windowShadingControl.ShadingDevice;
9490 :
9491 4 : if (IShadedConst == 0 && IShadingDevice == 0) {
9492 0 : ShowSevereError(state,
9493 0 : format("{}=\"{}\" has no matching shaded construction or shading device.",
9494 0 : s_ipsc->cCurrentModuleObject,
9495 0 : windowShadingControl.Name));
9496 0 : ErrorsFound = true;
9497 4 : } else if (IShadedConst == 0 && IShadingDevice > 0) {
9498 0 : if (ShTyp == DataSurfaces::WinShadingType::SwitchableGlazing) {
9499 0 : ShowSevereError(state,
9500 0 : format("{}=\"{}\" has {}= SwitchableGlazing but no matching shaded construction",
9501 0 : s_ipsc->cCurrentModuleObject,
9502 0 : windowShadingControl.Name,
9503 0 : s_ipsc->cAlphaArgs(3)));
9504 0 : ErrorsFound = true;
9505 : }
9506 0 : if ((ShTyp == DataSurfaces::WinShadingType::IntShade || ShTyp == DataSurfaces::WinShadingType::ExtShade) &&
9507 0 : s_mat->materials(IShadingDevice)->group != Material::Group::Shade) {
9508 0 : ShowSevereError(state,
9509 0 : format("{}=\"{}\" has {}= InteriorShade or ExteriorShade but matching shading device is not a window shade",
9510 0 : s_ipsc->cCurrentModuleObject,
9511 0 : windowShadingControl.Name,
9512 0 : s_ipsc->cAlphaArgs(3)));
9513 0 : ShowContinueError(state, format("{} in error=\"{}\".", s_ipsc->cAlphaFieldNames(8), s_mat->materials(IShadingDevice)->Name));
9514 0 : ErrorsFound = true;
9515 : }
9516 0 : if ((ShTyp == DataSurfaces::WinShadingType::ExtScreen) && s_mat->materials(IShadingDevice)->group != Material::Group::Screen) {
9517 0 : ShowSevereError(state,
9518 0 : format("{}=\"{}\" has {}= ExteriorScreen but matching shading device is not a window screen",
9519 0 : s_ipsc->cCurrentModuleObject,
9520 0 : windowShadingControl.Name,
9521 0 : s_ipsc->cAlphaArgs(3)));
9522 0 : ShowContinueError(state, format("{} in error=\"{}\".", s_ipsc->cAlphaFieldNames(8), s_mat->materials(IShadingDevice)->Name));
9523 0 : ErrorsFound = true;
9524 : }
9525 0 : if ((ShTyp == DataSurfaces::WinShadingType::IntBlind || ShTyp == DataSurfaces::WinShadingType::ExtBlind) &&
9526 0 : s_mat->materials(IShadingDevice)->group != Material::Group::Blind) {
9527 0 : ShowSevereError(state,
9528 0 : format("{}=\"{}\" has {}= InteriorBlind or ExteriorBlind but matching shading device is not a window blind",
9529 0 : s_ipsc->cCurrentModuleObject,
9530 0 : windowShadingControl.Name,
9531 0 : s_ipsc->cAlphaArgs(3)));
9532 0 : ShowContinueError(state, format("{} in error=\"{}\".", s_ipsc->cAlphaFieldNames(8), s_mat->materials(IShadingDevice)->Name));
9533 0 : ErrorsFound = true;
9534 : }
9535 0 : if (ShTyp == DataSurfaces::WinShadingType::BGShade || ShTyp == DataSurfaces::WinShadingType::BGBlind) {
9536 0 : ShowSevereError(state,
9537 0 : format("{}=\"{}\" has {}= BetweenGlassShade or BetweenGlassBlind and",
9538 0 : s_ipsc->cCurrentModuleObject,
9539 0 : windowShadingControl.Name,
9540 0 : s_ipsc->cAlphaArgs(3)));
9541 0 : ShowContinueError(state,
9542 0 : format("{} is specified. This is illegal. Specify shaded construction instead.", s_ipsc->cAlphaFieldNames(8)));
9543 0 : ErrorsFound = true;
9544 : }
9545 4 : } else if (IShadedConst > 0 && IShadingDevice > 0) {
9546 0 : IShadingDevice = 0;
9547 0 : ShowWarningError(state,
9548 0 : format("{}=\"{}\" Both {} and {} are specified.",
9549 0 : s_ipsc->cCurrentModuleObject,
9550 0 : windowShadingControl.Name,
9551 0 : s_ipsc->cAlphaFieldNames(4),
9552 0 : s_ipsc->cAlphaFieldNames(9)));
9553 0 : ShowContinueError(
9554 0 : state, format("The {}=\"{}\" will be used.", s_ipsc->cAlphaFieldNames(4), state.dataConstruction->Construct(IShadedConst).Name));
9555 : }
9556 :
9557 : // If type = interior or exterior shade or blind require that the shaded construction
9558 : // have a shade layer in the correct position
9559 4 : if (IShadedConst != 0) {
9560 :
9561 4 : NLayers = state.dataConstruction->Construct(IShadedConst).TotLayers;
9562 4 : BGShadeBlindError = false;
9563 4 : IShadingDevice = 0;
9564 4 : if (state.dataConstruction->Construct(IShadedConst).LayerPoint(NLayers) != 0) {
9565 4 : if (windowShadingControl.ShadingType == DataSurfaces::WinShadingType::IntShade) {
9566 1 : IShadingDevice = state.dataConstruction->Construct(IShadedConst).LayerPoint(NLayers);
9567 1 : if (s_mat->materials(state.dataConstruction->Construct(IShadedConst).LayerPoint(NLayers))->group != Material::Group::Shade) {
9568 0 : ErrorsFound = true;
9569 0 : ShowSevereError(state,
9570 0 : format("{}=\"{}\" the {}=\"{}\"",
9571 0 : s_ipsc->cCurrentModuleObject,
9572 0 : windowShadingControl.Name,
9573 0 : s_ipsc->cAlphaFieldNames(4),
9574 0 : s_ipsc->cAlphaArgs(4)));
9575 0 : ShowContinueError(state,
9576 0 : format("of {}=\"{}\" should have a shade layer on the inside of the window.",
9577 0 : s_ipsc->cAlphaFieldNames(3),
9578 0 : s_ipsc->cAlphaArgs(3)));
9579 : }
9580 3 : } else if (windowShadingControl.ShadingType == DataSurfaces::WinShadingType::ExtShade) {
9581 0 : IShadingDevice = state.dataConstruction->Construct(IShadedConst).LayerPoint(1);
9582 0 : if (s_mat->materials(state.dataConstruction->Construct(IShadedConst).LayerPoint(1))->group != Material::Group::Shade) {
9583 0 : ErrorsFound = true;
9584 0 : ShowSevereError(state,
9585 0 : format("{}=\"{}\" the {}=\"{}\"",
9586 0 : s_ipsc->cCurrentModuleObject,
9587 0 : windowShadingControl.Name,
9588 0 : s_ipsc->cAlphaFieldNames(43),
9589 0 : s_ipsc->cAlphaArgs(4)));
9590 0 : ShowContinueError(state,
9591 0 : format("of {}=\"{}\" should have a shade layer on the outside of the window.",
9592 0 : s_ipsc->cAlphaFieldNames(3),
9593 0 : s_ipsc->cAlphaArgs(3)));
9594 : }
9595 3 : } else if (windowShadingControl.ShadingType == DataSurfaces::WinShadingType::ExtScreen) {
9596 0 : IShadingDevice = state.dataConstruction->Construct(IShadedConst).LayerPoint(1);
9597 0 : if (s_mat->materials(state.dataConstruction->Construct(IShadedConst).LayerPoint(1))->group != Material::Group::Screen) {
9598 0 : ErrorsFound = true;
9599 0 : ShowSevereError(state,
9600 0 : format("{}=\"{}\" the {}=\"{}\"",
9601 0 : s_ipsc->cCurrentModuleObject,
9602 0 : windowShadingControl.Name,
9603 0 : s_ipsc->cAlphaFieldNames(4),
9604 0 : s_ipsc->cAlphaArgs(4)));
9605 0 : ShowContinueError(state,
9606 0 : format("of {}=\"{}\" should have a screen layer on the outside of the window.",
9607 0 : s_ipsc->cAlphaFieldNames(3),
9608 0 : s_ipsc->cAlphaArgs(3)));
9609 : }
9610 3 : } else if (windowShadingControl.ShadingType == DataSurfaces::WinShadingType::IntBlind) {
9611 1 : IShadingDevice = state.dataConstruction->Construct(IShadedConst).LayerPoint(NLayers);
9612 1 : if (s_mat->materials(state.dataConstruction->Construct(IShadedConst).LayerPoint(NLayers))->group != Material::Group::Blind) {
9613 0 : ErrorsFound = true;
9614 0 : ShowSevereError(state,
9615 0 : format("{}=\"{}\" the {}=\"{}\"",
9616 0 : s_ipsc->cCurrentModuleObject,
9617 0 : windowShadingControl.Name,
9618 0 : s_ipsc->cAlphaFieldNames(4),
9619 0 : s_ipsc->cAlphaArgs(4)));
9620 0 : ShowContinueError(state,
9621 0 : format("of {}=\"{}\" should have a blind layer on the inside of the window.",
9622 0 : s_ipsc->cAlphaFieldNames(3),
9623 0 : s_ipsc->cAlphaArgs(3)));
9624 : }
9625 2 : } else if (windowShadingControl.ShadingType == DataSurfaces::WinShadingType::ExtBlind) {
9626 0 : IShadingDevice = state.dataConstruction->Construct(IShadedConst).LayerPoint(1);
9627 0 : if (s_mat->materials(state.dataConstruction->Construct(IShadedConst).LayerPoint(1))->group != Material::Group::Blind) {
9628 0 : ErrorsFound = true;
9629 0 : ShowSevereError(state,
9630 0 : format("{}=\"{}\" the {}=\"{}\"",
9631 0 : s_ipsc->cCurrentModuleObject,
9632 0 : windowShadingControl.Name,
9633 0 : s_ipsc->cAlphaFieldNames(4),
9634 0 : s_ipsc->cAlphaArgs(4)));
9635 0 : ShowContinueError(state,
9636 0 : format("of {}=\"{}\" should have a blind layer on the outside of the window.",
9637 0 : s_ipsc->cAlphaFieldNames(3),
9638 0 : s_ipsc->cAlphaArgs(3)));
9639 : }
9640 2 : } else if (windowShadingControl.ShadingType == DataSurfaces::WinShadingType::BGShade) {
9641 0 : if (NLayers != 5 && NLayers != 7) BGShadeBlindError = true;
9642 0 : if (NLayers == 5) {
9643 0 : if (s_mat->materials(state.dataConstruction->Construct(IShadedConst).LayerPoint(3))->group != Material::Group::Shade)
9644 0 : BGShadeBlindError = true;
9645 : }
9646 0 : if (NLayers == 7) {
9647 0 : if (s_mat->materials(state.dataConstruction->Construct(IShadedConst).LayerPoint(5))->group != Material::Group::Shade)
9648 0 : BGShadeBlindError = true;
9649 : }
9650 0 : if (BGShadeBlindError) {
9651 0 : ErrorsFound = true;
9652 0 : ShowSevereError(state,
9653 0 : format("{}=\"{}\" the {}=\"{}\"",
9654 0 : s_ipsc->cCurrentModuleObject,
9655 0 : windowShadingControl.Name,
9656 0 : s_ipsc->cAlphaFieldNames(4),
9657 0 : s_ipsc->cAlphaArgs(4)));
9658 0 : ShowContinueError(state,
9659 0 : format("of {}=\"{}\" should have two or three glass layers and a",
9660 0 : s_ipsc->cAlphaFieldNames(3),
9661 0 : s_ipsc->cAlphaArgs(3)));
9662 0 : ShowContinueError(state, "between-glass shade layer with a gas layer on each side.");
9663 : }
9664 2 : } else if (windowShadingControl.ShadingType == DataSurfaces::WinShadingType::BGBlind) {
9665 0 : if (NLayers != 5 && NLayers != 7) BGShadeBlindError = true;
9666 0 : if (NLayers == 5) {
9667 0 : if (s_mat->materials(state.dataConstruction->Construct(IShadedConst).LayerPoint(3))->group != Material::Group::Blind)
9668 0 : BGShadeBlindError = true;
9669 : }
9670 0 : if (NLayers == 7) {
9671 0 : if (s_mat->materials(state.dataConstruction->Construct(IShadedConst).LayerPoint(5))->group != Material::Group::Blind)
9672 0 : BGShadeBlindError = true;
9673 : }
9674 0 : if (BGShadeBlindError) {
9675 0 : ErrorsFound = true;
9676 0 : ShowSevereError(state,
9677 0 : format("{}=\"{}\" the {}=\"{}\"",
9678 0 : s_ipsc->cCurrentModuleObject,
9679 0 : windowShadingControl.Name,
9680 0 : s_ipsc->cAlphaFieldNames(4),
9681 0 : s_ipsc->cAlphaArgs(4)));
9682 0 : ShowContinueError(state,
9683 0 : format("of {}=\"{}\" should have two or three glass layers and a",
9684 0 : s_ipsc->cAlphaFieldNames(3),
9685 0 : s_ipsc->cAlphaArgs(3)));
9686 0 : ShowContinueError(state, "between-glass blind layer with a gas layer on each side.");
9687 : }
9688 : }
9689 : }
9690 4 : if (IShadingDevice > 0) {
9691 3 : if ((ShTyp == DataSurfaces::WinShadingType::IntShade || ShTyp == DataSurfaces::WinShadingType::ExtShade) &&
9692 1 : s_mat->materials(IShadingDevice)->group != Material::Group::Shade) {
9693 0 : ShowSevereError(state,
9694 0 : format("{}=\"{}\" has {}= InteriorShade or ExteriorShade but matching shading device is not a window shade",
9695 0 : s_ipsc->cCurrentModuleObject,
9696 0 : windowShadingControl.Name,
9697 0 : s_ipsc->cAlphaFieldNames(3)));
9698 0 : ShowContinueError(state, format("Shading Device in error=\"{}\".", s_mat->materials(IShadingDevice)->Name));
9699 0 : ErrorsFound = true;
9700 : }
9701 2 : if ((ShTyp == DataSurfaces::WinShadingType::ExtScreen) && s_mat->materials(IShadingDevice)->group != Material::Group::Screen) {
9702 0 : ShowSevereError(state,
9703 0 : format("{}=\"{}\" has {}= ExteriorScreen but matching shading device is not an exterior window screen.",
9704 0 : s_ipsc->cCurrentModuleObject,
9705 0 : windowShadingControl.Name,
9706 0 : s_ipsc->cAlphaFieldNames(3)));
9707 0 : ShowContinueError(state, format("Shading Device in error=\"{}\".", s_mat->materials(IShadingDevice)->Name));
9708 0 : ErrorsFound = true;
9709 : }
9710 3 : if ((ShTyp == DataSurfaces::WinShadingType::IntBlind || ShTyp == DataSurfaces::WinShadingType::ExtBlind) &&
9711 1 : s_mat->materials(IShadingDevice)->group != Material::Group::Blind) {
9712 0 : ShowSevereError(state,
9713 0 : format("{}=\"{}\" has {}= InteriorBlind or ExteriorBlind but matching shading device is not a window blind.",
9714 0 : s_ipsc->cCurrentModuleObject,
9715 0 : windowShadingControl.Name,
9716 0 : s_ipsc->cAlphaFieldNames(3)));
9717 0 : ShowContinueError(state, format("Shading Device in error=\"{}\".", s_mat->materials(IShadingDevice)->Name));
9718 0 : ErrorsFound = true;
9719 : }
9720 : }
9721 : }
9722 : } // End of loop over window shading controls
9723 : }
9724 :
9725 218 : void InitialAssociateWindowShadingControlFenestration(EnergyPlusData &state, bool &ErrorsFound, int SurfNum)
9726 : {
9727 218 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
9728 : // J.Glazer 2018 - operates on SurfaceTmp array before final indices are known for windows and sets the activeWindowShadingControl
9729 273 : for (int iShadeCtrl = 1; iShadeCtrl <= state.dataSurface->TotWinShadingControl; ++iShadeCtrl) {
9730 55 : int curShadedConstruction = state.dataSurface->WindowShadingControl(iShadeCtrl).getInputShadedConstruction;
9731 257 : for (int jFeneRef = 1; jFeneRef <= state.dataSurface->WindowShadingControl(iShadeCtrl).FenestrationCount; ++jFeneRef) {
9732 202 : if (Util::SameString(state.dataSurface->WindowShadingControl(iShadeCtrl).FenestrationName(jFeneRef), surfTemp.Name)) {
9733 29 : state.dataGlobal->AndShadingControlInModel = true;
9734 29 : surfTemp.HasShadeControl = true;
9735 29 : surfTemp.windowShadingControlList.push_back(iShadeCtrl);
9736 29 : surfTemp.activeWindowShadingControl = iShadeCtrl;
9737 29 : surfTemp.shadedConstructionList.push_back(curShadedConstruction);
9738 29 : surfTemp.activeShadedConstruction = curShadedConstruction;
9739 :
9740 : // check to make the window refenced is an exterior window
9741 29 : if (surfTemp.ExtBoundCond != DataSurfaces::ExternalEnvironment) {
9742 0 : ErrorsFound = true;
9743 0 : ShowSevereError(
9744 : state,
9745 0 : format("InitialAssociateWindowShadingControlFenestration: \"{}\", invalid because it is not an exterior window.",
9746 0 : surfTemp.Name));
9747 0 : ShowContinueError(
9748 : state,
9749 0 : format(".. It appears on WindowShadingControl object: \"{}", state.dataSurface->WindowShadingControl(iShadeCtrl).Name));
9750 : }
9751 : // check to make sure the window is not using equivalent layer window construction
9752 29 : if (state.dataConstruction->Construct(surfTemp.Construction).WindowTypeEQL) {
9753 0 : ErrorsFound = true;
9754 0 : ShowSevereError(state, format("InitialAssociateWindowShadingControlFenestration: =\"{}\", invalid \".", surfTemp.Name));
9755 0 : ShowContinueError(state, ".. equivalent layer window model does not use shading control object.");
9756 0 : ShowContinueError(state, ".. Shading control is set to none or zero, and simulation continues.");
9757 0 : ShowContinueError(
9758 : state,
9759 0 : format(".. It appears on WindowShadingControl object: \"{}", state.dataSurface->WindowShadingControl(iShadeCtrl).Name));
9760 0 : surfTemp.activeWindowShadingControl = 0;
9761 : }
9762 : }
9763 : }
9764 : }
9765 218 : }
9766 :
9767 225 : void FinalAssociateWindowShadingControlFenestration(EnergyPlusData &state, bool &ErrorsFound)
9768 : {
9769 : // J.Glazer 2018 - operates on Surface array after final indices are known for windows and checks to make sure it is correct
9770 232 : for (int iShadeCtrl = 1; iShadeCtrl <= state.dataSurface->TotWinShadingControl; ++iShadeCtrl) {
9771 27 : for (int jFeneRef = 1; jFeneRef <= state.dataSurface->WindowShadingControl(iShadeCtrl).FenestrationCount; ++jFeneRef) {
9772 20 : int fenestrationIndex = Util::FindItemInList(state.dataSurface->WindowShadingControl(iShadeCtrl).FenestrationName(jFeneRef),
9773 20 : state.dataSurface->Surface,
9774 20 : state.dataSurface->TotSurfaces);
9775 20 : if (std::find(state.dataSurface->Surface(fenestrationIndex).windowShadingControlList.begin(),
9776 20 : state.dataSurface->Surface(fenestrationIndex).windowShadingControlList.end(),
9777 40 : iShadeCtrl) != state.dataSurface->Surface(fenestrationIndex).windowShadingControlList.end()) {
9778 20 : state.dataSurface->WindowShadingControl(iShadeCtrl).FenestrationIndex(jFeneRef) = fenestrationIndex;
9779 : } else {
9780 : // this error condition should not occur since the rearrangement of Surface() from SurfureTmp() is reliable.
9781 0 : ErrorsFound = true;
9782 0 : ShowSevereError(state,
9783 0 : format("FinalAssociateWindowShadingControlFenestration: Fenestration surface named \"{}\" has "
9784 : "WindowShadingContol index that does not match the initial index assigned.",
9785 0 : state.dataSurface->Surface(fenestrationIndex).Name));
9786 0 : ShowContinueError(state,
9787 0 : format("This occurs while WindowShadingControl object: \"{}\" is being evaluated. ",
9788 0 : state.dataSurface->WindowShadingControl(iShadeCtrl).Name));
9789 : }
9790 : }
9791 : }
9792 225 : }
9793 :
9794 226 : void CheckWindowShadingControlSimilarForWindow(EnergyPlusData &state, bool &ErrorsFound)
9795 : {
9796 : // For each window check if all window shading controls on list are the same except for name, schedule name, construction, and
9797 : // material
9798 2490 : for (auto &theSurf : state.dataSurface->Surface) {
9799 2264 : if (theSurf.HasShadeControl) {
9800 13 : if (theSurf.windowShadingControlList.size() > 1) {
9801 2 : int firstWindowShadingControl = theSurf.windowShadingControlList.front();
9802 8 : for (auto wsc = std::next(theSurf.windowShadingControlList.begin()); wsc != theSurf.windowShadingControlList.end(); ++wsc) {
9803 4 : if (!isWindowShadingControlSimilar(state, firstWindowShadingControl, *wsc)) {
9804 1 : ErrorsFound = true;
9805 2 : ShowSevereError(state,
9806 2 : format("CheckWindowShadingControlSimilarForWindow: Fenestration surface named \"{}\" has multiple "
9807 : "WindowShadingContols that are not similar.",
9808 1 : theSurf.Name));
9809 2 : ShowContinueError(state,
9810 2 : format("for: \"{} and: {}",
9811 1 : state.dataSurface->WindowShadingControl(firstWindowShadingControl).Name,
9812 1 : state.dataSurface->WindowShadingControl(*wsc).Name));
9813 : }
9814 : }
9815 : }
9816 : }
9817 : }
9818 226 : }
9819 :
9820 24 : bool isWindowShadingControlSimilar(EnergyPlusData &state, int a, int b)
9821 : {
9822 : // Compares two window shading controls are the same except for the name, schedule name, construction, and material
9823 24 : auto const &WindowShadingControlA = state.dataSurface->WindowShadingControl(a);
9824 24 : auto const &WindowShadingControlB = state.dataSurface->WindowShadingControl(b);
9825 47 : return (WindowShadingControlA.ZoneIndex == WindowShadingControlB.ZoneIndex &&
9826 23 : WindowShadingControlA.ShadingType == WindowShadingControlB.ShadingType &&
9827 22 : WindowShadingControlA.shadingControlType == WindowShadingControlB.shadingControlType &&
9828 21 : WindowShadingControlA.SetPoint == WindowShadingControlB.SetPoint &&
9829 19 : WindowShadingControlA.ShadingControlIsScheduled == WindowShadingControlB.ShadingControlIsScheduled &&
9830 18 : WindowShadingControlA.GlareControlIsActive == WindowShadingControlB.GlareControlIsActive &&
9831 17 : WindowShadingControlA.slatAngleControl == WindowShadingControlB.slatAngleControl &&
9832 31 : WindowShadingControlA.SetPoint2 == WindowShadingControlB.SetPoint2 &&
9833 15 : WindowShadingControlA.DaylightingControlName == WindowShadingControlB.DaylightingControlName &&
9834 60 : WindowShadingControlA.DaylightControlIndex == WindowShadingControlB.DaylightControlIndex &&
9835 37 : WindowShadingControlA.multiSurfaceControl == WindowShadingControlB.multiSurfaceControl);
9836 : }
9837 :
9838 192 : void GetStormWindowData(EnergyPlusData &state, bool &ErrorsFound) // If errors found in input
9839 : {
9840 :
9841 : // SUBROUTINE INFORMATION:
9842 : // AUTHOR Fred Winkelmann
9843 : // DATE WRITTEN December 2003
9844 :
9845 : // PURPOSE OF THIS SUBROUTINE:
9846 : // Reads in the storm window data from the input file, interprets it and puts it in the derived type
9847 :
9848 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
9849 : int IOStat; // IO Status when calling get input subroutine
9850 : int StormWinNumAlpha; // Number of alpha names being passed
9851 : int StormWinNumProp; // Number of properties being passed
9852 : int loop; // Do loop counter
9853 :
9854 192 : auto &s_ipsc = state.dataIPShortCut;
9855 192 : auto &s_mat = state.dataMaterial;
9856 :
9857 : // Get the total number of storm window input objects
9858 192 : s_ipsc->cCurrentModuleObject = "WindowProperty:StormWindow";
9859 192 : state.dataSurface->TotStormWin = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
9860 192 : if (state.dataSurface->TotStormWin == 0) return;
9861 :
9862 0 : state.dataSurface->StormWindow.allocate(state.dataSurface->TotStormWin);
9863 :
9864 0 : int StormWinNum = 0;
9865 0 : for (loop = 1; loop <= state.dataSurface->TotStormWin; ++loop) {
9866 :
9867 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
9868 0 : s_ipsc->cCurrentModuleObject,
9869 : loop,
9870 0 : s_ipsc->cAlphaArgs,
9871 : StormWinNumAlpha,
9872 0 : s_ipsc->rNumericArgs,
9873 : StormWinNumProp,
9874 : IOStat,
9875 0 : s_ipsc->lNumericFieldBlanks,
9876 0 : s_ipsc->lAlphaFieldBlanks,
9877 0 : s_ipsc->cAlphaFieldNames,
9878 0 : s_ipsc->cNumericFieldNames);
9879 0 : ++StormWinNum;
9880 0 : state.dataSurface->StormWindow(StormWinNum).BaseWindowNum =
9881 0 : Util::FindItemInList(s_ipsc->cAlphaArgs(1), state.dataSurface->Surface, state.dataSurface->TotSurfaces);
9882 0 : state.dataSurface->StormWindow(StormWinNum).StormWinMaterialNum = Material::GetMaterialNum(state, s_ipsc->cAlphaArgs(2));
9883 0 : state.dataSurface->StormWindow(StormWinNum).StormWinDistance = s_ipsc->rNumericArgs(1);
9884 0 : state.dataSurface->StormWindow(StormWinNum).MonthOn = s_ipsc->rNumericArgs(2);
9885 0 : state.dataSurface->StormWindow(StormWinNum).DayOfMonthOn = s_ipsc->rNumericArgs(3);
9886 0 : state.dataSurface->StormWindow(StormWinNum).DateOn =
9887 0 : General::OrdinalDay(state.dataSurface->StormWindow(StormWinNum).MonthOn, state.dataSurface->StormWindow(StormWinNum).DayOfMonthOn, 1);
9888 0 : state.dataSurface->StormWindow(StormWinNum).MonthOff = s_ipsc->rNumericArgs(4);
9889 0 : state.dataSurface->StormWindow(StormWinNum).DayOfMonthOff = s_ipsc->rNumericArgs(5);
9890 0 : state.dataSurface->StormWindow(StormWinNum).DateOff = General::OrdinalDay(
9891 0 : state.dataSurface->StormWindow(StormWinNum).MonthOff, state.dataSurface->StormWindow(StormWinNum).DayOfMonthOff, 1);
9892 :
9893 0 : if (state.dataSurface->StormWindow(StormWinNum).DateOn == state.dataSurface->StormWindow(StormWinNum).DateOff) {
9894 0 : ShowSevereError(state,
9895 0 : format("{}: Date On = Date Off -- not allowed, occurred in WindowProperty:StormWindow Input #{}",
9896 0 : s_ipsc->cCurrentModuleObject,
9897 : StormWinNum));
9898 0 : ErrorsFound = true;
9899 : }
9900 :
9901 : enum Month
9902 : {
9903 : January = 1,
9904 : February,
9905 : March,
9906 : April,
9907 : May,
9908 : June,
9909 : July,
9910 : August,
9911 : September,
9912 : October,
9913 : November,
9914 : December
9915 : };
9916 0 : constexpr std::array<int, 13> oneBasedDaysInMonth = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
9917 :
9918 0 : int const monthOn = state.dataSurface->StormWindow(StormWinNum).MonthOn;
9919 0 : if (monthOn >= January && monthOn <= December) {
9920 0 : if (state.dataSurface->StormWindow(StormWinNum).DayOfMonthOn >
9921 0 : oneBasedDaysInMonth[state.dataSurface->StormWindow(StormWinNum).MonthOn]) {
9922 0 : ShowSevereError(state,
9923 0 : format("{}: Date On (Day of Month) [{}], invalid for WindowProperty:StormWindow Input #{}",
9924 0 : s_ipsc->cCurrentModuleObject,
9925 0 : state.dataSurface->StormWindow(StormWinNum).DayOfMonthOn,
9926 : StormWinNum));
9927 0 : ErrorsFound = true;
9928 : }
9929 0 : break;
9930 : } else {
9931 0 : ShowSevereError(state,
9932 0 : format("{}: Date On Month [{}], invalid for WindowProperty:StormWindow Input #{}",
9933 0 : s_ipsc->cCurrentModuleObject,
9934 0 : state.dataSurface->StormWindow(StormWinNum).MonthOn,
9935 : StormWinNum));
9936 0 : ErrorsFound = true;
9937 : }
9938 :
9939 0 : int const monthOff = state.dataSurface->StormWindow(StormWinNum).MonthOff;
9940 0 : if (monthOff >= January && monthOff <= December) {
9941 0 : if (state.dataSurface->StormWindow(StormWinNum).DayOfMonthOff >
9942 0 : oneBasedDaysInMonth[state.dataSurface->StormWindow(StormWinNum).MonthOff]) {
9943 0 : ShowSevereError(state,
9944 0 : format("{}: Date Off (Day of Month) [{}], invalid for WindowProperty:StormWindow Input #{}",
9945 0 : s_ipsc->cCurrentModuleObject,
9946 0 : state.dataSurface->StormWindow(StormWinNum).DayOfMonthOff,
9947 : StormWinNum));
9948 0 : ErrorsFound = true;
9949 : }
9950 0 : break;
9951 : } else {
9952 0 : ShowSevereError(state,
9953 0 : format("{}: Date Off Month [{}], invalid for WindowProperty:StormWindow Input #{}",
9954 0 : s_ipsc->cCurrentModuleObject,
9955 0 : state.dataSurface->StormWindow(StormWinNum).MonthOff,
9956 : StormWinNum));
9957 0 : ErrorsFound = true;
9958 : }
9959 : }
9960 :
9961 : // Error checks
9962 :
9963 0 : for (StormWinNum = 1; StormWinNum <= state.dataSurface->TotStormWin; ++StormWinNum) {
9964 : // Require BaseWindowNum be that of an exterior window
9965 0 : int SurfNum = state.dataSurface->StormWindow(StormWinNum).BaseWindowNum;
9966 0 : if (SurfNum == 0) {
9967 0 : ShowSevereError(state, format("{}=\"{}\" invalid.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
9968 0 : ErrorsFound = true;
9969 : } else {
9970 0 : auto const &surf = state.dataSurface->Surface(SurfNum);
9971 0 : if (surf.Class != SurfaceClass::Window || surf.ExtBoundCond != 0) {
9972 0 : ShowSevereError(state, format("{}=\"{}\"", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
9973 0 : ShowSevereError(state, format("cannot be used with surface={}", surf.Name));
9974 0 : ShowContinueError(state, "because that surface is not an exterior window.");
9975 0 : ErrorsFound = true;
9976 : }
9977 : }
9978 :
9979 : // Require that storm window material be glass
9980 0 : int MatNum = state.dataSurface->StormWindow(StormWinNum).StormWinMaterialNum;
9981 0 : if (SurfNum > 0) {
9982 0 : if (MatNum == 0) {
9983 0 : ShowSevereError(state, format("{}=\"{}\"", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
9984 0 : ShowContinueError(state,
9985 0 : format("{}=\"{}\" not found as storm window layer.", s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2)));
9986 0 : ErrorsFound = true;
9987 : } else {
9988 0 : if (s_mat->materials(MatNum)->group != Material::Group::Glass) {
9989 0 : ShowSevereError(state, format("{}=\"{}\"", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
9990 0 : ShowContinueError(state,
9991 0 : format("{}=\"{}must be a WindowMaterial:Glazing or WindowMaterial:Glazing:RefractionExtinctionMethod",
9992 0 : s_ipsc->cAlphaFieldNames(2),
9993 0 : s_ipsc->cAlphaArgs(2)));
9994 0 : ErrorsFound = true;
9995 : }
9996 : }
9997 : // Error if base window has airflow control
9998 0 : if (state.dataSurface->SurfWinAirflowControlType(SurfNum) != DataSurfaces::WindowAirFlowControlType::Invalid) {
9999 0 : ShowSevereError(
10000 : state,
10001 0 : format("{}=\"{} cannot be used because it is an airflow window (i.e., has WindowProperty:AirflowControl specified)",
10002 0 : s_ipsc->cCurrentModuleObject,
10003 0 : s_ipsc->cAlphaArgs(1)));
10004 0 : ErrorsFound = true;
10005 : }
10006 : }
10007 :
10008 : // Check for reversal of on and off times
10009 0 : if (SurfNum > 0) {
10010 0 : if ((state.dataEnvrn->Latitude > 0.0 &&
10011 0 : (state.dataSurface->StormWindow(StormWinNum).MonthOn < state.dataSurface->StormWindow(StormWinNum).MonthOff)) ||
10012 0 : (state.dataEnvrn->Latitude <= 0.0 &&
10013 0 : (state.dataSurface->StormWindow(StormWinNum).MonthOn > state.dataSurface->StormWindow(StormWinNum).MonthOff))) {
10014 0 : ShowWarningError(state, format("{}=\"{}\" check times that storm window", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
10015 0 : ShowContinueError(state,
10016 0 : format("is put on (month={}, day={}) and taken off (month={}, day={});",
10017 0 : state.dataSurface->StormWindow(StormWinNum).MonthOn,
10018 0 : state.dataSurface->StormWindow(StormWinNum).DayOfMonthOn,
10019 0 : state.dataSurface->StormWindow(StormWinNum).MonthOff,
10020 0 : state.dataSurface->StormWindow(StormWinNum).DayOfMonthOff));
10021 0 : ShowContinueError(state, format("these times may be reversed for your building latitude={:.2R} deg.", state.dataEnvrn->Latitude));
10022 : }
10023 : }
10024 : }
10025 : }
10026 :
10027 192 : void GetWindowGapAirflowControlData(EnergyPlusData &state, bool &ErrorsFound) // If errors found in input
10028 : {
10029 :
10030 : // SUBROUTINE INFORMATION:
10031 : // AUTHOR Fred Winkelmann
10032 : // DATE WRITTEN Feb 2003
10033 : // MODIFIED June 2003, FCW: add destination = return air;
10034 : // more error messages
10035 :
10036 : // PURPOSE OF THIS SUBROUTINE:
10037 : // Reads in the window airflow control information from the input data file,
10038 : // interprets it and puts it in the SurfaceWindow derived type
10039 :
10040 : static constexpr std::string_view routineName = "GetWindowGapAirflowControlData";
10041 :
10042 : int IOStat; // IO Status when calling get input subroutine
10043 : int ControlNumAlpha; // Number of control alpha names being passed
10044 : int ControlNumProp; // Number of control properties being passed
10045 : int TotWinAirflowControl; // Total window airflow control statements
10046 : int Loop;
10047 192 : int ConstrNum(0); // Construction number
10048 : int ConstrNumSh; // Shaded Construction number
10049 : int MatGapFlow; // Material number of gas in airflow gap of window's construction
10050 : int MatGapFlow1; // Material number of gas on either side of a between-glass shade/blind
10051 : int MatGapFlow2;
10052 :
10053 192 : constexpr std::array<std::string_view, static_cast<int>(DataSurfaces::WindowAirFlowSource::Num)> WindowAirFlowSourceNamesUC{"INDOORAIR",
10054 : "OUTDOORAIR"};
10055 192 : constexpr std::array<std::string_view, static_cast<int>(DataSurfaces::WindowAirFlowDestination::Num)> WindowAirFlowDestinationNamesUC{
10056 : "INDOORAIR", "OUTDOORAIR", "RETURNAIR"};
10057 :
10058 : // of the shaded construction of airflow window
10059 192 : auto &s_ipsc = state.dataIPShortCut;
10060 192 : auto &s_mat = state.dataMaterial;
10061 :
10062 : // Get the total number of window airflow control statements
10063 192 : s_ipsc->cCurrentModuleObject = "WindowProperty:AirflowControl";
10064 192 : TotWinAirflowControl = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
10065 192 : if (TotWinAirflowControl == 0) return;
10066 :
10067 0 : for (Loop = 1; Loop <= TotWinAirflowControl; ++Loop) { // Loop through all surfaces in the input...
10068 :
10069 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
10070 0 : s_ipsc->cCurrentModuleObject,
10071 : Loop,
10072 0 : s_ipsc->cAlphaArgs,
10073 : ControlNumAlpha,
10074 0 : s_ipsc->rNumericArgs,
10075 : ControlNumProp,
10076 : IOStat,
10077 0 : s_ipsc->lNumericFieldBlanks,
10078 0 : s_ipsc->lAlphaFieldBlanks,
10079 0 : s_ipsc->cAlphaFieldNames,
10080 0 : s_ipsc->cNumericFieldNames);
10081 :
10082 0 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
10083 :
10084 0 : int SurfNum = Util::FindItemInList(s_ipsc->cAlphaArgs(1), state.dataSurface->Surface, state.dataSurface->TotSurfaces);
10085 0 : if (SurfNum == 0) {
10086 0 : ShowSevereError(state, format("{}=\"{}\" not found.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
10087 0 : ErrorsFound = true;
10088 : }
10089 : // Check that associated surface is a 2- or 3-pane exterior window
10090 0 : if (SurfNum != 0) {
10091 0 : bool WrongSurfaceType = false;
10092 0 : auto const &surf = state.dataSurface->Surface(SurfNum);
10093 0 : if (surf.Class != SurfaceClass::Window) WrongSurfaceType = true;
10094 0 : if (surf.Class == SurfaceClass::Window) {
10095 0 : ConstrNum = surf.Construction;
10096 0 : if (state.dataConstruction->Construct(ConstrNum).TotGlassLayers != 2 &&
10097 0 : state.dataConstruction->Construct(ConstrNum).TotGlassLayers != 3)
10098 0 : WrongSurfaceType = true;
10099 0 : if (surf.ExtBoundCond != DataSurfaces::ExternalEnvironment) WrongSurfaceType = true;
10100 : }
10101 0 : if (WrongSurfaceType) {
10102 0 : ShowSevereError(
10103 : state,
10104 0 : format("{}=\"{}\" is not an exterior window with 2 or 3 glass layers.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
10105 0 : ErrorsFound = true;
10106 : }
10107 : }
10108 :
10109 : // Error if illegal airflow source
10110 0 : if (s_ipsc->cAlphaArgs(2) != "INDOORAIR" && s_ipsc->cAlphaArgs(2) != "OUTDOORAIR") {
10111 0 : ErrorsFound = true;
10112 0 : ShowSevereError(state,
10113 0 : format("{}=\"{}\" invalid {}=\"{}\"",
10114 0 : s_ipsc->cCurrentModuleObject,
10115 0 : s_ipsc->cAlphaArgs(1),
10116 0 : s_ipsc->cAlphaFieldNames(2),
10117 0 : s_ipsc->cAlphaArgs(2)));
10118 : }
10119 :
10120 : // Error if illegal airflow destination
10121 0 : if (s_ipsc->cAlphaArgs(3) != "INDOORAIR" && s_ipsc->cAlphaArgs(3) != "OUTDOORAIR" && s_ipsc->cAlphaArgs(3) != "RETURNAIR") {
10122 0 : ErrorsFound = true;
10123 0 : ShowSevereError(state,
10124 0 : format("{}=\"{}\" invalid {}=\"{}\"",
10125 0 : s_ipsc->cCurrentModuleObject,
10126 0 : s_ipsc->cAlphaArgs(1),
10127 0 : s_ipsc->cAlphaFieldNames(3),
10128 0 : s_ipsc->cAlphaArgs(3)));
10129 : }
10130 :
10131 : // Error if source = OutsideAir and destination = ReturnAir
10132 0 : if (s_ipsc->cAlphaArgs(2) == "OUTDOORAIR" && s_ipsc->cAlphaArgs(3) == "RETURNAIR") {
10133 0 : ErrorsFound = true;
10134 0 : ShowSevereError(state,
10135 0 : format("{}=\"{}\" invalid {}=\"{}\"",
10136 0 : s_ipsc->cCurrentModuleObject,
10137 0 : s_ipsc->cAlphaArgs(1),
10138 0 : s_ipsc->cAlphaFieldNames(2),
10139 0 : s_ipsc->cAlphaArgs(2)));
10140 0 : ShowContinueError(state, format("..when {}=\"{}\"", s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3)));
10141 : }
10142 :
10143 : // Error if illegal airflow control type
10144 0 : if (s_ipsc->cAlphaArgs(4) != "ALWAYSONATMAXIMUMFLOW" && s_ipsc->cAlphaArgs(4) != "ALWAYSOFF" &&
10145 0 : s_ipsc->cAlphaArgs(4) != "SCHEDULEDONLY") {
10146 0 : ErrorsFound = true;
10147 0 : ShowSevereError(state,
10148 0 : format("{}=\"{}\" invalid {}=\"{}\"",
10149 0 : s_ipsc->cCurrentModuleObject,
10150 0 : s_ipsc->cAlphaArgs(1),
10151 0 : s_ipsc->cAlphaFieldNames(4),
10152 0 : s_ipsc->cAlphaArgs(4)));
10153 : }
10154 :
10155 : // Error if illegal value for Airflow Has Multiplier Schedule
10156 0 : if (s_ipsc->cAlphaArgs(5) != "YES" && s_ipsc->cAlphaArgs(5) != "NO") {
10157 0 : ErrorsFound = true;
10158 0 : ShowSevereError(state,
10159 0 : format("{}=\"{}\" invalid {}=\"{}\"",
10160 0 : s_ipsc->cCurrentModuleObject,
10161 0 : s_ipsc->cAlphaArgs(1),
10162 0 : s_ipsc->cAlphaFieldNames(5),
10163 0 : s_ipsc->cAlphaArgs(5)));
10164 : }
10165 :
10166 : // Error if Airflow Control Type = ScheduledOnly and Airflow Has Multiplier Schedule = No
10167 0 : if (s_ipsc->cAlphaArgs(4) == "SCHEDULEDONLY" && s_ipsc->cAlphaArgs(5) == "NO") {
10168 0 : ErrorsFound = true;
10169 0 : ShowSevereError(state,
10170 0 : format("{}=\"{}\" invalid {}=\"{}\"",
10171 0 : s_ipsc->cCurrentModuleObject,
10172 0 : s_ipsc->cAlphaArgs(1),
10173 0 : s_ipsc->cAlphaFieldNames(4),
10174 0 : s_ipsc->cAlphaArgs(4)));
10175 0 : ShowContinueError(state, format("..when {}=\"{}\"", s_ipsc->cAlphaFieldNames(5), s_ipsc->cAlphaArgs(5)));
10176 : }
10177 :
10178 : // Warning if Airflow Control Type = AlwaysOnAtMaxFlow and Airflow Has Multiplier Schedule = Yes
10179 0 : if (s_ipsc->cAlphaArgs(4) == "ALWAYSONATMAXIMUMFLOW" && s_ipsc->cAlphaArgs(5) == "YES") {
10180 0 : ShowWarningError(state,
10181 0 : format("{}=\"{}has {}=\"{}\"",
10182 0 : s_ipsc->cCurrentModuleObject,
10183 0 : s_ipsc->cAlphaArgs(1),
10184 0 : s_ipsc->cAlphaFieldNames(4),
10185 0 : s_ipsc->cAlphaArgs(4)));
10186 0 : ShowContinueError(state,
10187 0 : format("..but {}=\"{}If specified, the {} will be ignored.",
10188 0 : s_ipsc->cAlphaFieldNames(5),
10189 0 : s_ipsc->cAlphaArgs(5),
10190 0 : s_ipsc->cAlphaFieldNames(5)));
10191 : }
10192 :
10193 : // Warning if Airflow Control Type = AlwaysOff and Airflow Has Multiplier Schedule = Yes
10194 0 : if (s_ipsc->cAlphaArgs(4) == "ALWAYSOFF" && s_ipsc->cAlphaArgs(5) == "YES") {
10195 0 : ShowWarningError(state,
10196 0 : format("{}=\"{}has {}=\"{}\"",
10197 0 : s_ipsc->cCurrentModuleObject,
10198 0 : s_ipsc->cAlphaArgs(1),
10199 0 : s_ipsc->cAlphaFieldNames(4),
10200 0 : s_ipsc->cAlphaArgs(4)));
10201 0 : ShowContinueError(state,
10202 0 : format("..but {}=\"{}\". If specified, the {} will be ignored.",
10203 0 : s_ipsc->cAlphaFieldNames(5),
10204 0 : s_ipsc->cAlphaArgs(5),
10205 0 : s_ipsc->cAlphaFieldNames(5)));
10206 : }
10207 :
10208 0 : if (SurfNum > 0) {
10209 0 : auto const &surf = state.dataSurface->Surface(SurfNum);
10210 0 : state.dataSurface->AirflowWindows = true;
10211 0 : state.dataSurface->SurfWinAirflowSource(SurfNum) =
10212 0 : static_cast<DataSurfaces::WindowAirFlowSource>(getEnumValue(WindowAirFlowSourceNamesUC, s_ipsc->cAlphaArgs(2)));
10213 :
10214 0 : state.dataSurface->SurfWinAirflowDestination(SurfNum) =
10215 0 : static_cast<DataSurfaces::WindowAirFlowDestination>(getEnumValue(WindowAirFlowDestinationNamesUC, s_ipsc->cAlphaArgs(3)));
10216 :
10217 0 : if (state.dataSurface->SurfWinAirflowDestination(SurfNum) == DataSurfaces::WindowAirFlowDestination::Return) {
10218 0 : int controlledZoneNum = DataZoneEquipment::GetControlledZoneIndex(state, surf.ZoneName);
10219 0 : if (controlledZoneNum > 0) {
10220 0 : state.dataHeatBal->Zone(surf.Zone).HasAirFlowWindowReturn = true;
10221 : }
10222 :
10223 : // Set return air node number
10224 0 : state.dataSurface->SurfWinAirflowReturnNodePtr(SurfNum) = 0;
10225 0 : std::string retNodeName = "";
10226 0 : if (!s_ipsc->lAlphaFieldBlanks(7)) {
10227 0 : retNodeName = s_ipsc->cAlphaArgs(7);
10228 : }
10229 0 : std::string callDescription = s_ipsc->cCurrentModuleObject + "=" + surf.Name;
10230 0 : state.dataSurface->SurfWinAirflowReturnNodePtr(SurfNum) =
10231 0 : DataZoneEquipment::GetReturnAirNodeForZone(state, surf.Zone, retNodeName, callDescription);
10232 0 : if (state.dataSurface->SurfWinAirflowReturnNodePtr(SurfNum) == 0) {
10233 0 : ShowSevereError(state,
10234 0 : format("{}{}=\"{}\", airflow window return air node not found for {} = {}",
10235 : routineName,
10236 0 : s_ipsc->cCurrentModuleObject,
10237 0 : surf.Name,
10238 0 : s_ipsc->cAlphaFieldNames(3),
10239 0 : s_ipsc->cAlphaArgs(3)));
10240 0 : if (!s_ipsc->lAlphaFieldBlanks(7))
10241 0 : ShowContinueError(
10242 : state,
10243 0 : format("{}=\"{}\" did not find a matching return air node.", s_ipsc->cAlphaFieldNames(7), s_ipsc->cAlphaArgs(7)));
10244 0 : ShowContinueError(state,
10245 : "..Airflow windows with Airflow Destination = ReturnAir must reference a controlled Zone (appear in a "
10246 : "ZoneHVAC:EquipmentConnections object) with at least one return air node.");
10247 0 : ErrorsFound = true;
10248 : }
10249 0 : }
10250 0 : if (Util::SameString(s_ipsc->cAlphaArgs(4), "AlwaysOnAtMaximumFlow")) {
10251 0 : state.dataSurface->SurfWinAirflowControlType(SurfNum) = DataSurfaces::WindowAirFlowControlType::MaxFlow;
10252 0 : } else if (Util::SameString(s_ipsc->cAlphaArgs(4), "AlwaysOff")) {
10253 0 : state.dataSurface->SurfWinAirflowControlType(SurfNum) = DataSurfaces::WindowAirFlowControlType::AlwaysOff;
10254 0 : } else if (Util::SameString(s_ipsc->cAlphaArgs(4), "ScheduledOnly")) {
10255 0 : state.dataSurface->SurfWinAirflowControlType(SurfNum) = DataSurfaces::WindowAirFlowControlType::Schedule;
10256 : }
10257 0 : state.dataSurface->SurfWinMaxAirflow(SurfNum) = s_ipsc->rNumericArgs(1);
10258 0 : if (s_ipsc->cAlphaArgs(4) == "SCHEDULEDONLY" && s_ipsc->cAlphaArgs(5) == "YES") {
10259 0 : if (s_ipsc->lAlphaFieldBlanks(6)) {
10260 0 : ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(6), s_ipsc->cAlphaFieldNames(4), s_ipsc->cAlphaArgs(4));
10261 0 : ErrorsFound = true;
10262 0 : } else if ((state.dataSurface->SurfWinAirflowScheds(SurfNum) = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(6))) == nullptr) {
10263 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(6), s_ipsc->cAlphaArgs(6));
10264 0 : ErrorsFound = true;
10265 0 : ShowSevereError(state,
10266 0 : format("{}=\"{}\", has {}=\"{}\"",
10267 0 : s_ipsc->cCurrentModuleObject,
10268 0 : s_ipsc->cAlphaArgs(1),
10269 0 : s_ipsc->cAlphaFieldNames(4),
10270 0 : s_ipsc->cAlphaArgs(4)));
10271 0 : ShowContinueError(state,
10272 0 : format("..and {}=\"{}\", but no {} specified.",
10273 0 : s_ipsc->cAlphaFieldNames(5),
10274 0 : s_ipsc->cAlphaArgs(5),
10275 0 : s_ipsc->cAlphaFieldNames(6)));
10276 : } else {
10277 0 : state.dataSurface->SurfWinAirflowHasSchedule(SurfNum) = true;
10278 0 : if ((state.dataSurface->SurfWinAirflowScheds(SurfNum) = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(6))) == nullptr) {
10279 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(6), s_ipsc->cAlphaArgs(6));
10280 0 : ErrorsFound = true;
10281 : }
10282 : }
10283 : }
10284 : // Warning if associated window is an interior window
10285 0 : if (surf.ExtBoundCond != DataSurfaces::ExternalEnvironment && !ErrorsFound)
10286 0 : ShowWarningError(state,
10287 0 : format("{}=\"{}\", is an Interior window; cannot be an airflow window.",
10288 0 : s_ipsc->cCurrentModuleObject,
10289 0 : s_ipsc->cAlphaArgs(1)));
10290 0 : if (!ErrorsFound) {
10291 : // Require that gas in airflow gap has type = air
10292 0 : MatGapFlow = state.dataConstruction->Construct(ConstrNum).LayerPoint(2);
10293 0 : if (state.dataConstruction->Construct(ConstrNum).TotGlassLayers == 3)
10294 0 : MatGapFlow = state.dataConstruction->Construct(ConstrNum).LayerPoint(4);
10295 0 : if (dynamic_cast<Material::MaterialGasMix const *>(s_mat->materials(MatGapFlow))->gases[0].type != Material::GasType::Air) {
10296 0 : ErrorsFound = true;
10297 0 : ShowSevereError(state,
10298 0 : format("{}=\"{}\", Gas type not air in airflow gap of construction {}",
10299 0 : s_ipsc->cCurrentModuleObject,
10300 0 : s_ipsc->cAlphaArgs(1),
10301 0 : state.dataConstruction->Construct(ConstrNum).Name));
10302 : }
10303 : // Require that gas be air in airflow gaps on either side of a between glass shade/blind
10304 0 : if (surf.HasShadeControl) {
10305 0 : for (std::size_t listIndex = 0; listIndex < surf.windowShadingControlList.size(); ++listIndex) {
10306 0 : int WSCPtr = surf.windowShadingControlList[listIndex];
10307 0 : if (ANY_BETWEENGLASS_SHADE_BLIND(state.dataSurface->WindowShadingControl(WSCPtr).ShadingType)) {
10308 0 : ConstrNumSh = surf.shadedConstructionList[listIndex];
10309 0 : if (state.dataConstruction->Construct(ConstrNum).TotGlassLayers == 2) {
10310 0 : MatGapFlow1 = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(2);
10311 0 : MatGapFlow2 = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(4);
10312 : } else {
10313 0 : MatGapFlow1 = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(4);
10314 0 : MatGapFlow2 = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(6);
10315 : }
10316 0 : if (dynamic_cast<Material::MaterialGasMix const *>(s_mat->materials(MatGapFlow1))->gases[0].type !=
10317 0 : Material::GasType::Air ||
10318 0 : dynamic_cast<Material::MaterialGasMix const *>(s_mat->materials(MatGapFlow2))->gases[0].type !=
10319 : Material::GasType::Air) {
10320 0 : ErrorsFound = true;
10321 0 : ShowSevereError(state,
10322 0 : format("{}=\"{}\", gas type must be air on either side of the shade/blind",
10323 0 : s_ipsc->cCurrentModuleObject,
10324 0 : s_ipsc->cAlphaArgs(1)));
10325 : }
10326 0 : break; // only need the first window shading control since they should be the same
10327 : }
10328 : }
10329 : }
10330 : }
10331 : }
10332 :
10333 : } // End of loop over window airflow controls
10334 : }
10335 :
10336 234 : void GetFoundationData(EnergyPlusData &state, bool &ErrorsFound)
10337 : {
10338 :
10339 : int NumAlphas;
10340 : int NumProps;
10341 : int IOStat;
10342 :
10343 : static constexpr std::string_view routineName = "GetFoundationData";
10344 :
10345 234 : auto &s_ipsc = state.dataIPShortCut;
10346 :
10347 : // Read Kiva Settings
10348 234 : s_ipsc->cCurrentModuleObject = "Foundation:Kiva:Settings";
10349 234 : int TotKivaStgs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
10350 :
10351 234 : if (TotKivaStgs > 1) {
10352 0 : ErrorsFound = true;
10353 0 : ShowSevereError(state, format("Multiple {} objects found. Only one is allowed.", s_ipsc->cCurrentModuleObject));
10354 : }
10355 :
10356 234 : if (TotKivaStgs == 1) {
10357 4 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
10358 2 : s_ipsc->cCurrentModuleObject,
10359 : 1,
10360 2 : s_ipsc->cAlphaArgs,
10361 : NumAlphas,
10362 2 : s_ipsc->rNumericArgs,
10363 : NumProps,
10364 : IOStat,
10365 2 : s_ipsc->lNumericFieldBlanks,
10366 2 : s_ipsc->lAlphaFieldBlanks,
10367 2 : s_ipsc->cAlphaFieldNames,
10368 2 : s_ipsc->cNumericFieldNames);
10369 :
10370 2 : int numF = 1;
10371 2 : int alpF = 1;
10372 :
10373 2 : if (!s_ipsc->lNumericFieldBlanks(numF)) {
10374 2 : state.dataSurfaceGeometry->kivaManager.settings.soilK = s_ipsc->rNumericArgs(numF);
10375 : }
10376 2 : numF++;
10377 2 : if (!s_ipsc->lNumericFieldBlanks(numF)) {
10378 2 : state.dataSurfaceGeometry->kivaManager.settings.soilRho = s_ipsc->rNumericArgs(numF);
10379 : }
10380 2 : numF++;
10381 2 : if (!s_ipsc->lNumericFieldBlanks(numF)) {
10382 2 : state.dataSurfaceGeometry->kivaManager.settings.soilCp = s_ipsc->rNumericArgs(numF);
10383 : }
10384 2 : numF++;
10385 2 : if (!s_ipsc->lNumericFieldBlanks(numF)) {
10386 2 : state.dataSurfaceGeometry->kivaManager.settings.groundSolarAbs = s_ipsc->rNumericArgs(numF);
10387 : }
10388 2 : numF++;
10389 2 : if (!s_ipsc->lNumericFieldBlanks(numF)) {
10390 2 : state.dataSurfaceGeometry->kivaManager.settings.groundThermalAbs = s_ipsc->rNumericArgs(numF);
10391 : }
10392 2 : numF++;
10393 2 : if (!s_ipsc->lNumericFieldBlanks(numF)) {
10394 2 : state.dataSurfaceGeometry->kivaManager.settings.groundRoughness = s_ipsc->rNumericArgs(numF);
10395 : }
10396 2 : numF++;
10397 2 : if (!s_ipsc->lNumericFieldBlanks(numF)) {
10398 2 : state.dataSurfaceGeometry->kivaManager.settings.farFieldWidth = s_ipsc->rNumericArgs(numF);
10399 : }
10400 2 : numF++;
10401 :
10402 2 : if (!s_ipsc->lAlphaFieldBlanks(alpF)) {
10403 2 : if (Util::SameString(s_ipsc->cAlphaArgs(alpF), "ZeroFlux")) {
10404 1 : state.dataSurfaceGeometry->kivaManager.settings.deepGroundBoundary = HeatBalanceKivaManager::KivaManager::Settings::ZERO_FLUX;
10405 1 : } else if (Util::SameString(s_ipsc->cAlphaArgs(alpF), "GroundWater")) {
10406 0 : state.dataSurfaceGeometry->kivaManager.settings.deepGroundBoundary = HeatBalanceKivaManager::KivaManager::Settings::GROUNDWATER;
10407 1 : } else if (Util::SameString(s_ipsc->cAlphaArgs(alpF), "Autoselect")) {
10408 1 : state.dataSurfaceGeometry->kivaManager.settings.deepGroundBoundary = HeatBalanceKivaManager::KivaManager::Settings::AUTO;
10409 : } else {
10410 0 : ErrorsFound = true;
10411 0 : ShowSevereError(state,
10412 0 : format("{}, {} is not a valid choice for {}",
10413 0 : s_ipsc->cCurrentModuleObject,
10414 0 : s_ipsc->cAlphaArgs(alpF),
10415 0 : s_ipsc->cAlphaFieldNames(alpF)));
10416 : }
10417 : }
10418 2 : alpF++;
10419 :
10420 2 : if (s_ipsc->lNumericFieldBlanks(numF) || s_ipsc->rNumericArgs(numF) == Constant::AutoCalculate) {
10421 : // Autocalculate deep-ground depth (see KivaManager::defineDefaultFoundation() for actual calculation)
10422 1 : state.dataSurfaceGeometry->kivaManager.settings.deepGroundDepth = 40.0;
10423 1 : state.dataSurfaceGeometry->kivaManager.settings.autocalculateDeepGroundDepth = true;
10424 1 : if (state.dataSurfaceGeometry->kivaManager.settings.deepGroundBoundary != HeatBalanceKivaManager::KivaManager::Settings::AUTO) {
10425 1 : ErrorsFound = true;
10426 2 : ShowSevereError(state,
10427 4 : format("{}, {} should not be set to Autocalculate unless {} is set to Autoselect",
10428 1 : s_ipsc->cCurrentModuleObject,
10429 1 : s_ipsc->cNumericFieldNames(numF),
10430 1 : s_ipsc->cAlphaFieldNames(alpF - 1)));
10431 : }
10432 : } else {
10433 1 : state.dataSurfaceGeometry->kivaManager.settings.deepGroundDepth = s_ipsc->rNumericArgs(numF);
10434 1 : state.dataSurfaceGeometry->kivaManager.settings.autocalculateDeepGroundDepth = false;
10435 : }
10436 2 : numF++;
10437 2 : if (!s_ipsc->lNumericFieldBlanks(numF)) {
10438 0 : state.dataSurfaceGeometry->kivaManager.settings.minCellDim = s_ipsc->rNumericArgs(numF);
10439 : }
10440 2 : numF++;
10441 2 : if (!s_ipsc->lNumericFieldBlanks(numF)) {
10442 0 : state.dataSurfaceGeometry->kivaManager.settings.maxGrowthCoeff = s_ipsc->rNumericArgs(numF);
10443 : }
10444 2 : numF++;
10445 :
10446 2 : if (!s_ipsc->lAlphaFieldBlanks(alpF)) {
10447 0 : if (Util::SameString(s_ipsc->cAlphaArgs(alpF), "Hourly")) {
10448 0 : state.dataSurfaceGeometry->kivaManager.settings.timestepType = HeatBalanceKivaManager::KivaManager::Settings::HOURLY;
10449 0 : state.dataSurfaceGeometry->kivaManager.timestep = 3600.; // seconds
10450 : } else { // if (Util::SameString(s_ipsc->cAlphaArgs( alpF ), "Timestep"))
10451 0 : state.dataSurfaceGeometry->kivaManager.settings.timestepType = HeatBalanceKivaManager::KivaManager::Settings::TIMESTEP;
10452 0 : state.dataSurfaceGeometry->kivaManager.timestep = state.dataGlobal->MinutesInTimeStep * 60.;
10453 : }
10454 : }
10455 2 : alpF++;
10456 : }
10457 :
10458 : // Set default foundation (probably doesn't need to be called if there are no Kiva
10459 : // surfaces, but we don't know that yet). We call this here so that the default
10460 : // foundation is available for 1) the starting copy for user-defined Foundation:Kiva
10461 : // object default inputs, and 2) the actual default Foundation object if a
10462 : // user-defined Foundation:Kiva name is not referenced by a surface.
10463 234 : state.dataSurfaceGeometry->kivaManager.defineDefaultFoundation(state);
10464 :
10465 : // Read Foundation objects
10466 234 : s_ipsc->cCurrentModuleObject = "Foundation:Kiva";
10467 234 : int TotKivaFnds = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
10468 :
10469 234 : if (TotKivaFnds > 0) {
10470 1 : auto &s_mat = state.dataMaterial;
10471 2 : for (int Loop = 1; Loop <= TotKivaFnds; ++Loop) {
10472 2 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
10473 1 : s_ipsc->cCurrentModuleObject,
10474 : Loop,
10475 1 : s_ipsc->cAlphaArgs,
10476 : NumAlphas,
10477 1 : s_ipsc->rNumericArgs,
10478 : NumProps,
10479 : IOStat,
10480 1 : s_ipsc->lNumericFieldBlanks,
10481 1 : s_ipsc->lAlphaFieldBlanks,
10482 1 : s_ipsc->cAlphaFieldNames,
10483 1 : s_ipsc->cNumericFieldNames);
10484 :
10485 1 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
10486 :
10487 1 : int numF = 1;
10488 1 : int alpF = 1;
10489 :
10490 1 : bool ErrorInName = false;
10491 :
10492 1 : HeatBalanceKivaManager::FoundationKiva fndInput;
10493 :
10494 1 : fndInput.name = s_ipsc->cAlphaArgs(alpF);
10495 1 : alpF++;
10496 1 : Util::IsNameEmpty(state, fndInput.name, s_ipsc->cCurrentModuleObject, ErrorInName);
10497 1 : if (ErrorInName) {
10498 0 : ErrorsFound = true;
10499 0 : continue;
10500 : }
10501 :
10502 : // Start with copy of default
10503 1 : auto &fnd = fndInput.foundation;
10504 1 : fnd = state.dataSurfaceGeometry->kivaManager.defaultFoundation.foundation;
10505 :
10506 : // Indoor temperature
10507 1 : if (!s_ipsc->lNumericFieldBlanks(numF)) {
10508 1 : fndInput.assumedIndoorTemperature = s_ipsc->rNumericArgs(numF);
10509 : } else {
10510 0 : fndInput.assumedIndoorTemperature = -9999;
10511 : }
10512 1 : numF++;
10513 :
10514 : // Interior horizontal insulation
10515 1 : if (!s_ipsc->lAlphaFieldBlanks(alpF)) {
10516 0 : int index = Material::GetMaterialNum(state, s_ipsc->cAlphaArgs(alpF));
10517 0 : if (index == 0) {
10518 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(alpF), s_ipsc->cAlphaArgs(alpF));
10519 0 : ErrorsFound = true;
10520 0 : continue;
10521 : }
10522 0 : auto *m = s_mat->materials(index);
10523 0 : if (m->group != Material::Group::Regular || m->ROnly) {
10524 0 : ErrorsFound = true;
10525 0 : ShowSevereError(state,
10526 0 : format("{}=\"{}\", invalid {}=\"{}",
10527 0 : s_ipsc->cCurrentModuleObject,
10528 : fndInput.name,
10529 0 : s_ipsc->cAlphaFieldNames(alpF),
10530 0 : s_ipsc->cAlphaArgs(alpF)));
10531 0 : ShowContinueError(state, "Must be of type \"Material\"");
10532 0 : continue;
10533 : }
10534 0 : fndInput.intHIns.x = 0.0;
10535 0 : fndInput.intHIns.material = Kiva::Material(m->Conductivity, m->Density, m->SpecHeat);
10536 0 : fndInput.intHIns.depth = m->Thickness;
10537 : }
10538 1 : alpF++;
10539 :
10540 1 : if (!s_ipsc->lAlphaFieldBlanks(alpF - 1)) {
10541 0 : if (s_ipsc->lNumericFieldBlanks(numF)) {
10542 0 : fndInput.intHIns.z = 0.0;
10543 : } else {
10544 0 : fndInput.intHIns.z = s_ipsc->rNumericArgs(numF);
10545 : }
10546 0 : numF++;
10547 0 : if (s_ipsc->lNumericFieldBlanks(numF)) {
10548 0 : ErrorsFound = true;
10549 0 : ShowSevereError(state,
10550 0 : format("{}=\"{}\", {} defined, but no {}provided",
10551 0 : s_ipsc->cCurrentModuleObject,
10552 : fndInput.name,
10553 0 : s_ipsc->cAlphaFieldNames(alpF - 1),
10554 0 : s_ipsc->cNumericFieldNames(numF)));
10555 0 : continue;
10556 : } else {
10557 0 : fndInput.intHIns.width = -s_ipsc->rNumericArgs(numF);
10558 : }
10559 0 : numF++;
10560 : } else {
10561 1 : if (!s_ipsc->lNumericFieldBlanks(numF)) {
10562 0 : ShowWarningError(
10563 : state,
10564 0 : format("{}=\"{}\", no {} defined", s_ipsc->cCurrentModuleObject, fndInput.name, s_ipsc->cAlphaFieldNames(alpF - 1)));
10565 0 : ShowContinueError(state, format("{} will not be used.", s_ipsc->cNumericFieldNames(numF)));
10566 : }
10567 1 : numF++;
10568 1 : if (!s_ipsc->lNumericFieldBlanks(numF)) {
10569 0 : ShowWarningError(
10570 : state,
10571 0 : format("{}=\"{}\", no {} defined", s_ipsc->cCurrentModuleObject, fndInput.name, s_ipsc->cAlphaFieldNames(alpF - 1)));
10572 0 : ShowContinueError(state, format("{} will not be used.", s_ipsc->cNumericFieldNames(numF)));
10573 : }
10574 1 : numF++;
10575 : }
10576 :
10577 : // Interior vertical insulation
10578 1 : if (!s_ipsc->lAlphaFieldBlanks(alpF)) {
10579 0 : int index = Material::GetMaterialNum(state, s_ipsc->cAlphaArgs(alpF));
10580 0 : if (index == 0) {
10581 0 : ErrorsFound = true;
10582 0 : ShowSevereError(state,
10583 0 : format("Did not find matching material for {}=\"{}\", {}, missing material = {}",
10584 0 : s_ipsc->cCurrentModuleObject,
10585 : fndInput.name,
10586 0 : s_ipsc->cAlphaFieldNames(alpF),
10587 0 : s_ipsc->cAlphaArgs(alpF)));
10588 0 : continue;
10589 : }
10590 0 : auto *m = s_mat->materials(index);
10591 0 : if (m->group != Material::Group::Regular || m->ROnly) {
10592 0 : ErrorsFound = true;
10593 0 : ShowSevereError(state,
10594 0 : format("{}=\"{}\", invalid {}=\"{}",
10595 0 : s_ipsc->cCurrentModuleObject,
10596 : fndInput.name,
10597 0 : s_ipsc->cAlphaFieldNames(alpF),
10598 0 : s_ipsc->cAlphaArgs(alpF)));
10599 0 : ShowContinueError(state, "Must be of type \"Material\"");
10600 0 : continue;
10601 : }
10602 0 : fndInput.intVIns.material = Kiva::Material(m->Conductivity, m->Density, m->SpecHeat);
10603 0 : fndInput.intVIns.width = -m->Thickness;
10604 0 : fndInput.intVIns.x = 0.0;
10605 0 : fndInput.intVIns.z = 0.0;
10606 : }
10607 1 : alpF++;
10608 :
10609 1 : if (!s_ipsc->lAlphaFieldBlanks(alpF - 1)) {
10610 0 : if (s_ipsc->lNumericFieldBlanks(numF)) {
10611 0 : ErrorsFound = true;
10612 0 : ShowSevereError(state,
10613 0 : format("{}=\"{}\", {} defined, but no {}provided",
10614 0 : s_ipsc->cCurrentModuleObject,
10615 : fndInput.name,
10616 0 : s_ipsc->cAlphaFieldNames(alpF - 1),
10617 0 : s_ipsc->cNumericFieldNames(numF)));
10618 0 : continue;
10619 : } else {
10620 0 : fndInput.intVIns.depth = s_ipsc->rNumericArgs(numF);
10621 : }
10622 0 : numF++;
10623 : } else {
10624 1 : if (!s_ipsc->lNumericFieldBlanks(numF)) {
10625 0 : ShowWarningError(
10626 : state,
10627 0 : format("{}=\"{}\", no {} defined", s_ipsc->cCurrentModuleObject, fndInput.name, s_ipsc->cAlphaFieldNames(alpF - 1)));
10628 0 : ShowContinueError(state, format("{} will not be used.", s_ipsc->cNumericFieldNames(numF)));
10629 : }
10630 1 : numF++;
10631 : }
10632 :
10633 : // Exterior horizontal insulation
10634 1 : if (!s_ipsc->lAlphaFieldBlanks(alpF)) {
10635 0 : int index = Material::GetMaterialNum(state, s_ipsc->cAlphaArgs(alpF));
10636 0 : if (index == 0) {
10637 0 : ErrorsFound = true;
10638 0 : ShowSevereError(state,
10639 0 : format("Did not find matching material for {}=\"{}\", {}, missing material = {}",
10640 0 : s_ipsc->cCurrentModuleObject,
10641 : fndInput.name,
10642 0 : s_ipsc->cAlphaFieldNames(alpF),
10643 0 : s_ipsc->cAlphaArgs(alpF)));
10644 0 : continue;
10645 : }
10646 0 : auto *m = s_mat->materials(index);
10647 0 : if (m->group != Material::Group::Regular || m->ROnly) {
10648 0 : ErrorsFound = true;
10649 0 : ShowSevereError(state,
10650 0 : format("{}=\"{}\", invalid {}=\"{}",
10651 0 : s_ipsc->cCurrentModuleObject,
10652 : fndInput.name,
10653 0 : s_ipsc->cAlphaFieldNames(alpF),
10654 0 : s_ipsc->cAlphaArgs(alpF)));
10655 0 : ShowContinueError(state, "Must be of type \"Material\"");
10656 0 : continue;
10657 : }
10658 0 : fndInput.extHIns.x = 0.0;
10659 0 : fndInput.extHIns.material = Kiva::Material(m->Conductivity, m->Density, m->SpecHeat);
10660 0 : fndInput.extHIns.depth = m->Thickness;
10661 : }
10662 1 : alpF++;
10663 :
10664 1 : if (!s_ipsc->lAlphaFieldBlanks(alpF - 1)) {
10665 0 : if (s_ipsc->lNumericFieldBlanks(numF)) {
10666 0 : fndInput.extHIns.z = 0.0;
10667 : } else {
10668 0 : fndInput.extHIns.z = s_ipsc->rNumericArgs(numF);
10669 : }
10670 0 : numF++;
10671 0 : if (s_ipsc->lNumericFieldBlanks(numF)) {
10672 0 : ErrorsFound = true;
10673 0 : ShowSevereError(state,
10674 0 : format("{}=\"{}\", {} defined, but no {}provided",
10675 0 : s_ipsc->cCurrentModuleObject,
10676 : fndInput.name,
10677 0 : s_ipsc->cAlphaFieldNames(alpF - 1),
10678 0 : s_ipsc->cNumericFieldNames(numF)));
10679 0 : continue;
10680 : } else {
10681 0 : fndInput.extHIns.width = s_ipsc->rNumericArgs(numF);
10682 : }
10683 0 : numF++;
10684 : } else {
10685 1 : if (!s_ipsc->lNumericFieldBlanks(numF)) {
10686 0 : ShowWarningError(
10687 : state,
10688 0 : format("{}=\"{}\", no {} defined", s_ipsc->cCurrentModuleObject, fndInput.name, s_ipsc->cAlphaFieldNames(alpF - 1)));
10689 0 : ShowContinueError(state, format("{} will not be used.", s_ipsc->cNumericFieldNames(numF)));
10690 : }
10691 1 : numF++;
10692 1 : if (!s_ipsc->lNumericFieldBlanks(numF)) {
10693 0 : ShowWarningError(
10694 : state,
10695 0 : format("{}=\"{}\", no {} defined", s_ipsc->cCurrentModuleObject, fndInput.name, s_ipsc->cAlphaFieldNames(alpF - 1)));
10696 0 : ShowContinueError(state, format("{} will not be used.", s_ipsc->cNumericFieldNames(numF)));
10697 : }
10698 1 : numF++;
10699 : }
10700 :
10701 : // Exterior vertical insulation
10702 1 : if (!s_ipsc->lAlphaFieldBlanks(alpF)) {
10703 0 : int index = Material::GetMaterialNum(state, s_ipsc->cAlphaArgs(alpF));
10704 0 : if (index == 0) {
10705 0 : ErrorsFound = true;
10706 0 : ShowSevereError(state,
10707 0 : format("Did not find matching material for {}=\"{}\", {}, missing material = {}",
10708 0 : s_ipsc->cCurrentModuleObject,
10709 : fndInput.name,
10710 0 : s_ipsc->cAlphaFieldNames(alpF),
10711 0 : s_ipsc->cAlphaArgs(alpF)));
10712 0 : continue;
10713 : }
10714 0 : auto *m = s_mat->materials(index);
10715 0 : if (m->group != Material::Group::Regular || m->ROnly) {
10716 0 : ErrorsFound = true;
10717 0 : ShowSevereError(state,
10718 0 : format("{}=\"{}\", invalid {}=\"{}",
10719 0 : s_ipsc->cCurrentModuleObject,
10720 : fndInput.name,
10721 0 : s_ipsc->cAlphaFieldNames(alpF),
10722 0 : s_ipsc->cAlphaArgs(alpF)));
10723 0 : ShowContinueError(state, "Must be of type \"Material\"");
10724 0 : continue;
10725 : }
10726 0 : fndInput.extVIns.material = Kiva::Material(m->Conductivity, m->Density, m->SpecHeat);
10727 0 : fndInput.extVIns.width = m->Thickness;
10728 0 : fndInput.extVIns.x = 0.0;
10729 0 : fndInput.extVIns.z = 0.0;
10730 : }
10731 1 : alpF++;
10732 :
10733 1 : if (!s_ipsc->lAlphaFieldBlanks(alpF - 1)) {
10734 0 : if (s_ipsc->lNumericFieldBlanks(numF)) {
10735 0 : ErrorsFound = true;
10736 0 : ShowSevereError(state,
10737 0 : format("{}=\"{}\", {} defined, but no {}provided",
10738 0 : s_ipsc->cCurrentModuleObject,
10739 : fndInput.name,
10740 0 : s_ipsc->cAlphaFieldNames(alpF - 1),
10741 0 : s_ipsc->cNumericFieldNames(numF)));
10742 0 : continue;
10743 : } else {
10744 0 : fndInput.extVIns.depth = s_ipsc->rNumericArgs(numF);
10745 : }
10746 0 : numF++;
10747 : } else {
10748 1 : if (!s_ipsc->lNumericFieldBlanks(numF)) {
10749 0 : ShowWarningError(
10750 : state,
10751 0 : format("{}=\"{}\", no {} defined", s_ipsc->cCurrentModuleObject, fndInput.name, s_ipsc->cAlphaFieldNames(alpF - 1)));
10752 0 : ShowContinueError(state, format("{} will not be used.", s_ipsc->cNumericFieldNames(numF)));
10753 : }
10754 1 : numF++;
10755 : }
10756 :
10757 : // Foundation wall
10758 1 : if (!s_ipsc->lNumericFieldBlanks(numF)) {
10759 1 : fnd.wall.heightAboveGrade = s_ipsc->rNumericArgs(numF);
10760 : }
10761 1 : numF++;
10762 :
10763 1 : if (!s_ipsc->lNumericFieldBlanks(numF)) {
10764 1 : fnd.wall.depthBelowSlab = s_ipsc->rNumericArgs(numF);
10765 : }
10766 1 : numF++;
10767 :
10768 1 : if (!s_ipsc->lAlphaFieldBlanks(alpF)) {
10769 0 : fndInput.wallConstructionIndex = Util::FindItemInList(s_ipsc->cAlphaArgs(alpF), state.dataConstruction->Construct);
10770 0 : if (fndInput.wallConstructionIndex == 0) {
10771 0 : ErrorsFound = true;
10772 0 : ShowSevereError(state,
10773 0 : format("Did not find matching construction for {}=\"{}\", {}, missing construction = {}",
10774 0 : s_ipsc->cCurrentModuleObject,
10775 : fndInput.name,
10776 0 : s_ipsc->cAlphaFieldNames(alpF),
10777 0 : s_ipsc->cAlphaArgs(alpF)));
10778 0 : continue;
10779 : }
10780 0 : auto &c = state.dataConstruction->Construct(fndInput.wallConstructionIndex);
10781 0 : c.IsUsed = true;
10782 0 : if (c.TypeIsWindow) {
10783 0 : ErrorsFound = true;
10784 0 : ShowSevereError(state,
10785 0 : format("{}=\"{}\", invalid {}=\"{}",
10786 0 : s_ipsc->cCurrentModuleObject,
10787 : fndInput.name,
10788 0 : s_ipsc->cAlphaFieldNames(alpF),
10789 0 : s_ipsc->cAlphaArgs(alpF)));
10790 0 : ShowContinueError(state, "Cannot be a window construction");
10791 0 : continue;
10792 : }
10793 : } else {
10794 1 : fndInput.wallConstructionIndex = 0; // Use default wall construction
10795 : }
10796 1 : alpF++;
10797 :
10798 : // Footing
10799 1 : if (!s_ipsc->lAlphaFieldBlanks(alpF)) {
10800 0 : int index = Material::GetMaterialNum(state, s_ipsc->cAlphaArgs(alpF));
10801 0 : if (index == 0) {
10802 0 : ErrorsFound = true;
10803 0 : ShowSevereError(state,
10804 0 : format("Did not find matching material for {}=\"{}\", {}, missing material = {}",
10805 0 : s_ipsc->cCurrentModuleObject,
10806 : fndInput.name,
10807 0 : s_ipsc->cAlphaFieldNames(alpF),
10808 0 : s_ipsc->cAlphaArgs(alpF)));
10809 0 : continue;
10810 : }
10811 0 : auto *m = s_mat->materials(index);
10812 0 : if (m->group != Material::Group::Regular || m->ROnly) {
10813 0 : ErrorsFound = true;
10814 0 : ShowSevereError(state,
10815 0 : format("{}=\"{}\", invalid {}=\"{}",
10816 0 : s_ipsc->cCurrentModuleObject,
10817 : fndInput.name,
10818 0 : s_ipsc->cAlphaFieldNames(alpF),
10819 0 : s_ipsc->cAlphaArgs(alpF)));
10820 0 : ShowContinueError(state, "Must be of type \"Material\"");
10821 0 : continue;
10822 : }
10823 0 : fndInput.footing.material = Kiva::Material(m->Conductivity, m->Density, m->SpecHeat);
10824 0 : fndInput.footing.width = m->Thickness;
10825 0 : fndInput.footing.x = 0.0;
10826 0 : fndInput.footing.z = 0.0;
10827 : }
10828 1 : alpF++;
10829 :
10830 1 : if (!s_ipsc->lAlphaFieldBlanks(alpF - 1)) {
10831 0 : if (s_ipsc->lNumericFieldBlanks(numF)) {
10832 0 : ErrorsFound = true;
10833 0 : ShowSevereError(state,
10834 0 : format("{}=\"{}\", {} defined, but no {}provided",
10835 0 : s_ipsc->cCurrentModuleObject,
10836 : fndInput.name,
10837 0 : s_ipsc->cAlphaFieldNames(alpF - 1),
10838 0 : s_ipsc->cNumericFieldNames(numF)));
10839 0 : continue;
10840 : } else {
10841 0 : fndInput.footing.depth = s_ipsc->rNumericArgs(numF);
10842 : }
10843 0 : numF++;
10844 : } else {
10845 1 : if (!s_ipsc->lNumericFieldBlanks(numF)) {
10846 0 : ShowWarningError(
10847 : state,
10848 0 : format("{}=\"{}\", no {} defined", s_ipsc->cCurrentModuleObject, fndInput.name, s_ipsc->cAlphaFieldNames(alpF - 1)));
10849 0 : ShowContinueError(state, format("{} will not be used.", s_ipsc->cNumericFieldNames(numF)));
10850 : }
10851 1 : numF++;
10852 : }
10853 :
10854 : // General Blocks
10855 1 : int numRemainingFields = NumAlphas - (alpF - 1) + NumProps - (numF - 1);
10856 1 : if (numRemainingFields > 0) {
10857 1 : int numBlocks = numRemainingFields / 4;
10858 1 : if (mod(numRemainingFields, 4) != 0) {
10859 0 : ShowWarningError(state,
10860 0 : format("{}=\"{}\", number of Block fields not even multiple of 4. Will read in {}",
10861 0 : s_ipsc->cCurrentModuleObject,
10862 : fndInput.name,
10863 : numBlocks));
10864 : }
10865 2 : for (int blockNum = 0; blockNum < numBlocks; blockNum++) {
10866 1 : Kiva::InputBlock block;
10867 1 : if (!s_ipsc->lAlphaFieldBlanks(alpF)) {
10868 1 : int index = Material::GetMaterialNum(state, s_ipsc->cAlphaArgs(alpF));
10869 1 : if (index == 0) {
10870 0 : ErrorsFound = true;
10871 0 : ShowSevereError(state,
10872 0 : format("Did not find matching material for {}=\"{}\", {}, missing material = {}",
10873 0 : s_ipsc->cCurrentModuleObject,
10874 : fndInput.name,
10875 0 : s_ipsc->cAlphaFieldNames(alpF),
10876 0 : s_ipsc->cAlphaArgs(alpF)));
10877 0 : continue;
10878 : }
10879 1 : auto *m = s_mat->materials(index);
10880 1 : if (m->group != Material::Group::Regular || m->ROnly) {
10881 0 : ErrorsFound = true;
10882 0 : ShowSevereError(state,
10883 0 : format("{}=\"{}\", invalid {}=\"{}",
10884 0 : s_ipsc->cCurrentModuleObject,
10885 : fndInput.name,
10886 0 : s_ipsc->cAlphaFieldNames(alpF),
10887 0 : s_ipsc->cAlphaArgs(alpF)));
10888 0 : ShowContinueError(state, "Must be of type \"Material\"");
10889 0 : continue;
10890 : }
10891 1 : block.material = Kiva::Material(m->Conductivity, m->Density, m->SpecHeat);
10892 1 : block.width = m->Thickness;
10893 : } else {
10894 0 : ErrorsFound = true;
10895 0 : ShowSevereError(state,
10896 0 : format("{}=\"{}\", {} is required and not given.",
10897 0 : s_ipsc->cCurrentModuleObject,
10898 : fndInput.name,
10899 0 : s_ipsc->cAlphaFieldNames(alpF)));
10900 0 : continue;
10901 : }
10902 1 : alpF++;
10903 :
10904 1 : if (s_ipsc->lNumericFieldBlanks(numF)) {
10905 0 : block.depth = 0.0; // Temporary indicator to default to foundation depth
10906 : } else {
10907 1 : block.depth = s_ipsc->rNumericArgs(numF);
10908 : }
10909 1 : numF++;
10910 :
10911 1 : if (s_ipsc->lNumericFieldBlanks(numF)) {
10912 0 : ErrorsFound = true;
10913 0 : ShowSevereError(state,
10914 0 : format("{}=\"{}\", {} defined, but no {}provided",
10915 0 : s_ipsc->cCurrentModuleObject,
10916 : fndInput.name,
10917 0 : s_ipsc->cAlphaFieldNames(alpF - 1),
10918 0 : s_ipsc->cNumericFieldNames(numF)));
10919 0 : continue;
10920 : } else {
10921 1 : block.x = s_ipsc->rNumericArgs(numF);
10922 : }
10923 1 : numF++;
10924 :
10925 1 : if (s_ipsc->lNumericFieldBlanks(numF)) {
10926 0 : block.z = 0.0;
10927 : } else {
10928 1 : block.z = s_ipsc->rNumericArgs(numF);
10929 : }
10930 1 : numF++;
10931 :
10932 1 : fnd.inputBlocks.push_back(block);
10933 : }
10934 : }
10935 :
10936 1 : state.dataSurfaceGeometry->kivaManager.foundationInputs.push_back(fndInput);
10937 1 : }
10938 : }
10939 234 : }
10940 :
10941 231 : void GetOSCData(EnergyPlusData &state, bool &ErrorsFound)
10942 : {
10943 :
10944 : // SUBROUTINE INFORMATION:
10945 : // AUTHOR Linda Lawrie
10946 : // DATE WRITTEN May 2000
10947 : // MODIFIED Jul 2011, M.J. Witte and C.O. Pedersen, add new fields to OSC for last T, max and min
10948 :
10949 : // PURPOSE OF THIS SUBROUTINE:
10950 : // This subroutine gets the OtherSideCoefficient data.
10951 :
10952 : // REFERENCES:
10953 : // Other Side Coefficient Definition
10954 : // OtherSideCoefficients,
10955 : // \memo This object sets the other side conditions for a surface in a variety of ways.
10956 : // A1, \field OtherSideCoeff Name
10957 : // \required-field
10958 : // \reference OSCNames
10959 : // \reference OutFaceEnvNames
10960 : // N1, \field Combined convective/radiative film coefficient
10961 : // \required-field
10962 : // \type real
10963 : // \note if>0, N1 becomes exterior convective/radiative film coefficient and other fields
10964 : // \note are used to calc outside air temp then exterior surface temp based on outside air
10965 : // \note and specified coefficient
10966 : // \note if<=0, then remaining fields calculate the outside surface temperature(?)
10967 : // \note following fields are used in the equation:
10968 : // \note SurfTemp=N7*TempZone + N4*OutsideDryBulb + N2*N3 + GroundTemp*N5 + WindSpeed*N6*OutsideDryBulb
10969 : // N2, \field User selected Constant Temperature
10970 : // \units C
10971 : // \type real
10972 : // \note This parameter will be overwritten by the values from the schedule(A2 below) if one is present
10973 : // N3, \field Coefficient modifying the user selected constant temperature
10974 : // \note This coefficient is used even with a schedule. It should normally be 1.0 in that case
10975 : // N4, \field Coefficient modifying the external dry bulb temperature
10976 : // \type real
10977 : // N5, \field Coefficient modifying the ground temperature
10978 : // \type real
10979 : // N6, \field Coefficient modifying the wind speed term (s/m)
10980 : // \type real
10981 : // N7, \field Coefficient modifying the zone air temperature part of the equation
10982 : // \type real
10983 : // A2, \field ScheduleName for constant temperature
10984 : // \note Name of Schedule for values of "const" temperature.
10985 : // \note Schedule values replace N2 - User selected constant temperature.
10986 : // \type object-list
10987 : // \object-list ScheduleNames
10988 : // A3, \field Sinusoidal Variation of Constant Temperature Coefficient
10989 : // \note Optionally used to vary Constant Temperature Coefficient with unitary sine wave
10990 : // \type choice
10991 : // \key Yes
10992 : // \key No
10993 : // \default No
10994 : // N8; \field Period of Sinusoidal Variation
10995 : // \note Use with sinusoidal variation to define the time period
10996 : // \type real
10997 : // \units hr
10998 : // \default 24
10999 : // N9, \field Previous Other Side Temperature Coefficient
11000 : // \note This coefficient multiplies the other side temperature result from the
11001 : // \note previous zone timestep
11002 : // \type real
11003 : // \default 0
11004 : // N10, \field Minimum Other Side Temperature
11005 : // \type real
11006 : // \units C
11007 : // \default -100
11008 : // N11; \field Maximum Other Side Temperature
11009 : // \type real
11010 : // \units C
11011 : // \default 200
11012 :
11013 : static constexpr std::string_view routineName = "GetOSCData";
11014 : // Locals
11015 : // SUBROUTINE ARGUMENT DEFINITIONS:
11016 :
11017 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
11018 : int NumAlphas;
11019 : int NumProps;
11020 : int Loop;
11021 : int IOStat;
11022 231 : std::string cOSCLimitsString;
11023 :
11024 231 : auto &s_ipsc = state.dataIPShortCut;
11025 :
11026 231 : s_ipsc->cCurrentModuleObject = "SurfaceProperty:OtherSideCoefficients";
11027 231 : state.dataSurface->TotOSC = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
11028 231 : state.dataSurface->OSC.allocate(state.dataSurface->TotOSC);
11029 :
11030 231 : int OSCNum = 0;
11031 231 : for (Loop = 1; Loop <= state.dataSurface->TotOSC; ++Loop) {
11032 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
11033 0 : s_ipsc->cCurrentModuleObject,
11034 : Loop,
11035 0 : s_ipsc->cAlphaArgs,
11036 : NumAlphas,
11037 0 : s_ipsc->rNumericArgs,
11038 : NumProps,
11039 : IOStat,
11040 0 : s_ipsc->lNumericFieldBlanks,
11041 0 : s_ipsc->lAlphaFieldBlanks,
11042 0 : s_ipsc->cAlphaFieldNames,
11043 0 : s_ipsc->cNumericFieldNames);
11044 :
11045 0 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
11046 0 : bool ErrorInName = false;
11047 0 : bool IsBlank = false;
11048 0 : Util::VerifyName(
11049 0 : state, s_ipsc->cAlphaArgs(1), state.dataSurface->OSC, OSCNum, ErrorInName, IsBlank, s_ipsc->cCurrentModuleObject + " Name");
11050 0 : if (ErrorInName) {
11051 0 : ErrorsFound = true;
11052 0 : continue;
11053 : }
11054 :
11055 0 : ++OSCNum;
11056 0 : state.dataSurface->OSC(OSCNum).Name = s_ipsc->cAlphaArgs(1);
11057 0 : state.dataSurface->OSC(OSCNum).SurfFilmCoef = s_ipsc->rNumericArgs(1);
11058 0 : state.dataSurface->OSC(OSCNum).ConstTemp = s_ipsc->rNumericArgs(2); // This will be replaced if schedule is used
11059 0 : state.dataSurface->OSC(OSCNum).ConstTempCoef =
11060 0 : s_ipsc->rNumericArgs(3); // This multiplier is used (even with schedule). It should normally be 1.0
11061 0 : state.dataSurface->OSC(OSCNum).ExtDryBulbCoef = s_ipsc->rNumericArgs(4);
11062 0 : state.dataSurface->OSC(OSCNum).GroundTempCoef = s_ipsc->rNumericArgs(5);
11063 0 : state.dataSurface->OSC(OSCNum).WindSpeedCoef = s_ipsc->rNumericArgs(6);
11064 0 : state.dataSurface->OSC(OSCNum).ZoneAirTempCoef = s_ipsc->rNumericArgs(7);
11065 0 : state.dataSurface->OSC(OSCNum).SinusoidPeriod = s_ipsc->rNumericArgs(8);
11066 :
11067 0 : if ((NumAlphas == 1) || s_ipsc->lAlphaFieldBlanks(2)) { // Const temp will come from schedule specified below.
11068 0 : } else if ((state.dataSurface->OSC(OSCNum).constTempSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(2))) == nullptr) {
11069 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2));
11070 0 : ErrorsFound = true;
11071 : }
11072 :
11073 0 : if (!s_ipsc->lAlphaFieldBlanks(3)) {
11074 0 : if (BooleanSwitch bs = getYesNoValue(s_ipsc->cAlphaArgs(3)); bs != BooleanSwitch::Invalid) {
11075 0 : state.dataSurface->OSC(OSCNum).SinusoidalConstTempCoef = static_cast<bool>(bs);
11076 : } else {
11077 0 : ShowSevereInvalidBool(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3));
11078 0 : ErrorsFound = true;
11079 : }
11080 : }
11081 :
11082 0 : if (s_ipsc->rNumericArgs(1) > 0.0 && !any_ne(s_ipsc->rNumericArgs({3, 7}), 0.0) &&
11083 0 : (!state.dataSurface->OSC(OSCNum).SinusoidalConstTempCoef)) {
11084 0 : ShowSevereError(state, format("{}=\"{}\" has zeros for all coefficients.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
11085 0 : ShowContinueError(state, "...The outdoor air temperature for surfaces using this OtherSideCoefficients object will always be 0C.");
11086 : }
11087 :
11088 0 : if (s_ipsc->rNumericArgs(1) <= 0.0 && !any_ne(s_ipsc->rNumericArgs({3, 7}), 0.0) &&
11089 0 : (!state.dataSurface->OSC(OSCNum).SinusoidalConstTempCoef)) {
11090 0 : ShowSevereError(state, format("{}=\"{}\" has zeros for all coefficients.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
11091 0 : ShowContinueError(state,
11092 : "...The outside surface temperature for surfaces using this OtherSideCoefficients object will always be 0C.");
11093 : }
11094 :
11095 0 : state.dataSurface->OSC(OSCNum).TPreviousCoef = s_ipsc->rNumericArgs(9);
11096 :
11097 0 : if (!s_ipsc->lNumericFieldBlanks(10)) {
11098 0 : state.dataSurface->OSC(OSCNum).MinLimitPresent = true;
11099 0 : state.dataSurface->OSC(OSCNum).MinTempLimit = s_ipsc->rNumericArgs(10);
11100 0 : cOSCLimitsString = format("{:.3R}", s_ipsc->rNumericArgs(10));
11101 : } else {
11102 0 : cOSCLimitsString = "N/A";
11103 : }
11104 0 : if (!s_ipsc->lNumericFieldBlanks(11)) {
11105 0 : state.dataSurface->OSC(OSCNum).MaxLimitPresent = true;
11106 0 : state.dataSurface->OSC(OSCNum).MaxTempLimit = s_ipsc->rNumericArgs(11);
11107 0 : cOSCLimitsString += format(",{:.3R}", s_ipsc->rNumericArgs(10));
11108 : } else {
11109 0 : cOSCLimitsString += ",N/A";
11110 : }
11111 : }
11112 :
11113 231 : for (Loop = 1; Loop <= state.dataSurface->TotOSC; ++Loop) {
11114 0 : if (Loop == 1) {
11115 : static constexpr std::string_view OSCFormat1(
11116 : "! <Other Side Coefficients>,Name,Combined convective/radiative film coefficient {W/m2-K},User selected "
11117 : "Constant Temperature {C},Coefficient modifying the constant temperature term,Coefficient modifying the external "
11118 : "dry bulb temperature term,Coefficient modifying the ground temperature term,Coefficient modifying the wind speed "
11119 : "term {s/m},Coefficient modifying the zone air temperature term,Constant Temperature Schedule Name,Sinusoidal "
11120 : "Variation,Period of Sinusoidal Variation,Previous Other Side Temperature Coefficient,Minimum Other Side "
11121 : "Temperature {C},Maximum Other Side Temperature {C}");
11122 0 : print(state.files.eio, "{}\n", OSCFormat1);
11123 : }
11124 0 : if (state.dataSurface->OSC(Loop).SurfFilmCoef > 0.0) {
11125 0 : s_ipsc->cAlphaArgs(1) = format("{:.3R}", state.dataSurface->OSC(Loop).SurfFilmCoef);
11126 0 : SetupOutputVariable(state,
11127 : "Surface Other Side Coefficients Exterior Air Drybulb Temperature",
11128 : Constant::Units::C,
11129 0 : state.dataSurface->OSC(Loop).OSCTempCalc,
11130 : OutputProcessor::TimeStepType::System,
11131 : OutputProcessor::StoreType::Average,
11132 0 : state.dataSurface->OSC(Loop).Name);
11133 : } else {
11134 0 : s_ipsc->cAlphaArgs(1) = "N/A";
11135 : }
11136 :
11137 0 : print(state.files.eio,
11138 : "Other Side Coefficients,{},{},{},{:.3R},{:.3R},{:.3R},{:.3R},{:.3R},{},{},{:.3R},{:.3R},{}\n",
11139 0 : state.dataSurface->OSC(Loop).Name,
11140 0 : s_ipsc->cAlphaArgs(1),
11141 0 : (state.dataSurface->OSC(Loop).constTempSched != nullptr) ? "N/A" : format("{:.2R}", state.dataSurface->OSC(Loop).ConstTemp),
11142 0 : state.dataSurface->OSC(Loop).ConstTempCoef,
11143 0 : state.dataSurface->OSC(Loop).ExtDryBulbCoef,
11144 0 : state.dataSurface->OSC(Loop).GroundTempCoef,
11145 0 : state.dataSurface->OSC(Loop).WindSpeedCoef,
11146 0 : state.dataSurface->OSC(Loop).ZoneAirTempCoef,
11147 0 : (state.dataSurface->OSC(Loop).constTempSched == nullptr) ? "N/A" : state.dataSurface->OSC(Loop).constTempSched->Name,
11148 0 : s_ipsc->cAlphaArgs(3),
11149 0 : state.dataSurface->OSC(Loop).SinusoidPeriod,
11150 0 : state.dataSurface->OSC(Loop).TPreviousCoef,
11151 : cOSCLimitsString);
11152 : }
11153 231 : }
11154 :
11155 257 : void GetOSCMData(EnergyPlusData &state, bool &ErrorsFound)
11156 : {
11157 :
11158 : // SUBROUTINE INFORMATION:
11159 : // AUTHOR Brent Griffith
11160 : // DATE WRITTEN November 2004
11161 :
11162 : // PURPOSE OF THIS SUBROUTINE:
11163 : // This subroutine gets the OtherSideConditionsModel data.
11164 :
11165 : // REFERENCES:
11166 : // derived from GetOSCData subroutine by Linda Lawrie
11167 :
11168 : // OtherSideConditionsModel,
11169 : // \memo This object sets up modifying the other side conditions for a surface from other model results.
11170 : // A1, \field OtherSideConditionsModel Name
11171 : // \required-field
11172 : // \reference OSCMNames
11173 : // \reference OutFaceEnvNames
11174 : // A2; \field Type of Model to determine Boundary Conditions
11175 : // \type choice
11176 : // \key Transpired Collector
11177 : // \key Vented PV Cavity
11178 : // \key Hybrid PV Transpired Collector
11179 :
11180 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
11181 : int NumAlphas;
11182 : int NumProps;
11183 : int IOStat;
11184 :
11185 257 : auto &s_ipsc = state.dataIPShortCut;
11186 257 : s_ipsc->cCurrentModuleObject = "SurfaceProperty:OtherSideConditionsModel";
11187 257 : state.dataSurface->TotOSCM = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
11188 257 : state.dataSurface->OSCM.allocate(state.dataSurface->TotOSCM);
11189 : // OSCM is already initialized in derived type defn.
11190 :
11191 257 : int OSCMNum = 0;
11192 286 : for (int Loop = 1; Loop <= state.dataSurface->TotOSCM; ++Loop) {
11193 58 : state.dataInputProcessing->inputProcessor->getObjectItem(
11194 29 : state, s_ipsc->cCurrentModuleObject, Loop, s_ipsc->cAlphaArgs, NumAlphas, s_ipsc->rNumericArgs, NumProps, IOStat);
11195 29 : bool ErrorInName = false;
11196 29 : bool IsBlank = false;
11197 29 : Util::VerifyName(
11198 29 : state, s_ipsc->cAlphaArgs(1), state.dataSurface->OSCM, OSCMNum, ErrorInName, IsBlank, s_ipsc->cCurrentModuleObject + " Name");
11199 29 : if (ErrorInName) {
11200 0 : ErrorsFound = true;
11201 0 : continue;
11202 : }
11203 :
11204 29 : ++OSCMNum;
11205 29 : state.dataSurface->OSCM(OSCMNum).Name = s_ipsc->cAlphaArgs(1);
11206 : // Note no validation of the below at this time:
11207 29 : state.dataSurface->OSCM(OSCMNum).Class = s_ipsc->cAlphaArgs(2);
11208 : // setup output vars for modeled coefficients
11209 58 : SetupOutputVariable(state,
11210 : "Surface Other Side Conditions Modeled Convection Air Temperature",
11211 : Constant::Units::C,
11212 29 : state.dataSurface->OSCM(OSCMNum).TConv,
11213 : OutputProcessor::TimeStepType::System,
11214 : OutputProcessor::StoreType::Average,
11215 29 : state.dataSurface->OSCM(OSCMNum).Name);
11216 58 : SetupOutputVariable(state,
11217 : "Surface Other Side Conditions Modeled Convection Heat Transfer Coefficient",
11218 : Constant::Units::W_m2K,
11219 29 : state.dataSurface->OSCM(OSCMNum).HConv,
11220 : OutputProcessor::TimeStepType::System,
11221 : OutputProcessor::StoreType::Average,
11222 29 : state.dataSurface->OSCM(OSCMNum).Name);
11223 58 : SetupOutputVariable(state,
11224 : "Surface Other Side Conditions Modeled Radiation Temperature",
11225 : Constant::Units::C,
11226 29 : state.dataSurface->OSCM(OSCMNum).TRad,
11227 : OutputProcessor::TimeStepType::System,
11228 : OutputProcessor::StoreType::Average,
11229 29 : state.dataSurface->OSCM(OSCMNum).Name);
11230 58 : SetupOutputVariable(state,
11231 : "Surface Other Side Conditions Modeled Radiation Heat Transfer Coefficient",
11232 : Constant::Units::W_m2K,
11233 29 : state.dataSurface->OSCM(OSCMNum).HRad,
11234 : OutputProcessor::TimeStepType::System,
11235 : OutputProcessor::StoreType::Average,
11236 29 : state.dataSurface->OSCM(OSCMNum).Name);
11237 :
11238 29 : if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
11239 0 : SetupEMSActuator(state,
11240 : "Other Side Boundary Conditions",
11241 0 : state.dataSurface->OSCM(OSCMNum).Name,
11242 : "Convection Bulk Air Temperature",
11243 : "[C]",
11244 0 : state.dataSurface->OSCM(OSCMNum).EMSOverrideOnTConv,
11245 0 : state.dataSurface->OSCM(OSCMNum).EMSOverrideTConvValue);
11246 0 : SetupEMSActuator(state,
11247 : "Other Side Boundary Conditions",
11248 0 : state.dataSurface->OSCM(OSCMNum).Name,
11249 : "Convection Heat Transfer Coefficient",
11250 : "[W/m2-K]",
11251 0 : state.dataSurface->OSCM(OSCMNum).EMSOverrideOnHConv,
11252 0 : state.dataSurface->OSCM(OSCMNum).EMSOverrideHConvValue);
11253 0 : SetupEMSActuator(state,
11254 : "Other Side Boundary Conditions",
11255 0 : state.dataSurface->OSCM(OSCMNum).Name,
11256 : "Radiation Effective Temperature",
11257 : "[C]",
11258 0 : state.dataSurface->OSCM(OSCMNum).EMSOverrideOnTRad,
11259 0 : state.dataSurface->OSCM(OSCMNum).EMSOverrideTRadValue);
11260 0 : SetupEMSActuator(state,
11261 : "Other Side Boundary Conditions",
11262 0 : state.dataSurface->OSCM(OSCMNum).Name,
11263 : "Radiation Linear Heat Transfer Coefficient",
11264 : "[W/m2-K]",
11265 0 : state.dataSurface->OSCM(OSCMNum).EMSOverrideOnHrad,
11266 0 : state.dataSurface->OSCM(OSCMNum).EMSOverrideHradValue);
11267 : }
11268 : }
11269 :
11270 286 : for (int Loop = 1; Loop <= state.dataSurface->TotOSCM; ++Loop) {
11271 29 : if (Loop == 1) {
11272 : static constexpr std::string_view OSCMFormat1("! <Other Side Conditions Model>,Name,Class\n");
11273 29 : print(state.files.eio, OSCMFormat1);
11274 : }
11275 29 : print(state.files.eio, "Other Side Conditions Model,{},{}\n", state.dataSurface->OSCM(Loop).Name, state.dataSurface->OSCM(Loop).Class);
11276 : }
11277 257 : }
11278 :
11279 225 : void GetMovableInsulationData(EnergyPlusData &state, bool &ErrorsFound) // If errors found in input
11280 : {
11281 :
11282 : // SUBROUTINE INFORMATION:
11283 : // AUTHOR Linda Lawrie
11284 : // DATE WRITTEN May 2000
11285 :
11286 : // PURPOSE OF THIS SUBROUTINE:
11287 : // This subroutine gets the movable insulation data that can be associated with a surface.
11288 :
11289 : // REFERENCES:
11290 : // Movable Insulation Definition
11291 : // SurfaceControl:MovableInsulation,
11292 : // \memo Exterior or Interior Insulation on opaque surfaces
11293 : // A1, \field Insulation Type
11294 : // \required-field
11295 : // \type choice
11296 : // \key Outside
11297 : // \key Inside
11298 : // A2, \field Surface Name
11299 : // \required-field
11300 : // \type object-list
11301 : // \object-list SurfaceNames
11302 : // A3, \field Material Name
11303 : // \required-field
11304 : // \object-list MaterialName
11305 : // A4; \field Schedule Name
11306 : // \required-field
11307 : // \type object-list
11308 : // \object-list ScheduleNames
11309 :
11310 : static constexpr std::string_view routineName = "GetMovableInsulationInput";
11311 :
11312 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
11313 : int NAlphas;
11314 : int NNums;
11315 : int IOStat;
11316 :
11317 : enum class InsulationType
11318 : {
11319 : Invalid = -1,
11320 : Outside,
11321 : Inside,
11322 : Num
11323 : };
11324 225 : constexpr std::array<std::string_view, static_cast<int>(InsulationType::Num)> insulationTypeNamesUC = {"OUTSIDE", "INSIDE"};
11325 :
11326 225 : auto &s_ipsc = state.dataIPShortCut;
11327 225 : auto &s_mat = state.dataMaterial;
11328 :
11329 225 : s_ipsc->cCurrentModuleObject = "SurfaceControl:MovableInsulation";
11330 225 : int NMatInsul = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
11331 226 : for (int Loop = 1; Loop <= NMatInsul; ++Loop) {
11332 2 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
11333 1 : s_ipsc->cCurrentModuleObject,
11334 : Loop,
11335 1 : s_ipsc->cAlphaArgs,
11336 : NAlphas,
11337 1 : s_ipsc->rNumericArgs,
11338 : NNums,
11339 : IOStat,
11340 1 : s_ipsc->lNumericFieldBlanks,
11341 1 : s_ipsc->lAlphaFieldBlanks,
11342 1 : s_ipsc->cAlphaFieldNames,
11343 1 : s_ipsc->cNumericFieldNames);
11344 1 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
11345 :
11346 1 : InsulationType insulationType = static_cast<InsulationType>(getEnumValue(insulationTypeNamesUC, s_ipsc->cAlphaArgs(1)));
11347 1 : if (insulationType == InsulationType::Invalid) {
11348 0 : ShowSevereInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(1), s_ipsc->cAlphaArgs(1));
11349 0 : ErrorsFound = true;
11350 0 : continue;
11351 : }
11352 :
11353 : int SurfNum;
11354 1 : if ((SurfNum = Util::FindItemInList(s_ipsc->cAlphaArgs(2), state.dataSurface->Surface, state.dataSurface->TotSurfaces)) == 0) {
11355 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2));
11356 0 : ErrorsFound = true;
11357 0 : continue;
11358 : }
11359 :
11360 : int MaterNum;
11361 1 : if ((MaterNum = Material::GetMaterialNum(state, s_ipsc->cAlphaArgs(3))) == 0) {
11362 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3));
11363 0 : ErrorsFound = true;
11364 0 : continue;
11365 : }
11366 :
11367 1 : Sched::Schedule *sched = nullptr;
11368 1 : if (s_ipsc->lAlphaFieldBlanks(4)) {
11369 0 : ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(4));
11370 0 : ErrorsFound = true;
11371 0 : continue;
11372 1 : } else if ((sched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(4))) == nullptr) {
11373 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(4), s_ipsc->cAlphaArgs(4));
11374 0 : ErrorsFound = true;
11375 0 : continue;
11376 : }
11377 :
11378 1 : auto *thisMaterial = s_mat->materials(MaterNum);
11379 :
11380 : Array1D_string const cMaterialGroupType({-1, 18},
11381 : {"invalid",
11382 : "Material/Material:NoMass",
11383 : "Material:AirGap",
11384 : "WindowMaterial:Shade",
11385 : "WindowMaterial:Glazing*",
11386 : "WindowMaterial:Gas",
11387 : "WindowMaterial:Blind",
11388 : "WindowMaterial:GasMixture",
11389 : "WindowMaterial:Screen",
11390 : "Material:RoofVegetation",
11391 : "Material:InfraredTransparent",
11392 : "WindowMaterial:SimpleGlazingSystem",
11393 : "WindowMaterial:ComplexShade",
11394 : "WindowMaterial:Gap",
11395 : "WindowMaterial:Glazing:EquivalentLayer",
11396 : "WindowMaterial:Shade:EquivalentLayer",
11397 : "WindowMaterial:Drape:EquivalentLayer",
11398 : "WindowMaterial:Blind:EquivalentLayer",
11399 : "WindowMaterial:Screen:EquivalentLayer",
11400 1 : "WindowMaterial:Gap:EquivalentLayer"});
11401 :
11402 1 : Material::Group const MaterialLayerGroup = thisMaterial->group;
11403 1 : if ((MaterialLayerGroup == Material::Group::GlassSimple) || (MaterialLayerGroup == Material::Group::ShadeEQL) ||
11404 0 : (MaterialLayerGroup == Material::Group::DrapeEQL) || (MaterialLayerGroup == Material::Group::BlindEQL) ||
11405 0 : (MaterialLayerGroup == Material::Group::ScreenEQL) || (MaterialLayerGroup == Material::Group::WindowGapEQL)) {
11406 1 : ShowSevereError(state, format("Invalid movable insulation material for {}:", s_ipsc->cCurrentModuleObject));
11407 2 : ShowSevereError(
11408 2 : state, format("...Movable insulation material type specified = {}", cMaterialGroupType(static_cast<int>(MaterialLayerGroup))));
11409 1 : ShowSevereError(state, format("...Movable insulation material name specified = {}", s_ipsc->cAlphaArgs(3)));
11410 1 : ErrorsFound = true;
11411 : }
11412 :
11413 1 : switch (insulationType) {
11414 1 : case InsulationType::Outside: {
11415 1 : auto &movInsul = state.dataSurface->extMovInsuls(SurfNum);
11416 1 : if (movInsul.matNum > 0) {
11417 0 : ShowSevereDuplicateAssignment(
11418 0 : state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2), s_mat->materials(movInsul.matNum)->Name);
11419 0 : ErrorsFound = true;
11420 : }
11421 :
11422 1 : movInsul.matNum = MaterNum;
11423 1 : movInsul.sched = sched;
11424 1 : state.dataSurface->AnyMovableInsulation = true;
11425 1 : state.dataSurface->extMovInsulSurfNums.push_back(SurfNum);
11426 :
11427 1 : if (thisMaterial->Resistance <= 0.0) {
11428 0 : if (thisMaterial->Conductivity <= 0.0 || thisMaterial->Thickness <= 0.0) {
11429 0 : ShowSevereError(state,
11430 0 : format("{}, {}=\"{}\", invalid material.",
11431 0 : s_ipsc->cCurrentModuleObject,
11432 0 : s_ipsc->cAlphaFieldNames(2),
11433 0 : s_ipsc->cAlphaArgs(2)));
11434 0 : ShowContinueError(state, "\"Outside\", invalid material for movable insulation.");
11435 0 : ShowContinueError(state,
11436 0 : format("Material=\"{}\",Resistance=[{:.3R}], must be > 0 for use in Movable Insulation.",
11437 0 : thisMaterial->Name,
11438 0 : thisMaterial->Resistance));
11439 0 : ErrorsFound = true;
11440 0 : } else if (thisMaterial->Conductivity > 0.0) {
11441 0 : thisMaterial->Resistance = thisMaterial->Thickness / thisMaterial->Conductivity;
11442 : }
11443 : }
11444 :
11445 1 : if (thisMaterial->Conductivity <= 0.0) {
11446 0 : if (thisMaterial->Resistance <= 0.0) {
11447 0 : ShowSevereError(state,
11448 0 : format("{}, {}=\"{}\", invalid material.",
11449 0 : s_ipsc->cCurrentModuleObject,
11450 0 : s_ipsc->cAlphaFieldNames(2),
11451 0 : s_ipsc->cAlphaArgs(2)));
11452 0 : ShowContinueError(state, "\"Outside\", invalid material for movable insulation.");
11453 0 : ShowContinueError(state,
11454 0 : format("Material=\"{}\",Conductivity=[{:.3R}], must be > 0 for use in Movable Insulation.",
11455 0 : thisMaterial->Name,
11456 0 : thisMaterial->Conductivity));
11457 0 : ErrorsFound = true;
11458 : }
11459 : }
11460 1 : } break;
11461 :
11462 0 : case InsulationType::Inside: {
11463 0 : auto &movInsul = state.dataSurface->intMovInsuls(SurfNum);
11464 0 : if (movInsul.matNum > 0) {
11465 0 : ShowSevereDuplicateAssignment(
11466 0 : state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2), s_mat->materials(movInsul.matNum)->Name);
11467 0 : ErrorsFound = true;
11468 : }
11469 :
11470 0 : movInsul.matNum = MaterNum;
11471 0 : movInsul.sched = sched;
11472 0 : state.dataSurface->AnyMovableInsulation = true;
11473 0 : state.dataSurface->intMovInsulSurfNums.push_back(SurfNum);
11474 0 : if (thisMaterial->Resistance <= 0.0) {
11475 0 : if (thisMaterial->Conductivity <= 0.0 || thisMaterial->Thickness <= 0.0) {
11476 0 : ShowSevereError(state,
11477 0 : format("{}, {}=\"{}\", invalid material.",
11478 0 : s_ipsc->cCurrentModuleObject,
11479 0 : s_ipsc->cAlphaFieldNames(2),
11480 0 : s_ipsc->cAlphaArgs(2)));
11481 0 : ShowContinueError(state, "\"Inside\", invalid material for movable insulation.");
11482 0 : ShowContinueError(state,
11483 0 : format("Material=\"{}\",Resistance=[{:.3R}], must be > 0 for use in Movable Insulation.",
11484 0 : thisMaterial->Name,
11485 0 : thisMaterial->Resistance));
11486 0 : ErrorsFound = true;
11487 0 : } else if (thisMaterial->Conductivity > 0.0) {
11488 0 : thisMaterial->Resistance = thisMaterial->Thickness / thisMaterial->Conductivity;
11489 : }
11490 : }
11491 0 : } break;
11492 0 : default: {
11493 0 : assert(false);
11494 : } break;
11495 : } // switch (inulationType)
11496 :
11497 1 : if (state.dataSurface->Surface(SurfNum).Class == SurfaceClass::Window) {
11498 0 : ShowSevereError(state, format("{}, {}=\"{}\"", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2)));
11499 0 : ShowContinueError(state, "invalid use on a Window. Use WindowShadingControl instead.");
11500 0 : ErrorsFound = true;
11501 : }
11502 1 : } // for (Loop)
11503 225 : } // GetMovableInsulationData()
11504 :
11505 : // Calculates the volume (m3) of a zone using the surfaces as possible.
11506 197 : void CalculateZoneVolume(EnergyPlusData &state)
11507 : {
11508 : // SUBROUTINE INFORMATION:
11509 : // AUTHOR Legacy Code
11510 : // DATE WRITTEN 1992-1994
11511 : // MODIFIED Sep 2007, Mar 2017
11512 :
11513 : // METHODOLOGY EMPLOYED:
11514 : // Uses surface area information for calculations. Modified to use the
11515 : // user-entered ceiling height (x floor area, if applicable) instead of using
11516 : // the calculated volume when the user enters the ceiling height.
11517 :
11518 : // REFERENCES:
11519 : // Legacy Code (IBLAST)
11520 :
11521 197 : Vectors::Polyhedron ZoneStruct;
11522 197 : bool initmsg = true;
11523 394 : bool ShowZoneSurfaces = (state.dataInputProcessing->inputProcessor->getNumSectionsFound("SHOWZONESURFACES_DEBUG") > 0);
11524 197 : EPVector<int> surfacenotused;
11525 :
11526 : enum class ZoneVolumeCalcMethod
11527 : {
11528 : Invalid = -1,
11529 : Enclosed,
11530 : FloorAreaTimesHeight1,
11531 : FloorAreaTimesHeight2,
11532 : CeilingAreaTimesHeight,
11533 : OpWallAreaTimesDistance,
11534 : UserProvided,
11535 : Num
11536 : };
11537 :
11538 197 : int countNotFullyEnclosedZones = 0;
11539 477 : for (auto &thisZone : state.dataHeatBal->Zone) {
11540 280 : if (!thisZone.HasFloor) {
11541 32 : ShowWarningError(state,
11542 32 : format("No floor exists in Zone=\"{}\", zone floor area is zero. All values for this zone that are entered per "
11543 : "floor area will be zero.",
11544 16 : thisZone.Name));
11545 : }
11546 :
11547 280 : Real64 SumAreas = 0.0;
11548 280 : Real64 CalcVolume = 0.0;
11549 : // Use AllSurfaceFirst which includes air boundaries
11550 280 : int NFaces = thisZone.AllSurfaceLast - thisZone.AllSurfaceFirst + 1;
11551 280 : int notused = 0;
11552 280 : ZoneStruct.NumSurfaceFaces = NFaces;
11553 280 : ZoneStruct.SurfaceFace.allocate(NFaces);
11554 280 : int NActFaces = 0;
11555 280 : surfacenotused.dimension(NFaces, 0);
11556 :
11557 1922 : for (int SurfNum = thisZone.AllSurfaceFirst; SurfNum <= thisZone.AllSurfaceLast; ++SurfNum) {
11558 1642 : assert(SurfNum > 0);
11559 1642 : auto &thisSurface = state.dataSurface->Surface(SurfNum);
11560 : // Only include Base Surfaces in Calc.
11561 :
11562 1642 : if (thisSurface.Class != SurfaceClass::Wall && thisSurface.Class != SurfaceClass::Floor && thisSurface.Class != SurfaceClass::Roof) {
11563 145 : ++notused;
11564 145 : surfacenotused(notused) = SurfNum;
11565 145 : continue;
11566 : }
11567 :
11568 1497 : ++NActFaces;
11569 1497 : auto &thisFace = ZoneStruct.SurfaceFace(NActFaces);
11570 1497 : thisFace.FacePoints.allocate(thisSurface.Sides);
11571 1497 : thisFace.NSides = thisSurface.Sides;
11572 1497 : thisFace.SurfNum = SurfNum;
11573 1497 : thisFace.FacePoints({1, thisSurface.Sides}) = thisSurface.Vertex({1, thisSurface.Sides});
11574 1497 : Vectors::CreateNewellAreaVector(thisFace.FacePoints, thisFace.NSides, thisFace.NewellAreaVector);
11575 1497 : SumAreas += Vectors::VecLength(thisFace.NewellAreaVector);
11576 : }
11577 280 : ZoneStruct.NumSurfaceFaces = NActFaces;
11578 :
11579 280 : bool isFloorHorizontal = false;
11580 280 : bool isCeilingHorizontal = false;
11581 280 : bool areWallsVertical = false;
11582 280 : std::tie(isFloorHorizontal, isCeilingHorizontal, areWallsVertical) = areSurfaceHorizAndVert(state, ZoneStruct);
11583 280 : Real64 oppositeWallArea = 0.0;
11584 280 : Real64 distanceBetweenOppositeWalls = 0.0;
11585 :
11586 280 : bool areWallsSameHeight = areWallHeightSame(state, ZoneStruct);
11587 :
11588 280 : std::vector<EdgeOfSurf> listOfedgeNotUsedTwice;
11589 280 : bool isZoneEnclosed = isEnclosedVolume(ZoneStruct, listOfedgeNotUsedTwice);
11590 : ZoneVolumeCalcMethod volCalcMethod;
11591 :
11592 280 : Real64 floorAreaForVolume = (thisZone.FloorArea > 0.0) ? thisZone.FloorArea : thisZone.geometricFloorArea;
11593 280 : Real64 ceilingAreaForVolume = (thisZone.CeilingArea > 0.0) ? thisZone.CeilingArea : thisZone.geometricCeilingArea;
11594 :
11595 280 : if (isZoneEnclosed) {
11596 185 : CalcVolume = Vectors::CalcPolyhedronVolume(state, ZoneStruct);
11597 185 : volCalcMethod = ZoneVolumeCalcMethod::Enclosed;
11598 95 : } else if (floorAreaForVolume > 0.0 && thisZone.CeilingHeight > 0.0 && areFloorAndCeilingSame(state, ZoneStruct)) {
11599 18 : CalcVolume = floorAreaForVolume * thisZone.CeilingHeight;
11600 18 : volCalcMethod = ZoneVolumeCalcMethod::FloorAreaTimesHeight1;
11601 77 : } else if (isFloorHorizontal && areWallsVertical && areWallsSameHeight && floorAreaForVolume > 0.0 && thisZone.CeilingHeight > 0.0) {
11602 54 : CalcVolume = floorAreaForVolume * thisZone.CeilingHeight;
11603 54 : volCalcMethod = ZoneVolumeCalcMethod::FloorAreaTimesHeight2;
11604 23 : } else if (isCeilingHorizontal && areWallsVertical && areWallsSameHeight && ceilingAreaForVolume > 0.0 && thisZone.CeilingHeight > 0.0) {
11605 4 : CalcVolume = ceilingAreaForVolume * thisZone.CeilingHeight;
11606 4 : volCalcMethod = ZoneVolumeCalcMethod::CeilingAreaTimesHeight;
11607 19 : } else if (areOppositeWallsSame(state, ZoneStruct, oppositeWallArea, distanceBetweenOppositeWalls)) {
11608 2 : CalcVolume = oppositeWallArea * distanceBetweenOppositeWalls;
11609 2 : volCalcMethod = ZoneVolumeCalcMethod::OpWallAreaTimesDistance;
11610 17 : } else if (thisZone.Volume == Constant::AutoCalculate) { // no user entered zone volume
11611 24 : ShowSevereError(state,
11612 24 : format("For zone: {} it is not possible to calculate the volume from the surrounding surfaces so either provide the "
11613 : "volume value or define all the surfaces to fully enclose the zone.",
11614 12 : thisZone.Name));
11615 12 : CalcVolume = 0.;
11616 12 : volCalcMethod = ZoneVolumeCalcMethod::Invalid;
11617 : } else {
11618 5 : CalcVolume = 0.;
11619 5 : volCalcMethod = ZoneVolumeCalcMethod::UserProvided;
11620 : }
11621 280 : if (!isZoneEnclosed) {
11622 95 : ++countNotFullyEnclosedZones;
11623 95 : if (state.dataGlobal->DisplayExtraWarnings) { // report missing
11624 8 : ShowWarningError(state,
11625 8 : format("CalculateZoneVolume: The Zone=\"{}\" is not fully enclosed. To be fully enclosed, each edge of a "
11626 : "surface must also be an edge on one other surface.",
11627 4 : thisZone.Name));
11628 4 : switch (volCalcMethod) {
11629 1 : case ZoneVolumeCalcMethod::FloorAreaTimesHeight1:
11630 2 : ShowContinueError(state,
11631 : " The zone volume was calculated using the floor area times ceiling height method where the floor and "
11632 : "ceiling are the same except for the z-coordinates.");
11633 1 : break;
11634 0 : case ZoneVolumeCalcMethod::FloorAreaTimesHeight2:
11635 0 : ShowContinueError(state,
11636 : " The zone volume was calculated using the floor area times ceiling height method where the floor is "
11637 : "horizontal, the walls are vertical, and the wall heights are all the same.");
11638 0 : break;
11639 3 : case ZoneVolumeCalcMethod::CeilingAreaTimesHeight:
11640 6 : ShowContinueError(state,
11641 : " The zone volume was calculated using the ceiling area times ceiling height method where the ceiling is "
11642 : "horizontal, the walls are vertical, and the wall heights are all the same.");
11643 3 : break;
11644 0 : case ZoneVolumeCalcMethod::OpWallAreaTimesDistance:
11645 0 : ShowContinueError(state,
11646 : " The zone volume was calculated using the opposite wall area times the distance between them method ");
11647 0 : break;
11648 0 : case ZoneVolumeCalcMethod::UserProvided:
11649 0 : ShowContinueError(state, " The zone volume was provided as an input to the ZONE object ");
11650 0 : break;
11651 0 : case ZoneVolumeCalcMethod::Invalid:
11652 0 : ShowContinueError(state, " The zone volume was not calculated and an error exists. ");
11653 0 : break;
11654 0 : case ZoneVolumeCalcMethod::Enclosed: // should not be called but completes enumeration
11655 0 : ShowContinueError(state, " The zone volume was calculated using multiple pyramids and was fully enclosed. ");
11656 0 : break;
11657 0 : default:
11658 0 : assert(false);
11659 : }
11660 28 : for (auto &edge : listOfedgeNotUsedTwice) {
11661 24 : if (edge.count < 2) {
11662 24 : ShowContinueError(
11663 : state,
11664 24 : fmt::format(" The surface \"{}\" has an edge that was used only once: it is not an edge on another surface",
11665 24 : state.dataSurface->Surface(edge.surfNum).Name));
11666 :
11667 : } else {
11668 0 : ShowContinueError(
11669 : state,
11670 0 : fmt::format(" The surface \"{}\" has an edge that was used {} times: it is an edge on three or more surfaces: ",
11671 0 : state.dataSurface->Surface(edge.surfNum).Name,
11672 0 : edge.count));
11673 0 : std::string surfaceNames = " It was found on the following Surfaces: ";
11674 0 : for (int surfNum : edge.otherSurfNums) {
11675 0 : surfaceNames += fmt::format("'{}' ", state.dataSurface->Surface(surfNum).Name);
11676 : }
11677 0 : ShowContinueError(state, surfaceNames);
11678 0 : }
11679 24 : ShowContinueError(state, format(" Vertex start {{ {:.4R}, {:.4R}, {:.4R}}}", edge.start.x, edge.start.y, edge.start.z));
11680 24 : ShowContinueError(state, format(" Vertex end {{ {:.4R}, {:.4R}, {:.4R}}}", edge.end.x, edge.end.y, edge.end.z));
11681 : }
11682 : }
11683 : }
11684 280 : if (thisZone.Volume > 0.0) { // User entered zone volume, produce message if not near calculated
11685 43 : if (CalcVolume > 0.0) {
11686 36 : if (std::abs(CalcVolume - thisZone.Volume) / thisZone.Volume > 0.05) {
11687 8 : ++state.dataSurfaceGeometry->ErrCount5;
11688 8 : if (state.dataSurfaceGeometry->ErrCount5 == 1 && !state.dataGlobal->DisplayExtraWarnings) {
11689 8 : if (initmsg) {
11690 16 : ShowMessage(state,
11691 : "Note that the following warning(s) may/will occur if you have not enclosed your zone completely.");
11692 8 : initmsg = false;
11693 : }
11694 16 : ShowWarningError(state, "Entered Zone Volumes differ from calculated zone volume(s).");
11695 24 : ShowContinueError(state, "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on individual zones.");
11696 : }
11697 8 : if (state.dataGlobal->DisplayExtraWarnings) {
11698 0 : if (initmsg) {
11699 0 : ShowMessage(state,
11700 : "Note that the following warning(s) may/will occur if you have not enclosed your zone completely.");
11701 0 : initmsg = false;
11702 : }
11703 : // Warn user of using specified Zone Volume
11704 0 : ShowWarningError(
11705 : state,
11706 0 : format("Entered Volume entered for Zone=\"{}\" significantly different from calculated Volume", thisZone.Name));
11707 0 : ShowContinueError(state,
11708 0 : format("Entered Zone Volume value={:.2R}, Calculated Zone Volume value={:.2R}, entered volume will be "
11709 : "used in calculations.",
11710 0 : thisZone.Volume,
11711 : CalcVolume));
11712 : }
11713 : }
11714 : }
11715 237 : } else if (thisZone.ceilingHeightEntered) { // User did not enter zone volume, but entered ceiling height
11716 33 : if (floorAreaForVolume > 0.0) {
11717 30 : thisZone.Volume = floorAreaForVolume * thisZone.CeilingHeight;
11718 : } else { // ceiling height entered but floor area zero
11719 3 : thisZone.Volume = CalcVolume;
11720 : }
11721 : } else { // Neither ceiling height nor volume entered
11722 204 : thisZone.Volume = CalcVolume;
11723 : }
11724 :
11725 280 : if (thisZone.Volume <= 0.0) {
11726 16 : ShowWarningError(state, format("Indicated Zone Volume <= 0.0 for Zone={}", thisZone.Name));
11727 16 : ShowContinueError(state, format("The calculated Zone Volume was={:.2R}", thisZone.Volume));
11728 32 : ShowContinueError(state, "The simulation will continue with the Zone Volume set to 10.0 m3. ");
11729 32 : ShowContinueError(state, "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on individual zones.");
11730 16 : thisZone.Volume = 10.;
11731 : }
11732 : // For now - pro-rate space volumes by floor area, if not entered
11733 581 : for (int spaceNum : thisZone.spaceIndexes) {
11734 301 : auto &thisSpace = state.dataHeatBal->space(spaceNum);
11735 : // don't touch if already user-specified
11736 301 : if (thisSpace.Volume > 0.0) continue;
11737 300 : if (thisZone.numSpaces == 1) {
11738 260 : thisSpace.Volume = thisZone.Volume;
11739 40 : } else if (thisZone.geometricFloorArea > 0.0) {
11740 36 : thisSpace.Volume = thisZone.Volume * thisSpace.FloorArea / thisZone.geometricFloorArea;
11741 : }
11742 : }
11743 280 : Real64 totSpacesVolume = 0.0;
11744 581 : for (int spaceNum : thisZone.spaceIndexes) {
11745 301 : totSpacesVolume += state.dataHeatBal->space(spaceNum).Volume;
11746 : }
11747 280 : if (totSpacesVolume > 0.0) {
11748 572 : for (int spaceNum : thisZone.spaceIndexes) {
11749 297 : state.dataHeatBal->space(spaceNum).fracZoneVolume = state.dataHeatBal->space(spaceNum).Volume / totSpacesVolume;
11750 : }
11751 : } // else leave fractions at zero
11752 :
11753 280 : if (ShowZoneSurfaces) {
11754 0 : if (state.dataSurfaceGeometry->ShowZoneSurfaceHeaders) {
11755 0 : print(state.files.debug, "{}\n", "===================================");
11756 0 : print(state.files.debug, "{}\n", "showing zone surfaces used and not used in volume calculation");
11757 0 : print(state.files.debug, "{}\n", "for volume calculation, only floors, walls and roofs/ceilings are used");
11758 0 : print(state.files.debug, "{}\n", "surface class, 1=wall, 2=floor, 3=roof/ceiling");
11759 0 : print(state.files.debug, "{}\n", "unused surface class(es), 5=internal mass, 11=window, 12=glass door");
11760 0 : print(state.files.debug, "{}\n", " 13=door, 14=shading, 15=overhang, 16=fin");
11761 0 : print(state.files.debug, "{}\n", " 17=TDD Dome, 18=TDD Diffuser");
11762 0 : state.dataSurfaceGeometry->ShowZoneSurfaceHeaders = false;
11763 : }
11764 0 : print(state.files.debug, "{}\n", "===================================");
11765 0 : print(state.files.debug, "zone={} calc volume={}\n", thisZone.Name, CalcVolume);
11766 0 : print(state.files.debug, " nsurfaces={} nactual={}\n", NFaces, NActFaces);
11767 : }
11768 1777 : for (int faceNum = 1; faceNum <= ZoneStruct.NumSurfaceFaces; ++faceNum) {
11769 1497 : auto &thisFace = ZoneStruct.SurfaceFace(faceNum);
11770 1497 : if (ShowZoneSurfaces) {
11771 0 : if (faceNum <= NActFaces) {
11772 0 : auto &thisSurface = state.dataSurface->Surface(thisFace.SurfNum);
11773 0 : print(state.files.debug, "surface={} nsides={}\n", thisFace.SurfNum, thisFace.NSides);
11774 0 : print(state.files.debug, "surface name={} class={}\n", thisSurface.Name, thisSurface.Class);
11775 0 : print(state.files.debug, "area={}\n", thisSurface.GrossArea);
11776 0 : for (int iside = 1; iside <= thisFace.NSides; ++iside) {
11777 0 : auto const &FacePoint(thisFace.FacePoints(iside));
11778 0 : print(state.files.debug, "{} {} {}\n", FacePoint.x, FacePoint.y, FacePoint.z);
11779 : }
11780 : }
11781 : }
11782 1497 : thisFace.FacePoints.deallocate();
11783 : }
11784 280 : if (ShowZoneSurfaces) {
11785 0 : for (int SurfNum = 1; SurfNum <= notused; ++SurfNum) {
11786 0 : print(state.files.debug,
11787 : "notused:surface={} name={} class={}\n",
11788 : surfacenotused(SurfNum),
11789 0 : state.dataSurface->Surface(surfacenotused(SurfNum)).Name,
11790 0 : state.dataSurface->Surface(surfacenotused(SurfNum)).Class);
11791 : }
11792 : }
11793 :
11794 280 : ZoneStruct.SurfaceFace.deallocate();
11795 280 : surfacenotused.deallocate();
11796 :
11797 280 : } // zone loop
11798 197 : if (!state.dataGlobal->DisplayExtraWarnings) {
11799 184 : if (countNotFullyEnclosedZones == 1) {
11800 138 : ShowWarningError(
11801 : state, "CalculateZoneVolume: 1 zone is not fully enclosed. For more details use: Output:Diagnostics,DisplayExtrawarnings; ");
11802 138 : } else if (countNotFullyEnclosedZones > 1) {
11803 28 : ShowWarningError(state,
11804 28 : format("CalculateZoneVolume: {} zones are not fully enclosed. For more details use: "
11805 : "Output:Diagnostics,DisplayExtrawarnings; ",
11806 : countNotFullyEnclosedZones));
11807 : }
11808 : }
11809 197 : }
11810 :
11811 : // test if the volume described by the polyhedron if full enclosed (would not leak)
11812 285 : bool isEnclosedVolume(DataVectorTypes::Polyhedron const &zonePoly, std::vector<EdgeOfSurf> &edgeNot2)
11813 : {
11814 : // J. Glazer - March 2017
11815 :
11816 285 : std::vector<Vector> uniqueVertices = makeListOfUniqueVertices(zonePoly);
11817 :
11818 285 : std::vector<EdgeOfSurf> edgeNot2orig = edgesNotTwoForEnclosedVolumeTest(zonePoly, uniqueVertices);
11819 : // if all edges had two counts then it is fully enclosed
11820 285 : if (edgeNot2orig.empty()) {
11821 178 : edgeNot2 = edgeNot2orig;
11822 178 : return true;
11823 : } 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
11824 : // on the "other side" of the edge Go through all the points looking for the number that are colinear and see if that is
11825 : // consistent with the number of edges found that didn't have a count of two
11826 : DataVectorTypes::Polyhedron updatedZonePoly = updateZonePolygonsForMissingColinearPoints(
11827 107 : zonePoly, uniqueVertices); // this is done after initial test since it is computationally intensive.
11828 107 : std::vector<EdgeOfSurf> edgeNot2again = edgesNotTwoForEnclosedVolumeTest(updatedZonePoly, uniqueVertices);
11829 107 : if (edgeNot2again.empty()) {
11830 10 : return true;
11831 : } else {
11832 194 : edgeNot2 = edgesInBoth(edgeNot2orig,
11833 97 : edgeNot2again); // only return a list of those edges that appear in both the original edge and the
11834 : // revised edges this eliminates added edges that will confuse users and edges that
11835 : // were caught by the updateZonePoly routine
11836 97 : return false;
11837 : }
11838 107 : }
11839 285 : }
11840 :
11841 : // returns a vector of edges that are in both vectors
11842 97 : std::vector<EdgeOfSurf> edgesInBoth(std::vector<EdgeOfSurf> const &edges1, std::vector<EdgeOfSurf> const &edges2)
11843 : {
11844 : // J. Glazer - June 2017
11845 : // this is not optimized but the number of edges for a typical polyhedron is 12 and is probably rarely bigger than 20.
11846 :
11847 97 : std::vector<EdgeOfSurf> inBoth;
11848 697 : for (const auto &e1 : edges1) {
11849 2660 : for (const auto &e2 : edges2) {
11850 2586 : if (edgesEqualOnSameSurface(e1, e2)) {
11851 526 : inBoth.push_back(e1);
11852 526 : break;
11853 : }
11854 : }
11855 : }
11856 97 : return inBoth;
11857 0 : }
11858 :
11859 : // returns true if the edges match - including the surface number
11860 2586 : bool edgesEqualOnSameSurface(EdgeOfSurf a, EdgeOfSurf b)
11861 : {
11862 2586 : if (a.surfNum != b.surfNum) {
11863 1344 : return false;
11864 : }
11865 :
11866 : // vertex comparison (we compare indices, so absolute equal)
11867 1242 : return ((a.start == b.start && a.end == b.end) || (a.start == b.end && a.end == b.start));
11868 : }
11869 :
11870 : // returns the number of times the edges of the polyhedron of the zone are not used twice by the sides
11871 396 : std::vector<EdgeOfSurf> edgesNotTwoForEnclosedVolumeTest(DataVectorTypes::Polyhedron const &zonePoly, std::vector<Vector> const &uniqueVertices)
11872 : {
11873 : // J. Glazer - March 2017
11874 :
11875 : struct EdgeByPts
11876 : {
11877 : int start;
11878 : int end;
11879 : int count;
11880 : int firstSurfNum;
11881 : std::vector<int> otherSurfNums;
11882 4234 : EdgeByPts() : start(0), end(0), count(0), firstSurfNum(0)
11883 : {
11884 4234 : }
11885 : };
11886 396 : std::vector<EdgeByPts> uniqueEdges;
11887 396 : uniqueEdges.reserve(zonePoly.NumSurfaceFaces * 6);
11888 :
11889 : // construct list of unique edges
11890 396 : Vector curVertex;
11891 : int curVertexIndex;
11892 2419 : for (int iFace = 1; iFace <= zonePoly.NumSurfaceFaces; ++iFace) {
11893 2023 : Vector prevVertex;
11894 : int prevVertexIndex;
11895 10248 : for (int jVertex = 1; jVertex <= zonePoly.SurfaceFace(iFace).NSides; ++jVertex) {
11896 8225 : if (jVertex == 1) {
11897 2023 : prevVertex = zonePoly.SurfaceFace(iFace).FacePoints(zonePoly.SurfaceFace(iFace).NSides); // the last point
11898 2023 : prevVertexIndex = findIndexOfVertex(prevVertex, uniqueVertices);
11899 : } else {
11900 6202 : prevVertex = curVertex;
11901 6202 : prevVertexIndex = curVertexIndex;
11902 : }
11903 8225 : curVertex = zonePoly.SurfaceFace(iFace).FacePoints(jVertex);
11904 8225 : curVertexIndex = findIndexOfVertex(curVertex, uniqueVertices); // uses isAlmostEqual3dPt
11905 8225 : auto it = std::find_if(uniqueEdges.begin(), uniqueEdges.end(), [&curVertexIndex, &prevVertexIndex](const auto &edge) {
11906 99782 : return ((edge.start == curVertexIndex && edge.end == prevVertexIndex) ||
11907 99782 : (edge.start == prevVertexIndex && edge.end == curVertexIndex));
11908 : });
11909 8225 : if (it == uniqueEdges.end()) {
11910 4234 : EdgeByPts curEdge;
11911 4234 : curEdge.start = prevVertexIndex;
11912 4234 : curEdge.end = curVertexIndex;
11913 4234 : curEdge.count = 1;
11914 4234 : curEdge.firstSurfNum = zonePoly.SurfaceFace(iFace).SurfNum;
11915 4234 : uniqueEdges.emplace_back(curEdge);
11916 4234 : } else {
11917 3991 : ++(it->count);
11918 3991 : it->otherSurfNums.push_back(zonePoly.SurfaceFace(iFace).SurfNum);
11919 : }
11920 : }
11921 2023 : }
11922 : // All edges for an enclosed polyhedron should be shared by two (and only two) sides.
11923 : // So if the count is not two for all edges, the polyhedron is not enclosed
11924 396 : std::vector<EdgeOfSurf> edgesNotTwoCount;
11925 4630 : for (const auto &anEdge : uniqueEdges) {
11926 4234 : if (anEdge.count != 2) {
11927 1259 : EdgeOfSurf curEdgeOne;
11928 1259 : curEdgeOne.surfNum = anEdge.firstSurfNum;
11929 1259 : curEdgeOne.start = uniqueVertices[anEdge.start];
11930 1259 : curEdgeOne.end = uniqueVertices[anEdge.end];
11931 1259 : curEdgeOne.count = anEdge.count;
11932 1259 : curEdgeOne.otherSurfNums = anEdge.otherSurfNums;
11933 1259 : edgesNotTwoCount.push_back(curEdgeOne);
11934 1259 : }
11935 : }
11936 792 : return edgesNotTwoCount;
11937 396 : }
11938 :
11939 : // create a list of unique vertices given the polyhedron describing the zone
11940 289 : std::vector<Vector> makeListOfUniqueVertices(DataVectorTypes::Polyhedron const &zonePoly)
11941 : {
11942 : // J. Glazer - March 2017
11943 :
11944 289 : std::vector<Vector> uniqVertices;
11945 289 : uniqVertices.reserve(zonePoly.NumSurfaceFaces * 6);
11946 :
11947 1844 : for (int iFace = 1; iFace <= zonePoly.NumSurfaceFaces; ++iFace) {
11948 7781 : for (int jVertex = 1; jVertex <= zonePoly.SurfaceFace(iFace).NSides; ++jVertex) {
11949 6226 : Vector curVertex = zonePoly.SurfaceFace(iFace).FacePoints(jVertex);
11950 6226 : if (uniqVertices.size() == 0) {
11951 286 : uniqVertices.emplace_back(curVertex);
11952 : } else {
11953 5940 : bool found = false;
11954 28502 : for (const auto &unqV : uniqVertices) {
11955 26568 : if (isAlmostEqual3dPt(curVertex, unqV)) {
11956 4006 : found = true;
11957 4006 : break;
11958 : }
11959 : }
11960 5940 : if (!found) {
11961 1934 : uniqVertices.emplace_back(curVertex);
11962 : }
11963 : }
11964 6226 : }
11965 : }
11966 289 : return uniqVertices;
11967 0 : }
11968 :
11969 : // updates the polyhedron used to describe a zone to include points on an edge that are between and collinear to points already describing
11970 : // the edge
11971 108 : DataVectorTypes::Polyhedron updateZonePolygonsForMissingColinearPoints(DataVectorTypes::Polyhedron const &zonePoly,
11972 : std::vector<Vector> const &uniqVertices)
11973 : {
11974 : // J. Glazer - March 2017
11975 :
11976 108 : DataVectorTypes::Polyhedron updZonePoly = zonePoly; // set the return value to the original polyhedron describing the zone
11977 :
11978 639 : for (auto &updFace : updZonePoly.SurfaceFace) {
11979 531 : bool insertedVertext = true;
11980 1732 : while (insertedVertext) {
11981 670 : insertedVertext = false;
11982 670 : auto &vertices = updFace.FacePoints;
11983 2948 : for (auto it = vertices.begin(); it != vertices.end(); ++it) {
11984 :
11985 2417 : auto itnext = std::next(it);
11986 2417 : if (itnext == std::end(vertices)) {
11987 514 : itnext = std::begin(vertices);
11988 : }
11989 :
11990 2417 : auto curVertex = *it; // (AUTO_OK_OBJ) can't tell if a copy is the intended behavior here
11991 2417 : auto nextVertex = *itnext; // (AUTO_OK_OBJ)
11992 :
11993 : // now go through all the vertices and see if they are colinear with start and end vertices
11994 24055 : for (const auto &testVertex : uniqVertices) {
11995 21777 : if (!isAlmostEqual3dPt(curVertex, testVertex) && !isAlmostEqual3dPt(nextVertex, testVertex)) {
11996 17059 : if (isPointOnLineBetweenPoints(curVertex, nextVertex, testVertex)) {
11997 139 : vertices.insert(itnext, testVertex);
11998 139 : ++updFace.NSides;
11999 139 : insertedVertext = true;
12000 139 : break;
12001 : }
12002 : }
12003 : }
12004 : // Break out of the loop on vertices of the surface too, and start again at the while
12005 2417 : if (insertedVertext) {
12006 139 : break;
12007 : }
12008 2556 : }
12009 : }
12010 : }
12011 108 : return updZonePoly;
12012 0 : }
12013 :
12014 : // test if the ceiling and floor are the same except for their height difference by looking at the corners
12015 77 : bool areFloorAndCeilingSame(EnergyPlusData &state, DataVectorTypes::Polyhedron const &zonePoly)
12016 : {
12017 : // J. Glazer - March 2017
12018 :
12019 : // check if the floor and ceiling are the same
12020 : // this is almost equivalent to saying, if you ignore the z-coordinate, are the vertices the same
12021 : // so if you could all the unique vertices of the floor and ceiling, ignoring the z-coordinate, they
12022 : // should always be even (they would be two but you might define multiple surfaces that meet in a corner)
12023 :
12024 77 : std::vector<DataVectorTypes::Vector2dCount> floorCeilingXY;
12025 77 : floorCeilingXY.reserve(zonePoly.NumSurfaceFaces * 6);
12026 :
12027 : // make list of x and y coordinates for all faces that are on the floor or ceiling
12028 428 : for (int iFace = 1; iFace <= zonePoly.NumSurfaceFaces; ++iFace) {
12029 351 : int curSurfNum = zonePoly.SurfaceFace(iFace).SurfNum;
12030 579 : if (state.dataSurface->Surface(curSurfNum).Class == SurfaceClass::Floor ||
12031 228 : state.dataSurface->Surface(curSurfNum).Class == SurfaceClass::Roof) {
12032 928 : for (int jVertex = 1; jVertex <= zonePoly.SurfaceFace(iFace).NSides; ++jVertex) {
12033 742 : Vector curVertex = zonePoly.SurfaceFace(iFace).FacePoints(jVertex);
12034 742 : DataVectorTypes::Vector2dCount curXYc;
12035 742 : curXYc.x = curVertex.x;
12036 742 : curXYc.y = curVertex.y;
12037 742 : curXYc.count = 1;
12038 742 : bool found = false;
12039 2376 : for (DataVectorTypes::Vector2dCount &curFloorCeiling : floorCeilingXY) { // can't use just "auto" because updating floorCeilingXY
12040 2019 : if (isAlmostEqual2dPt(curXYc, curFloorCeiling)) { // count ignored in comparison
12041 385 : ++curFloorCeiling.count;
12042 385 : found = true;
12043 385 : break;
12044 : }
12045 : }
12046 742 : if (!found) {
12047 357 : floorCeilingXY.emplace_back(curXYc);
12048 : }
12049 742 : }
12050 : }
12051 : }
12052 : // now make sure every point has been counted and even number of times (usually twice)
12053 : // if they are then the ceiling and floor are (almost certainly) the same x and y coordinates.
12054 77 : bool areFlrAndClgSame = true;
12055 77 : if (floorCeilingXY.size() > 0) {
12056 188 : for (auto const &curFloorCeiling : floorCeilingXY) {
12057 169 : if (curFloorCeiling.count % 2 != 0) {
12058 57 : areFlrAndClgSame = false;
12059 57 : break;
12060 : }
12061 : }
12062 : } else {
12063 1 : areFlrAndClgSame = false;
12064 : }
12065 77 : return areFlrAndClgSame;
12066 77 : }
12067 :
12068 : // test if the walls of a zone are all the same height using the polyhedron describing the zone geometry
12069 288 : bool areWallHeightSame(EnergyPlusData &state, DataVectorTypes::Polyhedron const &zonePoly)
12070 : {
12071 : // J. Glazer - March 2017
12072 :
12073 : // test if all the wall heights are the same (all walls have the same maximum z-coordinate
12074 :
12075 288 : bool areWlHgtSame = true;
12076 288 : Real64 wallHeightZ = -Constant::BigNumber;
12077 288 : bool foundWallHeight = false;
12078 1717 : for (int iFace = 1; iFace <= zonePoly.NumSurfaceFaces; ++iFace) {
12079 1445 : int curSurfNum = zonePoly.SurfaceFace(iFace).SurfNum;
12080 1445 : if (state.dataSurface->Surface(curSurfNum).Class == SurfaceClass::Wall) {
12081 908 : Real64 maxZ = -Constant::BigNumber;
12082 4543 : for (int jVertex = 1; jVertex <= zonePoly.SurfaceFace(iFace).NSides; ++jVertex) {
12083 3635 : Vector curVertex = zonePoly.SurfaceFace(iFace).FacePoints(jVertex);
12084 3635 : if (maxZ < curVertex.z) {
12085 992 : maxZ = curVertex.z;
12086 : }
12087 3635 : }
12088 908 : if (foundWallHeight) {
12089 637 : if (std::abs(maxZ - wallHeightZ) > Constant::TwoCentimeters) {
12090 16 : areWlHgtSame = false;
12091 16 : break;
12092 : }
12093 : } else {
12094 271 : wallHeightZ = maxZ;
12095 271 : foundWallHeight = true;
12096 : }
12097 : }
12098 : }
12099 288 : return areWlHgtSame;
12100 : }
12101 :
12102 : // tests if the floor is horizontal, ceiling is horizontal, and walls are vertical and returns all three as a tuple of booleans
12103 292 : std::tuple<bool, bool, bool> areSurfaceHorizAndVert(EnergyPlusData &state, DataVectorTypes::Polyhedron const &zonePoly)
12104 : {
12105 : // J. Glazer - March 2017
12106 :
12107 : // check if floors and ceilings are horizontal and walls are vertical
12108 292 : bool isFlrHoriz = true;
12109 292 : bool isClgHoriz = true;
12110 292 : bool areWlVert = true;
12111 1897 : for (int iFace = 1; iFace <= zonePoly.NumSurfaceFaces; ++iFace) {
12112 1605 : int curSurfNum = zonePoly.SurfaceFace(iFace).SurfNum;
12113 1605 : if (state.dataSurface->Surface(curSurfNum).Class == SurfaceClass::Floor) {
12114 355 : if (std::abs(state.dataSurface->Surface(curSurfNum).Tilt - 180.) > 1.) { // with 1 degree angle
12115 25 : isFlrHoriz = false;
12116 : }
12117 1250 : } else if (state.dataSurface->Surface(curSurfNum).Class == SurfaceClass::Roof) { // includes ceilings
12118 296 : if (std::abs(state.dataSurface->Surface(curSurfNum).Tilt) > 1.) { // with 1 degree angle of
12119 58 : isClgHoriz = false;
12120 : }
12121 954 : } else if (state.dataSurface->Surface(curSurfNum).Class == SurfaceClass::Wall) {
12122 954 : if (std::abs(state.dataSurface->Surface(curSurfNum).Tilt - 90) > 1.) { // with 1 degree angle
12123 32 : areWlVert = false;
12124 : }
12125 : }
12126 : }
12127 584 : return std::make_tuple(isFlrHoriz, isClgHoriz, areWlVert);
12128 : }
12129 :
12130 : // tests whether a pair of walls in the zone are the same except offset from one another and facing the opposite direction and also
12131 : // returns the wall area and distance between
12132 25 : bool areOppositeWallsSame(EnergyPlusData &state,
12133 : DataVectorTypes::Polyhedron const &zonePoly,
12134 : Real64 &oppositeWallArea, // return the area of the wall that has an opposite wall
12135 : Real64 &distanceBetweenOppositeWalls // returns distance
12136 : )
12137 : {
12138 : // J. Glazer - March 2017
12139 :
12140 : // approach: if opposite surfaces have opposite azimuth and same area, then check the distance between the
12141 : // vertices( one counting backwards ) and if it is the same distance than assume that it is the same.
12142 25 : bool foundOppEqual = false;
12143 76 : for (int iFace = 1; iFace <= zonePoly.NumSurfaceFaces; ++iFace) {
12144 57 : int curSurfNum = zonePoly.SurfaceFace(iFace).SurfNum;
12145 57 : if (state.dataSurface->Surface(curSurfNum).Class == SurfaceClass::Wall) {
12146 31 : std::vector<int> facesAtAz = listOfFacesFacingAzimuth(state, zonePoly, state.dataSurface->Surface(curSurfNum).Azimuth);
12147 31 : bool allFacesEquidistant = true;
12148 31 : oppositeWallArea = 0.;
12149 42 : for (int curFace : facesAtAz) {
12150 36 : int possOppFace = findPossibleOppositeFace(state, zonePoly, curFace);
12151 36 : if (possOppFace > 0) { // an opposite fact was found
12152 20 : oppositeWallArea += state.dataSurface->Surface(zonePoly.SurfaceFace(curFace).SurfNum).Area;
12153 20 : if (!areCornersEquidistant(zonePoly, curFace, possOppFace, distanceBetweenOppositeWalls)) {
12154 9 : allFacesEquidistant = false;
12155 9 : break;
12156 : }
12157 : } else {
12158 16 : allFacesEquidistant = false;
12159 16 : break;
12160 : }
12161 : }
12162 31 : if (allFacesEquidistant) {
12163 6 : foundOppEqual = true;
12164 6 : break; // only need to find the first case where opposite walls are the same
12165 : }
12166 31 : }
12167 : }
12168 25 : return foundOppEqual;
12169 : }
12170 :
12171 : // provides a list of indices of polyhedron faces that are facing a specific azimuth
12172 39 : std::vector<int> listOfFacesFacingAzimuth(EnergyPlusData &state, DataVectorTypes::Polyhedron const &zonePoly, Real64 const azimuth)
12173 : {
12174 : // J. Glazer - March 2017
12175 :
12176 39 : std::vector<int> facingAzimuth;
12177 39 : facingAzimuth.reserve(zonePoly.NumSurfaceFaces);
12178 :
12179 287 : for (int iFace = 1; iFace <= zonePoly.NumSurfaceFaces; ++iFace) {
12180 248 : int curSurfNum = zonePoly.SurfaceFace(iFace).SurfNum;
12181 248 : if (General::rotAzmDiffDeg(state.dataSurface->Surface(curSurfNum).Azimuth, azimuth) < 1.) {
12182 65 : facingAzimuth.emplace_back(iFace);
12183 : }
12184 : }
12185 39 : return facingAzimuth;
12186 0 : }
12187 :
12188 : // returns the index of the face of a polyhedron that is probably opposite of the face index provided
12189 52 : int findPossibleOppositeFace(EnergyPlusData &state, DataVectorTypes::Polyhedron const &zonePoly, int const faceIndex)
12190 : {
12191 : // J. Glazer - March 2017
12192 :
12193 52 : int selectedSurNum = zonePoly.SurfaceFace(faceIndex).SurfNum;
12194 52 : Real64 selectedAzimuth = state.dataSurface->Surface(selectedSurNum).Azimuth;
12195 52 : Real64 oppositeAzimuth = fmod(selectedAzimuth + 180., 360.);
12196 52 : Real64 selectedArea = state.dataSurface->Surface(selectedSurNum).Area;
12197 52 : int selectedNumCorners = zonePoly.SurfaceFace(faceIndex).NSides;
12198 52 : int found = -1;
12199 :
12200 215 : for (int iFace = 1; iFace <= zonePoly.NumSurfaceFaces; ++iFace) {
12201 193 : int curSurfNum = zonePoly.SurfaceFace(iFace).SurfNum;
12202 368 : if ((zonePoly.SurfaceFace(iFace).NSides == selectedNumCorners) &&
12203 368 : (std::abs(state.dataSurface->Surface(curSurfNum).Area - selectedArea) < 0.01) &&
12204 98 : (std::abs(state.dataSurface->Surface(curSurfNum).Azimuth - oppositeAzimuth) < 1.)) {
12205 30 : found = iFace;
12206 30 : break;
12207 : }
12208 : }
12209 52 : return found;
12210 : }
12211 :
12212 : // tests if the corners of one face of the polyhedron are the same distance from corners of another face
12213 22 : bool areCornersEquidistant(DataVectorTypes::Polyhedron const &zonePoly, int const faceIndex, int const opFaceIndex, Real64 &distanceBetween)
12214 : {
12215 : // J. Glazer - March 2017
12216 :
12217 22 : bool allAreEquidistant = true;
12218 22 : Real64 firstDistance = -99.;
12219 22 : if (zonePoly.SurfaceFace(faceIndex).NSides == zonePoly.SurfaceFace(opFaceIndex).NSides) { // double check that the number of sides match
12220 82 : for (int iVertex = 1; iVertex <= zonePoly.SurfaceFace(faceIndex).NSides; ++iVertex) {
12221 70 : int iVertexOpp = 1 + zonePoly.SurfaceFace(faceIndex).NSides - iVertex; // count backwards for opposite face
12222 : Real64 curDistBetwCorners =
12223 70 : distance(zonePoly.SurfaceFace(faceIndex).FacePoints(iVertex), zonePoly.SurfaceFace(opFaceIndex).FacePoints(iVertexOpp));
12224 70 : if (iVertex == 1) {
12225 22 : firstDistance = curDistBetwCorners;
12226 : } else {
12227 48 : if (std::abs(curDistBetwCorners - firstDistance) > Constant::OneCentimeter) {
12228 10 : allAreEquidistant = false;
12229 10 : break;
12230 : }
12231 : }
12232 : }
12233 : } else {
12234 0 : allAreEquidistant = false;
12235 : }
12236 22 : if (allAreEquidistant) distanceBetween = firstDistance;
12237 22 : return allAreEquidistant;
12238 : }
12239 :
12240 : // test if two points in space are in the same position based on a small tolerance
12241 128523 : bool isAlmostEqual3dPt(DataVectorTypes::Vector v1, DataVectorTypes::Vector v2)
12242 : {
12243 : // J. Glazer - March 2017
12244 :
12245 160262 : return ((std::abs(v1.x - v2.x) < Constant::OneCentimeter) && (std::abs(v1.y - v2.y) < Constant::OneCentimeter) &&
12246 160262 : (std::abs(v1.z - v2.z) < Constant::OneCentimeter));
12247 : }
12248 :
12249 : // test if two points on a plane are in the same position based on a small tolerance
12250 2025 : bool isAlmostEqual2dPt(DataVectorTypes::Vector_2d v1, DataVectorTypes::Vector_2d v2)
12251 : {
12252 : // J. Glazer - March 2017
12253 :
12254 2025 : return ((std::abs(v1.x - v2.x) < Constant::OneCentimeter) && (std::abs(v1.y - v2.y) < Constant::OneCentimeter));
12255 : }
12256 :
12257 : // test if two points on a plane are in the same position based on a small tolerance (based on Vector2dCount comparison)
12258 0 : bool isAlmostEqual2dPt(DataVectorTypes::Vector2dCount v1, DataVectorTypes::Vector2dCount v2)
12259 : {
12260 : // J. Glazer - March 2017
12261 :
12262 0 : return ((std::abs(v1.x - v2.x) < Constant::OneCentimeter) && (std::abs(v1.y - v2.y) < Constant::OneCentimeter));
12263 : }
12264 :
12265 : // returns the index of vertex in a list that is in the same position in space as the given vertex
12266 10254 : int findIndexOfVertex(DataVectorTypes::Vector vertexToFind, std::vector<DataVectorTypes::Vector> const &listOfVertices)
12267 : {
12268 : // J. Glazer - March 2017
12269 :
12270 49165 : for (std::size_t i = 0; i < listOfVertices.size(); i++) {
12271 49163 : if (isAlmostEqual3dPt(listOfVertices[i], vertexToFind)) {
12272 10252 : return i;
12273 : }
12274 : }
12275 2 : return -1;
12276 : }
12277 :
12278 : // returns the distance between two points in space
12279 12591 : Real64 distance(DataVectorTypes::Vector v1, DataVectorTypes::Vector v2)
12280 : {
12281 : // J. Glazer - March 2017
12282 :
12283 12591 : return sqrt(pow(v1.x - v2.x, 2) + pow(v1.y - v2.y, 2) + pow(v1.z - v2.z, 2));
12284 : }
12285 :
12286 18396 : Real64 distanceFromPointToLine(DataVectorTypes::Vector start, DataVectorTypes::Vector end, DataVectorTypes::Vector test)
12287 : {
12288 : // np.linalg.norm(np.cross(e-s,p-s)/np.linalg.norm(e-s))
12289 18396 : DataVectorTypes::Vector t = end - start;
12290 18396 : t.normalize(); // Unit vector of start to end
12291 :
12292 18396 : DataVectorTypes::Vector other = test - start;
12293 :
12294 18396 : DataVectorTypes::Vector projection = DataVectorTypes::cross(t, other); // normal unit vector, that's the distance component
12295 36792 : return projection.length();
12296 18396 : }
12297 :
12298 : // tests if a point in space lies on the line segment defined by two other points
12299 18395 : bool isPointOnLineBetweenPoints(DataVectorTypes::Vector start, DataVectorTypes::Vector end, DataVectorTypes::Vector test)
12300 : {
12301 : // J. Glazer - March 2017
12302 : // 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
12303 : // floor to the roof, cf #7383 compute the shortest distance from the point to the line first to avoid false positive
12304 18395 : if (distanceFromPointToLine(start, end, test) <
12305 : Constant::OneCentimeter) { // distanceFromPointToLine always positive, it's calculated as norml_L2
12306 1080 : return (std::abs((distance(start, end) - (distance(start, test) + distance(test, end)))) < Constant::OneCentimeter);
12307 : }
12308 17315 : return false;
12309 : }
12310 :
12311 3059 : bool EdgeOfSurf::operator==(const EdgeOfSurf &other) const
12312 : {
12313 9264 : return ((isAlmostEqual3dPt(this->start, other.start) && isAlmostEqual3dPt(this->end, other.end)) ||
12314 6205 : (isAlmostEqual3dPt(this->start, other.end) && isAlmostEqual3dPt(this->end, other.start)));
12315 : }
12316 :
12317 0 : bool EdgeOfSurf::operator!=(const EdgeOfSurf &other) const
12318 : {
12319 0 : return !(*this == other);
12320 : }
12321 :
12322 2155 : bool EdgeOfSurf::containsPoints(const Vector &vertex) const
12323 : {
12324 5640 : return (!isAlmostEqual3dPt(this->start, vertex) && !isAlmostEqual3dPt(this->end, vertex) &&
12325 5640 : isPointOnLineBetweenPoints(this->start, this->end, vertex));
12326 : }
12327 :
12328 380 : double EdgeOfSurf::length() const
12329 : {
12330 380 : return distance(this->start, this->end);
12331 : }
12332 :
12333 1704 : void ProcessSurfaceVertices(EnergyPlusData &state, int const ThisSurf, bool &ErrorsFound)
12334 : {
12335 : // SUBROUTINE INFORMATION:
12336 : // AUTHOR Legacy Code (Walton)
12337 : // DATE WRITTEN 1976
12338 : // MODIFIED FW, Mar 2002: Add triangular windows
12339 : // FW, May 2002: modify test for 4-sided but non-rectangular subsurfaces
12340 : // FW, Sep 2002: add shape for base surfaces (walls and detached shading surfaces)
12341 :
12342 : // PURPOSE OF THIS SUBROUTINE:
12343 : // This subroutine processes each surface into the vertex representation used
12344 : // by the shading procedures.
12345 :
12346 : // METHODOLOGY EMPLOYED:
12347 : // Detached Shading, Base Surfaces, Attached Shading surfaces are represented in the
12348 : // same manner as original. Subsurfaces (windows, doors) are a "relative coordinate".
12349 :
12350 : static constexpr std::string_view RoutineName("ProcessSurfaceVertices: ");
12351 :
12352 : Real64 X1; // Intermediate Result
12353 : Real64 Y1; // Intermediate Result
12354 : Real64 Z1; // Intermediate Result
12355 : Real64 XLLC; // X-coordinate of lower left corner
12356 : Real64 YLLC; // Y-coordinate of lower left corner
12357 : Real64 ZLLC; // Z-coordinate of lower left corner
12358 : int n; // Vertex Number in Loop
12359 : int ThisBaseSurface; // Current base surface
12360 : Real64 Xp;
12361 : Real64 Yp;
12362 : Real64 Zp;
12363 : Real64 SurfWorldAz; // Surface Azimuth (facing)
12364 : Real64 SurfTilt; // Surface Tilt
12365 1704 : DataSurfaces::SurfaceShape ThisShape(DataSurfaces::SurfaceShape::None);
12366 : bool BaseSurface; // True if a base surface or a detached shading surface
12367 : Real64 ThisSurfAz;
12368 : Real64 ThisSurfTilt;
12369 : Real64 ThisReveal;
12370 : Real64 ThisWidth;
12371 : Real64 ThisHeight;
12372 : Real64 FrWidth; // Frame width for exterior windows (m)
12373 : Real64 FrArea; // Frame area for exterior windows(m2)
12374 : Real64 DivWidth; // Divider width for exterior windows (m)
12375 : Real64 DivArea; // Divider area for exterior windows (m2)
12376 : Real64 DivFrac; // Fraction of divider area without overlaps
12377 : bool ErrorInSurface; // false/true, depending on pass through routine
12378 : bool HeatTransSurf;
12379 : Real64 OutOfLine;
12380 :
12381 : // Object Data
12382 1704 : Vectors::PlaneEq BasePlane;
12383 1704 : Vector TVect;
12384 1704 : Vector CoordinateTransVector;
12385 :
12386 1704 : if (state.dataSurface->Surface(ThisSurf).VerticesProcessed) {
12387 10 : return;
12388 : }
12389 :
12390 1694 : ErrorInSurface = false;
12391 :
12392 1694 : if (state.dataSurfaceGeometry->ProcessSurfaceVerticesOneTimeFlag) {
12393 180 : state.dataSurfaceGeometry->Xpsv.allocate(state.dataSurface->MaxVerticesPerSurface);
12394 180 : state.dataSurfaceGeometry->Ypsv.allocate(state.dataSurface->MaxVerticesPerSurface);
12395 180 : state.dataSurfaceGeometry->Zpsv.allocate(state.dataSurface->MaxVerticesPerSurface);
12396 180 : state.dataSurfaceGeometry->Xpsv = 0.0;
12397 180 : state.dataSurfaceGeometry->Ypsv = 0.0;
12398 180 : state.dataSurfaceGeometry->Zpsv = 0.0;
12399 180 : state.dataSurfaceGeometry->ProcessSurfaceVerticesOneTimeFlag = false;
12400 : }
12401 :
12402 : // Categorize this surface
12403 1694 : auto &surf = state.dataSurface->Surface(ThisSurf);
12404 1694 : BaseSurface = (surf.BaseSurf == 0 || surf.BaseSurf == ThisSurf);
12405 :
12406 1694 : ThisBaseSurface = surf.BaseSurf; // Dont know if this is still needed or not
12407 1694 : HeatTransSurf = surf.HeatTransSurf;
12408 :
12409 : // Kludge for daylighting shelves
12410 1694 : if (surf.IsShadowing) {
12411 74 : ThisBaseSurface = ThisSurf;
12412 74 : HeatTransSurf = true;
12413 : }
12414 :
12415 : // IF (Surface(ThisSurf)%Name(1:3) /= 'Mir') THEN
12416 1694 : if (!surf.MirroredSurf) {
12417 : bool IsCoPlanar;
12418 : int LastVertexInError;
12419 1657 : Vectors::CalcCoPlanarNess(surf.Vertex, surf.Sides, IsCoPlanar, OutOfLine, LastVertexInError);
12420 1657 : if (!IsCoPlanar) {
12421 0 : if (OutOfLine > 0.01) {
12422 0 : ShowSevereError(state,
12423 0 : format("{}Suspected non-planar surface:\"{}\", Max \"out of line\"={:.5T} at Vertex # {}",
12424 : RoutineName,
12425 0 : surf.Name,
12426 : OutOfLine,
12427 : LastVertexInError));
12428 : } else {
12429 0 : ShowWarningError(state,
12430 0 : format("{}Possible non-planar surface:\"{}\", Max \"out of line\"={:.5T} at Vertex # {}",
12431 : RoutineName,
12432 0 : surf.Name,
12433 : OutOfLine,
12434 : LastVertexInError));
12435 : }
12436 : // ErrorInSurface=.TRUE.
12437 : }
12438 : }
12439 :
12440 1694 : if (BaseSurface) {
12441 1559 : SurfWorldAz = surf.Azimuth;
12442 1559 : SurfTilt = surf.Tilt;
12443 7801 : for (n = 1; n <= surf.Sides; ++n) {
12444 6242 : state.dataSurfaceGeometry->Xpsv(n) = surf.Vertex(n).x;
12445 6242 : state.dataSurfaceGeometry->Ypsv(n) = surf.Vertex(n).y;
12446 6242 : state.dataSurfaceGeometry->Zpsv(n) = surf.Vertex(n).z;
12447 : }
12448 1559 : TVect = surf.Vertex(3) - surf.Vertex(2);
12449 1559 : ThisWidth = Vectors::VecLength(TVect);
12450 1559 : TVect = surf.Vertex(2) - surf.Vertex(1);
12451 1559 : ThisHeight = Vectors::VecLength(TVect);
12452 1559 : surf.Width = ThisWidth;
12453 1559 : surf.Height = ThisHeight; // For a horizontal surface this is actually length!
12454 1559 : if (surf.Sides == 3) {
12455 16 : surf.Shape = DataSurfaces::SurfaceShape::Triangle;
12456 1543 : } else if (surf.Sides == 4) {
12457 : // Test for rectangularity
12458 1529 : if (isRectangle(state, ThisSurf)) {
12459 1404 : surf.Shape = DataSurfaces::SurfaceShape::Rectangle;
12460 : } else {
12461 125 : surf.Shape = DataSurfaces::SurfaceShape::Quadrilateral;
12462 : }
12463 : } else { // Surface( ThisSurf ).Sides > 4
12464 14 : surf.Shape = DataSurfaces::SurfaceShape::Polygonal;
12465 14 : if (std::abs(ThisHeight * ThisWidth - surf.GrossArea) > 0.001) {
12466 14 : surf.Width = std::sqrt(surf.GrossArea);
12467 14 : surf.Height = surf.Width;
12468 14 : ThisWidth = surf.Width;
12469 14 : ThisHeight = surf.Height;
12470 : }
12471 : }
12472 :
12473 : } else { // It's a subsurface to previous basesurface in this set of calls
12474 :
12475 135 : ThisSurfAz = surf.Azimuth;
12476 135 : ThisSurfTilt = surf.Tilt;
12477 :
12478 : // Retrieve base surface info
12479 135 : Real64 const baseSurfWorldAz = state.dataSurface->Surface(ThisBaseSurface).Azimuth;
12480 135 : Real64 const baseSurfTilt = state.dataSurface->Surface(ThisBaseSurface).Tilt;
12481 135 : Real64 const BaseCosAzimuth = std::cos(baseSurfWorldAz * Constant::DegToRad);
12482 135 : Real64 const BaseSinAzimuth = std::sin(baseSurfWorldAz * Constant::DegToRad);
12483 135 : Real64 const BaseCosTilt = std::cos(baseSurfTilt * Constant::DegToRad);
12484 135 : Real64 const BaseSinTilt = std::sin(baseSurfTilt * Constant::DegToRad);
12485 135 : Real64 const BaseXLLC = state.dataSurface->Surface(ThisBaseSurface).Vertex(2).x;
12486 135 : Real64 const BaseYLLC = state.dataSurface->Surface(ThisBaseSurface).Vertex(2).y;
12487 135 : Real64 const BaseZLLC = state.dataSurface->Surface(ThisBaseSurface).Vertex(2).z;
12488 :
12489 135 : if (HeatTransSurf) {
12490 :
12491 131 : if (surf.Sides == 4) {
12492 129 : ThisShape = DataSurfaces::SurfaceShape::RectangularDoorWindow;
12493 2 : } else if (surf.Sides == 3 && surf.Class == SurfaceClass::Window) {
12494 1 : ThisShape = DataSurfaces::SurfaceShape::TriangularWindow;
12495 1 : } else if (surf.Sides == 3 && surf.Class == SurfaceClass::Door) {
12496 1 : ThisShape = DataSurfaces::SurfaceShape::TriangularDoor;
12497 : } else {
12498 0 : assert(false);
12499 : }
12500 :
12501 : } else { // this is a shadowing subsurface
12502 :
12503 4 : if (std::abs(state.dataSurface->Surface(surf.BaseSurf).Tilt - ThisSurfTilt) <= 0.01) {
12504 : // left or right fin
12505 4 : if (ThisSurfAz < 0.0) ThisSurfAz += 360.0;
12506 4 : if (ThisSurfAz > state.dataSurface->Surface(surf.BaseSurf).Azimuth) {
12507 0 : ThisShape = DataSurfaces::SurfaceShape::RectangularLeftFin;
12508 : } else {
12509 4 : ThisShape = DataSurfaces::SurfaceShape::RectangularRightFin;
12510 : }
12511 : } else {
12512 0 : ThisShape = DataSurfaces::SurfaceShape::RectangularOverhang;
12513 : }
12514 : }
12515 :
12516 : // Setting relative coordinates for shadowing calculations for subsurfaces
12517 : bool SError; // Bool used for return value of calls to PlaneEquation
12518 135 : switch (ThisShape) {
12519 129 : case DataSurfaces::SurfaceShape::RectangularDoorWindow: { // Rectangular heat transfer subsurface
12520 258 : Vectors::PlaneEquation(
12521 129 : state.dataSurface->Surface(surf.BaseSurf).Vertex, state.dataSurface->Surface(surf.BaseSurf).Sides, BasePlane, SError);
12522 129 : if (SError) {
12523 0 : ShowSevereError(state, format("{}Degenerate surface (likely two vertices equal):\"{}\".", RoutineName, surf.Name));
12524 0 : ErrorInSurface = true;
12525 : }
12526 129 : ThisReveal = -Vectors::Pt2Plane(surf.Vertex(2), BasePlane);
12527 129 : if (std::abs(ThisReveal) < 0.0002) ThisReveal = 0.0;
12528 129 : surf.Reveal = ThisReveal;
12529 129 : Xp = surf.Vertex(2).x - BaseXLLC;
12530 129 : Yp = surf.Vertex(2).y - BaseYLLC;
12531 129 : Zp = surf.Vertex(2).z - BaseZLLC;
12532 129 : XLLC = -Xp * BaseCosAzimuth + Yp * BaseSinAzimuth;
12533 129 : YLLC = -Xp * BaseSinAzimuth * BaseCosTilt - Yp * BaseCosAzimuth * BaseCosTilt + Zp * BaseSinTilt;
12534 129 : ZLLC = Xp * BaseSinAzimuth * BaseSinTilt + Yp * BaseCosAzimuth * BaseSinTilt + Zp * BaseCosTilt;
12535 129 : TVect = surf.Vertex(3) - surf.Vertex(2);
12536 129 : ThisWidth = Vectors::VecLength(TVect);
12537 129 : TVect = surf.Vertex(2) - surf.Vertex(1);
12538 129 : ThisHeight = Vectors::VecLength(TVect);
12539 129 : surf.Width = ThisWidth;
12540 129 : surf.Height = ThisHeight;
12541 :
12542 : // Processing of 4-sided but non-rectangular Window, Door or GlassDoor, for use in calc of convective air flow.
12543 129 : if (!isRectangle(state, ThisSurf)) {
12544 :
12545 : // Transform the surface into an equivalent rectangular surface with the same area and aspect ratio.
12546 3 : MakeEquivalentRectangle(state, ThisSurf, ErrorsFound);
12547 :
12548 3 : if (state.dataGlobal->DisplayExtraWarnings) {
12549 0 : ShowWarningError(state, format("{}Suspected 4-sided but non-rectangular Window, Door or GlassDoor:", RoutineName));
12550 0 : ShowContinueError(
12551 : state,
12552 0 : format("Surface={} is transformed into an equivalent rectangular surface with the same area and aspect ratio. ",
12553 0 : surf.Name));
12554 : }
12555 : }
12556 :
12557 129 : state.dataSurfaceGeometry->Xpsv(1) = XLLC;
12558 129 : state.dataSurfaceGeometry->Xpsv(2) = XLLC;
12559 129 : state.dataSurfaceGeometry->Xpsv(3) = XLLC + surf.Width;
12560 129 : state.dataSurfaceGeometry->Xpsv(4) = XLLC + surf.Width;
12561 129 : state.dataSurfaceGeometry->Ypsv(1) = YLLC + surf.Height;
12562 129 : state.dataSurfaceGeometry->Ypsv(4) = YLLC + surf.Height;
12563 129 : state.dataSurfaceGeometry->Ypsv(2) = YLLC;
12564 129 : state.dataSurfaceGeometry->Ypsv(3) = YLLC;
12565 129 : state.dataSurfaceGeometry->Zpsv(1) = ZLLC;
12566 129 : state.dataSurfaceGeometry->Zpsv(2) = ZLLC;
12567 129 : state.dataSurfaceGeometry->Zpsv(3) = ZLLC;
12568 129 : state.dataSurfaceGeometry->Zpsv(4) = ZLLC;
12569 :
12570 129 : if (surf.Class == SurfaceClass::Window && surf.ExtBoundCond == DataSurfaces::ExternalEnvironment && surf.FrameDivider > 0) {
12571 19 : int FrDivNum = surf.FrameDivider;
12572 : // Set flag for calculating beam solar reflection from outside and/or inside window reveal
12573 0 : if ((surf.Reveal > 0.0 && state.dataSurface->FrameDivider(FrDivNum).OutsideRevealSolAbs > 0.0) ||
12574 19 : (state.dataSurface->FrameDivider(FrDivNum).InsideSillDepth > 0.0 &&
12575 38 : state.dataSurface->FrameDivider(FrDivNum).InsideSillSolAbs > 0.0) ||
12576 19 : (state.dataSurface->FrameDivider(FrDivNum).InsideReveal > 0.0 &&
12577 0 : state.dataSurface->FrameDivider(FrDivNum).InsideRevealSolAbs > 0.0))
12578 0 : state.dataHeatBal->CalcWindowRevealReflection = true;
12579 :
12580 : // For exterior window with frame, subtract frame area from base surface
12581 : // (only rectangular windows are allowed to have a frame and/or divider;
12582 : // Surface(ThisSurf)%FrameDivider will be 0 for triangular windows)
12583 19 : FrWidth = state.dataSurface->FrameDivider(FrDivNum).FrameWidth;
12584 19 : if (FrWidth > 0.0) {
12585 19 : FrArea = (surf.Height + 2.0 * FrWidth) * (surf.Width + 2.0 * FrWidth) - surf.Area / surf.Multiplier;
12586 19 : state.dataSurface->SurfWinFrameArea(ThisSurf) = FrArea * surf.Multiplier;
12587 19 : if ((state.dataSurface->Surface(surf.BaseSurf).Area - state.dataSurface->SurfWinFrameArea(ThisSurf)) <= 0.0) {
12588 0 : ShowSevereError(state, format("{}Base Surface=\"{}\", ", RoutineName, state.dataSurface->Surface(surf.BaseSurf).Name));
12589 0 : ShowContinueError(state,
12590 0 : format("Window Surface=\"{}\" area (with frame) is too large to fit on the surface.", surf.Name));
12591 0 : ShowContinueError(state,
12592 0 : format("Base surface area (-windows and doors)=[{:.2T}] m2, frame area=[{:.2T}] m2.",
12593 0 : state.dataSurface->Surface(surf.BaseSurf).Area,
12594 0 : state.dataSurface->SurfWinFrameArea(ThisSurf)));
12595 0 : ErrorInSurface = true;
12596 : }
12597 19 : state.dataSurface->Surface(surf.BaseSurf).Area -= state.dataSurface->SurfWinFrameArea(ThisSurf);
12598 : }
12599 : // If exterior window has divider, subtract divider area to get glazed area
12600 19 : DivWidth = state.dataSurface->FrameDivider(surf.FrameDivider).DividerWidth;
12601 19 : if (DivWidth > 0.0 && !ErrorInSurface) {
12602 19 : DivArea = DivWidth * (state.dataSurface->FrameDivider(FrDivNum).HorDividers * surf.Width +
12603 19 : state.dataSurface->FrameDivider(FrDivNum).VertDividers * surf.Height -
12604 19 : state.dataSurface->FrameDivider(FrDivNum).HorDividers *
12605 19 : state.dataSurface->FrameDivider(FrDivNum).VertDividers * DivWidth);
12606 19 : state.dataSurface->SurfWinDividerArea(ThisSurf) = DivArea * surf.Multiplier;
12607 19 : if ((surf.Area - state.dataSurface->SurfWinDividerArea(ThisSurf)) <= 0.0) {
12608 0 : ShowSevereError(state, format("{}Divider area exceeds glazed opening for window {}", RoutineName, surf.Name));
12609 0 : ShowContinueError(state,
12610 0 : format("Window surface area=[{:.2T}] m2, divider area=[{:.2T}] m2.",
12611 0 : surf.Area,
12612 0 : state.dataSurface->SurfWinDividerArea(ThisSurf)));
12613 0 : ErrorInSurface = true;
12614 : }
12615 19 : surf.Area -= state.dataSurface->SurfWinDividerArea(ThisSurf); // Glazed area
12616 19 : if (DivArea <= 0.0) {
12617 0 : ShowWarningError(state, format("{}Calculated Divider Area <= 0.0 for Window={}", RoutineName, surf.Name));
12618 0 : if (state.dataSurface->FrameDivider(FrDivNum).HorDividers == 0) {
12619 0 : ShowContinueError(state, "..Number of Horizontal Dividers = 0.");
12620 : }
12621 0 : if (state.dataSurface->FrameDivider(FrDivNum).VertDividers == 0) {
12622 0 : ShowContinueError(state, "..Number of Vertical Dividers = 0.");
12623 : }
12624 : } else {
12625 19 : auto &surfWin = state.dataSurface->SurfaceWindow(ThisSurf);
12626 19 : surfWin.glazedFrac = surf.Area / (surf.Area + state.dataSurface->SurfWinDividerArea(ThisSurf));
12627 : // Correction factor for portion of divider subject to divider projection correction
12628 19 : DivFrac = (1.0 - state.dataSurface->FrameDivider(FrDivNum).HorDividers *
12629 19 : state.dataSurface->FrameDivider(FrDivNum).VertDividers * pow_2(DivWidth) / DivArea);
12630 19 : state.dataSurface->SurfWinProjCorrDivOut(ThisSurf) =
12631 19 : DivFrac * state.dataSurface->FrameDivider(FrDivNum).DividerProjectionOut / DivWidth;
12632 19 : state.dataSurface->SurfWinProjCorrDivIn(ThisSurf) =
12633 19 : DivFrac * state.dataSurface->FrameDivider(FrDivNum).DividerProjectionIn / DivWidth;
12634 : // Correction factor for portion of frame subject to frame projection correction
12635 19 : if (FrWidth > 0.0) {
12636 19 : state.dataSurface->SurfWinProjCorrFrOut(ThisSurf) =
12637 19 : (state.dataSurface->FrameDivider(FrDivNum).FrameProjectionOut / FrWidth) *
12638 38 : (ThisHeight + ThisWidth -
12639 19 : (state.dataSurface->FrameDivider(FrDivNum).HorDividers +
12640 19 : state.dataSurface->FrameDivider(FrDivNum).VertDividers) *
12641 19 : DivWidth) /
12642 19 : (ThisHeight + ThisWidth + 2 * FrWidth);
12643 19 : state.dataSurface->SurfWinProjCorrFrIn(ThisSurf) =
12644 19 : (state.dataSurface->FrameDivider(FrDivNum).FrameProjectionIn / FrWidth) *
12645 38 : (ThisHeight + ThisWidth -
12646 19 : (state.dataSurface->FrameDivider(FrDivNum).HorDividers +
12647 19 : state.dataSurface->FrameDivider(FrDivNum).VertDividers) *
12648 19 : DivWidth) /
12649 19 : (ThisHeight + ThisWidth + 2 * FrWidth);
12650 : }
12651 : }
12652 : }
12653 : }
12654 129 : } break;
12655 2 : case DataSurfaces::SurfaceShape::TriangularWindow:
12656 : case DataSurfaces::SurfaceShape::TriangularDoor: {
12657 4 : Vectors::PlaneEquation(
12658 2 : state.dataSurface->Surface(surf.BaseSurf).Vertex, state.dataSurface->Surface(surf.BaseSurf).Sides, BasePlane, SError);
12659 2 : if (SError) {
12660 0 : ShowSevereError(state, format("{}Degenerate surface (likely two vertices equal):\"{}\".", RoutineName, surf.Name));
12661 0 : ErrorInSurface = true;
12662 : }
12663 2 : ThisReveal = -Vectors::Pt2Plane(surf.Vertex(2), BasePlane);
12664 2 : if (std::abs(ThisReveal) < 0.0002) ThisReveal = 0.0;
12665 2 : surf.Reveal = ThisReveal;
12666 2 : Xp = surf.Vertex(2).x - BaseXLLC;
12667 2 : Yp = surf.Vertex(2).y - BaseYLLC;
12668 2 : Zp = surf.Vertex(2).z - BaseZLLC;
12669 2 : state.dataSurfaceGeometry->Xpsv(2) = -Xp * BaseCosAzimuth + Yp * BaseSinAzimuth;
12670 2 : state.dataSurfaceGeometry->Ypsv(2) = -Xp * BaseSinAzimuth * BaseCosTilt - Yp * BaseCosAzimuth * BaseCosTilt + Zp * BaseSinTilt;
12671 2 : state.dataSurfaceGeometry->Zpsv(2) = Xp * BaseSinAzimuth * BaseSinTilt + Yp * BaseCosAzimuth * BaseSinTilt + Zp * BaseCosTilt;
12672 2 : TVect = surf.Vertex(3) - surf.Vertex(2);
12673 2 : ThisWidth = Vectors::VecLength(TVect);
12674 2 : TVect = surf.Vertex(2) - surf.Vertex(1);
12675 2 : ThisHeight = Vectors::VecLength(TVect);
12676 2 : surf.Width = ThisWidth;
12677 : // Effective height and width of a triangular window for use in calc of convective air flow
12678 : // in gap between glass and shading device when shading device is present
12679 2 : surf.Height = 4.0 * surf.Area / (3.0 * surf.Width);
12680 2 : surf.Width *= 0.75;
12681 :
12682 2 : Xp = surf.Vertex(1).x - BaseXLLC;
12683 2 : Yp = surf.Vertex(1).y - BaseYLLC;
12684 2 : Zp = surf.Vertex(1).z - BaseZLLC;
12685 2 : state.dataSurfaceGeometry->Xpsv(1) = -Xp * BaseCosAzimuth + Yp * BaseSinAzimuth;
12686 2 : state.dataSurfaceGeometry->Ypsv(1) = -Xp * BaseSinAzimuth * BaseCosTilt - Yp * BaseCosAzimuth * BaseCosTilt + Zp * BaseSinTilt;
12687 2 : state.dataSurfaceGeometry->Zpsv(1) = Xp * BaseSinAzimuth * BaseSinTilt + Yp * BaseCosAzimuth * BaseSinTilt + Zp * BaseCosTilt;
12688 :
12689 2 : Xp = surf.Vertex(3).x - BaseXLLC;
12690 2 : Yp = surf.Vertex(3).y - BaseYLLC;
12691 2 : Zp = surf.Vertex(3).z - BaseZLLC;
12692 2 : state.dataSurfaceGeometry->Xpsv(3) = -Xp * BaseCosAzimuth + Yp * BaseSinAzimuth;
12693 2 : state.dataSurfaceGeometry->Ypsv(3) = -Xp * BaseSinAzimuth * BaseCosTilt - Yp * BaseCosAzimuth * BaseCosTilt + Zp * BaseSinTilt;
12694 2 : state.dataSurfaceGeometry->Zpsv(3) = Xp * BaseSinAzimuth * BaseSinTilt + Yp * BaseCosAzimuth * BaseSinTilt + Zp * BaseCosTilt;
12695 2 : } break;
12696 0 : case DataSurfaces::SurfaceShape::RectangularOverhang: {
12697 0 : Xp = surf.Vertex(2).x - BaseXLLC;
12698 0 : Yp = surf.Vertex(2).y - BaseYLLC;
12699 0 : Zp = surf.Vertex(2).z - BaseZLLC;
12700 0 : XLLC = -Xp * BaseCosAzimuth + Yp * BaseSinAzimuth;
12701 0 : YLLC = -Xp * BaseSinAzimuth * BaseCosTilt - Yp * BaseCosAzimuth * BaseCosTilt + Zp * BaseSinTilt;
12702 0 : ZLLC = Xp * BaseSinAzimuth * BaseSinTilt + Yp * BaseCosAzimuth * BaseSinTilt + Zp * BaseCosTilt;
12703 0 : TVect = surf.Vertex(3) - surf.Vertex(2);
12704 0 : ThisWidth = Vectors::VecLength(TVect);
12705 0 : TVect = surf.Vertex(2) - surf.Vertex(1);
12706 0 : ThisHeight = Vectors::VecLength(TVect);
12707 0 : surf.Width = ThisWidth;
12708 0 : surf.Height = ThisHeight;
12709 0 : state.dataSurfaceGeometry->Xpsv(1) = XLLC;
12710 0 : state.dataSurfaceGeometry->Xpsv(2) = XLLC;
12711 0 : state.dataSurfaceGeometry->Xpsv(3) = XLLC + surf.Width;
12712 0 : state.dataSurfaceGeometry->Xpsv(4) = XLLC + surf.Width;
12713 0 : state.dataSurfaceGeometry->Ypsv(1) = YLLC;
12714 0 : state.dataSurfaceGeometry->Ypsv(2) = YLLC;
12715 0 : state.dataSurfaceGeometry->Ypsv(3) = YLLC;
12716 0 : state.dataSurfaceGeometry->Ypsv(4) = YLLC;
12717 0 : state.dataSurfaceGeometry->Zpsv(1) = surf.Height;
12718 0 : state.dataSurfaceGeometry->Zpsv(4) = surf.Height;
12719 0 : state.dataSurfaceGeometry->Zpsv(2) = 0.0;
12720 0 : state.dataSurfaceGeometry->Zpsv(3) = 0.0;
12721 0 : } break;
12722 0 : case DataSurfaces::SurfaceShape::RectangularLeftFin: {
12723 0 : Xp = surf.Vertex(2).x - BaseXLLC;
12724 0 : Yp = surf.Vertex(2).y - BaseYLLC;
12725 0 : Zp = surf.Vertex(2).z - BaseZLLC;
12726 0 : XLLC = -Xp * BaseCosAzimuth + Yp * BaseSinAzimuth;
12727 0 : YLLC = -Xp * BaseSinAzimuth * BaseCosTilt - Yp * BaseCosAzimuth * BaseCosTilt + Zp * BaseSinTilt;
12728 0 : ZLLC = Xp * BaseSinAzimuth * BaseSinTilt + Yp * BaseCosAzimuth * BaseSinTilt + Zp * BaseCosTilt;
12729 0 : TVect = surf.Vertex(3) - surf.Vertex(2);
12730 0 : ThisWidth = Vectors::VecLength(TVect);
12731 0 : TVect = surf.Vertex(2) - surf.Vertex(1);
12732 0 : ThisHeight = Vectors::VecLength(TVect);
12733 0 : surf.Width = ThisWidth;
12734 0 : surf.Height = ThisHeight;
12735 0 : state.dataSurfaceGeometry->Xpsv(1) = XLLC;
12736 0 : state.dataSurfaceGeometry->Xpsv(2) = XLLC;
12737 0 : state.dataSurfaceGeometry->Xpsv(3) = XLLC;
12738 0 : state.dataSurfaceGeometry->Xpsv(4) = XLLC;
12739 0 : state.dataSurfaceGeometry->Ypsv(1) = YLLC;
12740 0 : state.dataSurfaceGeometry->Ypsv(2) = YLLC;
12741 0 : state.dataSurfaceGeometry->Ypsv(3) = YLLC + surf.Width;
12742 0 : state.dataSurfaceGeometry->Ypsv(4) = YLLC + surf.Width;
12743 0 : state.dataSurfaceGeometry->Zpsv(1) = surf.Height;
12744 0 : state.dataSurfaceGeometry->Zpsv(4) = surf.Height;
12745 0 : state.dataSurfaceGeometry->Zpsv(2) = 0.0;
12746 0 : state.dataSurfaceGeometry->Zpsv(3) = 0.0;
12747 0 : } break;
12748 4 : case DataSurfaces::SurfaceShape::RectangularRightFin: {
12749 4 : Xp = surf.Vertex(2).x - BaseXLLC;
12750 4 : Yp = surf.Vertex(2).y - BaseYLLC;
12751 4 : Zp = surf.Vertex(2).z - BaseZLLC;
12752 4 : XLLC = -Xp * BaseCosAzimuth + Yp * BaseSinAzimuth;
12753 4 : YLLC = -Xp * BaseSinAzimuth * BaseCosTilt - Yp * BaseCosAzimuth * BaseCosTilt + Zp * BaseSinTilt;
12754 4 : ZLLC = Xp * BaseSinAzimuth * BaseSinTilt + Yp * BaseCosAzimuth * BaseSinTilt + Zp * BaseCosTilt;
12755 4 : TVect = surf.Vertex(3) - surf.Vertex(2);
12756 4 : ThisWidth = Vectors::VecLength(TVect);
12757 4 : TVect = surf.Vertex(2) - surf.Vertex(1);
12758 4 : ThisHeight = Vectors::VecLength(TVect);
12759 4 : surf.Width = ThisWidth;
12760 4 : surf.Height = ThisHeight;
12761 4 : state.dataSurfaceGeometry->Xpsv(1) = XLLC;
12762 4 : state.dataSurfaceGeometry->Xpsv(2) = XLLC;
12763 4 : state.dataSurfaceGeometry->Xpsv(3) = XLLC;
12764 4 : state.dataSurfaceGeometry->Xpsv(4) = XLLC;
12765 4 : state.dataSurfaceGeometry->Ypsv(1) = YLLC + surf.Width;
12766 4 : state.dataSurfaceGeometry->Ypsv(2) = YLLC + surf.Width;
12767 4 : state.dataSurfaceGeometry->Ypsv(3) = YLLC;
12768 4 : state.dataSurfaceGeometry->Ypsv(4) = YLLC;
12769 4 : state.dataSurfaceGeometry->Zpsv(1) = surf.Height;
12770 4 : state.dataSurfaceGeometry->Zpsv(4) = surf.Height;
12771 4 : state.dataSurfaceGeometry->Zpsv(2) = 0.0;
12772 4 : state.dataSurfaceGeometry->Zpsv(3) = 0.0;
12773 4 : } break;
12774 0 : default: {
12775 : // Error Condition
12776 0 : ShowSevereError(state, format("{}Incorrect surface shape number.", RoutineName), OptionalOutputFileRef{state.files.eso});
12777 0 : ShowContinueError(state, "Please notify EnergyPlus support of this error and send input file.");
12778 0 : ErrorInSurface = true;
12779 0 : } break;
12780 : }
12781 :
12782 673 : for (n = 1; n <= surf.Sides; ++n) {
12783 : // if less than 1/10 inch
12784 538 : state.dataSurfaceGeometry->Xpsv(n) = nint64(10000.0 * state.dataSurfaceGeometry->Xpsv(n)) / 10000.0;
12785 538 : if (std::abs(state.dataSurfaceGeometry->Xpsv(n)) < 0.0025) state.dataSurfaceGeometry->Xpsv(n) = 0.0;
12786 538 : state.dataSurfaceGeometry->Ypsv(n) = nint64(10000.0 * state.dataSurfaceGeometry->Ypsv(n)) / 10000.0;
12787 538 : if (std::abs(state.dataSurfaceGeometry->Ypsv(n)) < 0.0025) state.dataSurfaceGeometry->Ypsv(n) = 0.0;
12788 538 : state.dataSurfaceGeometry->Zpsv(n) = nint64(10000.0 * state.dataSurfaceGeometry->Zpsv(n)) / 10000.0;
12789 538 : if (std::abs(state.dataSurfaceGeometry->Zpsv(n)) < 0.0025) state.dataSurfaceGeometry->Zpsv(n) = 0.0;
12790 : }
12791 :
12792 135 : surf.Shape = ThisShape;
12793 :
12794 : } // End of check if ThisSurf is a base surface
12795 :
12796 1694 : if (ErrorInSurface) {
12797 0 : ErrorsFound = true;
12798 0 : return;
12799 : }
12800 :
12801 : // Transfer to XV,YV,ZV arrays
12802 :
12803 1694 : state.dataSurface->ShadeV(ThisSurf).NVert = surf.Sides;
12804 1694 : state.dataSurface->ShadeV(ThisSurf).XV.allocate(surf.Sides);
12805 1694 : state.dataSurface->ShadeV(ThisSurf).YV.allocate(surf.Sides);
12806 1694 : state.dataSurface->ShadeV(ThisSurf).ZV.allocate(surf.Sides);
12807 :
12808 8474 : for (n = 1; n <= surf.Sides; ++n) {
12809 : // if less than 1/10 inch
12810 6780 : state.dataSurface->ShadeV(ThisSurf).XV(n) = state.dataSurfaceGeometry->Xpsv(n);
12811 6780 : state.dataSurface->ShadeV(ThisSurf).YV(n) = state.dataSurfaceGeometry->Ypsv(n);
12812 6780 : state.dataSurface->ShadeV(ThisSurf).ZV(n) = state.dataSurfaceGeometry->Zpsv(n);
12813 : }
12814 :
12815 : // Process Surfaces According to Type of Coordinate Origin.
12816 1694 : if (BaseSurface) {
12817 :
12818 : // General Surfaces:
12819 1559 : CalcCoordinateTransformation(state, ThisSurf, CoordinateTransVector); // X00,Y00,Z00,X,Y,Z,A) ! Compute Coordinate Transformation
12820 :
12821 : // RECORD DIRECTION COSINES.
12822 1559 : if (HeatTransSurf) { // This is a general surface but not detached shading surface
12823 :
12824 : // RECORD COORDINATE TRANSFORMATION FOR BASE SURFACES.
12825 1513 : state.dataSurface->X0(ThisBaseSurface) = CoordinateTransVector.x;
12826 1513 : state.dataSurface->Y0(ThisBaseSurface) = CoordinateTransVector.y;
12827 1513 : state.dataSurface->Z0(ThisBaseSurface) = CoordinateTransVector.z;
12828 :
12829 : // COMPUTE INVERSE TRANSFORMATION.
12830 1513 : X1 = state.dataSurfaceGeometry->Xpsv(2) - CoordinateTransVector.x;
12831 1513 : Y1 = state.dataSurfaceGeometry->Ypsv(2) - CoordinateTransVector.y;
12832 1513 : Z1 = state.dataSurfaceGeometry->Zpsv(2) - CoordinateTransVector.z;
12833 : // Store the relative coordinate shift values for later use by any subsurfaces
12834 3026 : state.dataSurface->Surface(ThisBaseSurface).XShift = state.dataSurface->Surface(ThisBaseSurface).lcsx.x * X1 +
12835 1513 : state.dataSurface->Surface(ThisBaseSurface).lcsx.y * Y1 +
12836 1513 : state.dataSurface->Surface(ThisBaseSurface).lcsx.z * Z1;
12837 3026 : state.dataSurface->Surface(ThisBaseSurface).YShift = state.dataSurface->Surface(ThisBaseSurface).lcsy.x * X1 +
12838 1513 : state.dataSurface->Surface(ThisBaseSurface).lcsy.y * Y1 +
12839 1513 : state.dataSurface->Surface(ThisBaseSurface).lcsy.z * Z1;
12840 1513 : state.dataSurface->Surface(ThisBaseSurface).VerticesProcessed = true;
12841 : }
12842 :
12843 : // SUBSURFACES: (Surface(ThisSurf)%BaseSurf /= ThisSurf)
12844 : } else {
12845 : // WINDOWS OR DOORS:
12846 :
12847 : // SHIFT RELATIVE COORDINATES FROM LOWER LEFT CORNER TO ORIGIN DEFINED
12848 : // BY CTRAN AND SET DIRECTION COSINES SAME AS BASE SURFACE.
12849 135 : if (!state.dataSurface->Surface(ThisBaseSurface).VerticesProcessed) {
12850 :
12851 4 : if (surf.IsAirBoundarySurf) {
12852 4 : ProcessSurfaceVertices(state, ThisBaseSurface, ErrorsFound);
12853 : } else {
12854 :
12855 0 : ShowSevereError(state, format("{}Developer error for Subsurface={}", RoutineName, surf.Name));
12856 0 : ShowContinueError(state,
12857 0 : format("Base surface={} vertices must be processed before any subsurfaces.",
12858 0 : state.dataSurface->Surface(ThisBaseSurface).Name));
12859 0 : ShowFatalError(state, std::string{RoutineName});
12860 : }
12861 : }
12862 :
12863 673 : for (n = 1; n <= surf.Sides; ++n) {
12864 538 : state.dataSurface->ShadeV(ThisSurf).XV(n) += state.dataSurface->Surface(ThisBaseSurface).XShift;
12865 538 : state.dataSurface->ShadeV(ThisSurf).YV(n) += state.dataSurface->Surface(ThisBaseSurface).YShift;
12866 : }
12867 : }
12868 1714 : }
12869 :
12870 1559 : void CalcCoordinateTransformation(EnergyPlusData &state,
12871 : int const SurfNum, // Surface Number
12872 : Vector &CompCoordTranslVector // Coordinate Translation Vector
12873 : )
12874 : {
12875 : // SUBROUTINE INFORMATION:
12876 : // AUTHOR George Walton, BLAST
12877 : // DATE WRITTEN August 1976
12878 : // MODIFIED LKL, May 2004 -- >4 sided polygons
12879 : // RE-ENGINEERED Yes
12880 :
12881 : // PURPOSE OF THIS SUBROUTINE:
12882 : // This subroutine develops a coordinate transformation such that the X-axis goes
12883 : // through points 2 and 3 and the Y-axis goes through point 1
12884 : // of a plane figure in 3-d space.
12885 :
12886 : // REFERENCES:
12887 : // 'NECAP' - NASA'S Energy-Cost Analysis Program
12888 :
12889 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
12890 : Real64 Gamma; // Intermediate Result
12891 : Real64 DotSelfX23;
12892 :
12893 : // Object Data
12894 1559 : Vector x21;
12895 1559 : Vector x23;
12896 :
12897 : // Determine Components of the Coordinate Translation Vector.
12898 1559 : auto const &surf = state.dataSurface->Surface(SurfNum);
12899 :
12900 1559 : x21 = surf.Vertex(2) - surf.Vertex(1);
12901 1559 : x23 = surf.Vertex(2) - surf.Vertex(3);
12902 :
12903 1559 : DotSelfX23 = magnitude_squared(x23);
12904 :
12905 1559 : if (DotSelfX23 <= Constant::OneMillionth) {
12906 0 : ShowSevereError(state, format("CalcCoordinateTransformation: Invalid dot product, surface=\"{}\":", surf.Name));
12907 0 : for (int I = 1; I <= surf.Sides; ++I) {
12908 0 : auto const &point = surf.Vertex(I);
12909 0 : ShowContinueError(state, format(" ({:8.3F},{:8.3F},{:8.3F})", point.x, point.y, point.z));
12910 : }
12911 0 : ShowFatalError(
12912 0 : state, "CalcCoordinateTransformation: Program terminates due to preceding condition.", OptionalOutputFileRef{state.files.eso});
12913 0 : return;
12914 : }
12915 :
12916 1559 : Gamma = dot(x21, x23) / magnitude_squared(x23);
12917 :
12918 1559 : CompCoordTranslVector = surf.Vertex(2) + Gamma * (surf.Vertex(3) - surf.Vertex(2));
12919 1559 : }
12920 :
12921 0 : void CreateShadedWindowConstruction(EnergyPlusData &state,
12922 : int const SurfNum, // Surface number
12923 : int const WSCPtr, // Pointer to WindowShadingControl for SurfNum
12924 : int const ShDevNum, // Shading device material number for WSCptr
12925 : int const shadeControlIndex // index to the Surface().windowShadingControlList,
12926 : // Surface().shadedConstructionList, and Surface().shadedStormWinConstructionList
12927 : )
12928 : {
12929 : // SUBROUTINE INFORMATION:
12930 : // AUTHOR Fred Winkelmann
12931 : // DATE WRITTEN Nov 2001
12932 :
12933 : // PURPOSE OF THIS SUBROUTINE:
12934 : // Creates a shaded window construction for windows whose WindowShadingControl
12935 : // has a shading device specified instead of a shaded construction
12936 :
12937 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
12938 : int ConstrNewSh; // Number of shaded construction that is created
12939 0 : std::string ConstrNameSh; // Shaded construction name
12940 :
12941 0 : auto &s_mat = state.dataMaterial;
12942 0 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
12943 :
12944 0 : std::string const &ShDevName = s_mat->materials(ShDevNum)->Name;
12945 0 : int ConstrNum = surfTemp.Construction;
12946 0 : std::string const &ConstrName = state.dataConstruction->Construct(ConstrNum).Name;
12947 :
12948 0 : if (ANY_INTERIOR_SHADE_BLIND(state.dataSurface->WindowShadingControl(WSCPtr).ShadingType)) {
12949 0 : ConstrNameSh = ConstrName + ':' + ShDevName + ":INT";
12950 : } else {
12951 0 : ConstrNameSh = ConstrName + ':' + ShDevName + ":EXT";
12952 : }
12953 :
12954 : // If this construction name already exists, set the surface's shaded construction number to it
12955 :
12956 0 : ConstrNewSh = Util::FindItemInList(ConstrNameSh, state.dataConstruction->Construct);
12957 :
12958 0 : if (ConstrNewSh > 0) {
12959 0 : surfTemp.shadedConstructionList[shadeControlIndex] = ConstrNewSh;
12960 0 : surfTemp.activeShadedConstruction = ConstrNewSh; // set the active to the current for now
12961 : } else {
12962 :
12963 : // Create new construction
12964 :
12965 0 : ConstrNewSh = state.dataHeatBal->TotConstructs + 1;
12966 0 : surfTemp.shadedConstructionList[shadeControlIndex] = ConstrNewSh;
12967 0 : surfTemp.activeShadedConstruction = ConstrNewSh; // set the active to the current for now
12968 0 : state.dataHeatBal->TotConstructs = ConstrNewSh;
12969 0 : state.dataConstruction->Construct.redimension(state.dataHeatBal->TotConstructs);
12970 0 : state.dataHeatBal->NominalRforNominalUCalculation.redimension(state.dataHeatBal->TotConstructs);
12971 0 : state.dataHeatBal->NominalRforNominalUCalculation(state.dataHeatBal->TotConstructs) = 0.0;
12972 0 : state.dataHeatBal->NominalU.redimension(state.dataHeatBal->TotConstructs);
12973 0 : state.dataHeatBal->NominalU(state.dataHeatBal->TotConstructs) = 0.0;
12974 0 : state.dataHeatBal->NominalUBeforeAdjusted.redimension(state.dataHeatBal->TotConstructs);
12975 0 : state.dataHeatBal->CoeffAdjRatio.redimension(state.dataHeatBal->TotConstructs) = 1.0;
12976 :
12977 0 : state.dataConstruction->Construct(state.dataHeatBal->TotConstructs).setArraysBasedOnMaxSolidWinLayers(state);
12978 :
12979 0 : int TotLayersOld = state.dataConstruction->Construct(ConstrNum).TotLayers;
12980 0 : int TotLayersNew = TotLayersOld + 1;
12981 :
12982 0 : state.dataConstruction->Construct(ConstrNewSh).LayerPoint = 0;
12983 :
12984 0 : auto const *thisMaterialSh = s_mat->materials(ShDevNum);
12985 0 : auto &thisConstructNewSh = state.dataConstruction->Construct(ConstrNewSh);
12986 0 : if (state.dataSurface->WindowShadingControl(WSCPtr).ShadingType == DataSurfaces::WinShadingType::IntShade ||
12987 0 : state.dataSurface->WindowShadingControl(WSCPtr).ShadingType == DataSurfaces::WinShadingType::IntBlind) {
12988 : // Interior shading device
12989 0 : thisConstructNewSh.LayerPoint({1, TotLayersOld}) = state.dataConstruction->Construct(ConstrNum).LayerPoint({1, TotLayersOld});
12990 0 : thisConstructNewSh.LayerPoint(TotLayersNew) = ShDevNum;
12991 0 : thisConstructNewSh.InsideAbsorpSolar = thisMaterialSh->AbsorpSolar;
12992 0 : auto const *thisMaterialShLayer1 = s_mat->materials(state.dataConstruction->Construct(ConstrNewSh).LayerPoint(1));
12993 0 : thisConstructNewSh.OutsideAbsorpSolar = thisMaterialShLayer1->AbsorpSolar;
12994 0 : thisConstructNewSh.OutsideAbsorpThermal = thisMaterialShLayer1->AbsorpThermalFront;
12995 : } else {
12996 : // Exterior shading device
12997 0 : thisConstructNewSh.LayerPoint(1) = ShDevNum;
12998 0 : thisConstructNewSh.LayerPoint({2, TotLayersNew}) = state.dataConstruction->Construct(ConstrNum).LayerPoint({1, TotLayersOld});
12999 0 : auto const *thisMaterialShInside = s_mat->materials(state.dataConstruction->Construct(ConstrNewSh).LayerPoint(TotLayersNew));
13000 0 : thisConstructNewSh.InsideAbsorpSolar = thisMaterialShInside->AbsorpSolar;
13001 0 : thisConstructNewSh.OutsideAbsorpSolar = thisMaterialSh->AbsorpSolar;
13002 0 : thisConstructNewSh.OutsideAbsorpThermal = thisMaterialSh->AbsorpThermalFront;
13003 : }
13004 : // The following InsideAbsorpThermal applies only to inside glass; it is corrected
13005 : // later in InitGlassOpticalCalculations if construction has inside shade or blind.
13006 0 : thisConstructNewSh.InsideAbsorpThermal =
13007 0 : s_mat->materials(state.dataConstruction->Construct(ConstrNum).LayerPoint(TotLayersOld))->AbsorpThermalBack;
13008 0 : thisConstructNewSh.OutsideRoughness = Material::SurfaceRoughness::VerySmooth;
13009 0 : thisConstructNewSh.DayltPropPtr = 0;
13010 0 : thisConstructNewSh.CTFCross.fill(0.0);
13011 0 : thisConstructNewSh.CTFFlux.fill(0.0);
13012 0 : thisConstructNewSh.CTFInside.fill(0.0);
13013 0 : thisConstructNewSh.CTFOutside.fill(0.0);
13014 0 : thisConstructNewSh.CTFSourceIn.fill(0.0);
13015 0 : thisConstructNewSh.CTFSourceOut.fill(0.0);
13016 0 : thisConstructNewSh.CTFTimeStep = 0.0;
13017 0 : thisConstructNewSh.CTFTSourceOut.fill(0.0);
13018 0 : thisConstructNewSh.CTFTSourceIn.fill(0.0);
13019 0 : thisConstructNewSh.CTFTSourceQ.fill(0.0);
13020 0 : thisConstructNewSh.CTFTUserOut.fill(0.0);
13021 0 : thisConstructNewSh.CTFTUserIn.fill(0.0);
13022 0 : thisConstructNewSh.CTFTUserSource.fill(0.0);
13023 0 : thisConstructNewSh.NumHistories = 0;
13024 0 : thisConstructNewSh.NumCTFTerms = 0;
13025 0 : thisConstructNewSh.UValue = 0.0;
13026 0 : thisConstructNewSh.SourceSinkPresent = false;
13027 0 : thisConstructNewSh.SolutionDimensions = 0;
13028 0 : thisConstructNewSh.SourceAfterLayer = 0;
13029 0 : thisConstructNewSh.TempAfterLayer = 0;
13030 0 : thisConstructNewSh.ThicknessPerpend = 0.0;
13031 0 : thisConstructNewSh.AbsDiff = 0.0;
13032 0 : thisConstructNewSh.AbsDiffBack = 0.0;
13033 0 : thisConstructNewSh.AbsDiffShade = 0.0;
13034 0 : thisConstructNewSh.AbsDiffBackShade = 0.0;
13035 0 : thisConstructNewSh.ShadeAbsorpThermal = 0.0;
13036 0 : std::fill(thisConstructNewSh.AbsBeamShadeCoef.begin(), thisConstructNewSh.AbsBeamShadeCoef.end(), 0.0);
13037 0 : thisConstructNewSh.TransDiff = 0.0;
13038 0 : thisConstructNewSh.TransDiffVis = 0.0;
13039 0 : thisConstructNewSh.ReflectSolDiffBack = 0.0;
13040 0 : thisConstructNewSh.ReflectSolDiffFront = 0.0;
13041 0 : thisConstructNewSh.ReflectVisDiffBack = 0.0;
13042 0 : thisConstructNewSh.ReflectVisDiffFront = 0.0;
13043 0 : std::fill(thisConstructNewSh.TransSolBeamCoef.begin(), thisConstructNewSh.TransSolBeamCoef.end(), 0.0);
13044 0 : std::fill(thisConstructNewSh.TransVisBeamCoef.begin(), thisConstructNewSh.TransVisBeamCoef.end(), 0.0);
13045 0 : std::fill(thisConstructNewSh.ReflSolBeamFrontCoef.begin(), thisConstructNewSh.ReflSolBeamFrontCoef.end(), 0.0);
13046 0 : std::fill(thisConstructNewSh.ReflSolBeamBackCoef.begin(), thisConstructNewSh.ReflSolBeamBackCoef.end(), 0.0);
13047 0 : thisConstructNewSh.W5FrameDivider = 0;
13048 0 : thisConstructNewSh.FromWindow5DataFile = false;
13049 :
13050 0 : thisConstructNewSh.Name = ConstrNameSh;
13051 0 : thisConstructNewSh.TotLayers = TotLayersNew;
13052 0 : thisConstructNewSh.TotSolidLayers = state.dataConstruction->Construct(ConstrNum).TotSolidLayers + 1;
13053 0 : thisConstructNewSh.TotGlassLayers = state.dataConstruction->Construct(ConstrNum).TotGlassLayers;
13054 0 : thisConstructNewSh.TypeIsWindow = true;
13055 0 : thisConstructNewSh.IsUsed = true;
13056 :
13057 0 : for (int Layer = 1; Layer <= state.dataHeatBal->MaxSolidWinLayers; ++Layer) {
13058 0 : std::fill(thisConstructNewSh.AbsBeamCoef(Layer).begin(), thisConstructNewSh.AbsBeamCoef(Layer).end(), 0.0);
13059 0 : std::fill(thisConstructNewSh.AbsBeamBackCoef(Layer).begin(), thisConstructNewSh.AbsBeamBackCoef(Layer).end(), 0.0);
13060 : }
13061 : }
13062 0 : }
13063 :
13064 0 : void CreateStormWindowConstructions(EnergyPlusData &state)
13065 : {
13066 : // For windows with an associated StormWindow object, creates a construction
13067 : // consisting of the base construction plus a storm window and air gap on the outside.
13068 : // If the window has an interior or between-glass shade/blind, also creates a
13069 : // construction consisting of the storm window added to the shaded construction.
13070 0 : DisplayString(state, "Creating Storm Window Constructions");
13071 :
13072 0 : auto &s_mat = state.dataMaterial;
13073 :
13074 0 : for (int StormWinNum = 1; StormWinNum <= state.dataSurface->TotStormWin; ++StormWinNum) {
13075 0 : int SurfNum = state.dataSurface->StormWindow(StormWinNum).BaseWindowNum; // Surface number
13076 0 : auto &surf = state.dataSurface->Surface(SurfNum);
13077 0 : int ConstrNum = surf.Construction; // Number of unshaded construction
13078 : // Fatal error if base construction has more than three glass layers
13079 0 : if (state.dataConstruction->Construct(ConstrNum).TotGlassLayers > 3) {
13080 0 : ShowFatalError(state, format("Window={} has more than 3 glass layers; a storm window cannot be applied.", surf.Name));
13081 : }
13082 :
13083 : // create unshaded construction with storm window
13084 0 : const std::string ChrNum = fmt::to_string(StormWinNum);
13085 0 : std::string ConstrNameSt = "BARECONSTRUCTIONWITHSTORMWIN:" + ChrNum; // Name of unshaded construction with storm window
13086 : // If this construction name already exists, set the surface's storm window construction number to it
13087 0 : int ConstrNewSt = Util::FindItemInList(ConstrNameSt,
13088 0 : state.dataConstruction->Construct,
13089 0 : state.dataHeatBal->TotConstructs); // Number of unshaded storm window construction that is created
13090 : // If necessary, create new material corresponding to the air layer between the storm window and the rest of the window
13091 0 : int MatNewStAir = createAirMaterialFromDistance(state, state.dataSurface->StormWindow(StormWinNum).StormWinDistance, "AIR:STORMWIN:");
13092 0 : if (ConstrNewSt == 0) {
13093 0 : ConstrNewSt = createConstructionWithStorm(
13094 0 : state, ConstrNum, ConstrNameSt, state.dataSurface->StormWindow(StormWinNum).StormWinMaterialNum, MatNewStAir);
13095 : }
13096 0 : state.dataSurface->SurfWinStormWinConstr(SurfNum) = ConstrNewSt;
13097 :
13098 : // create shaded constructions with storm window
13099 0 : surf.shadedStormWinConstructionList.resize(surf.shadedConstructionList.size(),
13100 0 : 0); // make the shaded storm window size the same size as the number of shaded constructions
13101 0 : for (std::size_t iConstruction = 0; iConstruction < surf.shadedConstructionList.size(); ++iConstruction) {
13102 0 : int curConstruction = surf.shadedConstructionList[iConstruction];
13103 : // Set ShAndSt, which is true if the window has a shaded construction to which a storm window
13104 : // can be added. (A storm window can be added if there is an interior shade or blind and up to three
13105 : // glass layers, or there is a between-glass shade or blind and two glass layers.)
13106 0 : bool ShAndSt = false; // True if unshaded and shaded window can have a storm window
13107 0 : int TotLayers = state.dataConstruction->Construct(curConstruction).TotLayers; // Total layers in a construction
13108 0 : int MatIntSh = state.dataConstruction->Construct(curConstruction).LayerPoint(TotLayers); // Material number of interior shade or blind
13109 0 : int MatBetweenGlassSh = 0; // Material number of between-glass shade or blind
13110 0 : if (TotLayers == 5) MatBetweenGlassSh = state.dataConstruction->Construct(curConstruction).LayerPoint(3);
13111 0 : if (state.dataConstruction->Construct(curConstruction).TotGlassLayers <= 3 &&
13112 0 : (s_mat->materials(MatIntSh)->group == Material::Group::Shade || s_mat->materials(MatIntSh)->group == Material::Group::Blind))
13113 0 : ShAndSt = true;
13114 0 : if (MatBetweenGlassSh > 0) {
13115 0 : if (s_mat->materials(MatBetweenGlassSh)->group == Material::Group::Shade ||
13116 0 : s_mat->materials(MatBetweenGlassSh)->group == Material::Group::Blind) {
13117 0 : ShAndSt = true;
13118 : } else {
13119 0 : ShowContinueError(state, format("Window={} has a shaded construction to which a storm window cannot be applied.", surf.Name));
13120 0 : ShowContinueError(state, "Storm windows can only be applied to shaded constructions that:");
13121 0 : ShowContinueError(state, "have an interior shade or blind and up to three glass layers, or");
13122 0 : ShowContinueError(state, "have a between-glass shade or blind and two glass layers.");
13123 0 : ShowFatalError(state, "EnergyPlus is exiting due to reason stated above.");
13124 : }
13125 : }
13126 0 : if (ShAndSt) {
13127 0 : std::string ConstrNameStSh = "SHADEDCONSTRUCTIONWITHSTORMWIN:" + state.dataConstruction->Construct(iConstruction).Name + ":" +
13128 0 : ChrNum; // Name of shaded construction with storm window
13129 0 : int ConstrNewStSh = createConstructionWithStorm(
13130 0 : state, ConstrNum, ConstrNameStSh, state.dataSurface->StormWindow(StormWinNum).StormWinMaterialNum, MatNewStAir);
13131 0 : surf.shadedStormWinConstructionList[iConstruction] = ConstrNewStSh; // put in same index as the shaded construction
13132 0 : }
13133 : } // end of loop for shaded constructions
13134 0 : } // end of loop over storm window objects
13135 0 : }
13136 :
13137 3 : int createAirMaterialFromDistance(EnergyPlusData &state, Real64 distance, std::string_view namePrefix)
13138 : {
13139 3 : auto const &s_mat = state.dataMaterial;
13140 :
13141 3 : int mmDistance = int(1000 * distance); // Thickness of air gap in mm (usually between storm window and rest of window)
13142 3 : std::string MatNameStAir = format("{}{}MM", namePrefix, mmDistance); // Name of created air layer material
13143 3 : int matNum = Material::GetMaterialNum(state, MatNameStAir);
13144 3 : if (matNum != 0) return matNum;
13145 :
13146 : // Create new material
13147 2 : auto *mat = new Material::MaterialGasMix;
13148 2 : mat->Name = MatNameStAir;
13149 2 : mat->group = Material::Group::Gas;
13150 :
13151 2 : s_mat->materials.push_back(mat);
13152 2 : mat->Num = s_mat->materials.isize();
13153 2 : s_mat->materialMap.insert_or_assign(Util::makeUPPER(mat->Name), mat->Num);
13154 :
13155 2 : mat->Roughness = Material::SurfaceRoughness::MediumRough;
13156 2 : mat->Conductivity = 0.0;
13157 2 : mat->Density = 0.0;
13158 2 : mat->Resistance = 0.0;
13159 2 : mat->SpecHeat = 0.0;
13160 2 : mat->Thickness = distance;
13161 2 : mat->numGases = 1;
13162 2 : mat->gases[0] = Material::gases[(int)Material::GasType::Air];
13163 2 : mat->gasFracts[0] = 1.0;
13164 2 : mat->AbsorpSolar = 0.0;
13165 2 : mat->AbsorpThermal = 0.0;
13166 2 : mat->AbsorpVisible = 0.0;
13167 2 : return mat->Num;
13168 3 : }
13169 :
13170 : // create a new construction with storm based on an old construction and storm and gap materials
13171 1 : int createConstructionWithStorm(EnergyPlusData &state, int oldConstruction, std::string name, int stormMaterial, int gapMaterial)
13172 : {
13173 1 : int newConstruct = Util::FindItemInList(name,
13174 1 : state.dataConstruction->Construct,
13175 1 : state.dataHeatBal->TotConstructs); // Number of shaded storm window construction that is created
13176 1 : if (newConstruct == 0) {
13177 1 : auto &s_mat = state.dataMaterial;
13178 1 : state.dataHeatBal->TotConstructs = state.dataHeatBal->TotConstructs + 1;
13179 1 : newConstruct = state.dataHeatBal->TotConstructs;
13180 1 : state.dataConstruction->Construct.redimension(state.dataHeatBal->TotConstructs);
13181 1 : state.dataHeatBal->NominalRforNominalUCalculation.redimension(state.dataHeatBal->TotConstructs);
13182 1 : state.dataHeatBal->NominalU.redimension(state.dataHeatBal->TotConstructs);
13183 1 : state.dataHeatBal->NominalUBeforeAdjusted.redimension(state.dataHeatBal->TotConstructs);
13184 1 : state.dataHeatBal->CoeffAdjRatio.redimension(state.dataHeatBal->TotConstructs) = 1.0;
13185 :
13186 1 : auto &thisConstruct = state.dataConstruction->Construct(state.dataHeatBal->TotConstructs);
13187 : // these Construct arrays dimensioned based on MaxSolidWinLayers
13188 1 : thisConstruct.setArraysBasedOnMaxSolidWinLayers(state);
13189 :
13190 1 : int TotLayersOld = state.dataConstruction->Construct(oldConstruction).TotLayers;
13191 1 : thisConstruct.LayerPoint({1, Construction::MaxLayersInConstruct}) = 0;
13192 1 : thisConstruct.LayerPoint(1) = stormMaterial;
13193 1 : thisConstruct.LayerPoint(2) = gapMaterial;
13194 1 : thisConstruct.LayerPoint({3, TotLayersOld + 2}) = state.dataConstruction->Construct(oldConstruction).LayerPoint({1, TotLayersOld});
13195 1 : thisConstruct.Name = name;
13196 1 : thisConstruct.TotLayers = TotLayersOld + 2;
13197 1 : thisConstruct.TotSolidLayers = state.dataConstruction->Construct(oldConstruction).TotSolidLayers + 1;
13198 1 : thisConstruct.TotGlassLayers = state.dataConstruction->Construct(oldConstruction).TotGlassLayers + 1;
13199 1 : thisConstruct.TypeIsWindow = true;
13200 1 : thisConstruct.InsideAbsorpVis = 0.0;
13201 1 : thisConstruct.OutsideAbsorpVis = 0.0;
13202 1 : thisConstruct.InsideAbsorpSolar = 0.0;
13203 1 : thisConstruct.OutsideAbsorpSolar = 0.0;
13204 1 : thisConstruct.InsideAbsorpThermal = state.dataConstruction->Construct(oldConstruction).InsideAbsorpThermal;
13205 1 : thisConstruct.OutsideAbsorpThermal = s_mat->materials(stormMaterial)->AbsorpThermalFront;
13206 1 : thisConstruct.OutsideRoughness = Material::SurfaceRoughness::VerySmooth;
13207 1 : thisConstruct.DayltPropPtr = 0;
13208 1 : thisConstruct.CTFCross.fill(0.0);
13209 1 : thisConstruct.CTFFlux.fill(0.0);
13210 1 : thisConstruct.CTFInside.fill(0.0);
13211 1 : thisConstruct.CTFOutside.fill(0.0);
13212 1 : thisConstruct.CTFSourceIn.fill(0.0);
13213 1 : thisConstruct.CTFSourceOut.fill(0.0);
13214 1 : thisConstruct.CTFTimeStep = 0.0;
13215 1 : thisConstruct.CTFTSourceOut.fill(0.0);
13216 1 : thisConstruct.CTFTSourceIn.fill(0.0);
13217 1 : thisConstruct.CTFTSourceQ.fill(0.0);
13218 1 : thisConstruct.CTFTUserOut.fill(0.0);
13219 1 : thisConstruct.CTFTUserIn.fill(0.0);
13220 1 : thisConstruct.CTFTUserSource.fill(0.0);
13221 1 : thisConstruct.NumHistories = 0;
13222 1 : thisConstruct.NumCTFTerms = 0;
13223 1 : thisConstruct.UValue = 0.0;
13224 1 : thisConstruct.SourceSinkPresent = false;
13225 1 : thisConstruct.SolutionDimensions = 0;
13226 1 : thisConstruct.SourceAfterLayer = 0;
13227 1 : thisConstruct.TempAfterLayer = 0;
13228 1 : thisConstruct.ThicknessPerpend = 0.0;
13229 1 : thisConstruct.AbsDiffIn = 0.0;
13230 1 : thisConstruct.AbsDiffOut = 0.0;
13231 1 : thisConstruct.AbsDiff = 0.0;
13232 1 : thisConstruct.AbsDiffBack = 0.0;
13233 1 : thisConstruct.AbsDiffShade = 0.0;
13234 1 : thisConstruct.AbsDiffBackShade = 0.0;
13235 1 : thisConstruct.ShadeAbsorpThermal = 0.0;
13236 1 : std::fill(thisConstruct.AbsBeamShadeCoef.begin(), thisConstruct.AbsBeamShadeCoef.end(), 0.0);
13237 1 : thisConstruct.TransDiff = 0.0;
13238 1 : thisConstruct.TransDiffVis = 0.0;
13239 1 : thisConstruct.ReflectSolDiffBack = 0.0;
13240 1 : thisConstruct.ReflectSolDiffFront = 0.0;
13241 1 : thisConstruct.ReflectVisDiffBack = 0.0;
13242 1 : thisConstruct.ReflectVisDiffFront = 0.0;
13243 1 : std::fill(thisConstruct.TransSolBeamCoef.begin(), thisConstruct.TransSolBeamCoef.end(), 0.0);
13244 1 : std::fill(thisConstruct.TransVisBeamCoef.begin(), thisConstruct.TransVisBeamCoef.end(), 0.0);
13245 1 : std::fill(thisConstruct.ReflSolBeamFrontCoef.begin(), thisConstruct.ReflSolBeamFrontCoef.end(), 0.0);
13246 1 : std::fill(thisConstruct.ReflSolBeamBackCoef.begin(), thisConstruct.ReflSolBeamBackCoef.end(), 0.0);
13247 1 : thisConstruct.W5FrameDivider = 0;
13248 1 : thisConstruct.FromWindow5DataFile = false;
13249 1 : thisConstruct.W5FileMullionWidth = 0.0;
13250 1 : thisConstruct.W5FileMullionOrientation = DataWindowEquivalentLayer::Orientation::Invalid;
13251 1 : thisConstruct.W5FileGlazingSysWidth = 0.0;
13252 1 : thisConstruct.W5FileGlazingSysHeight = 0.0;
13253 1 : for (int Layer = 1; Layer <= state.dataHeatBal->MaxSolidWinLayers; ++Layer) {
13254 0 : std::fill(thisConstruct.AbsBeamCoef(Layer).begin(), thisConstruct.AbsBeamCoef(Layer).end(), 0.0);
13255 0 : std::fill(thisConstruct.AbsBeamBackCoef(Layer).begin(), thisConstruct.AbsBeamBackCoef(Layer).end(), 0.0);
13256 : }
13257 : }
13258 1 : return (newConstruct);
13259 : }
13260 :
13261 0 : void ModifyWindow(EnergyPlusData &state,
13262 : int const SurfNum, // SurfNum has construction of glazing system from Window5 Data File;
13263 : bool &ErrorsFound, // Set to true if errors found
13264 : int &AddedSubSurfaces // Subsurfaces added when window references a
13265 : )
13266 : {
13267 : // SUBROUTINE INFORMATION:
13268 : // AUTHOR Fred Winkelmann
13269 : // DATE WRITTEN Feb 2002
13270 : // MODIFIED June 2004, FCW: SinAzim, CosAzim, SinTilt, CosTilt, OutNormVec, GrossArea
13271 : // and Perimeter weren't being set for created window for case when
13272 : // window from Window5DataFile had two different glazing systems. Also,
13273 : // GrossArea and Perimeter of original window were not being recalculated.
13274 : // October 2007, LKL: Net area for shading calculations was not being
13275 : // recalculated.
13276 :
13277 : // PURPOSE OF THIS SUBROUTINE:
13278 : // If a window from the Window5DataFile has one glazing system, modify the
13279 : // vertex coordinates of the original window to correspond to the dimensions
13280 : // of the glazing system on the Data File.
13281 : // If a window from the Window5DataFile has two different glazing systems, split
13282 : // the window into two separate windows with different properties and adjust the
13283 : // vertices of these windows taking into account the dimensions of the glazing systems
13284 : // on the Data File and the width and orientation of the mullion that separates
13285 : // the glazing systems.
13286 :
13287 : // SUBROUTINE ARGUMENT DEFINITIONS:
13288 : // If there is a second glazing system on the Data File, SurfNum+1
13289 : // has the construction of the second glazing system.
13290 :
13291 : // 2-glazing system Window5 data file entry
13292 :
13293 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
13294 : Real64 H; // Height and width of original window (m)
13295 : Real64 W;
13296 : // unused1208 REAL(r64) :: MulWidth ! Mullion width (m)
13297 : Real64 h1; // height and width of first glazing system (m)
13298 : Real64 w1;
13299 : // unused1208 REAL(r64) :: h2,w2 ! height and width of second glazing system (m)
13300 : // unused1208 type (rectangularwindow) :: NewCoord
13301 : int IConst; // Construction number of first glazing system
13302 : int IConst2; // Construction number of second glazing system
13303 0 : std::string Const2Name; // Name of construction of second glazing system
13304 : // unused1208 REAL(r64) :: AreaNew ! Sum of areas of the two glazing systems (m2)
13305 :
13306 0 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
13307 :
13308 : struct rectangularwindow
13309 : {
13310 : // Members
13311 : Array1D<Vector> Vertex;
13312 :
13313 : // Default Constructor
13314 0 : rectangularwindow() : Vertex(4)
13315 : {
13316 0 : }
13317 : };
13318 :
13319 : // Object Data
13320 0 : Vector TVect;
13321 0 : rectangularwindow OriginalCoord;
13322 :
13323 0 : IConst = surfTemp.Construction;
13324 :
13325 : // Height and width of original window
13326 0 : TVect = surfTemp.Vertex(3) - surfTemp.Vertex(2);
13327 0 : W = Vectors::VecLength(TVect); // SQRT((X(3)-X(2))**2 + (Y(3)-Y(2))**2 + (Z(3)-Z(2))**2)
13328 0 : TVect = surfTemp.Vertex(2) - surfTemp.Vertex(1);
13329 0 : H = Vectors::VecLength(TVect); // SQRT((X(1)-X(2))**2 + (Y(1)-Y(2))**2 + (Z(1)-Z(2))**2)
13330 :
13331 : // Save coordinates of original window in case Window 5 data overwrites.
13332 0 : OriginalCoord.Vertex({1, surfTemp.Sides}) = surfTemp.Vertex({1, surfTemp.Sides});
13333 :
13334 : // Height and width of first glazing system
13335 0 : h1 = state.dataConstruction->Construct(IConst).W5FileGlazingSysHeight;
13336 0 : w1 = state.dataConstruction->Construct(IConst).W5FileGlazingSysWidth;
13337 :
13338 0 : Const2Name = state.dataConstruction->Construct(IConst).Name + ":2";
13339 0 : IConst2 = Util::FindItemInList(Const2Name, state.dataConstruction->Construct);
13340 :
13341 0 : if (IConst2 == 0) { // Only one glazing system on Window5 Data File for this window.
13342 :
13343 : // So... original dimensions and area of window are used (entered in IDF)
13344 : // Warning if dimensions of original window differ from those on Data File by more than 10%
13345 :
13346 0 : if (std::abs((H - h1) / H) > 0.10 || std::abs((W - w1) / W) > 0.10) {
13347 :
13348 0 : if (state.dataGlobal->DisplayExtraWarnings) {
13349 0 : ShowWarningError(state,
13350 0 : format("SurfaceGeometry: ModifyWindow: Window {} uses the Window5 Data File Construction {}",
13351 0 : surfTemp.Name,
13352 0 : state.dataConstruction->Construct(IConst).Name));
13353 0 : ShowContinueError(state, format("The height {:.3R}(m) or width (m) of this window differs by more than 10%{:.3R}", H, W));
13354 0 : ShowContinueError(state,
13355 0 : format("from the corresponding height {:.3R} (m) or width (m) on the Window5 Data file.{:.3R}", h1, w1));
13356 0 : ShowContinueError(state, "This will affect the frame heat transfer calculation if the frame in the Data File entry");
13357 0 : ShowContinueError(state, "is not uniform, i.e., has sections with different geometry and/or thermal properties.");
13358 : } else {
13359 0 : ++state.dataSurfaceGeometry->Warning1Count;
13360 : }
13361 : }
13362 :
13363 : // Calculate net area for base surface
13364 0 : state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).Area -= surfTemp.Area;
13365 0 : if (state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).Area <= 0.0) {
13366 0 : ShowSevereError(
13367 : state,
13368 0 : format("Subsurfaces have too much area for base surface={}", state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).Name));
13369 0 : ShowContinueError(state, format("Subsurface creating error={}", surfTemp.Name));
13370 0 : ErrorsFound = true;
13371 : }
13372 :
13373 : // Net area of base surface with unity window multipliers (used in shadowing checks)
13374 0 : state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).NetAreaShadowCalc -= surfTemp.Area / surfTemp.Multiplier;
13375 :
13376 : } else { // Two glazing systems on Window5 data file for this window
13377 :
13378 : // if exterior window, okay.
13379 :
13380 0 : if (surfTemp.ExtBoundCond == DataSurfaces::ExternalEnvironment) {
13381 : // There are two glazing systems (separated by a vertical or horizontal mullion) on the Window5 Data File.
13382 : // Fill in geometry data for the second window (corresponding to the second glazing system on the data file.
13383 : // The first glazing system is assumed to be at left for vertical mullion, at bottom for horizontal mullion.
13384 : // The second glazing system is assumed to be at right for vertical mullion, at top for horizontal mullion.
13385 : // The lower left-hand corner of the original window (its vertex #2) is assumed to coincide with
13386 : // vertex #2 of the first glazing system.
13387 :
13388 0 : if (state.dataGlobal->DisplayExtraWarnings) {
13389 0 : ShowMessage(state,
13390 0 : format("SurfaceGeometry: ModifyWindow: Window {} has been replaced with the Window 5/6 two glazing system=\"{}\".",
13391 0 : surfTemp.Name,
13392 0 : state.dataConstruction->Construct(IConst).Name));
13393 0 : ShowContinueError(state, "Note that originally entered dimensions are overridden.");
13394 : } else {
13395 0 : ++state.dataSurfaceGeometry->Warning2Count;
13396 : }
13397 :
13398 : // Allocate another window
13399 0 : AddWindow(state, SurfNum, ErrorsFound, AddedSubSurfaces);
13400 :
13401 0 : } else if (surfTemp.ExtBoundCond > 0) { // Interior window, specified ! not external environment
13402 :
13403 0 : if (state.dataGlobal->DisplayExtraWarnings) {
13404 0 : ShowWarningError(
13405 : state,
13406 0 : format("SurfaceGeometry: ModifyWindow: Interior Window {} has been replaced with the Window 5/6 two glazing system=\"{}\".",
13407 0 : surfTemp.Name,
13408 0 : state.dataConstruction->Construct(IConst).Name));
13409 0 : ShowContinueError(
13410 : state, "Please check to make sure interior window is correct. Note that originally entered dimensions are overridden.");
13411 : } else {
13412 0 : ++state.dataSurfaceGeometry->Warning3Count;
13413 : }
13414 :
13415 0 : AddWindow(state, SurfNum, ErrorsFound, AddedSubSurfaces);
13416 :
13417 : } else { // Interior window, specified not entered
13418 :
13419 0 : ShowSevereError(state, format("SurfaceGeometry: ModifyWindow: Interior Window {} is a window in an adjacent zone.", surfTemp.Name));
13420 0 : ShowContinueError(
13421 : state,
13422 0 : format("Attempted to add/reverse Window 5/6 multiple glazing system=\"{}\".", state.dataConstruction->Construct(IConst).Name));
13423 0 : ShowContinueError(state, "Cannot use these Window 5/6 constructs for these Interior Windows. Program will terminate.");
13424 0 : ErrorsFound = true;
13425 : }
13426 :
13427 : } // End of check if one or two glazing systems are on the Window5 Data File
13428 0 : }
13429 :
13430 0 : void AddWindow(EnergyPlusData &state,
13431 : int const SurfNum, // SurfNum has construction of glazing system from Window5 Data File;
13432 : bool &ErrorsFound, // Set to true if errors found
13433 : int &AddedSubSurfaces // Subsurfaces added when window references a
13434 : )
13435 : {
13436 : // SUBROUTINE INFORMATION:
13437 : // AUTHOR Linda Lawrie
13438 : // DATE WRITTEN Nov 2008
13439 :
13440 : // PURPOSE OF THIS SUBROUTINE:
13441 : // This routine is called from ModifyWindow to add a window. Allows it to be
13442 : // called in more than one place in the calling routine so as to be able to have
13443 : // specific warnings or errors issued.
13444 :
13445 : // SUBROUTINE ARGUMENT DEFINITIONS:
13446 : // If there is a second glazing system on the Data File, SurfNum+1
13447 : // has the construction of the second glazing system.
13448 :
13449 : // 2-glazing system Window5 data file entry
13450 :
13451 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
13452 : int loop; // DO loop index
13453 : Real64 H; // Height and width of original window (m)
13454 : Real64 W;
13455 : Real64 MulWidth; // Mullion width (m)
13456 : Real64 h1; // height and width of first glazing system (m)
13457 : Real64 w1;
13458 : Real64 h2; // height and width of second glazing system (m)
13459 : Real64 w2;
13460 : Real64 xa; // Vertex intermediate variables (m)
13461 : Real64 ya;
13462 : Real64 za;
13463 : Real64 xb;
13464 : Real64 yb;
13465 : Real64 zb;
13466 : Real64 dx; // Vertex displacements from original window (m)
13467 : Real64 dy;
13468 : int IConst; // Construction number of first glazing system
13469 : int IConst2; // Construction number of second glazing system
13470 0 : std::string Const2Name; // Name of construction of second glazing system
13471 : Real64 AreaNew; // Sum of areas of the two glazing systems (m2)
13472 :
13473 : struct rectangularwindow
13474 : {
13475 : // Members
13476 : Array1D<Vector> Vertex;
13477 :
13478 : // Default Constructor
13479 0 : rectangularwindow() : Vertex(4)
13480 : {
13481 0 : }
13482 : };
13483 :
13484 : // Object Data
13485 0 : Vector TVect;
13486 0 : rectangularwindow NewCoord;
13487 0 : rectangularwindow OriginalCoord;
13488 :
13489 0 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
13490 :
13491 0 : IConst = surfTemp.Construction;
13492 :
13493 : // Height and width of original window
13494 0 : TVect = surfTemp.Vertex(3) - surfTemp.Vertex(2);
13495 0 : W = Vectors::VecLength(TVect); // SQRT((X(3)-X(2))**2 + (Y(3)-Y(2))**2 + (Z(3)-Z(2))**2)
13496 0 : TVect = surfTemp.Vertex(2) - surfTemp.Vertex(1);
13497 0 : H = Vectors::VecLength(TVect); // SQRT((X(1)-X(2))**2 + (Y(1)-Y(2))**2 + (Z(1)-Z(2))**2)
13498 :
13499 : // Save coordinates of original window in case Window 5 data overwrites.
13500 0 : OriginalCoord.Vertex({1, surfTemp.Sides}) = surfTemp.Vertex({1, surfTemp.Sides});
13501 :
13502 : // Height and width of first glazing system
13503 0 : h1 = state.dataConstruction->Construct(IConst).W5FileGlazingSysHeight;
13504 0 : w1 = state.dataConstruction->Construct(IConst).W5FileGlazingSysWidth;
13505 :
13506 0 : Const2Name = state.dataConstruction->Construct(IConst).Name + ":2";
13507 0 : IConst2 = Util::FindItemInList(Const2Name, state.dataConstruction->Construct);
13508 :
13509 0 : ++AddedSubSurfaces;
13510 0 : state.dataSurfaceGeometry->SurfaceTmp.redimension(++state.dataSurface->TotSurfaces);
13511 :
13512 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Vertex.allocate(4);
13513 :
13514 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Name = surfTemp.Name + ":2";
13515 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Construction = IConst2;
13516 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).ConstructionStoredInputValue = IConst2;
13517 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Class = surfTemp.Class;
13518 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Azimuth = surfTemp.Azimuth;
13519 : // Sine and cosine of azimuth and tilt
13520 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).SinAzim = surfTemp.SinAzim;
13521 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).CosAzim = surfTemp.CosAzim;
13522 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).SinTilt = surfTemp.SinTilt;
13523 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).CosTilt = surfTemp.CosTilt;
13524 : // Outward normal unit vector (pointing away from room)
13525 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Centroid = surfTemp.Centroid;
13526 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).lcsx = surfTemp.lcsx;
13527 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).lcsy = surfTemp.lcsy;
13528 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).lcsz = surfTemp.lcsz;
13529 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).NewellAreaVector = surfTemp.NewellAreaVector;
13530 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).OutNormVec = surfTemp.OutNormVec;
13531 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Reveal = surfTemp.Reveal;
13532 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Shape = surfTemp.Shape;
13533 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Sides = surfTemp.Sides;
13534 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Tilt = surfTemp.Tilt;
13535 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).convOrientation = Convect::GetSurfConvOrientation(surfTemp.Tilt);
13536 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).HeatTransSurf = surfTemp.HeatTransSurf;
13537 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).BaseSurfName = surfTemp.BaseSurfName;
13538 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).BaseSurf = surfTemp.BaseSurf;
13539 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).ZoneName = surfTemp.ZoneName;
13540 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Zone = surfTemp.Zone;
13541 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).ExtBoundCondName = surfTemp.ExtBoundCondName;
13542 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).ExtBoundCond = surfTemp.ExtBoundCond;
13543 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).ExtSolar = surfTemp.ExtSolar;
13544 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).ExtWind = surfTemp.ExtWind;
13545 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).ViewFactorGround = surfTemp.ViewFactorGround;
13546 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).ViewFactorSky = surfTemp.ViewFactorSky;
13547 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).ViewFactorGroundIR = surfTemp.ViewFactorGroundIR;
13548 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).ViewFactorSkyIR = surfTemp.ViewFactorSkyIR;
13549 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).OSCPtr = surfTemp.OSCPtr;
13550 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).shadowSurfSched = surfTemp.shadowSurfSched;
13551 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).activeWindowShadingControl = surfTemp.activeWindowShadingControl;
13552 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).windowShadingControlList = surfTemp.windowShadingControlList;
13553 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).HasShadeControl = surfTemp.HasShadeControl;
13554 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).activeShadedConstruction = surfTemp.activeShadedConstruction;
13555 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).windowShadingControlList = surfTemp.windowShadingControlList;
13556 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).shadedStormWinConstructionList =
13557 0 : surfTemp.shadedStormWinConstructionList;
13558 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).FrameDivider = surfTemp.FrameDivider;
13559 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Multiplier = surfTemp.Multiplier;
13560 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).NetAreaShadowCalc = surfTemp.NetAreaShadowCalc;
13561 :
13562 0 : MulWidth = state.dataConstruction->Construct(IConst).W5FileMullionWidth;
13563 0 : w2 = state.dataConstruction->Construct(IConst2).W5FileGlazingSysWidth;
13564 0 : h2 = state.dataConstruction->Construct(IConst2).W5FileGlazingSysHeight;
13565 :
13566 : // Correction to net area of base surface. Add back in the original glazing area and subtract the
13567 : // area of the two glazing systems. Note that for Surface(SurfNum)%Class = 'Window' the effect
13568 : // of a window multiplier is included in the glazing area. Note that frame areas are subtracted later.
13569 :
13570 0 : AreaNew = surfTemp.Multiplier * (h1 * w1 + h2 * w2); // both glazing systems
13571 : // Adjust net area for base surface
13572 0 : state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).Area -= AreaNew;
13573 :
13574 : // Net area of base surface with unity window multipliers (used in shadowing checks)
13575 0 : state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).NetAreaShadowCalc -= AreaNew / surfTemp.Multiplier;
13576 :
13577 : // Reset area, etc. of original window
13578 0 : surfTemp.Area = surfTemp.Multiplier * (h1 * w1);
13579 0 : surfTemp.GrossArea = surfTemp.Area;
13580 0 : surfTemp.NetAreaShadowCalc = h1 * w1;
13581 0 : surfTemp.Perimeter = 2 * (h1 + w1);
13582 0 : surfTemp.Height = h1;
13583 0 : surfTemp.Width = w1;
13584 : // Set area, etc. of new window
13585 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Area =
13586 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Multiplier * (h2 * w2);
13587 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).GrossArea =
13588 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Area;
13589 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).NetAreaShadowCalc = h2 * w2;
13590 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Perimeter = 2 * (h2 + w2);
13591 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Height = h2;
13592 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Width = w2;
13593 :
13594 0 : if (state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).Area <= 0.0) {
13595 0 : ShowSevereError(state,
13596 0 : format("SurfaceGeometry: ModifyWindow: Subsurfaces have too much area for base surface={}",
13597 0 : state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).Name));
13598 0 : ShowContinueError(state, format("Subsurface (window) creating error={}", surfTemp.Name));
13599 0 : ShowContinueError(state,
13600 0 : format("This window has been replaced by two windows from the Window5 Data File of total area {:.2R} m2", AreaNew));
13601 0 : ErrorsFound = true;
13602 : }
13603 :
13604 : // Assign vertices to the new window; modify vertices of original window.
13605 : // In the following, vertices are numbered counter-clockwise with vertex #1 at the upper left.
13606 :
13607 0 : if (state.dataConstruction->Construct(IConst).W5FileMullionOrientation == DataWindowEquivalentLayer::Orientation::Vertical) {
13608 :
13609 : // VERTICAL MULLION: original window is modified to become left-hand glazing (system #1);
13610 : // new window is created to become right-hand glazing (system #2)
13611 :
13612 : // Left-hand glazing
13613 :
13614 : // Vertex 1
13615 0 : dx = 0.0;
13616 0 : dy = H - h1;
13617 0 : xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
13618 0 : ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
13619 0 : za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
13620 0 : xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
13621 0 : yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
13622 0 : zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
13623 0 : NewCoord.Vertex(1).x = xa + (dx / W) * (xb - xa);
13624 0 : NewCoord.Vertex(1).y = ya + (dx / W) * (yb - ya);
13625 0 : NewCoord.Vertex(1).z = za + (dx / W) * (zb - za);
13626 :
13627 : // Vertex 2
13628 0 : dx = 0.0;
13629 0 : dy = H;
13630 0 : xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
13631 0 : ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
13632 0 : za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
13633 0 : xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
13634 0 : yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
13635 0 : zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
13636 0 : NewCoord.Vertex(2).x = xa + (dx / W) * (xb - xa);
13637 0 : NewCoord.Vertex(2).y = ya + (dx / W) * (yb - ya);
13638 0 : NewCoord.Vertex(2).z = za + (dx / W) * (zb - za);
13639 :
13640 : // Vertex 3
13641 0 : dx = w1;
13642 0 : dy = H;
13643 0 : xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
13644 0 : ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
13645 0 : za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
13646 0 : xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
13647 0 : yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
13648 0 : zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
13649 0 : NewCoord.Vertex(3).x = xa + (dx / W) * (xb - xa);
13650 0 : NewCoord.Vertex(3).y = ya + (dx / W) * (yb - ya);
13651 0 : NewCoord.Vertex(3).z = za + (dx / W) * (zb - za);
13652 :
13653 : // Vertex 4
13654 0 : dx = w1;
13655 0 : dy = H - h1;
13656 0 : xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
13657 0 : ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
13658 0 : za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
13659 0 : xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
13660 0 : yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
13661 0 : zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
13662 0 : NewCoord.Vertex(4).x = xa + (dx / W) * (xb - xa);
13663 0 : NewCoord.Vertex(4).y = ya + (dx / W) * (yb - ya);
13664 0 : NewCoord.Vertex(4).z = za + (dx / W) * (zb - za);
13665 :
13666 0 : for (loop = 1; loop <= surfTemp.Sides; ++loop) {
13667 0 : surfTemp.Vertex(loop) = NewCoord.Vertex(loop);
13668 : }
13669 :
13670 : // Right-hand glazing
13671 :
13672 : // Vertex 1
13673 0 : dx = w1 + MulWidth;
13674 0 : dy = H - (h1 + h2) / 2.0;
13675 0 : xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
13676 0 : ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
13677 0 : za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
13678 0 : xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
13679 0 : yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
13680 0 : zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
13681 0 : NewCoord.Vertex(1).x = xa + (dx / W) * (xb - xa);
13682 0 : NewCoord.Vertex(1).y = ya + (dx / W) * (yb - ya);
13683 0 : NewCoord.Vertex(1).z = za + (dx / W) * (zb - za);
13684 :
13685 : // Vertex 2
13686 0 : dx = w1 + MulWidth;
13687 0 : dy = H + (h2 - h1) / 2.0;
13688 0 : xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
13689 0 : ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
13690 0 : za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
13691 0 : xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
13692 0 : yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
13693 0 : zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
13694 0 : NewCoord.Vertex(2).x = xa + (dx / W) * (xb - xa);
13695 0 : NewCoord.Vertex(2).y = ya + (dx / W) * (yb - ya);
13696 0 : NewCoord.Vertex(2).z = za + (dx / W) * (zb - za);
13697 :
13698 : // Vertex 3
13699 0 : dx = w1 + MulWidth + w2;
13700 0 : dy = H + (h2 - h1) / 2.0;
13701 0 : xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
13702 0 : ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
13703 0 : za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
13704 0 : xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
13705 0 : yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
13706 0 : zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
13707 0 : NewCoord.Vertex(3).x = xa + (dx / W) * (xb - xa);
13708 0 : NewCoord.Vertex(3).y = ya + (dx / W) * (yb - ya);
13709 0 : NewCoord.Vertex(3).z = za + (dx / W) * (zb - za);
13710 :
13711 : // Vertex 4
13712 0 : dx = w1 + MulWidth + w2;
13713 0 : dy = H - (h1 + h2) / 2.0;
13714 0 : xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
13715 0 : ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
13716 0 : za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
13717 0 : xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
13718 0 : yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
13719 0 : zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
13720 0 : NewCoord.Vertex(4).x = xa + (dx / W) * (xb - xa);
13721 0 : NewCoord.Vertex(4).y = ya + (dx / W) * (yb - ya);
13722 0 : NewCoord.Vertex(4).z = za + (dx / W) * (zb - za);
13723 :
13724 0 : for (loop = 1; loop <= state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Sides; ++loop) {
13725 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Vertex(loop) = NewCoord.Vertex(loop);
13726 : }
13727 :
13728 : } else { // Horizontal mullion
13729 :
13730 : // HORIZONTAL MULLION: original window is modified to become bottom glazing (system #1);
13731 : // new window is created to become top glazing (system #2)
13732 :
13733 : // Bottom glazing
13734 :
13735 : // Vertex 1
13736 0 : dx = 0.0;
13737 0 : dy = H - h1;
13738 0 : xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
13739 0 : ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
13740 0 : za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
13741 0 : xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
13742 0 : yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
13743 0 : zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
13744 0 : NewCoord.Vertex(1).x = xa + (dx / W) * (xb - xa);
13745 0 : NewCoord.Vertex(1).y = ya + (dx / W) * (yb - ya);
13746 0 : NewCoord.Vertex(1).z = za + (dx / W) * (zb - za);
13747 :
13748 : // Vertex 2
13749 0 : dx = 0.0;
13750 0 : dy = H;
13751 0 : xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
13752 0 : ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
13753 0 : za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
13754 0 : xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
13755 0 : yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
13756 0 : zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
13757 0 : NewCoord.Vertex(2).x = xa + (dx / W) * (xb - xa);
13758 0 : NewCoord.Vertex(2).y = ya + (dx / W) * (yb - ya);
13759 0 : NewCoord.Vertex(2).z = za + (dx / W) * (zb - za);
13760 :
13761 : // Vertex 3
13762 0 : dx = w1;
13763 0 : dy = H;
13764 0 : xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
13765 0 : ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
13766 0 : za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
13767 0 : xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
13768 0 : yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
13769 0 : zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
13770 0 : NewCoord.Vertex(3).x = xa + (dx / W) * (xb - xa);
13771 0 : NewCoord.Vertex(3).y = ya + (dx / W) * (yb - ya);
13772 0 : NewCoord.Vertex(3).z = za + (dx / W) * (zb - za);
13773 :
13774 : // Vertex 4
13775 0 : dx = w1;
13776 0 : dy = H - h1;
13777 0 : xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
13778 0 : ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
13779 0 : za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
13780 0 : xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
13781 0 : yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
13782 0 : zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
13783 0 : NewCoord.Vertex(4).x = xa + (dx / W) * (xb - xa);
13784 0 : NewCoord.Vertex(4).y = ya + (dx / W) * (yb - ya);
13785 0 : NewCoord.Vertex(4).z = za + (dx / W) * (zb - za);
13786 :
13787 0 : for (loop = 1; loop <= surfTemp.Sides; ++loop) {
13788 0 : surfTemp.Vertex(loop) = NewCoord.Vertex(loop);
13789 : }
13790 :
13791 : // Top glazing
13792 :
13793 : // Vertex 1
13794 0 : dx = (w1 - w2) / 2.0;
13795 0 : dy = H - (h1 + h2 + MulWidth);
13796 0 : xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
13797 0 : ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
13798 0 : za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
13799 0 : xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
13800 0 : yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
13801 0 : zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
13802 0 : NewCoord.Vertex(1).x = xa + (dx / W) * (xb - xa);
13803 0 : NewCoord.Vertex(1).y = ya + (dx / W) * (yb - ya);
13804 0 : NewCoord.Vertex(1).z = za + (dx / W) * (zb - za);
13805 :
13806 : // Vertex 2
13807 0 : dx = (w1 - w2) / 2.0;
13808 0 : dy = H - (h1 + MulWidth);
13809 0 : xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
13810 0 : ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
13811 0 : za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
13812 0 : xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
13813 0 : yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
13814 0 : zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
13815 0 : NewCoord.Vertex(2).x = xa + (dx / W) * (xb - xa);
13816 0 : NewCoord.Vertex(2).y = ya + (dx / W) * (yb - ya);
13817 0 : NewCoord.Vertex(2).z = za + (dx / W) * (zb - za);
13818 :
13819 : // Vertex 3
13820 0 : dx = (w1 + w2) / 2.0;
13821 0 : dy = H - (h1 + MulWidth);
13822 0 : xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
13823 0 : ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
13824 0 : za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
13825 0 : xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
13826 0 : yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
13827 0 : zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
13828 0 : NewCoord.Vertex(3).x = xa + (dx / W) * (xb - xa);
13829 0 : NewCoord.Vertex(3).y = ya + (dx / W) * (yb - ya);
13830 0 : NewCoord.Vertex(3).z = za + (dx / W) * (zb - za);
13831 :
13832 : // Vertex 4
13833 0 : dx = (w1 + w2) / 2.0;
13834 0 : dy = H - (h1 + h2 + MulWidth);
13835 0 : xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
13836 0 : ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
13837 0 : za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
13838 0 : xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
13839 0 : yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
13840 0 : zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
13841 0 : NewCoord.Vertex(4).x = xa + (dx / W) * (xb - xa);
13842 0 : NewCoord.Vertex(4).y = ya + (dx / W) * (yb - ya);
13843 0 : NewCoord.Vertex(4).z = za + (dx / W) * (zb - za);
13844 :
13845 0 : for (loop = 1; loop <= state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Sides; ++loop) {
13846 0 : state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Vertex(loop) = NewCoord.Vertex(loop);
13847 : }
13848 :
13849 : } // End of check if vertical or horizontal mullion
13850 0 : }
13851 :
13852 2215 : void TransformVertsByAspect(EnergyPlusData &state,
13853 : int const SurfNum, // Current surface number
13854 : int const NSides // Number of sides to figure
13855 : )
13856 : {
13857 : // SUBROUTINE INFORMATION:
13858 : // AUTHOR Brent T Griffith
13859 : // DATE WRITTEN April 2003
13860 :
13861 : // PURPOSE OF THIS SUBROUTINE:
13862 : // Alter input for surface geometry
13863 : // Optimizing building design for energy can involve
13864 : // altering building geometry. Rather than assemble routines to transform
13865 : // geometry through pre-processing on input, it may be simpler to change
13866 : // vertices within EnergyPlus since it already reads the data from the input
13867 : // file and there would no longer be a need to rewrite the text data.
13868 : // This is essentially a crude hack to allow adjusting geometry with
13869 : // a single parameter...
13870 :
13871 : // METHODOLOGY EMPLOYED:
13872 : // once vertices have been converted to WCS, change them to reflect a different aspect
13873 : // ratio for the entire building based on user input.
13874 : // This routine is called once for each surface by subroutine GetVertices
13875 :
13876 2637 : static std::string const CurrentModuleObject("GeometryTransform");
13877 :
13878 2215 : Array1D_string cAlphas(1);
13879 2215 : Array1D<Real64> rNumerics(2);
13880 2215 : auto &OldAspectRatio = state.dataSurfaceGeometry->OldAspectRatio;
13881 2215 : auto &NewAspectRatio = state.dataSurfaceGeometry->NewAspectRatio;
13882 : int n;
13883 : Real64 Xo;
13884 : Real64 XnoRot;
13885 : Real64 Xtrans;
13886 : Real64 Yo;
13887 : Real64 YnoRot;
13888 : Real64 Ytrans;
13889 : // begin execution
13890 : // get user input...
13891 :
13892 2215 : auto &s_ipsc = state.dataIPShortCut;
13893 2215 : auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
13894 :
13895 2215 : if (state.dataSurfaceGeometry->firstTime) {
13896 220 : if (state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject) == 1) {
13897 : int NAlphas;
13898 : int NNum;
13899 : int IOStat;
13900 0 : auto &s_ipsc = state.dataIPShortCut;
13901 0 : auto &transformPlane = state.dataSurfaceGeometry->transformPlane;
13902 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
13903 : CurrentModuleObject,
13904 : 1,
13905 : cAlphas,
13906 : NAlphas,
13907 : rNumerics,
13908 : NNum,
13909 : IOStat,
13910 0 : s_ipsc->lNumericFieldBlanks,
13911 0 : s_ipsc->lAlphaFieldBlanks,
13912 0 : s_ipsc->cAlphaFieldNames,
13913 0 : s_ipsc->cNumericFieldNames);
13914 0 : OldAspectRatio = rNumerics(1);
13915 0 : NewAspectRatio = rNumerics(2);
13916 0 : transformPlane = cAlphas(1);
13917 0 : if (transformPlane != "XY") {
13918 0 : ShowWarningError(state, format("{}: invalid {}=\"{}...ignored.", CurrentModuleObject, s_ipsc->cAlphaFieldNames(1), cAlphas(1)));
13919 : }
13920 0 : state.dataSurfaceGeometry->firstTime = false;
13921 0 : state.dataSurfaceGeometry->noTransform = false;
13922 0 : state.dataSurface->AspectTransform = true;
13923 0 : if (state.dataSurface->WorldCoordSystem) {
13924 0 : ShowWarningError(state, format("{}: must use Relative Coordinate System. Transform request ignored.", CurrentModuleObject));
13925 0 : state.dataSurfaceGeometry->noTransform = true;
13926 0 : state.dataSurface->AspectTransform = false;
13927 : }
13928 : } else {
13929 220 : state.dataSurfaceGeometry->firstTime = false;
13930 : }
13931 : }
13932 2215 : if (state.dataSurfaceGeometry->noTransform) return;
13933 :
13934 : // check surface type.
13935 0 : if (!surfTemp.HeatTransSurf) {
13936 : // Site Shading do not get transformed.
13937 0 : if (surfTemp.Class == SurfaceClass::Detached_F) return;
13938 : }
13939 :
13940 : // testing method of transforming x and y coordinates as follows
13941 :
13942 : // this works if not rotated wrt north axis ... but if it is, then trouble
13943 : // try to first derotate it , transform by aspect and then rotate back.
13944 :
13945 0 : for (n = 1; n <= NSides; ++n) {
13946 0 : Xo = surfTemp.Vertex(n).x; // world coordinates.... shifted by relative north angle...
13947 0 : Yo = surfTemp.Vertex(n).y;
13948 : // next derotate the building
13949 0 : XnoRot = Xo * state.dataSurfaceGeometry->CosBldgRelNorth + Yo * state.dataSurfaceGeometry->SinBldgRelNorth;
13950 0 : YnoRot = Yo * state.dataSurfaceGeometry->CosBldgRelNorth - Xo * state.dataSurfaceGeometry->SinBldgRelNorth;
13951 : // translate
13952 0 : Xtrans = XnoRot * std::sqrt(NewAspectRatio / OldAspectRatio);
13953 0 : Ytrans = YnoRot * std::sqrt(OldAspectRatio / NewAspectRatio);
13954 : // rerotate
13955 0 : surfTemp.Vertex(n).x = Xtrans * state.dataSurfaceGeometry->CosBldgRelNorth - Ytrans * state.dataSurfaceGeometry->SinBldgRelNorth;
13956 :
13957 0 : surfTemp.Vertex(n).y = Xtrans * state.dataSurfaceGeometry->SinBldgRelNorth + Ytrans * state.dataSurfaceGeometry->CosBldgRelNorth;
13958 : }
13959 4430 : }
13960 :
13961 225 : void CalcSurfaceCentroid(EnergyPlusData &state)
13962 : {
13963 : // SUBROUTINE INFORMATION:
13964 : // AUTHOR B. Griffith
13965 : // DATE WRITTEN Feb. 2004
13966 :
13967 : // PURPOSE OF THIS SUBROUTINE:
13968 : // compute centroid of all the surfaces in the main
13969 : // surface structure. Store the vertex coordinates of
13970 : // the centroid in the 'SURFACE' derived type.
13971 :
13972 : // METHODOLOGY EMPLOYED:
13973 : // The centroid of triangle is easily computed by averaging the vertices
13974 : // The centroid of a quadrilateral is computed by area weighting the centroids
13975 : // of two triangles.
13976 : // (Algorithm would need to be changed for higher order
13977 : // polygons with more than four sides).
13978 :
13979 225 : auto &Triangle1 = state.dataSurfaceGeometry->Triangle1;
13980 225 : auto &Triangle2 = state.dataSurfaceGeometry->Triangle2;
13981 225 : static Vector const zero_vector(0.0);
13982 225 : Vector centroid;
13983 :
13984 225 : int negZcount(0); // for warning error in surface centroids
13985 :
13986 : // loop through all the surfaces
13987 2497 : for (int ThisSurf = 1; ThisSurf <= state.dataSurface->TotSurfaces; ++ThisSurf) {
13988 2272 : auto &surface = state.dataSurface->Surface(ThisSurf);
13989 :
13990 2272 : if (surface.Class == SurfaceClass::IntMass) continue;
13991 :
13992 2256 : auto const &vertex = surface.Vertex;
13993 :
13994 2256 : if (surface.Sides == 3) { // 3-sided polygon
13995 :
13996 30 : centroid = cen(vertex(1), vertex(2), vertex(3));
13997 :
13998 2226 : } else if (surface.Sides == 4) { // 4-sided polygon
13999 :
14000 : // split into 2 3-sided polygons (Triangle 1 and Triangle 2)
14001 2204 : Triangle1(1) = vertex(1);
14002 2204 : Triangle1(2) = vertex(2);
14003 2204 : Triangle1(3) = vertex(3);
14004 2204 : Triangle2(1) = vertex(1);
14005 2204 : Triangle2(2) = vertex(3);
14006 2204 : Triangle2(3) = vertex(4);
14007 :
14008 : // get total Area of quad.
14009 2204 : Real64 TotalArea(surface.GrossArea);
14010 2204 : if (TotalArea <= 0.0) {
14011 : // catch a problem....
14012 0 : ShowWarningError(state, format("CalcSurfaceCentroid: zero area surface, for surface={}", surface.Name));
14013 0 : continue;
14014 : }
14015 :
14016 : // get area fraction of triangles.
14017 2204 : Real64 Tri1Area(Vectors::AreaPolygon(3, Triangle1) / TotalArea);
14018 2204 : Real64 Tri2Area(Vectors::AreaPolygon(3, Triangle2) / TotalArea);
14019 :
14020 : // check if sum of fractions are slightly greater than 1.0 which is a symptom of the triangles for a non-convex
14021 : // quadrilateral using the wrong two triangles
14022 2204 : if ((Tri1Area + Tri2Area) > 1.05) {
14023 :
14024 : // if so repeat the process with the other two possible triangles (notice the vertices are in a different order this
14025 : // time) split into 2 3-sided polygons (Triangle 1 and Triangle 2)
14026 3 : Triangle1(1) = vertex(1);
14027 3 : Triangle1(2) = vertex(2);
14028 3 : Triangle1(3) = vertex(4);
14029 3 : Triangle2(1) = vertex(2);
14030 3 : Triangle2(2) = vertex(3);
14031 3 : Triangle2(3) = vertex(4);
14032 :
14033 : // get area fraction of triangles.
14034 3 : Real64 AreaTriangle1 = Vectors::AreaPolygon(3, Triangle1);
14035 3 : Real64 AreaTriangle2 = Vectors::AreaPolygon(3, Triangle2);
14036 3 : TotalArea = AreaTriangle1 + AreaTriangle2;
14037 3 : Tri1Area = AreaTriangle1 / TotalArea;
14038 3 : Tri2Area = AreaTriangle2 / TotalArea;
14039 : }
14040 :
14041 : // get centroid of Triangle 1
14042 2204 : Vector cen1(cen(Triangle1(1), Triangle1(2), Triangle1(3)));
14043 :
14044 : // get centroid of Triangle 2
14045 2204 : Vector cen2(cen(Triangle2(1), Triangle2(2), Triangle2(3)));
14046 :
14047 : // find area weighted combination of the two centroids (coded to avoid temporary Vectors)
14048 2204 : cen1 *= Tri1Area;
14049 2204 : cen2 *= Tri2Area;
14050 2204 : centroid = cen1;
14051 2204 : centroid += cen2;
14052 :
14053 2226 : } else if (surface.Sides >= 5) { // multi-sided polygon
14054 : // (Maybe triangulate? For now, use old "z" average method")
14055 : // and X and Y -- straight average
14056 :
14057 : // X1=MINVAL(Surface(ThisSurf)%Vertex(1:Surface(ThisSurf)%Sides)%x)
14058 : // X2=MAXVAL(Surface(ThisSurf)%Vertex(1:Surface(ThisSurf)%Sides)%x)
14059 : // Y1=MINVAL(Surface(ThisSurf)%Vertex(1:Surface(ThisSurf)%Sides)%y)
14060 : // Y2=MAXVAL(Surface(ThisSurf)%Vertex(1:Surface(ThisSurf)%Sides)%y)
14061 : // Z1=MINVAL(Surface(ThisSurf)%Vertex(1:Surface(ThisSurf)%Sides)%z)
14062 : // Z2=MAXVAL(Surface(ThisSurf)%Vertex(1:Surface(ThisSurf)%Sides)%z)
14063 : // Xcm=(X1+X2)/2.0d0
14064 : // Ycm=(Y1+Y2)/2.0d0
14065 : // Zcm=(Z1+Z2)/2.0d0
14066 :
14067 : // Calc centroid as average of surfaces
14068 13 : centroid = 0.0;
14069 86 : for (int vert = 1; vert <= surface.Sides; ++vert) {
14070 73 : centroid += vertex(vert);
14071 : }
14072 13 : centroid /= double(surface.Sides);
14073 :
14074 : } else {
14075 :
14076 9 : if (!surface.Name.empty()) {
14077 0 : ShowWarningError(state, format("CalcSurfaceCentroid: caught problem with # of sides, for surface={}", surface.Name));
14078 0 : ShowContinueError(state, format("... number of sides must be >= 3, this surface # sides={}", surface.Sides));
14079 : } else {
14080 9 : ShowWarningError(state, format("CalcSurfaceCentroid: caught problem with # of sides, for surface=#{}", ThisSurf));
14081 18 : ShowContinueError(state,
14082 : "...surface name is blank. Examine surfaces -- this may be a problem with ill-formed interzone surfaces.");
14083 9 : ShowContinueError(state, format("... number of sides must be >= 3, this surface # sides={}", surface.Sides));
14084 : }
14085 9 : centroid = 0.0;
14086 : }
14087 :
14088 : // store result in the surface structure in DataSurfaces
14089 2256 : surface.Centroid = centroid;
14090 :
14091 2256 : if (centroid.z < 0.0) {
14092 5 : if (surface.ExtWind || surface.ExtBoundCond == DataSurfaces::ExternalEnvironment) ++negZcount;
14093 : }
14094 :
14095 : } // loop through surfaces
14096 :
14097 225 : if (negZcount > 0) {
14098 1 : ShowWarningError(state, format("CalcSurfaceCentroid: {} Surfaces have the Z coordinate < 0.", negZcount));
14099 2 : ShowContinueError(state, "...in any calculations, Wind Speed will be 0.0 for these surfaces.");
14100 2 : ShowContinueError(state,
14101 2 : format("...in any calculations, Outside temperatures will be the outside temperature + {:.3R} for these surfaces.",
14102 1 : state.dataEnvrn->WeatherFileTempModCoeff));
14103 3 : ShowContinueError(state, "...that is, these surfaces will have conditions as though at ground level.");
14104 : }
14105 225 : }
14106 :
14107 224 : void SetupShadeSurfacesForSolarCalcs(EnergyPlusData &state)
14108 : {
14109 : // SUBROUTINE INFORMATION:
14110 : // AUTHOR B. Griffith
14111 : // DATE WRITTEN Dec. 2008
14112 :
14113 : // PURPOSE OF THIS SUBROUTINE:
14114 : // determine if Shading surfaces need full solar calcs because they
14115 : // are also used to define geometry of an active solar component.
14116 : // Normally, a shading surface is not included in calculations of incident solar, only shading
14117 :
14118 : // METHODOLOGY EMPLOYED:
14119 : // Mine solar renewables input and collect surface names.
14120 : // find shading surfaces with names that match those in solar objects.
14121 : // setup flags for shading surfaces so that the solar renewables can reuse incident solar calcs
14122 : // new solar component models that use shading surfaces will have to extend the code here.
14123 :
14124 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
14125 224 : Array1D_string TmpCandidateSurfaceNames;
14126 224 : Array1D_string TmpCandidateICSSurfaceNames;
14127 224 : Array1D_string TmpCandidateICSBCTypeNames;
14128 : int NumAlphas; // Number of alpha names being passed
14129 : int NumNumbers; // Number of numeric parameters being passed
14130 : int IOStatus;
14131 :
14132 224 : auto &s_ipsc = state.dataIPShortCut;
14133 : // First collect names of surfaces referenced by active solar components
14134 224 : s_ipsc->cCurrentModuleObject = "SolarCollector:FlatPlate:Water";
14135 224 : int NumOfFlatPlateUnits = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
14136 224 : s_ipsc->cCurrentModuleObject = "SolarCollector:FlatPlate:PhotovoltaicThermal";
14137 224 : int NumPVTs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
14138 224 : s_ipsc->cCurrentModuleObject = "Generator:Photovoltaic";
14139 224 : int NumPVs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
14140 224 : s_ipsc->cCurrentModuleObject = "SolarCollector:IntegralCollectorStorage";
14141 224 : int NumOfICSUnits = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
14142 :
14143 224 : int NumCandidateNames = NumOfFlatPlateUnits + NumPVTs + NumPVs + NumOfICSUnits;
14144 224 : int NumOfCollectors = NumOfFlatPlateUnits + NumOfICSUnits;
14145 :
14146 224 : TmpCandidateSurfaceNames.allocate(NumCandidateNames);
14147 224 : TmpCandidateICSSurfaceNames.allocate(NumOfCollectors);
14148 224 : TmpCandidateICSBCTypeNames.allocate(NumOfCollectors);
14149 :
14150 224 : if (NumOfCollectors > 0) {
14151 0 : s_ipsc->cCurrentModuleObject = "SolarCollector:FlatPlate:Water";
14152 0 : for (int CollectorNum = 1; CollectorNum <= NumOfFlatPlateUnits; ++CollectorNum) {
14153 :
14154 0 : state.dataInputProcessing->inputProcessor->getObjectItem(
14155 0 : state, s_ipsc->cCurrentModuleObject, CollectorNum, s_ipsc->cAlphaArgs, NumAlphas, s_ipsc->rNumericArgs, NumNumbers, IOStatus);
14156 :
14157 0 : TmpCandidateSurfaceNames(CollectorNum) = s_ipsc->cAlphaArgs(3);
14158 0 : TmpCandidateICSBCTypeNames(CollectorNum) = "";
14159 : }
14160 : }
14161 :
14162 224 : if (NumPVTs > 0) {
14163 2 : s_ipsc->cCurrentModuleObject = "SolarCollector:FlatPlate:PhotovoltaicThermal";
14164 4 : for (int PVTnum = 1; PVTnum <= NumPVTs; ++PVTnum) {
14165 :
14166 4 : state.dataInputProcessing->inputProcessor->getObjectItem(
14167 2 : state, s_ipsc->cCurrentModuleObject, PVTnum, s_ipsc->cAlphaArgs, NumAlphas, s_ipsc->rNumericArgs, NumNumbers, IOStatus);
14168 :
14169 2 : TmpCandidateSurfaceNames(NumOfFlatPlateUnits + PVTnum) = s_ipsc->cAlphaArgs(2);
14170 : }
14171 : }
14172 :
14173 224 : if (NumPVs > 0) {
14174 2 : s_ipsc->cCurrentModuleObject = "Generator:Photovoltaic";
14175 4 : for (int PVnum = 1; PVnum <= NumPVs; ++PVnum) {
14176 4 : state.dataInputProcessing->inputProcessor->getObjectItem(
14177 2 : state, s_ipsc->cCurrentModuleObject, PVnum, s_ipsc->cAlphaArgs, NumAlphas, s_ipsc->rNumericArgs, NumNumbers, IOStatus);
14178 2 : TmpCandidateSurfaceNames(NumOfFlatPlateUnits + NumPVTs + PVnum) = s_ipsc->cAlphaArgs(2);
14179 : }
14180 : }
14181 :
14182 224 : if (NumOfICSUnits > 0) {
14183 0 : s_ipsc->cCurrentModuleObject = "SolarCollector:IntegralCollectorStorage";
14184 0 : for (int CollectorNum = 1; CollectorNum <= NumOfICSUnits; ++CollectorNum) {
14185 0 : state.dataInputProcessing->inputProcessor->getObjectItem(
14186 0 : state, s_ipsc->cCurrentModuleObject, CollectorNum, s_ipsc->cAlphaArgs, NumAlphas, s_ipsc->rNumericArgs, NumNumbers, IOStatus);
14187 0 : TmpCandidateSurfaceNames(NumOfFlatPlateUnits + NumPVTs + NumPVs + CollectorNum) = s_ipsc->cAlphaArgs(3);
14188 0 : TmpCandidateICSSurfaceNames(NumOfFlatPlateUnits + CollectorNum) = s_ipsc->cAlphaArgs(3);
14189 0 : TmpCandidateICSBCTypeNames(NumOfFlatPlateUnits + CollectorNum) = s_ipsc->cAlphaArgs(4);
14190 : }
14191 : }
14192 :
14193 : // loop through all the surfaces
14194 2486 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
14195 2262 : auto &surf = state.dataSurface->Surface(SurfNum);
14196 2262 : int Found = Util::FindItemInList(surf.Name, TmpCandidateSurfaceNames, NumCandidateNames);
14197 2262 : if (Found > 0) {
14198 2 : if (!surf.HeatTransSurf) { // not BIPV, must be a shading surf with solar device
14199 : // Setup missing values to allow shading surfaces to model incident solar and wind
14200 1 : surf.ExtSolar = true;
14201 1 : surf.ExtWind = true;
14202 1 : surf.ViewFactorGround = 0.5 * (1.0 - surf.CosTilt);
14203 : }
14204 : // check if this surface is used for ICS collector mounting and has OthersideCondictionsModel as its
14205 : // boundary condition
14206 2 : if (NumOfICSUnits > 0) {
14207 0 : for (int CollectorNum = 1; CollectorNum <= NumOfCollectors; ++CollectorNum) {
14208 0 : if (Util::SameString(surf.Name, TmpCandidateICSSurfaceNames(CollectorNum)) &&
14209 0 : Util::SameString(TmpCandidateICSBCTypeNames(CollectorNum), "OTHERSIDECONDITIONSMODEL")) {
14210 0 : state.dataSurface->SurfIsICS(SurfNum) = true;
14211 0 : state.dataSurface->SurfICSPtr(SurfNum) = CollectorNum;
14212 : }
14213 : }
14214 : }
14215 :
14216 : } // end of IF (Found > 0) Then
14217 : }
14218 224 : }
14219 :
14220 : void
14221 416 : SetupEnclosuresAndAirBoundaries(EnergyPlusData &state,
14222 : EPVector<DataViewFactorInformation::EnclosureViewFactorInformation> &Enclosures, // Radiant or Solar Enclosures
14223 : SurfaceGeometry::enclosureType const EnclosureType, // Radiant or Solar
14224 : bool &ErrorsFound) // Set to true if errors found
14225 : {
14226 : static constexpr std::string_view RoutineName = "SetupEnclosuresAndAirBoundaries";
14227 416 : bool anyGroupedSpaces = false;
14228 416 : bool radiantSetup = false;
14229 416 : bool solarSetup = false;
14230 416 : std::string RadiantOrSolar = "";
14231 416 : int enclosureNum = 0;
14232 416 : if (EnclosureType == RadiantEnclosures) {
14233 224 : radiantSetup = true;
14234 224 : RadiantOrSolar = "Radiant";
14235 224 : state.dataViewFactor->EnclRadInfo.allocate(state.dataGlobal->numSpaces);
14236 192 : } else if (EnclosureType == SolarEnclosures) {
14237 192 : solarSetup = true;
14238 192 : RadiantOrSolar = "Solar";
14239 192 : state.dataViewFactor->EnclSolInfo.allocate(state.dataGlobal->numSpaces);
14240 : } else {
14241 0 : ShowFatalError(
14242 0 : state, format("{}: Illegal call to this function. Second argument must be 'RadiantEnclosures' or 'SolarEnclosures'", RoutineName));
14243 : }
14244 416 : if (std::any_of(state.dataConstruction->Construct.begin(),
14245 416 : state.dataConstruction->Construct.end(),
14246 1390 : [](Construction::ConstructionProps const &e) { return e.TypeIsAirBoundary; })) {
14247 18 : int errorCount = 0;
14248 222 : for (int surfNum = 1; surfNum <= state.dataSurface->TotSurfaces; ++surfNum) {
14249 204 : auto &surf = state.dataSurface->Surface(surfNum);
14250 204 : if (surf.Construction == 0) continue;
14251 204 : auto &constr = state.dataConstruction->Construct(surf.Construction);
14252 204 : if (!constr.TypeIsAirBoundary) continue;
14253 84 : surf.IsAirBoundarySurf = true;
14254 :
14255 : // Check for invalid air boundary surfaces - valid only on non-adiabatic interzone surfaces
14256 : // Only check this once during radiant setup, skip for solar setup
14257 84 : if (radiantSetup && (surf.ExtBoundCond <= 0 || surf.ExtBoundCond == surfNum)) {
14258 0 : ErrorsFound = true;
14259 0 : if (!state.dataGlobal->DisplayExtraWarnings) {
14260 0 : ++errorCount;
14261 : } else {
14262 0 : ShowSevereError(
14263 0 : state, format("{}: Surface=\"{}\" uses Construction:AirBoundary in a non-interzone surface.", RoutineName, surf.Name));
14264 : }
14265 : } else {
14266 : // Process air boundary - set surface properties and set up enclosures Radiant exchange, Boundary is grouped - assign enclosure
14267 84 : state.dataHeatBal->AnyAirBoundary = true;
14268 84 : int thisSideEnclosureNum = 0;
14269 84 : int otherSideEnclosureNum = 0;
14270 84 : if (radiantSetup) {
14271 : // Radiant enclosure setup
14272 42 : constr.IsUsedCTF = false;
14273 42 : surf.HeatTransSurf = false;
14274 42 : surf.HeatTransferAlgorithm = DataSurfaces::HeatTransferModel::AirBoundaryNoHT;
14275 42 : thisSideEnclosureNum = state.dataHeatBal->space(surf.spaceNum).radiantEnclosureNum;
14276 42 : otherSideEnclosureNum = state.dataHeatBal->space(state.dataSurface->Surface(surf.ExtBoundCond).spaceNum).radiantEnclosureNum;
14277 : } else {
14278 : // Solar enclosure setup
14279 42 : thisSideEnclosureNum = state.dataHeatBal->space(surf.spaceNum).solarEnclosureNum;
14280 42 : otherSideEnclosureNum = state.dataHeatBal->space(state.dataSurface->Surface(surf.ExtBoundCond).spaceNum).solarEnclosureNum;
14281 : }
14282 84 : anyGroupedSpaces = true;
14283 84 : if ((thisSideEnclosureNum == 0) && (otherSideEnclosureNum == 0)) {
14284 : // Neither zone is assigned to an enclosure, so increment the counter and assign to both
14285 22 : ++enclosureNum;
14286 22 : auto &thisEnclosure = Enclosures(enclosureNum);
14287 22 : thisSideEnclosureNum = enclosureNum;
14288 22 : thisEnclosure.Name = format("{} Enclosure {}", RadiantOrSolar, enclosureNum);
14289 22 : thisEnclosure.spaceNames.push_back(state.dataHeatBal->space(surf.spaceNum).Name);
14290 22 : thisEnclosure.spaceNums.push_back(surf.spaceNum);
14291 22 : thisEnclosure.FloorArea += state.dataHeatBal->space(surf.spaceNum).FloorArea;
14292 22 : otherSideEnclosureNum = enclosureNum;
14293 22 : int otherSideSpaceNum = state.dataSurface->Surface(surf.ExtBoundCond).spaceNum;
14294 22 : if (otherSideSpaceNum != surf.spaceNum) {
14295 20 : thisEnclosure.spaceNames.push_back(state.dataHeatBal->space(otherSideSpaceNum).Name);
14296 20 : thisEnclosure.spaceNums.push_back(otherSideSpaceNum);
14297 20 : thisEnclosure.FloorArea += state.dataHeatBal->space(otherSideSpaceNum).FloorArea;
14298 : }
14299 22 : if (radiantSetup) {
14300 11 : state.dataHeatBal->space(surf.spaceNum).radiantEnclosureNum = thisSideEnclosureNum;
14301 11 : state.dataHeatBal->space(state.dataSurface->Surface(surf.ExtBoundCond).spaceNum).radiantEnclosureNum =
14302 : otherSideEnclosureNum;
14303 : } else {
14304 11 : thisEnclosure.ExtWindowArea += state.dataHeatBal->space(surf.spaceNum).extWindowArea;
14305 11 : thisEnclosure.TotalSurfArea += state.dataHeatBal->space(surf.spaceNum).totalSurfArea;
14306 11 : if (otherSideSpaceNum != surf.spaceNum) {
14307 10 : thisEnclosure.ExtWindowArea += state.dataHeatBal->space(otherSideSpaceNum).extWindowArea;
14308 10 : thisEnclosure.TotalSurfArea += state.dataHeatBal->space(otherSideSpaceNum).totalSurfArea;
14309 : }
14310 11 : state.dataHeatBal->space(surf.spaceNum).solarEnclosureNum = thisSideEnclosureNum;
14311 11 : state.dataHeatBal->space(state.dataSurface->Surface(surf.ExtBoundCond).spaceNum).solarEnclosureNum =
14312 : otherSideEnclosureNum;
14313 : }
14314 84 : } else if (thisSideEnclosureNum == 0) {
14315 : // Other side is assigned, so use that one for both
14316 0 : thisSideEnclosureNum = otherSideEnclosureNum;
14317 0 : auto &thisEnclosure = Enclosures(thisSideEnclosureNum);
14318 0 : thisEnclosure.spaceNames.push_back(state.dataHeatBal->space(surf.spaceNum).Name);
14319 0 : thisEnclosure.spaceNums.push_back(surf.spaceNum);
14320 0 : thisEnclosure.FloorArea += state.dataHeatBal->space(surf.spaceNum).FloorArea;
14321 0 : if (radiantSetup) {
14322 0 : state.dataHeatBal->space(surf.spaceNum).radiantEnclosureNum = thisSideEnclosureNum;
14323 : } else {
14324 0 : thisEnclosure.ExtWindowArea += state.dataHeatBal->space(surf.spaceNum).extWindowArea;
14325 0 : thisEnclosure.TotalSurfArea += state.dataHeatBal->space(surf.spaceNum).totalSurfArea;
14326 0 : state.dataHeatBal->space(surf.spaceNum).solarEnclosureNum = thisSideEnclosureNum;
14327 : }
14328 62 : } else if (otherSideEnclosureNum == 0) {
14329 : // This side is assigned, so use that one for both
14330 14 : otherSideEnclosureNum = thisSideEnclosureNum;
14331 14 : auto &thisEnclosure = Enclosures(thisSideEnclosureNum);
14332 14 : thisEnclosure.spaceNames.push_back(state.dataHeatBal->space(state.dataSurface->Surface(surf.ExtBoundCond).spaceNum).Name);
14333 14 : thisEnclosure.spaceNums.push_back(state.dataSurface->Surface(surf.ExtBoundCond).spaceNum);
14334 14 : thisEnclosure.FloorArea += state.dataHeatBal->space(state.dataSurface->Surface(surf.ExtBoundCond).spaceNum).FloorArea;
14335 14 : if (radiantSetup) {
14336 7 : state.dataHeatBal->space(state.dataSurface->Surface(surf.ExtBoundCond).spaceNum).radiantEnclosureNum =
14337 : otherSideEnclosureNum;
14338 : } else {
14339 7 : thisEnclosure.ExtWindowArea +=
14340 7 : state.dataHeatBal->space(state.dataSurface->Surface(surf.ExtBoundCond).spaceNum).extWindowArea;
14341 7 : thisEnclosure.TotalSurfArea +=
14342 7 : state.dataHeatBal->space(state.dataSurface->Surface(surf.ExtBoundCond).spaceNum).totalSurfArea;
14343 7 : state.dataHeatBal->space(state.dataSurface->Surface(surf.ExtBoundCond).spaceNum).solarEnclosureNum =
14344 : otherSideEnclosureNum;
14345 : }
14346 48 : } else if (thisSideEnclosureNum != otherSideEnclosureNum) {
14347 : // If both sides are already assigned to an enclosure, then merge the two enclosures
14348 4 : auto const &thisEnclosure = Enclosures(thisSideEnclosureNum);
14349 4 : auto &otherEnclosure = Enclosures(otherSideEnclosureNum);
14350 16 : for (const auto &zName : thisEnclosure.spaceNames) {
14351 12 : otherEnclosure.spaceNames.push_back(zName);
14352 : }
14353 16 : for (int zNum : thisEnclosure.spaceNums) {
14354 12 : otherEnclosure.spaceNums.push_back(zNum);
14355 12 : if (radiantSetup) {
14356 6 : state.dataHeatBal->space(zNum).radiantEnclosureNum = otherSideEnclosureNum;
14357 : } else {
14358 6 : state.dataHeatBal->space(zNum).solarEnclosureNum = otherSideEnclosureNum;
14359 : }
14360 : }
14361 4 : otherEnclosure.FloorArea += thisEnclosure.FloorArea;
14362 4 : otherEnclosure.ExtWindowArea += thisEnclosure.ExtWindowArea;
14363 4 : otherEnclosure.TotalSurfArea += thisEnclosure.TotalSurfArea;
14364 : // Move any enclosures beyond thisEnclosure down one slot - at this point all enclosures are named "Radiant
14365 : // Enclosure N"
14366 8 : for (int enclNum = thisSideEnclosureNum; enclNum < enclosureNum; ++enclNum) {
14367 4 : std::string saveName = Enclosures(enclNum).Name;
14368 4 : Enclosures(enclNum) = Enclosures(enclNum + 1);
14369 4 : Enclosures(enclNum).Name = saveName;
14370 22 : for (int sNum : Enclosures(enclNum).spaceNums) {
14371 18 : if (radiantSetup) {
14372 9 : state.dataHeatBal->space(sNum).radiantEnclosureNum = enclNum;
14373 : } else {
14374 9 : state.dataHeatBal->space(sNum).solarEnclosureNum = enclNum;
14375 : }
14376 : }
14377 4 : }
14378 : // Clear the last rad enclosure and reduce the total number of enclosures by 1
14379 4 : Enclosures(enclosureNum).Name.clear();
14380 4 : Enclosures(enclosureNum).spaceNames.clear();
14381 4 : Enclosures(enclosureNum).spaceNums.clear();
14382 4 : Enclosures(enclosureNum).FloorArea = 0;
14383 4 : Enclosures(enclosureNum).ExtWindowArea = 0;
14384 4 : Enclosures(enclosureNum).TotalSurfArea = 0;
14385 4 : enclosureNum -= 1;
14386 : }
14387 84 : if (solarSetup && constr.TypeIsAirBoundaryMixing) {
14388 : // Set up mixing air boundaries only once, during solar setup
14389 4 : int spaceNum1 = min(surf.spaceNum, state.dataSurface->Surface(surf.ExtBoundCond).spaceNum);
14390 4 : int spaceNum2 = max(surf.spaceNum, state.dataSurface->Surface(surf.ExtBoundCond).spaceNum);
14391 : // This pair already saved?
14392 4 : bool found = false;
14393 4 : for (auto const &thisAirBoundaryMixing : state.dataHeatBal->airBoundaryMixing) {
14394 2 : if ((spaceNum1 == thisAirBoundaryMixing.space1) && (spaceNum2 == thisAirBoundaryMixing.space2)) {
14395 2 : found = true;
14396 2 : break;
14397 : }
14398 : }
14399 4 : if (!found) {
14400 : // Store the space pairs, schedule, and flow rate to use later to create cross mixing objects
14401 2 : DataHeatBalance::AirBoundaryMixingSpecs newAirBoundaryMixing;
14402 2 : newAirBoundaryMixing.space1 = spaceNum1;
14403 2 : newAirBoundaryMixing.space2 = spaceNum2;
14404 2 : newAirBoundaryMixing.sched = state.dataConstruction->Construct(surf.Construction).airBoundaryMixingSched;
14405 2 : Real64 mixingVolume = state.dataConstruction->Construct(surf.Construction).AirBoundaryACH *
14406 2 : min(state.dataHeatBal->space(spaceNum1).Volume, state.dataHeatBal->space(spaceNum2).Volume) /
14407 2 : Constant::rSecsInHour;
14408 2 : newAirBoundaryMixing.mixingVolumeFlowRate = mixingVolume;
14409 2 : state.dataHeatBal->airBoundaryMixing.push_back(newAirBoundaryMixing);
14410 : }
14411 : }
14412 : }
14413 : }
14414 18 : if (errorCount > 0) {
14415 0 : ShowSevereError(state, format("{}: {} surfaces use Construction:AirBoundary in non-interzone surfaces.", RoutineName, errorCount));
14416 0 : ShowContinueError(state, "For explicit details on each use, use Output:Diagnostics,DisplayExtraWarnings;");
14417 : }
14418 : }
14419 : // Check for any spaces defined only by floor surface(s) and group them
14420 1045 : for (auto const &zone : state.dataHeatBal->Zone) {
14421 629 : int newEnclosureNum = 0;
14422 1302 : for (int const spaceNum : zone.spaceIndexes) {
14423 673 : int spaceEnclosureNum = 0;
14424 673 : bool spaceHasOnlyFloors = false;
14425 673 : if (radiantSetup) {
14426 376 : spaceEnclosureNum = state.dataHeatBal->space(spaceNum).radiantEnclosureNum;
14427 : } else {
14428 297 : spaceEnclosureNum = state.dataHeatBal->space(spaceNum).solarEnclosureNum;
14429 : }
14430 673 : if (spaceEnclosureNum == 0) {
14431 616 : spaceHasOnlyFloors = true;
14432 699 : for (int const surfNum : state.dataHeatBal->space(spaceNum).surfaces) {
14433 630 : if (state.dataSurface->Surface(surfNum).Class == SurfaceClass::IntMass) continue;
14434 630 : if (state.dataSurface->Surface(surfNum).Class != SurfaceClass::Floor) {
14435 547 : spaceHasOnlyFloors = false;
14436 547 : break;
14437 : }
14438 : }
14439 : }
14440 673 : if (spaceEnclosureNum == 0 && spaceHasOnlyFloors) {
14441 69 : anyGroupedSpaces = true;
14442 69 : if (newEnclosureNum == 0) {
14443 : // Assign one new enclosure for all loose floors in this zone
14444 47 : ++enclosureNum;
14445 47 : newEnclosureNum = enclosureNum;
14446 : }
14447 69 : if (radiantSetup) {
14448 36 : state.dataHeatBal->space(spaceNum).radiantEnclosureNum = enclosureNum;
14449 : } else {
14450 33 : state.dataHeatBal->space(spaceNum).solarEnclosureNum = enclosureNum;
14451 : }
14452 69 : auto &thisEnclosure = Enclosures(enclosureNum);
14453 : // Give this enclosure the zone name and assign this to the zone-remainder space if it exists
14454 69 : thisEnclosure.Name = zone.Name;
14455 69 : thisEnclosure.spaceNames.push_back(state.dataHeatBal->space(spaceNum).Name);
14456 69 : thisEnclosure.spaceNums.push_back(spaceNum);
14457 69 : thisEnclosure.FloorArea = state.dataHeatBal->space(spaceNum).FloorArea;
14458 69 : thisEnclosure.ExtWindowArea = state.dataHeatBal->space(spaceNum).extWindowArea;
14459 69 : thisEnclosure.TotalSurfArea = state.dataHeatBal->space(spaceNum).totalSurfArea;
14460 : }
14461 : }
14462 : }
14463 :
14464 416 : if (anyGroupedSpaces) {
14465 : // All grouped spaces have been assigned to an enclosure, now assign remaining spaces
14466 207 : for (int spaceNum = 1; spaceNum <= state.dataGlobal->numSpaces; ++spaceNum) {
14467 156 : auto &curSpace = state.dataHeatBal->space(spaceNum);
14468 156 : int spaceEnclosureNum = 0;
14469 156 : if (radiantSetup) {
14470 80 : spaceEnclosureNum = curSpace.radiantEnclosureNum;
14471 : } else {
14472 76 : spaceEnclosureNum = curSpace.solarEnclosureNum;
14473 : }
14474 156 : if (spaceEnclosureNum == 0) {
14475 31 : if (Util::SameString(curSpace.Name, state.dataHeatBal->Zone(curSpace.zoneNum).Name + "-REMAINDER")) {
14476 : // Search for existing enclosure with same name as the zone
14477 0 : spaceEnclosureNum = Util::FindItemInList(state.dataHeatBal->Zone(curSpace.zoneNum).Name, Enclosures);
14478 : }
14479 31 : if (spaceEnclosureNum == 0) {
14480 : // Otherwise add a new one named for the space
14481 31 : ++enclosureNum;
14482 31 : spaceEnclosureNum = enclosureNum;
14483 31 : Enclosures(spaceEnclosureNum).Name = curSpace.Name;
14484 : }
14485 31 : if (radiantSetup) {
14486 16 : curSpace.radiantEnclosureNum = spaceEnclosureNum;
14487 : } else {
14488 15 : curSpace.solarEnclosureNum = spaceEnclosureNum;
14489 : }
14490 31 : auto &thisEnclosure = Enclosures(spaceEnclosureNum);
14491 31 : thisEnclosure.spaceNames.push_back(curSpace.Name);
14492 31 : thisEnclosure.spaceNums.push_back(spaceNum);
14493 31 : thisEnclosure.FloorArea += curSpace.FloorArea;
14494 31 : thisEnclosure.ExtWindowArea += curSpace.extWindowArea;
14495 31 : thisEnclosure.TotalSurfArea += curSpace.totalSurfArea;
14496 : }
14497 : }
14498 51 : if (radiantSetup) {
14499 27 : state.dataViewFactor->NumOfRadiantEnclosures = enclosureNum;
14500 : } else {
14501 24 : state.dataViewFactor->NumOfSolarEnclosures = enclosureNum;
14502 : }
14503 : } else {
14504 : // There are no grouped radiant air boundaries, assign each space to it's own radiant enclosure
14505 882 : for (int spaceNum = 1; spaceNum <= state.dataGlobal->numSpaces; ++spaceNum) {
14506 517 : auto &thisEnclosure = Enclosures(spaceNum);
14507 517 : thisEnclosure.Name = state.dataHeatBal->space(spaceNum).Name;
14508 517 : thisEnclosure.spaceNames.push_back(state.dataHeatBal->space(spaceNum).Name);
14509 517 : thisEnclosure.spaceNums.push_back(spaceNum);
14510 517 : thisEnclosure.FloorArea = state.dataHeatBal->space(spaceNum).FloorArea;
14511 517 : if (radiantSetup) {
14512 296 : state.dataHeatBal->space(spaceNum).radiantEnclosureNum = spaceNum;
14513 : } else {
14514 221 : state.dataHeatBal->space(spaceNum).solarEnclosureNum = spaceNum;
14515 221 : thisEnclosure.ExtWindowArea = state.dataHeatBal->space(spaceNum).extWindowArea;
14516 221 : thisEnclosure.TotalSurfArea = state.dataHeatBal->space(spaceNum).totalSurfArea;
14517 : }
14518 : }
14519 365 : if (radiantSetup) {
14520 197 : state.dataViewFactor->NumOfRadiantEnclosures = state.dataGlobal->numSpaces;
14521 : } else {
14522 168 : state.dataViewFactor->NumOfSolarEnclosures = state.dataGlobal->numSpaces;
14523 : }
14524 : }
14525 416 : if (radiantSetup) {
14526 224 : assert(state.dataViewFactor->NumOfRadiantEnclosures <= int(Enclosures.size()));
14527 224 : Enclosures.resize(state.dataViewFactor->NumOfRadiantEnclosures);
14528 : } else {
14529 192 : assert(state.dataViewFactor->NumOfSolarEnclosures <= int(Enclosures.size()));
14530 192 : Enclosures.resize(state.dataViewFactor->NumOfSolarEnclosures);
14531 : }
14532 :
14533 1029 : for (auto &thisEnclosure : state.dataViewFactor->EnclRadInfo) {
14534 1226 : SetupOutputVariable(state,
14535 : "Enclosure Mean Radiant Temperature",
14536 : Constant::Units::C,
14537 613 : thisEnclosure.MRT,
14538 : OutputProcessor::TimeStepType::Zone,
14539 : OutputProcessor::StoreType::Average,
14540 613 : thisEnclosure.Name);
14541 : }
14542 :
14543 : // TODO MJW: For now, set the max and min enclosure numbers for each zone to be used in CalcInteriorRadExchange with ZoneToResimulate
14544 1045 : for (int zoneNum = 1; zoneNum <= state.dataGlobal->NumOfZones; ++zoneNum) {
14545 1302 : for (int spaceNum : state.dataHeatBal->Zone(zoneNum).spaceIndexes) {
14546 673 : if (state.dataHeatBal->Zone(zoneNum).zoneRadEnclosureFirst == -1) { // initial value
14547 354 : state.dataHeatBal->Zone(zoneNum).zoneRadEnclosureFirst = state.dataHeatBal->space(spaceNum).radiantEnclosureNum;
14548 : } else {
14549 319 : state.dataHeatBal->Zone(zoneNum).zoneRadEnclosureFirst =
14550 319 : min(state.dataHeatBal->Zone(zoneNum).zoneRadEnclosureFirst, state.dataHeatBal->space(spaceNum).radiantEnclosureNum);
14551 : }
14552 673 : state.dataHeatBal->Zone(zoneNum).zoneRadEnclosureLast =
14553 673 : max(state.dataHeatBal->Zone(zoneNum).zoneRadEnclosureLast, state.dataHeatBal->space(spaceNum).radiantEnclosureNum);
14554 : }
14555 629 : assert(state.dataHeatBal->Zone(zoneNum).zoneRadEnclosureFirst != -1);
14556 629 : assert(state.dataHeatBal->Zone(zoneNum).zoneRadEnclosureLast != -1);
14557 629 : assert(state.dataHeatBal->Zone(zoneNum).zoneRadEnclosureFirst <= state.dataHeatBal->Zone(zoneNum).zoneRadEnclosureLast);
14558 : }
14559 416 : }
14560 :
14561 2203 : void CheckConvexity(EnergyPlusData &state,
14562 : int const SurfNum, // Current surface number
14563 : int const NSides // Number of sides to figure
14564 : )
14565 : {
14566 : // SUBROUTINE INFORMATION:
14567 : // AUTHOR Tyler Hoyt
14568 : // DATE WRITTEN December 2010
14569 : // MODIFIED CR8752 - incorrect note of non-convex polygons
14570 :
14571 : // PURPOSE OF THIS SUBROUTINE: This subroutine verifies the convexity of a
14572 : // surface that is exposed to the sun in the case that full shading calculations
14573 : // are required. The calculation conveniently detects collinear points as well,
14574 : // and returns a list of indices that are collinear within the plane of the surface.
14575 :
14576 : // METHODOLOGY EMPLOYED: First the surface is determined to have dimension 2 in
14577 : // either the xy, yz, or xz plane. That plane is selected to do the testing.
14578 : // Vectors representing the edges of the polygon and the perpendicular dot product
14579 : // between adjacent edges are computed. This allows the turning angle to be determined.
14580 : // If the turning angle is greater than pi/2, it turns to the right, and if it is
14581 : // less than pi/2, it turns left. The direction of the turn is stored, and if it
14582 : // changes as the edges are iterated the surface is not convex. Meanwhile it stores
14583 : // the indices of vertices that are collinear and are later removed.
14584 :
14585 : // REFERENCES:
14586 : // http://mathworld.wolfram.com/ConvexPolygon.html
14587 :
14588 2203 : constexpr Real64 TurnThreshold = 0.000001; // Sensitivity of convexity test, in radians
14589 :
14590 2203 : Real64 LastTheta = 0.0; // Angle between edge vectors
14591 : bool SignFlag; // Direction of edge turn : true is right, false is left
14592 2203 : bool PrevSignFlag(false); // Container for the sign of the previous iteration's edge turn
14593 2203 : bool PrevSignFlagInitialized(false); // Whether we picked a PrevSignFlag already or not
14594 2203 : auto &X = state.dataSurfaceGeometry->X; // containers for x,y,z vertices of the surface
14595 2203 : auto &Y = state.dataSurfaceGeometry->Y;
14596 2203 : auto &Z = state.dataSurfaceGeometry->Z;
14597 2203 : auto &A = state.dataSurfaceGeometry->A; // containers for convexity test
14598 2203 : auto &B = state.dataSurfaceGeometry->B;
14599 2203 : auto &VertSize = state.dataSurfaceGeometry->VertSize; // size of X,Y,Z,A,B arrays
14600 :
14601 2203 : std::vector<int> surfCollinearVerts; // index of vertices to remove, 1-indexed
14602 2203 : surfCollinearVerts.reserve(NSides + 2);
14603 :
14604 2203 : if (state.dataSurfaceGeometry->CheckConvexityFirstTime) {
14605 225 : X.allocate(state.dataSurface->MaxVerticesPerSurface + 2);
14606 225 : Y.allocate(state.dataSurface->MaxVerticesPerSurface + 2);
14607 225 : Z.allocate(state.dataSurface->MaxVerticesPerSurface + 2);
14608 225 : A.allocate(state.dataSurface->MaxVerticesPerSurface + 2);
14609 225 : B.allocate(state.dataSurface->MaxVerticesPerSurface + 2);
14610 225 : VertSize = state.dataSurface->MaxVerticesPerSurface;
14611 225 : state.dataSurfaceGeometry->CheckConvexityFirstTime = false;
14612 : }
14613 :
14614 2203 : if (NSides > VertSize) {
14615 7 : X.deallocate();
14616 7 : Y.deallocate();
14617 7 : Z.deallocate();
14618 7 : A.deallocate();
14619 7 : B.deallocate();
14620 7 : X.allocate(state.dataSurface->MaxVerticesPerSurface + 2);
14621 7 : Y.allocate(state.dataSurface->MaxVerticesPerSurface + 2);
14622 7 : Z.allocate(state.dataSurface->MaxVerticesPerSurface + 2);
14623 7 : A.allocate(state.dataSurface->MaxVerticesPerSurface + 2);
14624 7 : B.allocate(state.dataSurface->MaxVerticesPerSurface + 2);
14625 7 : VertSize = state.dataSurface->MaxVerticesPerSurface;
14626 : }
14627 :
14628 2203 : auto &surfaceTmp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
14629 2203 : auto &vertices = surfaceTmp.Vertex;
14630 :
14631 11079 : for (int n = 1; n <= NSides; ++n) {
14632 8876 : X(n) = vertices(n).x;
14633 8876 : Y(n) = vertices(n).y;
14634 8876 : Z(n) = vertices(n).z;
14635 : }
14636 2203 : X(NSides + 1) = vertices(1).x;
14637 2203 : Y(NSides + 1) = vertices(1).y;
14638 2203 : Z(NSides + 1) = vertices(1).z;
14639 2203 : X(NSides + 2) = vertices(2).x;
14640 2203 : Y(NSides + 2) = vertices(2).y;
14641 2203 : Z(NSides + 2) = vertices(2).z;
14642 :
14643 : // Determine a suitable plane in which to do the tests
14644 2203 : Real64 Det = 0.0;
14645 11079 : for (int n = 1; n <= NSides; ++n) {
14646 8876 : Det += X(n) * Y(n + 1) - X(n + 1) * Y(n);
14647 : }
14648 2203 : if (std::abs(Det) > Constant::SmallDistance) {
14649 852 : A = X;
14650 852 : B = Y;
14651 : } else {
14652 1351 : Det = 0.0;
14653 6755 : for (int n = 1; n <= NSides; ++n) {
14654 5404 : Det += X(n) * Z(n + 1) - X(n + 1) * Z(n);
14655 : }
14656 1351 : if (std::abs(Det) > Constant::SmallDistance) {
14657 848 : A = X;
14658 848 : B = Z;
14659 : } else {
14660 503 : Det = 0.0;
14661 2514 : for (int n = 1; n <= NSides; ++n) {
14662 2011 : Det += Y(n) * Z(n + 1) - Y(n + 1) * Z(n);
14663 : }
14664 503 : if (std::abs(Det) > Constant::SmallDistance) {
14665 502 : A = Y;
14666 502 : B = Z;
14667 : } else {
14668 : // This condition should not be reached if the surfaces are guaranteed to be planar already
14669 1 : ShowSevereError(state, format("CheckConvexity: Surface=\"{}\" is non-planar.", surfaceTmp.Name));
14670 2 : ShowContinueError(state, "Coincident Vertices will be removed as possible.");
14671 4 : for (int n = 1; n <= surfaceTmp.Sides; ++n) {
14672 3 : auto const &point = vertices(n);
14673 : static constexpr std::string_view ErrFmt = " ({:8.3F},{:8.3F},{:8.3F})";
14674 3 : ShowContinueError(state, format(ErrFmt, point.x, point.y, point.z));
14675 : }
14676 : }
14677 : }
14678 : }
14679 :
14680 11079 : for (int n = 1; n <= NSides; ++n) { // perform convexity test in the plane determined above.
14681 :
14682 8876 : DataVectorTypes::Vector_2d pt0(A(n), B(n));
14683 8876 : DataVectorTypes::Vector_2d pt1(A(n + 1), B(n + 1));
14684 8876 : DataVectorTypes::Vector_2d pt2(A(n + 2), B(n + 2));
14685 :
14686 8876 : DataVectorTypes::Vector_2d V1 = pt1 - pt0;
14687 8876 : DataVectorTypes::Vector_2d V2 = pt2 - pt1;
14688 :
14689 8876 : Real64 V1len = V1.length(); // = norm_L2()
14690 8876 : Real64 V2len = V2.length();
14691 8876 : if (V1len <= 1.e-8 || V2len <= 1.e-8) {
14692 : // At least two points are coincident. Should this happen? GetVertices is supposed to pop these vertices
14693 0 : continue;
14694 : }
14695 8876 : Real64 CrossProd = V1.cross(V2);
14696 8876 : Real64 sinarg = CrossProd / (V1len * V2len);
14697 8876 : if (sinarg < -1.0) {
14698 16 : sinarg = -1.0;
14699 8860 : } else if (sinarg > 1.0) {
14700 12 : sinarg = 1.0;
14701 : }
14702 8876 : Real64 Theta = std::asin(sinarg);
14703 8876 : if (Theta > TurnThreshold) {
14704 4530 : SignFlag = true;
14705 4346 : } else if (Theta < -TurnThreshold) {
14706 4322 : SignFlag = false;
14707 : } else { // std::abs(Theta) < TurnThreshold
14708 : // Store the index of the collinear vertex for removal
14709 24 : int colinearIndex = n + 1;
14710 24 : if (colinearIndex > NSides) {
14711 2 : colinearIndex -= NSides;
14712 : }
14713 24 : if (state.dataGlobal->DisplayExtraWarnings) {
14714 0 : ShowWarningError(
14715 : state,
14716 0 : format("CheckConvexity: Surface=\"{}\", vertex {} is colinear with previous and next.", surfaceTmp.Name, colinearIndex));
14717 : }
14718 24 : ++state.dataErrTracking->TotalCoincidentVertices;
14719 24 : surfCollinearVerts.push_back(colinearIndex);
14720 24 : continue;
14721 24 : }
14722 :
14723 8852 : if (!PrevSignFlagInitialized) {
14724 2203 : PrevSignFlag = SignFlag;
14725 2203 : LastTheta = Theta;
14726 2203 : PrevSignFlagInitialized = true;
14727 2203 : continue;
14728 : }
14729 :
14730 6649 : if (SignFlag != PrevSignFlag) {
14731 37 : if (state.dataGlobal->DisplayExtraWarnings && surfaceTmp.ExtSolar &&
14732 0 : (state.dataHeatBal->SolarDistribution != DataHeatBalance::Shadowing::Minimal) && surfaceTmp.IsConvex &&
14733 37 : !state.dataSysVars->SutherlandHodgman &&
14734 0 : (state.dataSysVars->shadingMethod == DataSystemVariables::ShadingMethod::PolygonClipping)) {
14735 0 : ShowWarningError(state,
14736 0 : format("CheckConvexity: Zone=\"{}\", Surface=\"{}\" is non-convex.",
14737 0 : state.dataHeatBal->Zone(surfaceTmp.Zone).Name,
14738 0 : surfaceTmp.Name));
14739 0 : int Np1 = n + 1;
14740 0 : if (Np1 > NSides) {
14741 0 : Np1 -= NSides;
14742 : }
14743 0 : int Np2 = n + 2;
14744 0 : if (Np2 > NSides) {
14745 0 : Np2 -= NSides;
14746 : }
14747 0 : ShowContinueError(state, format("...vertex {} to vertex {} to vertex {}", n, Np1, Np2));
14748 0 : ShowContinueError(state, format("...vertex {}=[{:.2R},{:.2R},{:.2R}]", n, X(n), Y(n), Z(n)));
14749 0 : ShowContinueError(state, format("...vertex {}=[{:.2R},{:.2R},{:.2R}]", Np1, X(n + 1), Y(n + 1), Z(n + 1)));
14750 0 : ShowContinueError(state, format("...vertex {}=[{:.2R},{:.2R},{:.2R}]", Np2, X(n + 2), Y(n + 2), Z(n + 2)));
14751 : // ShowContinueError(state, format("...theta angle=[{:.6R}]", Theta));
14752 : // ShowContinueError(state, format("...last theta angle=[{:.6R}]", LastTheta));
14753 : }
14754 34 : surfaceTmp.IsConvex = false;
14755 : // #10103 - We do not want to break early, because we do want to consistently remove colinear vertices
14756 : // to avoid potential vertex size mismatch fatal errors
14757 : // break;
14758 : }
14759 6649 : PrevSignFlag = SignFlag;
14760 6649 : LastTheta = Theta;
14761 17784 : }
14762 :
14763 : // must check to make sure don't remove NSides below 3
14764 2203 : int M = surfCollinearVerts.size();
14765 2203 : if (M > 0) { // Remove the collinear points determined above
14766 6 : if (NSides - M >= 3) {
14767 6 : surfaceTmp.Sides = NSides - M;
14768 6 : if (state.dataGlobal->DisplayExtraWarnings) {
14769 0 : ShowWarningError(state,
14770 0 : format("CheckConvexity: Surface=\"{}\" has [{}] collinear points that have been removed.", surfaceTmp.Name, M));
14771 : }
14772 : } else { // too many
14773 0 : if (state.dataGlobal->DisplayExtraWarnings) {
14774 0 : ShowWarningError(state, format("CheckConvexity: Surface=\"{}\" has [{}] collinear points.", surfaceTmp.Name, M));
14775 0 : ShowContinueError(state, "...too many to remove all. Will leave the surface with 3 sides. But this is now a degenerate surface");
14776 : }
14777 0 : ++state.dataErrTracking->TotalDegenerateSurfaces;
14778 0 : surfaceTmp.Sides = 3; // max(NSides - M, 3) = 3 since NSide - M is < 3;
14779 0 : surfCollinearVerts.resize(NSides - 3);
14780 : }
14781 :
14782 : // remove duplicated points: For that we construct a new array of vertices, only copying indices that aren't in SurfCollinearVerts
14783 : // Then we move that array into the original one
14784 6 : Array1D<Vector> newVertices;
14785 6 : newVertices.allocate(surfaceTmp.Sides);
14786 :
14787 6 : int n = 0;
14788 58 : for (int i = 1; i <= NSides; ++i) {
14789 52 : if (std::find(surfCollinearVerts.cbegin(), surfCollinearVerts.cend(), i) == surfCollinearVerts.cend()) {
14790 28 : newVertices(++n) = vertices(i);
14791 : }
14792 : }
14793 6 : vertices = std::move(newVertices);
14794 :
14795 6 : if (state.dataGlobal->DisplayExtraWarnings) {
14796 0 : ShowWarningError(state,
14797 0 : format("CheckConvexity: Surface=\"{}\": The vertex points has been reprocessed as Sides = {}",
14798 0 : surfaceTmp.Name,
14799 0 : surfaceTmp.Sides));
14800 : }
14801 6 : }
14802 2203 : }
14803 :
14804 1664 : bool isRectangle(EnergyPlusData &state, int const ThisSurf // Surface number
14805 : )
14806 : {
14807 : // SUBROUTINE INFORMATION:
14808 : // AUTHOR M.J. Witte
14809 : // DATE WRITTEN October 2015
14810 :
14811 : // PURPOSE: Check if a 4-sided surface is a rectangle
14812 :
14813 : Real64 Diagonal1; // Length of diagonal of 4-sided figure from vertex 1 to vertex 3 (m)
14814 : Real64 Diagonal2; // Length of diagonal of 4-sided figure from vertex 2 to vertex 4 (m)
14815 : Real64 DotProd; // Dot product of two adjacent sides - to test for right angle
14816 1664 : Real64 const cos89deg = std::cos(89.0 * Constant::DegToRad); // tolerance for right angle
14817 1664 : Vector Vect32; // normalized vector from vertex 3 to vertex 2
14818 1664 : Vector Vect21; // normalized vector from vertex 2 to vertex 1
14819 :
14820 1664 : auto &surf = state.dataSurface->Surface(ThisSurf);
14821 1664 : Diagonal1 = Vectors::VecLength(surf.Vertex(1) - surf.Vertex(3));
14822 1664 : Diagonal2 = Vectors::VecLength(surf.Vertex(2) - surf.Vertex(4));
14823 : // Test for rectangularity
14824 1664 : if (std::abs(Diagonal1 - Diagonal2) < 0.020) { // This tolerance based on coincident vertex tolerance of 0.01
14825 1615 : Vect32 = Vectors::VecNormalize(surf.Vertex(3) - surf.Vertex(2));
14826 1615 : Vect21 = Vectors::VecNormalize(surf.Vertex(2) - surf.Vertex(1));
14827 1615 : DotProd = dot(Vect32, Vect21);
14828 1615 : if (std::abs(DotProd) <= cos89deg) {
14829 1531 : return true;
14830 : } else {
14831 84 : return false;
14832 : }
14833 : } else {
14834 49 : return false;
14835 : }
14836 1664 : }
14837 :
14838 6 : void MakeEquivalentRectangle(EnergyPlusData &state,
14839 : int const SurfNum, // Surface number
14840 : bool &ErrorsFound // Error flag indicator (true if errors found)
14841 : )
14842 : {
14843 : // SUBROUTINE INFORMATION:
14844 : // AUTHOR R. Zhang, LBNL
14845 : // DATE WRITTEN September 2016
14846 :
14847 : // PURPOSE OF THIS SUBROUTINE:
14848 : // Processing of 4-sided but non-rectangular Window, Door or GlassDoor.
14849 : // Calculate the effective height and width of the surface.
14850 : //
14851 : // METHODOLOGY EMPLOYED:
14852 : // Transform the surface into an equivalent rectangular surface with the same area and aspect ratio.
14853 :
14854 : Real64 AspectRatio; // Aspect ratio
14855 : Real64 WidthEff; // Effective width of the surface
14856 : Real64 WidthMax; // X difference between the vertex on the most left and the one on the most right
14857 : Real64 HeightEff; // Effective height of the surface
14858 : Real64 HeightMax; // Y difference between the lowest and highest vertices
14859 : Real64 Xp;
14860 : Real64 Yp;
14861 : Real64 Zp;
14862 : Real64 XLLC;
14863 : Real64 YLLC;
14864 : Real64 ZLLC;
14865 :
14866 6 : if (SurfNum == 0) {
14867 : // invalid surface
14868 0 : ErrorsFound = true;
14869 0 : return;
14870 : }
14871 :
14872 6 : auto &surf = state.dataSurface->Surface(SurfNum);
14873 6 : if (surf.Sides != 4) {
14874 : // the method is designed for 4-sided surface
14875 0 : return;
14876 6 : } else if (isRectangle(state, SurfNum)) {
14877 : // no need to transform
14878 1 : return;
14879 : }
14880 :
14881 5 : Real64 SurfWorldAz = surf.Azimuth;
14882 5 : Real64 SurfTilt = surf.Tilt;
14883 5 : Real64 BaseCosAzimuth = std::cos(SurfWorldAz * Constant::DegToRad);
14884 5 : Real64 BaseSinAzimuth = std::sin(SurfWorldAz * Constant::DegToRad);
14885 5 : Real64 BaseCosTilt = std::cos(SurfTilt * Constant::DegToRad);
14886 5 : Real64 BaseSinTilt = std::sin(SurfTilt * Constant::DegToRad);
14887 5 : int NumSurfSides = surf.Sides;
14888 :
14889 : // Calculate WidthMax and HeightMax
14890 5 : WidthMax = 0.0;
14891 5 : HeightMax = 0.0;
14892 20 : for (int i = 1; i < NumSurfSides; ++i) {
14893 45 : for (int j = i + 1; j <= NumSurfSides; ++j) {
14894 :
14895 30 : Xp = surf.Vertex(j).x - surf.Vertex(i).x;
14896 30 : Yp = surf.Vertex(j).y - surf.Vertex(i).y;
14897 30 : Zp = surf.Vertex(j).z - surf.Vertex(i).z;
14898 :
14899 30 : XLLC = -Xp * BaseCosAzimuth + Yp * BaseSinAzimuth;
14900 30 : YLLC = -Xp * BaseSinAzimuth * BaseCosTilt - Yp * BaseCosAzimuth * BaseCosTilt + Zp * BaseSinTilt;
14901 30 : ZLLC = Xp * BaseSinAzimuth * BaseSinTilt + Yp * BaseCosAzimuth * BaseSinTilt + Zp * BaseCosTilt;
14902 :
14903 30 : if (std::abs(XLLC) > WidthMax) WidthMax = std::abs(XLLC);
14904 30 : if (std::abs(YLLC) > WidthMax) HeightMax = std::abs(YLLC);
14905 : }
14906 : }
14907 :
14908 : // Perform transformation by calculating WidthEff and HeightEff
14909 5 : if ((WidthMax > 0) && (HeightMax > 0)) {
14910 2 : AspectRatio = WidthMax / HeightMax;
14911 : } else {
14912 3 : AspectRatio = 1;
14913 : }
14914 5 : WidthEff = std::sqrt(surf.Area * AspectRatio);
14915 5 : HeightEff = std::sqrt(surf.Area / AspectRatio);
14916 :
14917 : // Assign the effective width and length to the surface
14918 5 : surf.Width = WidthEff;
14919 5 : surf.Height = HeightEff;
14920 : }
14921 :
14922 201 : void CheckForReversedLayers(EnergyPlusData &state,
14923 : bool &RevLayerDiffs, // true when differences are discovered in interzone constructions
14924 : int const ConstrNum, // construction index
14925 : int const ConstrNumRev, // construction index for reversed construction
14926 : int const TotalLayers // total layers for construction definition
14927 : )
14928 : {
14929 201 : auto &s_mat = state.dataMaterial;
14930 201 : RevLayerDiffs = false;
14931 :
14932 625 : for (int LayerNo = 1; LayerNo <= TotalLayers; ++LayerNo) {
14933 :
14934 427 : int thisConstLayer = state.dataConstruction->Construct(ConstrNum).LayerPoint(LayerNo);
14935 427 : int revConstLayer = state.dataConstruction->Construct(ConstrNumRev).LayerPoint(TotalLayers - LayerNo + 1);
14936 427 : if (thisConstLayer == revConstLayer) continue;
14937 :
14938 6 : auto const *mat = s_mat->materials(thisConstLayer);
14939 6 : auto const *matRev = s_mat->materials(revConstLayer);
14940 :
14941 : // If not point to the same layer, check to see if this is window glass which might need to have
14942 : // front and back material properties reversed.
14943 6 : Real64 constexpr SmallDiff = 0.0001;
14944 6 : if ((mat->group == Material::Group::Glass) && (matRev->group == Material::Group::Glass)) {
14945 3 : auto const *matGlass = dynamic_cast<Material::MaterialGlass const *>(mat);
14946 3 : auto const *matGlassRev = dynamic_cast<Material::MaterialGlass const *>(matRev);
14947 3 : assert(matGlass != nullptr);
14948 3 : assert(matGlassRev != nullptr);
14949 :
14950 : // Both layers are window glass, so need to check to see if the properties are reversed
14951 6 : if ((abs(matGlass->Thickness - matGlassRev->Thickness) > SmallDiff) ||
14952 6 : (abs(matGlass->ReflectSolBeamBack - matGlassRev->ReflectSolBeamFront) > SmallDiff) ||
14953 6 : (abs(matGlass->ReflectSolBeamFront - matGlassRev->ReflectSolBeamBack) > SmallDiff) ||
14954 6 : (abs(matGlass->TransVis - matGlassRev->TransVis) > SmallDiff) ||
14955 5 : (abs(matGlass->ReflectVisBeamBack - matGlassRev->ReflectVisBeamFront) > SmallDiff) ||
14956 4 : (abs(matGlass->ReflectVisBeamFront - matGlassRev->ReflectVisBeamBack) > SmallDiff) ||
14957 4 : (abs(matGlass->TransThermal - matGlassRev->TransThermal) > SmallDiff) ||
14958 4 : (abs(matGlass->AbsorpThermalBack - matGlassRev->AbsorpThermalFront) > SmallDiff) ||
14959 4 : (abs(matGlass->AbsorpThermalFront - matGlassRev->AbsorpThermalBack) > SmallDiff) ||
14960 4 : (abs(matGlass->Conductivity - matGlassRev->Conductivity) > SmallDiff) ||
14961 2 : (abs(matGlass->GlassTransDirtFactor - matGlassRev->GlassTransDirtFactor) > SmallDiff) ||
14962 4 : (matGlass->SolarDiffusing != matGlassRev->SolarDiffusing) ||
14963 8 : (abs(matGlass->YoungModulus - matGlassRev->YoungModulus) > SmallDiff) ||
14964 2 : (abs(matGlass->PoissonsRatio - matGlassRev->PoissonsRatio) > SmallDiff)) {
14965 1 : RevLayerDiffs = true;
14966 1 : break; // exit when diff
14967 : } // If none of the above conditions is met, then these should be the same layers in reverse (RevLayersDiffs = false)
14968 5 : } else if ((mat->group == Material::Group::GlassEQL) && (matRev->group == Material::Group::GlassEQL)) {
14969 2 : auto const *matGlass = dynamic_cast<Material::MaterialGlassEQL const *>(mat);
14970 2 : auto const *matGlassRev = dynamic_cast<Material::MaterialGlassEQL const *>(matRev);
14971 :
14972 4 : if ((abs(matGlass->TAR.Sol.Bk.Bm[0].BmTra - matGlassRev->TAR.Sol.Ft.Bm[0].BmTra) > SmallDiff) ||
14973 4 : (abs(matGlass->TAR.Sol.Ft.Bm[0].BmTra - matGlassRev->TAR.Sol.Bk.Bm[0].BmTra) > SmallDiff) ||
14974 4 : (abs(matGlass->TAR.Sol.Bk.Bm[0].BmRef - matGlassRev->TAR.Sol.Ft.Bm[0].BmRef) > SmallDiff) ||
14975 4 : (abs(matGlass->TAR.Sol.Ft.Bm[0].BmRef - matGlassRev->TAR.Sol.Bk.Bm[0].BmRef) > SmallDiff) ||
14976 4 : (abs(matGlass->TAR.Vis.Bk.Bm[0].BmTra - matGlassRev->TAR.Vis.Ft.Bm[0].BmTra) > SmallDiff) ||
14977 4 : (abs(matGlass->TAR.Vis.Ft.Bm[0].BmTra - matGlassRev->TAR.Vis.Bk.Bm[0].BmTra) > SmallDiff) ||
14978 4 : (abs(matGlass->TAR.Vis.Bk.Bm[0].BmRef - matGlassRev->TAR.Vis.Ft.Bm[0].BmRef) > SmallDiff) ||
14979 4 : (abs(matGlass->TAR.Vis.Ft.Bm[0].BmRef - matGlassRev->TAR.Vis.Bk.Bm[0].BmRef) > SmallDiff) ||
14980 4 : (abs(matGlass->TAR.Sol.Bk.Bm[0].DfTra - matGlassRev->TAR.Sol.Ft.Bm[0].DfTra) > SmallDiff) ||
14981 4 : (abs(matGlass->TAR.Sol.Ft.Bm[0].DfTra - matGlassRev->TAR.Sol.Bk.Bm[0].DfTra) > SmallDiff) ||
14982 4 : (abs(matGlass->TAR.Sol.Bk.Bm[0].DfRef - matGlassRev->TAR.Sol.Ft.Bm[0].DfRef) > SmallDiff) ||
14983 4 : (abs(matGlass->TAR.Sol.Ft.Bm[0].DfRef - matGlassRev->TAR.Sol.Bk.Bm[0].DfRef) > SmallDiff) ||
14984 4 : (abs(matGlass->TAR.Vis.Bk.Bm[0].DfTra - matGlassRev->TAR.Vis.Ft.Bm[0].DfTra) > SmallDiff) ||
14985 4 : (abs(matGlass->TAR.Vis.Ft.Bm[0].DfTra - matGlassRev->TAR.Vis.Bk.Bm[0].DfTra) > SmallDiff) ||
14986 4 : (abs(matGlass->TAR.Vis.Bk.Bm[0].DfRef - matGlassRev->TAR.Vis.Ft.Bm[0].DfRef) > SmallDiff) ||
14987 4 : (abs(matGlass->TAR.Vis.Ft.Bm[0].DfRef - matGlassRev->TAR.Vis.Bk.Bm[0].DfRef) > SmallDiff) ||
14988 4 : (abs(matGlass->TAR.Sol.Ft.Df.Tra - matGlassRev->TAR.Sol.Ft.Df.Tra) > SmallDiff) ||
14989 4 : (abs(matGlass->TAR.Sol.Bk.Df.Ref - matGlassRev->TAR.Sol.Ft.Df.Ref) > SmallDiff) ||
14990 4 : (abs(matGlass->TAR.Sol.Ft.Df.Ref - matGlassRev->TAR.Sol.Bk.Df.Ref) > SmallDiff) ||
14991 4 : (abs(matGlass->TAR.Vis.Ft.Df.Tra - matGlassRev->TAR.Vis.Ft.Df.Tra) > SmallDiff) ||
14992 4 : (abs(matGlass->TAR.Vis.Bk.Df.Ref - matGlassRev->TAR.Vis.Ft.Df.Ref) > SmallDiff) ||
14993 4 : (abs(matGlass->TAR.Vis.Ft.Df.Ref - matGlassRev->TAR.Vis.Bk.Df.Ref) > SmallDiff) ||
14994 4 : (abs(matGlass->TAR.IR.Ft.Tra - matGlassRev->TAR.IR.Ft.Tra) > SmallDiff) ||
14995 3 : (abs(matGlass->TAR.IR.Bk.Emi - matGlassRev->TAR.IR.Ft.Emi) > SmallDiff) ||
14996 5 : (abs(matGlass->TAR.IR.Ft.Emi - matGlassRev->TAR.IR.Bk.Emi) > SmallDiff) ||
14997 1 : (abs(matGlass->Resistance - matGlassRev->Resistance) > SmallDiff)) {
14998 1 : RevLayerDiffs = true;
14999 1 : break; // exit when diff
15000 : } // If none of the above conditions is met, then these should be the same layers in reverse (RevLayersDiffs = false)
15001 :
15002 1 : } else {
15003 : // Other material types do not have reversed constructions so if they are not the same layer there is a problem
15004 : // (RevLayersDiffs = true)
15005 1 : RevLayerDiffs = true;
15006 1 : break; // exit when diff
15007 : } // End check of whether or not these are WindowGlass
15008 : }
15009 201 : }
15010 :
15011 134 : void GetGeoSummaryRoof(EnergyPlusData const &state, GeoSummary &geoSummaryRoof)
15012 : {
15013 134 : std::vector<Vector> uniqueRoofVertices;
15014 134 : std::vector<SurfaceGeometry::EdgeOfSurf> uniqEdgeOfSurfs; // I'm only partially using this
15015 990 : for (const auto &surface : state.dataSurface->Surface) {
15016 :
15017 856 : if (surface.ExtBoundCond != DataSurfaces::ExternalEnvironment) {
15018 264 : continue;
15019 : }
15020 592 : if (!surface.HeatTransSurf) {
15021 20 : continue;
15022 : }
15023 :
15024 572 : if (surface.Tilt > 45.0) { // TODO Double check tilt wrt outside vs inside?
15025 448 : continue;
15026 : }
15027 :
15028 124 : Real64 const z_min(minval(surface.Vertex, &Vector::z));
15029 124 : Real64 const z_max(maxval(surface.Vertex, &Vector::z));
15030 124 : Real64 const verticalHeight = z_max - z_min;
15031 124 : geoSummaryRoof.Height += verticalHeight * surface.Area;
15032 124 : geoSummaryRoof.Tilt += surface.Tilt * surface.Area;
15033 124 : geoSummaryRoof.Azimuth += surface.Azimuth * surface.Area;
15034 124 : geoSummaryRoof.Area += surface.Area;
15035 :
15036 620 : for (auto it = surface.Vertex.begin(); it != surface.Vertex.end(); ++it) {
15037 :
15038 496 : auto itnext = std::next(it);
15039 992 : if (itnext == std::end(surface.Vertex)) {
15040 248 : itnext = std::begin(surface.Vertex);
15041 : }
15042 :
15043 496 : auto &curVertex = *it;
15044 496 : auto &nextVertex = *itnext;
15045 496 : auto it2 = std::find_if(uniqueRoofVertices.begin(), uniqueRoofVertices.end(), [&curVertex](const auto &unqV) {
15046 1008 : return SurfaceGeometry::isAlmostEqual3dPt(curVertex, unqV);
15047 : });
15048 496 : if (it2 == std::end(uniqueRoofVertices)) {
15049 421 : uniqueRoofVertices.emplace_back(curVertex);
15050 : }
15051 :
15052 496 : SurfaceGeometry::EdgeOfSurf thisEdge;
15053 496 : thisEdge.start = std::move(curVertex);
15054 496 : thisEdge.end = std::move(nextVertex);
15055 496 : thisEdge.count = 1;
15056 :
15057 : // Uses the custom operator== that uses isAlmostEqual3dPt internally and doesn't care about order of the start/end
15058 496 : auto itEdge = std::find(uniqEdgeOfSurfs.begin(), uniqEdgeOfSurfs.end(), thisEdge);
15059 496 : if (itEdge == uniqEdgeOfSurfs.end()) {
15060 431 : uniqEdgeOfSurfs.emplace_back(std::move(thisEdge));
15061 : } else {
15062 65 : ++(itEdge->count);
15063 : }
15064 496 : }
15065 : }
15066 :
15067 134 : if (geoSummaryRoof.Area > 0) {
15068 95 : geoSummaryRoof.Height /= geoSummaryRoof.Area;
15069 95 : geoSummaryRoof.Tilt /= geoSummaryRoof.Area;
15070 95 : geoSummaryRoof.Azimuth /= geoSummaryRoof.Area;
15071 : } else {
15072 39 : geoSummaryRoof.Height = 0.0;
15073 39 : geoSummaryRoof.Tilt = 0.0;
15074 39 : geoSummaryRoof.Azimuth = 0.0;
15075 : }
15076 :
15077 : // Remove the ones that are already used twice
15078 268 : uniqEdgeOfSurfs.erase(
15079 565 : std::remove_if(uniqEdgeOfSurfs.begin(), uniqEdgeOfSurfs.end(), [](const auto &edge) -> bool { return edge.count == 2; }),
15080 134 : uniqEdgeOfSurfs.end());
15081 :
15082 : // Intersect with unique vertices as much as needed
15083 134 : bool insertedVertext = true;
15084 272 : while (insertedVertext) {
15085 138 : insertedVertext = false;
15086 :
15087 547 : for (auto &edge : uniqEdgeOfSurfs) {
15088 :
15089 : // now go through all the vertices and see if they are colinear with start and end vertices
15090 2564 : for (const auto &testVertex : uniqueRoofVertices) {
15091 2155 : if (edge.containsPoints(testVertex)) {
15092 4 : SurfaceGeometry::EdgeOfSurf newEdgeOfSurface;
15093 4 : newEdgeOfSurface.start = testVertex;
15094 4 : newEdgeOfSurface.end = edge.end;
15095 4 : edge.end = testVertex;
15096 4 : uniqEdgeOfSurfs.emplace_back(std::move(newEdgeOfSurface));
15097 4 : insertedVertext = true;
15098 4 : break;
15099 4 : }
15100 : }
15101 : // Break out of the loop on edges, and start again at the while
15102 413 : if (insertedVertext) {
15103 4 : break;
15104 : }
15105 : }
15106 : }
15107 :
15108 : // recount
15109 520 : for (auto &edge : uniqEdgeOfSurfs) {
15110 386 : edge.count = std::count(uniqEdgeOfSurfs.begin(), uniqEdgeOfSurfs.end(), edge);
15111 : }
15112 :
15113 268 : uniqEdgeOfSurfs.erase(
15114 520 : std::remove_if(uniqEdgeOfSurfs.begin(), uniqEdgeOfSurfs.end(), [](const auto &edge) -> bool { return edge.count == 2; }),
15115 134 : uniqEdgeOfSurfs.end());
15116 :
15117 134 : geoSummaryRoof.Perimeter =
15118 134 : std::accumulate(uniqEdgeOfSurfs.cbegin(), uniqEdgeOfSurfs.cend(), 0.0, [](const double &sum, const SurfaceGeometry::EdgeOfSurf &edge) {
15119 380 : return sum + edge.length();
15120 : });
15121 134 : }
15122 :
15123 : } // namespace SurfaceGeometry
15124 :
15125 : } // namespace EnergyPlus
|