LCOV - code coverage report
Current view: top level - EnergyPlus - SurfaceGeometry.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 56.1 % 9355 5244
Test Date: 2025-06-02 12:03:30 Functions: 90.9 % 99 90

            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) {
     305            0 :             CreateStormWindowConstructions(state);
     306              :         }
     307              : 
     308          192 :         DataHeatBalance::SetFlagForWindowConstructionWithShadeOrBlindLayer(state);
     309              : 
     310          192 :         state.dataSurfaceGeometry->CosZoneRelNorth.deallocate();
     311          192 :         state.dataSurfaceGeometry->SinZoneRelNorth.deallocate();
     312              : 
     313          192 :         state.dataHeatBal->CalcWindowRevealReflection = false; // Set to True in ProcessSurfaceVertices if beam solar reflection from window reveals
     314              :         // is requested for one or more exterior windows.
     315          192 :         state.dataSurface->BuildingShadingCount = 0;
     316          192 :         state.dataSurface->FixedShadingCount = 0;
     317          192 :         state.dataSurface->AttachedShadingCount = 0;
     318          192 :         state.dataSurface->ShadingSurfaceFirst = 0;
     319          192 :         state.dataSurface->ShadingSurfaceLast = -1;
     320              : 
     321              :         // Reserve space to avoid excess allocations
     322          192 :         state.dataSurface->AllExtSolAndShadingSurfaceList.reserve(state.dataSurface->TotSurfaces);
     323              : 
     324         1881 :         for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) { // Loop through all surfaces...
     325         1689 :             auto &thisSurface = state.dataSurface->Surface(SurfNum);
     326              : 
     327         1689 :             state.dataSurface->SurfAirSkyRadSplit(SurfNum) = std::sqrt(0.5 * (1.0 + thisSurface.CosTilt));
     328              : 
     329              :             // Set flag that determines whether a surface is a shadowing surface
     330         1689 :             thisSurface.IsShadowing = false;
     331         1689 :             if (thisSurface.Class == SurfaceClass::Shading || thisSurface.Class == SurfaceClass::Detached_F ||
     332         1635 :                 thisSurface.Class == SurfaceClass::Detached_B) {
     333           74 :                 thisSurface.IsShadowing = true;
     334           74 :                 if (state.dataSurface->ShadingSurfaceFirst == 0) {
     335           19 :                     state.dataSurface->ShadingSurfaceFirst = SurfNum;
     336              :                 }
     337           74 :                 state.dataSurface->ShadingSurfaceLast = SurfNum;
     338              :             }
     339         1689 :             if ((thisSurface.HeatTransSurf && thisSurface.ExtSolar) || thisSurface.IsShadowing) {
     340              :                 // Some attached shading surfaces may be true for both
     341         1091 :                 state.dataSurface->AllExtSolAndShadingSurfaceList.push_back(SurfNum);
     342              :             }
     343         1689 :             if (thisSurface.Class == SurfaceClass::Shading) {
     344           48 :                 ++state.dataSurface->AttachedShadingCount;
     345              :             }
     346         1689 :             if (thisSurface.Class == SurfaceClass::Detached_F) {
     347            6 :                 ++state.dataSurface->FixedShadingCount;
     348              :             }
     349         1689 :             if (thisSurface.Class == SurfaceClass::Detached_B) {
     350           20 :                 ++state.dataSurface->BuildingShadingCount;
     351              :             }
     352              : 
     353         1689 :             if (thisSurface.Class != SurfaceClass::IntMass) {
     354         1683 :                 ProcessSurfaceVertices(state, SurfNum, ErrorsFound);
     355              :             }
     356              :         }
     357              : 
     358          467 :         for (auto &e : state.dataHeatBal->Zone) {
     359          275 :             e.ExtWindowArea = 0.0;
     360          275 :             e.HasWindow = false;
     361          275 :             e.ExtGrossWallArea = 0.0;
     362          275 :             e.ExtNetWallArea = 0.0;
     363          275 :             e.TotalSurfArea = 0.0;
     364          192 :         }
     365              : 
     366          488 :         for (auto &s : state.dataHeatBal->space) {
     367          296 :             s.extWindowArea = 0.0;
     368          296 :             s.totalSurfArea = 0.0;
     369          192 :         }
     370          384 :         bool DetailedWWR = (state.dataInputProcessing->inputProcessor->getNumSectionsFound("DETAILEDWWR_DEBUG") > 0);
     371          192 :         if (DetailedWWR) {
     372            0 :             print(state.files.debug, "{}", "=======User Entered Classification =================");
     373            0 :             print(state.files.debug, "{}", "Surface,Class,Area,Tilt");
     374              :         }
     375              : 
     376         1881 :         for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) { // Loop through all surfaces to find windows...
     377         1689 :             auto &thisSurface = state.dataSurface->Surface(SurfNum);
     378              : 
     379         1689 :             if (!thisSurface.HeatTransSurf && !thisSurface.IsAirBoundarySurf) {
     380           74 :                 continue; // Skip shadowing (sub)surfaces
     381              :             }
     382         1615 :             auto &thisZone = state.dataHeatBal->Zone(thisSurface.Zone);
     383         1615 :             auto &thisSpace = state.dataHeatBal->space(thisSurface.spaceNum);
     384              : 
     385         1615 :             thisZone.TotalSurfArea += thisSurface.Area;
     386         1615 :             thisSpace.totalSurfArea += thisSurface.Area;
     387         1615 :             if (thisSurface.Class == SurfaceClass::Roof) {
     388          256 :                 thisZone.geometricCeilingArea += thisSurface.GrossArea;
     389         1359 :             } else if (thisSurface.Class == SurfaceClass::Floor) {
     390          327 :                 thisZone.geometricFloorArea += thisSurface.GrossArea;
     391              :             }
     392         1615 :             if (state.dataConstruction->Construct(thisSurface.Construction).TypeIsWindow) {
     393          125 :                 thisZone.TotalSurfArea += state.dataSurface->SurfWinFrameArea(SurfNum);
     394          125 :                 thisZone.HasWindow = true;
     395          125 :                 thisSpace.totalSurfArea += state.dataSurface->SurfWinFrameArea(SurfNum);
     396          125 :                 if (((thisSurface.ExtBoundCond == DataSurfaces::ExternalEnvironment) ||
     397            6 :                      (thisSurface.ExtBoundCond == DataSurfaces::OtherSideCondModeledExt)) &&
     398          119 :                     (thisSurface.Class != SurfaceClass::TDD_Dome)) {
     399          112 :                     thisZone.ExtWindowArea += thisSurface.GrossArea;
     400          112 :                     thisSpace.extWindowArea += thisSurface.GrossArea;
     401          112 :                     thisZone.ExtWindowArea_Multiplied =
     402          112 :                         thisZone.ExtWindowArea + thisSurface.GrossArea * thisSurface.Multiplier * thisZone.Multiplier * thisZone.ListMultiplier;
     403          112 :                     if (DetailedWWR) {
     404            0 :                         print(state.files.debug,
     405              :                               "{},Window,{:.2R},{:.1R}\n",
     406            0 :                               thisSurface.Name,
     407            0 :                               thisSurface.GrossArea * thisSurface.Multiplier * thisZone.Multiplier * thisZone.ListMultiplier,
     408            0 :                               thisSurface.Tilt);
     409              :                     }
     410              :                 }
     411              :             } else {
     412         1490 :                 if (thisSurface.ExtBoundCond == DataSurfaces::ExternalEnvironment ||
     413          525 :                     thisSurface.ExtBoundCond == DataSurfaces::OtherSideCondModeledExt) {
     414          966 :                     thisZone.ExteriorTotalSurfArea += thisSurface.GrossArea;
     415          966 :                     thisSpace.ExteriorTotalSurfArea += thisSurface.GrossArea;
     416          966 :                     if (thisSurface.Class == SurfaceClass::Wall) {
     417          643 :                         thisZone.ExtNetWallArea += thisSurface.Area;
     418          643 :                         thisZone.ExtGrossWallArea += thisSurface.GrossArea;
     419          643 :                         thisSpace.ExtGrossWallArea += thisSurface.GrossArea;
     420          643 :                         thisZone.ExtGrossWallArea_Multiplied += thisSurface.GrossArea * thisZone.Multiplier * thisZone.ListMultiplier;
     421          643 :                         thisZone.extPerimeter += thisSurface.Width;
     422          643 :                         thisSpace.extPerimeter += thisSurface.Width;
     423          643 :                         if (DetailedWWR) {
     424            0 :                             print(state.files.debug,
     425              :                                   "{},Wall,{:.2R},{:.1R}\n",
     426            0 :                                   thisSurface.Name,
     427            0 :                                   thisSurface.GrossArea * thisZone.Multiplier * thisZone.ListMultiplier,
     428            0 :                                   thisSurface.Tilt);
     429              :                         }
     430              :                     }
     431          524 :                 } else if (thisSurface.ExtBoundCond == DataSurfaces::Ground || thisSurface.ExtBoundCond == DataSurfaces::GroundFCfactorMethod ||
     432          419 :                            thisSurface.ExtBoundCond == DataSurfaces::KivaFoundation) {
     433          105 :                     thisZone.ExteriorTotalGroundSurfArea += thisSurface.GrossArea;
     434          105 :                     if (thisSurface.Class == SurfaceClass::Wall) {
     435            3 :                         thisZone.ExtGrossGroundWallArea += thisSurface.GrossArea;
     436            3 :                         thisZone.ExtGrossGroundWallArea_Multiplied += thisSurface.GrossArea * thisZone.Multiplier * thisZone.ListMultiplier;
     437            3 :                         if (DetailedWWR) {
     438            0 :                             print(state.files.debug,
     439              :                                   "{},Wall-GroundContact,{:.2R},{:.1R}\n",
     440            0 :                                   thisSurface.Name,
     441            0 :                                   thisSurface.GrossArea * thisZone.Multiplier * thisZone.ListMultiplier,
     442            0 :                                   thisSurface.Tilt);
     443              :                         }
     444              :                     }
     445              :                 }
     446              :             }
     447              : 
     448              :         } // ...end of surfaces windows DO loop
     449              : 
     450          192 :         if (DetailedWWR) {
     451            0 :             print(state.files.debug, "{}\n", "========================");
     452            0 :             print(state.files.debug, "{}\n", "Zone,ExtWallArea,ExtWindowArea");
     453              :         }
     454              : 
     455          467 :         for (auto &thisZone : state.dataHeatBal->Zone) {
     456          275 :             int CeilCount = 0;
     457          275 :             int FloorCount = 0;
     458          275 :             int WallCount = 0;
     459          275 :             Real64 AverageHeight = 0.0; // Used to keep track of average height of a surface/zone
     460          275 :             Real64 ZMax = -99999.0;     // Maximum Z of a surface (detailed outside coefficient calculation)
     461          275 :             Real64 ZMin = 99999.0;      // Minimum Z of a surface (detailed outside coefficient calculation)
     462          275 :             Real64 ZCeilAvg = 0.0;
     463          275 :             Real64 ZFlrAvg = 0.0;
     464          275 :             if (DetailedWWR) {
     465            0 :                 print(state.files.debug, "{},{:.2R},{:.2R}\n", thisZone.Name, thisZone.ExtGrossWallArea, thisZone.ExtWindowArea);
     466              :             }
     467          571 :             for (int spaceNum : thisZone.spaceIndexes) {
     468          296 :                 auto const &thisSpace = state.dataHeatBal->space(spaceNum);
     469              :                 // Use AllSurfaceFirst which includes air boundaries
     470         1911 :                 for (int SurfNum = thisSpace.AllSurfaceFirst; SurfNum <= thisSpace.AllSurfaceLast; ++SurfNum) {
     471         1615 :                     auto &thisSurface = state.dataSurface->Surface(SurfNum);
     472              : 
     473         1615 :                     if (thisSurface.Class == SurfaceClass::Roof) {
     474              :                         // Use Average Z for surface, more important for roofs than floors...
     475          256 :                         ++CeilCount;
     476          256 :                         Real64 Z1 = minval(thisSurface.Vertex, &Vector::z);
     477          256 :                         Real64 Z2 = maxval(thisSurface.Vertex, &Vector::z);
     478              :                         //        ZCeilAvg=ZCeilAvg+(Z1+Z2)/2.d0
     479          256 :                         ZCeilAvg += ((Z1 + Z2) / 2.0) * (thisSurface.GrossArea / thisZone.geometricCeilingArea);
     480              :                     }
     481         1615 :                     if (thisSurface.Class == SurfaceClass::Floor) {
     482              :                         // Use Average Z for surface, more important for roofs than floors...
     483          327 :                         ++FloorCount;
     484          327 :                         Real64 Z1 = minval(thisSurface.Vertex, &Vector::z);
     485          327 :                         Real64 Z2 = maxval(thisSurface.Vertex, &Vector::z);
     486              :                         //        ZFlrAvg=ZFlrAvg+(Z1+Z2)/2.d0
     487          327 :                         ZFlrAvg += ((Z1 + Z2) / 2.0) * (thisSurface.GrossArea / thisZone.geometricFloorArea);
     488              :                     }
     489         1615 :                     if (thisSurface.Class == SurfaceClass::Wall) {
     490              :                         // Use Wall calculation in case no roof & floor in zone
     491          887 :                         ++WallCount;
     492          887 :                         if (WallCount == 1) {
     493          258 :                             ZMax = thisSurface.Vertex(1).z;
     494          258 :                             ZMin = ZMax;
     495              :                         }
     496          887 :                         ZMax = max(ZMax, maxval(thisSurface.Vertex, &Vector::z));
     497          887 :                         ZMin = min(ZMin, minval(thisSurface.Vertex, &Vector::z));
     498              :                     }
     499              :                 }
     500          275 :             }
     501          275 :             if (CeilCount > 0 && FloorCount > 0) {
     502          197 :                 AverageHeight = ZCeilAvg - ZFlrAvg;
     503              :             } else {
     504           78 :                 AverageHeight = (ZMax - ZMin);
     505              :             }
     506          275 :             if (AverageHeight <= 0.0) {
     507           24 :                 AverageHeight = (ZMax - ZMin);
     508              :             }
     509              : 
     510          275 :             if (thisZone.CeilingHeight > 0.0) {
     511           70 :                 thisZone.ceilingHeightEntered = true;
     512           70 :                 if (AverageHeight > 0.0) {
     513           67 :                     if (std::abs(AverageHeight - thisZone.CeilingHeight) / thisZone.CeilingHeight > 0.05) {
     514            4 :                         if (state.dataSurfaceGeometry->ErrCount == 1 && !state.dataGlobal->DisplayExtraWarnings) {
     515            0 :                             ShowWarningError(
     516              :                                 state,
     517            0 :                                 format("{}Entered Ceiling Height for some zone(s) significantly different from calculated Ceiling Height",
     518              :                                        RoutineName));
     519            0 :                             ShowContinueError(state,
     520              :                                               "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on each max iteration exceeded.");
     521              :                         }
     522            4 :                         if (state.dataGlobal->DisplayExtraWarnings) {
     523            0 :                             ShowWarningError(state,
     524            0 :                                              format("{}Entered Ceiling Height for Zone=\"{}\" significantly different from calculated Ceiling Height",
     525              :                                                     RoutineName,
     526            0 :                                                     thisZone.Name));
     527              :                             static constexpr std::string_view ValFmt("{:.2F}");
     528            0 :                             std::string String1 = format(ValFmt, thisZone.CeilingHeight);
     529            0 :                             std::string String2 = format(ValFmt, AverageHeight);
     530            0 :                             ShowContinueError(
     531              :                                 state,
     532            0 :                                 format("{}Entered Ceiling Height={}, Calculated Ceiling Height={}, entered height will be used in calculations.",
     533              :                                        RoutineName,
     534              :                                        String1,
     535              :                                        String2));
     536            0 :                         }
     537              :                     }
     538              :                 }
     539              :             }
     540          275 :             if ((thisZone.CeilingHeight <= 0.0) && (AverageHeight > 0.0)) {
     541          191 :                 thisZone.CeilingHeight = AverageHeight;
     542              :             }
     543              :             // Need to add check here - don't touch if already user-specified
     544          192 :         }
     545              : 
     546          192 :         CalculateZoneVolume(state); // Calculate Zone Volumes
     547              : 
     548              :         // Calculate zone centroid (and min/max x,y,z for zone)
     549              :         // Use AllSurfaceFirst which includes air boundaries
     550          467 :         for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
     551          275 :             auto &thisZone = state.dataHeatBal->Zone(ZoneNum);
     552          275 :             bool nonInternalMassSurfacesPresent = false;
     553          275 :             bool internalMassSurfacesPresent = false;
     554          275 :             Real64 TotSurfArea = 0.0;
     555          275 :             thisZone.Centroid = Vector(0.0, 0.0, 0.0);
     556          275 :             if ((thisZone.AllSurfaceFirst > 0) && (state.dataSurface->Surface(thisZone.AllSurfaceFirst).Sides > 0)) {
     557          272 :                 thisZone.MinimumX = state.dataSurface->Surface(thisZone.AllSurfaceFirst).Vertex(1).x;
     558          272 :                 thisZone.MaximumX = state.dataSurface->Surface(thisZone.AllSurfaceFirst).Vertex(1).x;
     559          272 :                 thisZone.MinimumY = state.dataSurface->Surface(thisZone.AllSurfaceFirst).Vertex(1).y;
     560          272 :                 thisZone.MaximumY = state.dataSurface->Surface(thisZone.AllSurfaceFirst).Vertex(1).y;
     561          272 :                 thisZone.MinimumZ = state.dataSurface->Surface(thisZone.AllSurfaceFirst).Vertex(1).z;
     562          272 :                 thisZone.MaximumZ = state.dataSurface->Surface(thisZone.AllSurfaceFirst).Vertex(1).z;
     563              :             }
     564          571 :             for (int spaceNum : thisZone.spaceIndexes) {
     565          296 :                 auto const &thisSpace = state.dataHeatBal->space(spaceNum);
     566              : 
     567         1911 :                 for (int SurfNum = thisSpace.AllSurfaceFirst; SurfNum <= thisSpace.AllSurfaceLast; ++SurfNum) {
     568         1615 :                     auto &thisSurface = state.dataSurface->Surface(SurfNum);
     569         1615 :                     if (thisSurface.Class == SurfaceClass::IntMass) {
     570            6 :                         internalMassSurfacesPresent = true;
     571            6 :                         continue;
     572              :                     }
     573         1609 :                     if (!thisSurface.IsAirBoundarySurf) {
     574         1567 :                         nonInternalMassSurfacesPresent = true;
     575              :                     }
     576         1609 :                     if (thisSurface.Class == SurfaceClass::Wall || (thisSurface.Class == SurfaceClass::Roof) ||
     577          466 :                         (thisSurface.Class == SurfaceClass::Floor)) {
     578              : 
     579         1470 :                         thisZone.Centroid.x += thisSurface.Centroid.x * thisSurface.GrossArea;
     580         1470 :                         thisZone.Centroid.y += thisSurface.Centroid.y * thisSurface.GrossArea;
     581         1470 :                         thisZone.Centroid.z += thisSurface.Centroid.z * thisSurface.GrossArea;
     582         1470 :                         TotSurfArea += thisSurface.GrossArea;
     583              :                     }
     584         1609 :                     thisZone.MinimumX = min(thisZone.MinimumX, minval(thisSurface.Vertex, &Vector::x));
     585         1609 :                     thisZone.MaximumX = max(thisZone.MaximumX, maxval(thisSurface.Vertex, &Vector::x));
     586         1609 :                     thisZone.MinimumY = min(thisZone.MinimumY, minval(thisSurface.Vertex, &Vector::y));
     587         1609 :                     thisZone.MaximumY = max(thisZone.MaximumY, maxval(thisSurface.Vertex, &Vector::y));
     588         1609 :                     thisZone.MinimumZ = min(thisZone.MinimumZ, minval(thisSurface.Vertex, &Vector::z));
     589         1609 :                     thisZone.MaximumZ = max(thisZone.MaximumZ, maxval(thisSurface.Vertex, &Vector::z));
     590              :                 }
     591          275 :             }
     592          275 :             if (TotSurfArea > 0.0) {
     593          272 :                 thisZone.Centroid.x /= TotSurfArea;
     594          272 :                 thisZone.Centroid.y /= TotSurfArea;
     595          272 :                 thisZone.Centroid.z /= TotSurfArea;
     596              :             }
     597          275 :             if (internalMassSurfacesPresent && !nonInternalMassSurfacesPresent) {
     598            0 :                 ShowSevereError(
     599            0 :                     state, format("{}Zone=\"{}\" has only internal mass surfaces.  Need at least one other surface.", RoutineName, thisZone.Name));
     600            0 :                 ErrorsFound = true;
     601              :             }
     602              :         }
     603              : 
     604          192 :         state.dataSurface->SurfAdjacentZone.dimension(state.dataSurface->TotSurfaces, 0);
     605              :         // note -- adiabatic surfaces will show same zone as surface
     606         1881 :         for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
     607         1689 :             if (state.dataSurface->Surface(SurfNum).ExtBoundCond <= 0) {
     608         1264 :                 continue;
     609              :             }
     610          425 :             state.dataSurface->SurfAdjacentZone(SurfNum) = state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).ExtBoundCond).Zone;
     611              :         }
     612              : 
     613          467 :         for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
     614         4181 :             for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
     615         3906 :                 auto const &thisSurface = state.dataSurface->Surface(SurfNum);
     616         3906 :                 if (!thisSurface.HeatTransSurf && thisSurface.ZoneName == state.dataHeatBal->Zone(ZoneNum).Name) {
     617           90 :                     ++state.dataHeatBal->Zone(ZoneNum).NumShadingSurfaces;
     618              :                 }
     619              : 
     620         3906 :                 if (thisSurface.Zone != ZoneNum) {
     621         2291 :                     continue;
     622              :                 }
     623              : 
     624         1615 :                 if (thisSurface.HeatTransSurf && (thisSurface.Class == SurfaceClass::Wall || thisSurface.Class == SurfaceClass::Roof ||
     625          467 :                                                   thisSurface.Class == SurfaceClass::Floor)) {
     626         1432 :                     ++state.dataHeatBal->Zone(ZoneNum).NumSurfaces;
     627              :                 }
     628              : 
     629         1615 :                 if (thisSurface.HeatTransSurf && (thisSurface.Class == SurfaceClass::Window || thisSurface.Class == SurfaceClass::GlassDoor ||
     630         1455 :                                                   thisSurface.Class == SurfaceClass::Door || thisSurface.Class == SurfaceClass::TDD_Dome ||
     631         1438 :                                                   thisSurface.Class == SurfaceClass::TDD_Diffuser)) {
     632          135 :                     ++state.dataHeatBal->Zone(ZoneNum).NumSubSurfaces;
     633              :                 }
     634              : 
     635              :             } // surfaces
     636              :         } // zones
     637              : 
     638         1881 :         for (int const SurfNum : state.dataSurface->AllSurfaceListReportOrder) {
     639         1689 :             auto const &thisSurface = state.dataSurface->Surface(SurfNum);
     640         1689 :             Real64 NominalUwithConvCoeffs = 0.0;
     641         1689 :             if (thisSurface.Construction > 0 && thisSurface.Construction <= state.dataHeatBal->TotConstructs) {
     642         1615 :                 bool isWithConvCoefValid = false;
     643         1615 :                 NominalUwithConvCoeffs = DataHeatBalance::ComputeNominalUwithConvCoeffs(state, SurfNum, isWithConvCoefValid);
     644              :             }
     645              : 
     646              :             // populate the predefined report related to u-values with films
     647              :             // only exterior surfaces including underground
     648         1689 :             DataSurfaces::SurfaceClass const SurfaceClass(thisSurface.Class);
     649         1689 :             if ((thisSurface.ExtBoundCond == DataSurfaces::ExternalEnvironment) || (thisSurface.ExtBoundCond == DataSurfaces::Ground) ||
     650          426 :                 (thisSurface.ExtBoundCond == DataSurfaces::KivaFoundation) || (thisSurface.ExtBoundCond == DataSurfaces::GroundFCfactorMethod)) {
     651         1263 :                 if ((SurfaceClass == SurfaceClass::Wall) || (SurfaceClass == SurfaceClass::Floor) || (SurfaceClass == SurfaceClass::Roof)) {
     652         2132 :                     OutputReportPredefined::PreDefTableEntry(
     653         3198 :                         state, state.dataOutRptPredefined->pdchOpUfactFilm, thisSurface.Name, NominalUwithConvCoeffs, 3);
     654          197 :                 } else if (SurfaceClass == SurfaceClass::Door) {
     655            8 :                     OutputReportPredefined::PreDefTableEntry(
     656           12 :                         state, state.dataOutRptPredefined->pdchDrUfactFilm, thisSurface.Name, NominalUwithConvCoeffs, 3);
     657              :                 }
     658              :             } else {
     659          426 :                 if ((SurfaceClass == SurfaceClass::Wall) || (SurfaceClass == SurfaceClass::Floor) || (SurfaceClass == SurfaceClass::Roof)) {
     660          808 :                     OutputReportPredefined::PreDefTableEntry(
     661         1212 :                         state, state.dataOutRptPredefined->pdchIntOpUfactFilm, thisSurface.Name, NominalUwithConvCoeffs, 3);
     662           22 :                 } else if (SurfaceClass == SurfaceClass::Door) {
     663           16 :                     OutputReportPredefined::PreDefTableEntry(
     664           24 :                         state, state.dataOutRptPredefined->pdchIntDrUfactFilm, thisSurface.Name, NominalUwithConvCoeffs, 3);
     665              :                 }
     666              :             }
     667          192 :         } // surfaces
     668              : 
     669              :         // Write number of shadings to initialization output file
     670          192 :         print(state.files.eio,
     671              :               "! <Shading Summary>, Number of Fixed Detached Shades, Number of Building Detached Shades, Number of Attached Shades\n");
     672              : 
     673          192 :         print(state.files.eio,
     674              :               " Shading Summary,{},{},{}\n",
     675          192 :               state.dataSurface->FixedShadingCount,
     676          192 :               state.dataSurface->BuildingShadingCount,
     677          192 :               state.dataSurface->AttachedShadingCount);
     678              : 
     679              :         // Write number of zones header to initialization output file
     680          192 :         print(state.files.eio, "! <Zone Summary>, Number of Zones, Number of Zone Surfaces, Number of SubSurfaces\n");
     681              : 
     682          192 :         print(state.files.eio,
     683              :               " Zone Summary,{},{},{}\n",
     684          192 :               state.dataGlobal->NumOfZones,
     685          192 :               state.dataSurface->TotSurfaces - state.dataSurface->FixedShadingCount - state.dataSurface->BuildingShadingCount -
     686          192 :                   state.dataSurface->AttachedShadingCount,
     687          192 :               sum(state.dataHeatBal->Zone, &DataHeatBalance::ZoneData::NumSubSurfaces));
     688              : 
     689              :         // Write Zone Information header to the initialization output file
     690              :         static constexpr std::string_view Format_721(
     691              :             "! <Zone Information>,Zone Name,North Axis {deg},Origin X-Coordinate {m},Origin Y-Coordinate {m},Origin Z-Coordinate "
     692              :             "{m},Centroid X-Coordinate {m},Centroid Y-Coordinate {m},Centroid Z-Coordinate {m},Type,Zone Multiplier,Zone List "
     693              :             "Multiplier,Minimum X {m},Maximum X {m},Minimum Y {m},Maximum Y {m},Minimum Z {m},Maximum Z {m},Ceiling Height {m},Volume "
     694              :             "{m3},Zone Inside Convection Algorithm {Simple-Detailed-CeilingDiffuser-TrombeWall},Zone Outside Convection Algorithm "
     695              :             "{Simple-Detailed-Tarp-MoWitt-DOE-2-BLAST}, Floor Area {m2},Exterior Gross Wall Area {m2},Exterior Net Wall Area {m2},Exterior "
     696              :             "Window "
     697              :             "Area {m2}, Number of Surfaces, Number of SubSurfaces, Number of Shading SubSurfaces,  Part of Total Building Area");
     698          192 :         print(state.files.eio, "{}\n", Format_721);
     699              : 
     700          467 :         for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
     701              :             // Write Zone Information to the initialization output file
     702          275 :             std::string String1;
     703          275 :             std::string String2;
     704          275 :             std::string String3;
     705              : 
     706          275 :             switch (state.dataHeatBal->Zone(ZoneNum).IntConvAlgo) {
     707           78 :             case Convect::HcInt::ASHRAESimple: {
     708           78 :                 String1 = "Simple";
     709           78 :             } break;
     710          190 :             case Convect::HcInt::ASHRAETARP: {
     711          190 :                 String1 = "TARP";
     712          190 :             } break;
     713            0 :             case Convect::HcInt::CeilingDiffuser: {
     714            0 :                 String1 = "CeilingDiffuser";
     715            0 :             } break;
     716            0 :             case Convect::HcInt::TrombeWall: {
     717            0 :                 String1 = "TrombeWall";
     718            0 :             } break;
     719            7 :             case Convect::HcInt::AdaptiveConvectionAlgorithm: {
     720            7 :                 String1 = "AdaptiveConvectionAlgorithm";
     721            7 :             } break;
     722            0 :             case Convect::HcInt::ASTMC1340: {
     723            0 :                 String1 = "ASTMC1340";
     724            0 :             } break;
     725            0 :             default:
     726            0 :                 break;
     727              :             }
     728              : 
     729          275 :             switch (state.dataHeatBal->Zone(ZoneNum).ExtConvAlgo) {
     730           78 :             case Convect::HcExt::ASHRAESimple: {
     731           78 :                 String2 = "Simple";
     732           78 :             } break;
     733           10 :             case Convect::HcExt::ASHRAETARP: {
     734           10 :                 String2 = "TARP";
     735           10 :             } break;
     736            0 :             case Convect::HcExt::TarpHcOutside: {
     737            0 :                 String2 = "TARP";
     738            0 :             } break;
     739            0 :             case Convect::HcExt::MoWiTTHcOutside: {
     740            0 :                 String2 = "MoWitt";
     741            0 :             } break;
     742          187 :             case Convect::HcExt::DOE2HcOutside: {
     743          187 :                 String2 = "DOE-2";
     744          187 :             } break;
     745            0 :             case Convect::HcExt::AdaptiveConvectionAlgorithm: {
     746            0 :                 String2 = "AdaptiveConvectionAlgorithm";
     747            0 :             } break;
     748            0 :             default:
     749            0 :                 break;
     750              :             }
     751              : 
     752          275 :             String3 = (state.dataHeatBal->Zone(ZoneNum).isPartOfTotalArea) ? "Yes" : "No";
     753              : 
     754              :             static constexpr std::string_view Format_720(
     755              :                 " Zone Information, "
     756              :                 "{},{:.1R},{:.2R},{:.2R},{:.2R},{:.2R},{:.2R},{:.2R},{},{},{},{:.2R},{:.2R},{:.2R},{:.2R},{:.2R},{:.2R},"
     757              :                 "{:.2R},{:.2R},{},{},{:.2R},{:.2R},{:.2R},{:.2R},{},{},{},{}\n");
     758              : 
     759          275 :             print(state.files.eio,
     760              :                   Format_720,
     761          275 :                   state.dataHeatBal->Zone(ZoneNum).Name,
     762          275 :                   state.dataHeatBal->Zone(ZoneNum).RelNorth,
     763          275 :                   state.dataHeatBal->Zone(ZoneNum).OriginX,
     764          275 :                   state.dataHeatBal->Zone(ZoneNum).OriginY,
     765          275 :                   state.dataHeatBal->Zone(ZoneNum).OriginZ,
     766          275 :                   state.dataHeatBal->Zone(ZoneNum).Centroid.x,
     767          275 :                   state.dataHeatBal->Zone(ZoneNum).Centroid.y,
     768          275 :                   state.dataHeatBal->Zone(ZoneNum).Centroid.z,
     769          275 :                   state.dataHeatBal->Zone(ZoneNum).OfType,
     770          275 :                   state.dataHeatBal->Zone(ZoneNum).Multiplier,
     771          275 :                   state.dataHeatBal->Zone(ZoneNum).ListMultiplier,
     772          275 :                   state.dataHeatBal->Zone(ZoneNum).MinimumX,
     773          275 :                   state.dataHeatBal->Zone(ZoneNum).MaximumX,
     774          275 :                   state.dataHeatBal->Zone(ZoneNum).MinimumY,
     775          275 :                   state.dataHeatBal->Zone(ZoneNum).MaximumY,
     776          275 :                   state.dataHeatBal->Zone(ZoneNum).MinimumZ,
     777          275 :                   state.dataHeatBal->Zone(ZoneNum).MaximumZ,
     778          275 :                   state.dataHeatBal->Zone(ZoneNum).CeilingHeight,
     779          275 :                   state.dataHeatBal->Zone(ZoneNum).Volume,
     780              :                   String1,
     781              :                   String2,
     782          275 :                   state.dataHeatBal->Zone(ZoneNum).FloorArea,
     783          275 :                   state.dataHeatBal->Zone(ZoneNum).ExtGrossWallArea,
     784          275 :                   state.dataHeatBal->Zone(ZoneNum).ExtNetWallArea,
     785          275 :                   state.dataHeatBal->Zone(ZoneNum).ExtWindowArea,
     786          275 :                   state.dataHeatBal->Zone(ZoneNum).NumSurfaces,
     787          275 :                   state.dataHeatBal->Zone(ZoneNum).NumSubSurfaces,
     788          275 :                   state.dataHeatBal->Zone(ZoneNum).NumShadingSurfaces,
     789              :                   String3);
     790              : 
     791          275 :         } // ZoneNum
     792              : 
     793              :         // Set up solar distribution enclosures allowing for any air boundaries
     794          192 :         SetupEnclosuresAndAirBoundaries(state, state.dataViewFactor->EnclSolInfo, SurfaceGeometry::enclosureType::SolarEnclosures, ErrorsFound);
     795              : 
     796              :         // Do the Stratosphere check
     797          192 :         DataHeatBalance::SetZoneOutBulbTempAt(state);
     798          192 :         DataHeatBalance::CheckZoneOutBulbTempAt(state);
     799              :     }
     800              : 
     801          228 :     void AllocateSurfaceArrays(EnergyPlusData &state)
     802              :     {
     803              : 
     804              :         // SUBROUTINE INFORMATION:
     805              :         //       AUTHOR         Rick Strand
     806              :         //       DATE WRITTEN   February 1998
     807              : 
     808              :         // PURPOSE OF THIS SUBROUTINE:
     809              :         // This subroutine allocates all of the arrays at the module level which require allocation.
     810              : 
     811              :         // METHODOLOGY EMPLOYED:
     812              :         // Allocation is dependent on the user input file.
     813              : 
     814          228 :         state.dataSurface->ShadeV.allocate(state.dataSurface->TotSurfaces);
     815         2504 :         for (auto &e : state.dataSurface->ShadeV) {
     816         2276 :             e.NVert = 0;
     817          228 :         }
     818              :         // Individual components (XV,YV,ZV) allocated in routine ProcessSurfaceVertices
     819          228 :         state.dataSurface->X0.dimension(state.dataSurface->TotSurfaces, 0.0);
     820          228 :         state.dataSurface->Y0.dimension(state.dataSurface->TotSurfaces, 0.0);
     821          228 :         state.dataSurface->Z0.dimension(state.dataSurface->TotSurfaces, 0.0);
     822              : 
     823              :         // Surface EMS arrays
     824          228 :         state.dataSurface->SurfEMSConstructionOverrideON.allocate(state.dataSurface->TotSurfaces);
     825          228 :         state.dataSurface->SurfEMSConstructionOverrideValue.allocate(state.dataSurface->TotSurfaces);
     826          228 :         state.dataSurface->SurfEMSOverrideIntConvCoef.allocate(state.dataSurface->TotSurfaces);
     827          228 :         state.dataSurface->SurfEMSValueForIntConvCoef.allocate(state.dataSurface->TotSurfaces);
     828          228 :         state.dataSurface->SurfEMSOverrideExtConvCoef.allocate(state.dataSurface->TotSurfaces);
     829          228 :         state.dataSurface->SurfEMSValueForExtConvCoef.allocate(state.dataSurface->TotSurfaces);
     830          228 :         state.dataSurface->SurfOutDryBulbTempEMSOverrideOn.allocate(state.dataSurface->TotSurfaces);
     831          228 :         state.dataSurface->SurfOutDryBulbTempEMSOverrideValue.allocate(state.dataSurface->TotSurfaces);
     832          228 :         state.dataSurface->SurfOutWetBulbTempEMSOverrideOn.allocate(state.dataSurface->TotSurfaces);
     833          228 :         state.dataSurface->SurfOutWetBulbTempEMSOverrideValue.allocate(state.dataSurface->TotSurfaces);
     834          228 :         state.dataSurface->SurfWindSpeedEMSOverrideOn.allocate(state.dataSurface->TotSurfaces);
     835          228 :         state.dataSurface->SurfWindSpeedEMSOverrideValue.allocate(state.dataSurface->TotSurfaces);
     836          228 :         state.dataSurface->SurfViewFactorGroundEMSOverrideOn.allocate(state.dataSurface->TotSurfaces);
     837          228 :         state.dataSurface->SurfViewFactorGroundEMSOverrideValue.allocate(state.dataSurface->TotSurfaces);
     838          228 :         state.dataSurface->SurfWindDirEMSOverrideOn.allocate(state.dataSurface->TotSurfaces);
     839          228 :         state.dataSurface->SurfWindDirEMSOverrideValue.allocate(state.dataSurface->TotSurfaces);
     840         2504 :         for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
     841         2276 :             state.dataSurface->SurfEMSConstructionOverrideON(SurfNum) = false;
     842         2276 :             state.dataSurface->SurfEMSConstructionOverrideValue(SurfNum) = 0.0;
     843         2276 :             state.dataSurface->SurfEMSOverrideIntConvCoef(SurfNum) = false;
     844         2276 :             state.dataSurface->SurfEMSValueForIntConvCoef(SurfNum) = 0.0;
     845         2276 :             state.dataSurface->SurfEMSOverrideExtConvCoef(SurfNum) = false;
     846         2276 :             state.dataSurface->SurfEMSValueForExtConvCoef(SurfNum) = 0.0;
     847         2276 :             state.dataSurface->SurfOutDryBulbTempEMSOverrideOn(SurfNum) = false;
     848         2276 :             state.dataSurface->SurfOutDryBulbTempEMSOverrideValue(SurfNum) = 0.0;
     849         2276 :             state.dataSurface->SurfOutWetBulbTempEMSOverrideOn(SurfNum) = false;
     850         2276 :             state.dataSurface->SurfOutWetBulbTempEMSOverrideValue(SurfNum) = 0.0;
     851         2276 :             state.dataSurface->SurfWindSpeedEMSOverrideOn(SurfNum) = false;
     852         2276 :             state.dataSurface->SurfWindSpeedEMSOverrideValue(SurfNum) = 0.0;
     853         2276 :             state.dataSurface->SurfViewFactorGroundEMSOverrideOn(SurfNum) = false;
     854         2276 :             state.dataSurface->SurfViewFactorGroundEMSOverrideValue(SurfNum) = 0.0;
     855         2276 :             state.dataSurface->SurfWindDirEMSOverrideOn(SurfNum) = false;
     856         2276 :             state.dataSurface->SurfWindDirEMSOverrideValue(SurfNum) = 0.0;
     857              :         }
     858              :         // Following are surface hb arrays
     859          228 :         state.dataSurface->SurfOutDryBulbTemp.allocate(state.dataSurface->TotSurfaces);
     860          228 :         state.dataSurface->SurfOutWetBulbTemp.allocate(state.dataSurface->TotSurfaces);
     861          228 :         state.dataSurface->SurfOutWindSpeed.allocate(state.dataSurface->TotSurfaces);
     862          228 :         state.dataSurface->SurfOutWindDir.allocate(state.dataSurface->TotSurfaces);
     863          228 :         state.dataSurface->SurfGenericContam.allocate(state.dataSurface->TotSurfaces);
     864          228 :         state.dataSurface->SurfPenumbraID.allocate(state.dataSurface->TotSurfaces);
     865          228 :         state.dataSurface->SurfAirSkyRadSplit.allocate(state.dataSurface->TotSurfaces);
     866         2504 :         for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
     867         2276 :             state.dataSurface->SurfOutDryBulbTemp(SurfNum) = 0.0;
     868         2276 :             state.dataSurface->SurfOutWetBulbTemp(SurfNum) = 0.0;
     869         2276 :             state.dataSurface->SurfOutWindSpeed(SurfNum) = 0.0;
     870         2276 :             state.dataSurface->SurfOutWindDir(SurfNum) = 0.0;
     871         2276 :             state.dataSurface->SurfGenericContam(SurfNum) = 0.0;
     872         2276 :             state.dataSurface->SurfPenumbraID(SurfNum) = -1;
     873         2276 :             state.dataSurface->SurfAirSkyRadSplit(SurfNum) = 0.0;
     874              :         }
     875              :         // Following are surface property arrays used in SurfaceGeometry
     876          228 :         state.dataSurface->SurfShadowRecSurfNum.allocate(state.dataSurface->TotSurfaces);
     877          228 :         state.dataSurface->SurfShadowDisabledZoneList.allocate(state.dataSurface->TotSurfaces);
     878          228 :         state.dataSurface->SurfShadowDiffuseSolRefl.allocate(state.dataSurface->TotSurfaces);
     879          228 :         state.dataSurface->SurfShadowDiffuseVisRefl.allocate(state.dataSurface->TotSurfaces);
     880          228 :         state.dataSurface->SurfShadowGlazingFrac.allocate(state.dataSurface->TotSurfaces);
     881          228 :         state.dataSurface->SurfShadowGlazingConstruct.allocate(state.dataSurface->TotSurfaces);
     882         2504 :         for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
     883         2276 :             state.dataSurface->SurfShadowRecSurfNum(SurfNum) = 0;
     884         2276 :             state.dataSurface->SurfShadowDiffuseSolRefl(SurfNum) = 0.0;
     885         2276 :             state.dataSurface->SurfShadowDiffuseVisRefl(SurfNum) = 0.0;
     886         2276 :             state.dataSurface->SurfShadowGlazingFrac(SurfNum) = 0.0;
     887         2276 :             state.dataSurface->SurfShadowGlazingConstruct(SurfNum) = 0;
     888              :         }
     889          228 :         state.dataSurface->SurfExtEcoRoof.allocate(state.dataSurface->TotSurfaces);
     890          228 :         state.dataSurface->SurfExtCavityPresent.allocate(state.dataSurface->TotSurfaces);
     891          228 :         state.dataSurface->SurfExtCavNum.allocate(state.dataSurface->TotSurfaces);
     892          228 :         state.dataSurface->SurfIsPV.allocate(state.dataSurface->TotSurfaces);
     893          228 :         state.dataSurface->SurfIsICS.allocate(state.dataSurface->TotSurfaces);
     894          228 :         state.dataSurface->SurfIsPool.allocate(state.dataSurface->TotSurfaces);
     895          228 :         state.dataSurface->SurfICSPtr.allocate(state.dataSurface->TotSurfaces);
     896          228 :         state.dataSurface->SurfIsRadSurfOrVentSlabOrPool.allocate(state.dataSurface->TotSurfaces);
     897          228 :         state.dataSurface->SurfDaylightingShelfInd.allocate(state.dataSurface->TotSurfaces);
     898         2504 :         for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
     899         2276 :             state.dataSurface->SurfExtEcoRoof(SurfNum) = false;
     900         2276 :             state.dataSurface->SurfExtCavityPresent(SurfNum) = false;
     901         2276 :             state.dataSurface->SurfExtCavNum(SurfNum) = 0;
     902         2276 :             state.dataSurface->SurfIsPV(SurfNum) = false;
     903         2276 :             state.dataSurface->SurfIsICS(SurfNum) = false;
     904         2276 :             state.dataSurface->SurfIsPool(SurfNum) = false;
     905         2276 :             state.dataSurface->SurfICSPtr(SurfNum) = 0;
     906         2276 :             state.dataSurface->SurfIsRadSurfOrVentSlabOrPool(SurfNum) = false;
     907         2276 :             state.dataSurface->SurfDaylightingShelfInd(SurfNum) = 0;
     908              :         }
     909          228 :         state.dataSurface->SurfLowTempErrCount.allocate(state.dataSurface->TotSurfaces);
     910          228 :         state.dataSurface->SurfHighTempErrCount.allocate(state.dataSurface->TotSurfaces);
     911          228 :         state.dataSurface->surfIntConv.allocate(state.dataSurface->TotSurfaces);
     912          228 :         state.dataSurface->SurfTAirRef.allocate(state.dataSurface->TotSurfaces);
     913          228 :         state.dataSurface->SurfTAirRefRpt.allocate(state.dataSurface->TotSurfaces);
     914          228 :         state.dataSurface->surfExtConv.allocate(state.dataSurface->TotSurfaces);
     915         2504 :         for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
     916         2276 :             state.dataSurface->SurfLowTempErrCount(SurfNum) = 0;
     917         2276 :             state.dataSurface->SurfHighTempErrCount(SurfNum) = 0;
     918         2276 :             state.dataSurface->surfIntConv(SurfNum) = DataSurfaces::SurfIntConv();
     919         2276 :             state.dataSurface->surfExtConv(SurfNum) = DataSurfaces::SurfExtConv();
     920         2276 :             state.dataSurface->SurfTAirRef(SurfNum) = DataSurfaces::RefAirTemp::Invalid;
     921         2276 :             state.dataSurface->SurfTAirRefRpt(SurfNum) = static_cast<int>(DataSurfaces::RefAirTemp::Invalid);
     922              :         }
     923              : 
     924          228 :         state.dataSurface->intMovInsuls.allocate(state.dataSurface->TotSurfaces);
     925          228 :         state.dataSurface->extMovInsuls.allocate(state.dataSurface->TotSurfaces);
     926          228 :     }
     927              : 
     928          244 :     void GetSurfaceData(EnergyPlusData &state, bool &ErrorsFound) // If errors found in input
     929              :     {
     930              : 
     931              :         // SUBROUTINE INFORMATION:
     932              :         //       AUTHOR         Richard Liesen
     933              :         //       DATE WRITTEN   November 1997
     934              :         //       MODIFIED       April 1999, Linda Lawrie
     935              :         //                      Dec. 2000, FW (add "one-wall zone" checks)
     936              :         //       RE-ENGINEERED  May 2000, Linda Lawrie (breakout surface type gets)
     937              : 
     938              :         // PURPOSE OF THIS SUBROUTINE:
     939              :         // The purpose of this subroutine is to read in the surface information
     940              :         // from the input data file and interpret and put in the derived type
     941              : 
     942              :         // METHODOLOGY EMPLOYED:
     943              :         // The order of surfaces does not matter and the surfaces are resorted into
     944              :         // the hierarchical order:
     945              :         //  All Shading Surfaces
     946              :         //  Airwalls for space x1
     947              :         //  Base Surfaces for space x1
     948              :         //  Opaque Subsurfaces for space x1
     949              :         //  Window Subsurfaces for space x1
     950              :         //  TDD Dome Surfaces for space x1
     951              :         //  Airwalls for space x2
     952              :         //  Base Surfaces for space x2
     953              :         //  etc
     954              :         //  Pointers are set in the spaces (AllSurfaceFirst/Last, HTSurfaceFirst/Last, OpaqOrIntMassSurfaceFirst/Last, WindowSurfaceFirst/Last,
     955              :         //  OpaqOrWinSurfaceFirst/Last, TDDDomeFirst/Last)
     956              : 
     957              :         // REFERENCES:
     958              :         //   This routine manages getting the input for the following Objects:
     959              :         // SurfaceGeometry
     960              :         // Surface:Shading:Detached
     961              :         // Surface:HeatTransfer
     962              :         // Surface:HeatTransfer:Sub
     963              :         // Surface:Shading:Attached
     964              :         // Surface:InternalMass
     965              : 
     966              :         // Vertex input:
     967              :         //  N3 , \field Number of Surface Vertices -- Number of (X,Y,Z) groups in this surface
     968              :         //       \note currently limited 3 or 4, later?
     969              :         //       \min 3
     970              :         //       \max 4
     971              :         //       \memo vertices are given in SurfaceGeometry coordinates -- if relative, all surface coordinates
     972              :         //       \memo are "relative" to the Zone Origin.  if WCS, then building and zone origins are used
     973              :         //       \memo for some internal calculations, but all coordinates are given in an "absolute" system.
     974              :         //  N4,  \field Vertex 1 X-coordinate
     975              :         //       \units m
     976              :         //       \type real
     977              :         //  N5 , \field Vertex 1 Y-coordinate
     978              :         //       \units m
     979              :         //       \type real
     980              :         //  N6 , \field Vertex 1 Z-coordinate
     981              :         //       \units m
     982              :         //       \type real
     983              :         //  N7,  \field Vertex 2 X-coordinate
     984              :         //       \units m
     985              :         //       \type real
     986              :         //  N8,  \field Vertex 2 Y-coordinate
     987              :         //       \units m
     988              :         //       \type real
     989              :         //  N9,  \field Vertex 2 Z-coordinate
     990              :         //       \units m
     991              :         //       \type real
     992              :         //  N10, \field Vertex 3 X-coordinate
     993              :         //       \units m
     994              :         //       \type real
     995              :         //  N11, \field Vertex 3 Y-coordinate
     996              :         //       \units m
     997              :         //       \type real
     998              :         //  N12, \field Vertex 3 Z-coordinate
     999              :         //       \units m
    1000              :         //       \type real
    1001              :         //  N13, \field Vertex 4 X-coordinate
    1002              :         //       \units m
    1003              :         //       \type real
    1004              :         //  N14, \field Vertex 4 Y-coordinate
    1005              :         //       \type real
    1006              :         //       \units m
    1007              :         //  N15; \field Vertex 4 Z-coordinate
    1008              :         //       \units m
    1009              :         //       \type real
    1010              : 
    1011              :         // The vertices are stored in the surface derived type.
    1012              :         //      +(1)-------------------------(4)+
    1013              :         //      |                               |
    1014              :         //      |                               |
    1015              :         //      |                               |
    1016              :         //      +(2)-------------------------(3)+
    1017              :         //  The above diagram shows the actual coordinate points of a typical wall
    1018              :         //  (you're on the outside looking toward the wall) as stored into
    1019              :         //  Surface%Vertex(1:<number-of-sides>)
    1020              : 
    1021              :         static constexpr std::string_view RoutineName = "GetSurfaceData: ";
    1022              :         using namespace Vectors;
    1023              :         using namespace DataErrorTracking;
    1024              : 
    1025              :         int ConstrNumFound;    // Construction number of matching interzone surface
    1026          244 :         bool NonMatch(false);  // Error for non-matching interzone surfaces
    1027              :         int MovedSurfs;        // Number of Moved Surfaces (when sorting into hierarchical structure)
    1028          244 :         bool SurfError(false); // General Surface Error, causes fatal error at end of routine
    1029              :         int TotLay;            // Total layers in a construction
    1030              :         int TotLayFound;       // Total layers in the construction of a matching interzone surface
    1031              :         // Simple Surfaces (Rectangular)
    1032              :         int LayNumOutside; // Outside material numbers for a shaded construction
    1033              :         // entries with two glazing systems
    1034              :         int NeedToAddSurfaces;    // Surfaces that will be added due to "unentered" other zone surface
    1035              :         int NeedToAddSubSurfaces; // SubSurfaces that will be added due to "unentered" other zone surface
    1036          244 :         int CurNewSurf = 0;
    1037              :         Real64 SurfWorldAz;
    1038              :         Real64 SurfTilt;
    1039              : 
    1040              :         int MultFound;
    1041              :         int MultSurfNum;
    1042              :         bool SubSurfaceSevereDisplayed;
    1043          244 :         bool subSurfaceError(false);
    1044              :         bool errFlag;
    1045              : 
    1046              :         bool izConstDiff;    // differences in construction for IZ surfaces
    1047              :         bool izConstDiffMsg; // display message about hb diffs only once.
    1048              : 
    1049              :         // Get the total number of surfaces to allocate derived type and for surface loops
    1050              : 
    1051          244 :         if (state.dataSurfaceGeometry->GetSurfaceDataOneTimeFlag) {
    1052           18 :             return;
    1053              :         } else {
    1054          226 :             state.dataSurfaceGeometry->GetSurfaceDataOneTimeFlag = true;
    1055              :         }
    1056              : 
    1057          226 :         GetGeometryParameters(state, ErrorsFound);
    1058              : 
    1059          226 :         if (state.dataSurface->WorldCoordSystem) {
    1060           82 :             bool RelWarning = false;
    1061           82 :             if (state.dataHeatBal->BuildingAzimuth != 0.0) {
    1062            0 :                 RelWarning = true;
    1063              :             }
    1064          209 :             for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
    1065          127 :                 if (state.dataHeatBal->Zone(ZoneNum).RelNorth != 0.0) {
    1066            0 :                     RelWarning = true;
    1067              :                 }
    1068              :             }
    1069           82 :             if (RelWarning && !state.dataSurfaceGeometry->WarningDisplayed) {
    1070            0 :                 ShowWarningError(
    1071              :                     state,
    1072            0 :                     format("{}World Coordinate System selected.  Any non-zero Building/Zone North Axes or non-zero Zone Origins are ignored.",
    1073              :                            RoutineName));
    1074            0 :                 ShowContinueError(state,
    1075              :                                   "These may be used in daylighting reference point coordinate calculations but not in normal geometry inputs.");
    1076            0 :                 state.dataSurfaceGeometry->WarningDisplayed = true;
    1077              :             }
    1078           82 :             RelWarning = false;
    1079          209 :             for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
    1080          127 :                 if (state.dataHeatBal->Zone(ZoneNum).OriginX != 0.0) {
    1081            4 :                     RelWarning = true;
    1082              :                 }
    1083          127 :                 if (state.dataHeatBal->Zone(ZoneNum).OriginY != 0.0) {
    1084            4 :                     RelWarning = true;
    1085              :                 }
    1086          127 :                 if (state.dataHeatBal->Zone(ZoneNum).OriginZ != 0.0) {
    1087            0 :                     RelWarning = true;
    1088              :                 }
    1089              :             }
    1090           82 :             if (RelWarning && !state.dataSurfaceGeometry->WarningDisplayed) {
    1091            2 :                 ShowWarningError(
    1092              :                     state,
    1093            2 :                     format("{}World Coordinate System selected.  Any non-zero Building/Zone North Axes or non-zero Zone Origins are ignored.",
    1094              :                            RoutineName));
    1095            2 :                 ShowContinueError(state,
    1096              :                                   "These may be used in daylighting reference point coordinate calculations but not in normal geometry inputs.");
    1097            1 :                 state.dataSurfaceGeometry->WarningDisplayed = true;
    1098              :             }
    1099              :         }
    1100              : 
    1101          226 :         int TotDetachedFixed = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Site:Detailed");
    1102          226 :         int TotDetachedBldg = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Building:Detailed");
    1103          226 :         int TotRectDetachedFixed = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Site");
    1104          226 :         int TotRectDetachedBldg = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Building");
    1105          226 :         int TotHTSurfs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "BuildingSurface:Detailed");
    1106          226 :         int TotDetailedWalls = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Wall:Detailed");
    1107          226 :         int TotDetailedRoofs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "RoofCeiling:Detailed");
    1108          226 :         int TotDetailedFloors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Floor:Detailed");
    1109          226 :         int TotHTSubs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "FenestrationSurface:Detailed");
    1110          226 :         int TotShdSubs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Zone:Detailed");
    1111          226 :         int TotOverhangs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Overhang");
    1112          226 :         int TotOverhangsProjection = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Overhang:Projection");
    1113          226 :         int TotFins = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Fin");
    1114          226 :         int TotFinsProjection = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Fin:Projection");
    1115          226 :         int TotRectWindows = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Window");
    1116          226 :         int TotRectDoors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Door");
    1117          226 :         int TotRectGlazedDoors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "GlazedDoor");
    1118          226 :         int TotRectIZWindows = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Window:Interzone");
    1119          226 :         int TotRectIZDoors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Door:Interzone");
    1120          226 :         int TotRectIZGlazedDoors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "GlazedDoor:Interzone");
    1121          226 :         int TotRectExtWalls = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Wall:Exterior");
    1122          226 :         int TotRectIntWalls = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Wall:Adiabatic");
    1123          226 :         int TotRectIZWalls = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Wall:Interzone");
    1124          226 :         int TotRectUGWalls = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Wall:Underground");
    1125          226 :         int TotRectRoofs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Roof");
    1126          226 :         int TotRectCeilings = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Ceiling:Adiabatic");
    1127          226 :         int TotRectIZCeilings = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Ceiling:Interzone");
    1128          226 :         int TotRectGCFloors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Floor:GroundContact");
    1129          226 :         int TotRectIntFloors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Floor:Adiabatic");
    1130          226 :         int TotRectIZFloors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Floor:Interzone");
    1131              : 
    1132          226 :         state.dataSurface->TotOSC = 0;
    1133              : 
    1134          226 :         int TotIntMassSurfaces = GetNumIntMassSurfaces(state);
    1135              : 
    1136          452 :         state.dataSurface->TotSurfaces = (TotDetachedFixed + TotDetachedBldg + TotRectDetachedFixed + TotRectDetachedBldg) * 2 + TotHTSurfs +
    1137          226 :                                          TotHTSubs + TotShdSubs * 2 + TotIntMassSurfaces + TotOverhangs * 2 + TotOverhangsProjection * 2 +
    1138          226 :                                          TotFins * 4 + TotFinsProjection * 4 + TotDetailedWalls + TotDetailedRoofs + TotDetailedFloors +
    1139          226 :                                          TotRectWindows + TotRectDoors + TotRectGlazedDoors + TotRectIZWindows + TotRectIZDoors +
    1140          226 :                                          TotRectIZGlazedDoors + TotRectExtWalls + TotRectIntWalls + TotRectIZWalls + TotRectUGWalls + TotRectRoofs +
    1141          226 :                                          TotRectCeilings + TotRectIZCeilings + TotRectGCFloors + TotRectIntFloors + TotRectIZFloors;
    1142              : 
    1143          226 :         state.dataSurfaceGeometry->SurfaceTmp.allocate(state.dataSurface->TotSurfaces); // Allocate the Surface derived type appropriately
    1144          226 :         state.dataSurfaceGeometry->UniqueSurfaceNames.reserve(state.dataSurface->TotSurfaces);
    1145              :         // SurfaceTmp structure is allocated via derived type initialization.
    1146              : 
    1147          226 :         int NumSurfs = 0;
    1148          226 :         int AddedSubSurfaces = 0;
    1149          226 :         state.dataErrTracking->AskForSurfacesReport = true;
    1150              : 
    1151          226 :         GetDetShdSurfaceData(state, ErrorsFound, NumSurfs, TotDetachedFixed, TotDetachedBldg);
    1152              : 
    1153          226 :         GetRectDetShdSurfaceData(state, ErrorsFound, NumSurfs, TotRectDetachedFixed, TotRectDetachedBldg);
    1154              : 
    1155          226 :         GetHTSurfaceData(state,
    1156              :                          ErrorsFound,
    1157              :                          NumSurfs,
    1158              :                          TotHTSurfs,
    1159              :                          TotDetailedWalls,
    1160              :                          TotDetailedRoofs,
    1161              :                          TotDetailedFloors,
    1162          226 :                          state.dataSurfaceGeometry->BaseSurfCls,
    1163          226 :                          state.dataSurfaceGeometry->BaseSurfIDs,
    1164              :                          NeedToAddSurfaces);
    1165              : 
    1166          226 :         GetRectSurfaces(state,
    1167              :                         ErrorsFound,
    1168              :                         NumSurfs,
    1169              :                         TotRectExtWalls,
    1170              :                         TotRectIntWalls,
    1171              :                         TotRectIZWalls,
    1172              :                         TotRectUGWalls,
    1173              :                         TotRectRoofs,
    1174              :                         TotRectCeilings,
    1175              :                         TotRectIZCeilings,
    1176              :                         TotRectGCFloors,
    1177              :                         TotRectIntFloors,
    1178              :                         TotRectIZFloors,
    1179          226 :                         state.dataSurfaceGeometry->BaseSurfIDs,
    1180              :                         NeedToAddSurfaces);
    1181              : 
    1182          226 :         GetHTSubSurfaceData(state,
    1183              :                             ErrorsFound,
    1184              :                             NumSurfs,
    1185              :                             TotHTSubs,
    1186          226 :                             state.dataSurfaceGeometry->SubSurfCls,
    1187          226 :                             state.dataSurfaceGeometry->SubSurfIDs,
    1188              :                             AddedSubSurfaces,
    1189              :                             NeedToAddSubSurfaces);
    1190              : 
    1191          226 :         GetRectSubSurfaces(state,
    1192              :                            ErrorsFound,
    1193              :                            NumSurfs,
    1194              :                            TotRectWindows,
    1195              :                            TotRectDoors,
    1196              :                            TotRectGlazedDoors,
    1197              :                            TotRectIZWindows,
    1198              :                            TotRectIZDoors,
    1199              :                            TotRectIZGlazedDoors,
    1200          226 :                            state.dataSurfaceGeometry->SubSurfIDs,
    1201              :                            AddedSubSurfaces,
    1202              :                            NeedToAddSubSurfaces);
    1203              : 
    1204          226 :         GetAttShdSurfaceData(state, ErrorsFound, NumSurfs, TotShdSubs);
    1205              : 
    1206          226 :         GetSimpleShdSurfaceData(state, ErrorsFound, NumSurfs, TotOverhangs, TotOverhangsProjection, TotFins, TotFinsProjection);
    1207              : 
    1208          226 :         GetIntMassSurfaceData(state, ErrorsFound, NumSurfs);
    1209              : 
    1210          226 :         state.dataSurface->TotSurfaces = NumSurfs + AddedSubSurfaces + NeedToAddSurfaces + NeedToAddSubSurfaces;
    1211              : 
    1212          226 :         if (ErrorsFound) {
    1213            4 :             ShowFatalError(state, format("{}Errors discovered, program terminates.", RoutineName));
    1214              :         }
    1215              : 
    1216          224 :         state.dataSurface->Surface.allocate(state.dataSurface->TotSurfaces); // Allocate the Surface derived type appropriately
    1217          224 :         state.dataSurface->SurfaceWindow.allocate(state.dataSurface->TotSurfaces);
    1218          224 :         state.dataSurface->surfShades.allocate(state.dataSurface->TotSurfaces);
    1219          224 :         AllocateSurfaceArrays(state);
    1220          224 :         AllocateSurfaceWindows(state, state.dataSurface->TotSurfaces);
    1221              : 
    1222              :         // Have to make room for added surfaces, if needed
    1223          224 :         int FirstTotalSurfaces = NumSurfs + AddedSubSurfaces;
    1224          224 :         if (NeedToAddSurfaces + NeedToAddSubSurfaces > 0) {
    1225            5 :             state.dataSurfaceGeometry->SurfaceTmp.redimension(state.dataSurface->TotSurfaces);
    1226            5 :             CurNewSurf = FirstTotalSurfaces;
    1227              :         }
    1228              : 
    1229              :         // add the "need to add" surfaces
    1230              :         // Debug    write(outputfiledebug,*) ' need to add ',NeedtoAddSurfaces+NeedToAddSubSurfaces
    1231         2468 :         for (int SurfNum = 1; SurfNum <= FirstTotalSurfaces; ++SurfNum) {
    1232         2244 :             auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    1233         2244 :             if ((surfTemp.ExtBoundCond != unenteredAdjacentZoneSurface) && (surfTemp.ExtBoundCond != unenteredAdjacentSpaceSurface)) {
    1234         2228 :                 continue;
    1235              :             }
    1236              :             // Need to add surface
    1237           16 :             ++CurNewSurf;
    1238              :             // Debug    write(outputfiledebug,*) ' adding surface=',curnewsurf
    1239           16 :             auto &newSurf = state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf);
    1240           16 :             newSurf = surfTemp;
    1241              :             //  Basic parameters are the same for both surfaces.
    1242           16 :             if (surfTemp.ExtBoundCond == unenteredAdjacentZoneSurface) {
    1243           12 :                 int Found = Util::FindItemInList(surfTemp.ExtBoundCondName, state.dataHeatBal->Zone, state.dataGlobal->NumOfZones);
    1244           12 :                 if (Found == 0) {
    1245            0 :                     continue;
    1246              :                 }
    1247           12 :                 newSurf.Zone = Found;
    1248           12 :                 auto &newZone = state.dataHeatBal->Zone(Found);
    1249           12 :                 newSurf.ZoneName = newZone.Name;
    1250           12 :                 assert(newZone.spaceIndexes.size() >= 1);
    1251           12 :                 newSurf.spaceNum = 0; // clear this here and set later
    1252            4 :             } else if (surfTemp.ExtBoundCond == unenteredAdjacentSpaceSurface) {
    1253            4 :                 int Found = Util::FindItemInList(surfTemp.ExtBoundCondName, state.dataHeatBal->space, state.dataGlobal->numSpaces);
    1254            4 :                 if (Found == 0) {
    1255            0 :                     continue;
    1256              :                 }
    1257            4 :                 newSurf.spaceNum = Found;
    1258            4 :                 int zoneNum = state.dataHeatBal->space(Found).zoneNum;
    1259            4 :                 newSurf.Zone = zoneNum;
    1260            4 :                 newSurf.ZoneName = state.dataHeatBal->Zone(zoneNum).Name;
    1261              :             }
    1262              :             // Reverse Construction
    1263           16 :             newSurf.Construction = DataHeatBalance::AssignReverseConstructionNumber(state, surfTemp.Construction, SurfError);
    1264           16 :             newSurf.ConstructionStoredInputValue = newSurf.Construction;
    1265              :             // Reverse Vertices
    1266           16 :             int NVert = surfTemp.Sides;
    1267           80 :             for (int Vert = 1; Vert <= surfTemp.Sides; ++Vert) {
    1268           64 :                 newSurf.Vertex(Vert) = surfTemp.Vertex(NVert);
    1269           64 :                 --NVert;
    1270              :             }
    1271           16 :             if (newSurf.Sides > 2) {
    1272           16 :                 Vectors::CreateNewellAreaVector(newSurf.Vertex, newSurf.Sides, newSurf.NewellAreaVector);
    1273           16 :                 newSurf.GrossArea = Vectors::VecLength(newSurf.NewellAreaVector);
    1274           16 :                 newSurf.Area = newSurf.GrossArea;
    1275           16 :                 newSurf.NetAreaShadowCalc = newSurf.Area;
    1276           16 :                 Vectors::CreateNewellSurfaceNormalVector(newSurf.Vertex, newSurf.Sides, newSurf.NewellSurfaceNormalVector);
    1277           16 :                 Vectors::DetermineAzimuthAndTilt(
    1278           16 :                     newSurf.Vertex, SurfWorldAz, SurfTilt, newSurf.lcsx, newSurf.lcsy, newSurf.lcsz, newSurf.NewellSurfaceNormalVector);
    1279           16 :                 newSurf.Azimuth = SurfWorldAz;
    1280           16 :                 newSurf.Tilt = SurfTilt;
    1281           16 :                 newSurf.convOrientation = Convect::GetSurfConvOrientation(newSurf.Tilt);
    1282              : 
    1283              :                 // Sine and cosine of azimuth and tilt
    1284           16 :                 newSurf.SinAzim = std::sin(SurfWorldAz * Constant::DegToRad);
    1285           16 :                 newSurf.CosAzim = std::cos(SurfWorldAz * Constant::DegToRad);
    1286           16 :                 newSurf.SinTilt = std::sin(SurfTilt * Constant::DegToRad);
    1287           16 :                 newSurf.CosTilt = std::cos(SurfTilt * Constant::DegToRad);
    1288              :                 // Outward normal unit vector (pointing away from room)
    1289           16 :                 newSurf.OutNormVec = newSurf.NewellSurfaceNormalVector;
    1290           64 :                 for (int n = 1; n <= 3; ++n) {
    1291           48 :                     if (std::abs(newSurf.OutNormVec(n) - 1.0) < 1.e-06) {
    1292            3 :                         newSurf.OutNormVec(n) = +1.0;
    1293              :                     }
    1294           48 :                     if (std::abs(newSurf.OutNormVec(n) + 1.0) < 1.e-06) {
    1295           13 :                         newSurf.OutNormVec(n) = -1.0;
    1296              :                     }
    1297           48 :                     if (std::abs(newSurf.OutNormVec(n)) < 1.e-06) {
    1298           32 :                         newSurf.OutNormVec(n) = 0.0;
    1299              :                     }
    1300              :                 }
    1301              : 
    1302              :                 // Can perform tests on this surface here
    1303           16 :                 newSurf.ViewFactorSky = 0.5 * (1.0 + newSurf.CosTilt);
    1304           16 :                 newSurf.ViewFactorGround = 0.5 * (1.0 - newSurf.CosTilt);
    1305              : 
    1306              :                 // The following IR view factors are modified in subr. SkyDifSolarShading if there are shadowing
    1307              :                 // surfaces
    1308           16 :                 newSurf.ViewFactorSkyIR = newSurf.ViewFactorSky;
    1309           16 :                 newSurf.ViewFactorGroundIR = 0.5 * (1.0 - newSurf.CosTilt);
    1310              :             }
    1311              : 
    1312              :             // Change Name
    1313           16 :             newSurf.Name = "iz-" + surfTemp.Name;
    1314              :             // Debug   write(outputfiledebug,*) ' new surf name=',TRIM(SurfaceTmp(CurNewSurf)%Name)
    1315              :             // Debug   write(outputfiledebug,*) ' new surf in zone=',TRIM(surfacetmp(curnewsurf)%zoneName)
    1316           16 :             newSurf.ExtBoundCond = unreconciledZoneSurface;
    1317           16 :             surfTemp.ExtBoundCond = unreconciledZoneSurface;
    1318           16 :             newSurf.ExtBoundCondName = surfTemp.Name;
    1319           16 :             surfTemp.ExtBoundCondName = newSurf.Name;
    1320           16 :             if (newSurf.Class == SurfaceClass::Roof || newSurf.Class == SurfaceClass::Wall || newSurf.Class == SurfaceClass::Floor) {
    1321              :                 // base surface
    1322           10 :                 if (surfTemp.Class == SurfaceClass::Roof) {
    1323            1 :                     newSurf.Class = SurfaceClass::Floor;
    1324              :                     // Debug          write(outputfiledebug,*) ' new surfaces is a floor'
    1325            9 :                 } else if (surfTemp.Class == SurfaceClass::Floor) {
    1326            3 :                     newSurf.Class = SurfaceClass::Roof;
    1327              :                     // Debug          write(outputfiledebug,*) ' new surfaces is a roof'
    1328              :                 }
    1329           10 :                 newSurf.BaseSurf = CurNewSurf;
    1330           10 :                 newSurf.BaseSurfName = newSurf.Name;
    1331              :                 // Debug        write(outputfiledebug,*) ' basesurf, extboundcondname=',TRIM(SurfaceTmp(CurNewSurf)%ExtBoundCondName)
    1332              :             } else {
    1333              :                 // subsurface
    1334              :                 int Found =
    1335            6 :                     Util::FindItemInList("iz-" + surfTemp.BaseSurfName, state.dataSurfaceGeometry->SurfaceTmp, FirstTotalSurfaces + CurNewSurf - 1);
    1336            6 :                 if (Found > 0) {
    1337            6 :                     newSurf.BaseSurfName = "iz-" + surfTemp.BaseSurfName;
    1338            6 :                     newSurf.BaseSurf = Found;
    1339            6 :                     auto &foundBaseSurf = state.dataSurfaceGeometry->SurfaceTmp(Found);
    1340            6 :                     foundBaseSurf.Area -= newSurf.Area;
    1341            6 :                     if (newSurf.Class == SurfaceClass::Window || newSurf.Class == SurfaceClass::GlassDoor) {
    1342            3 :                         foundBaseSurf.NetAreaShadowCalc -= newSurf.Area / newSurf.Multiplier;
    1343              :                     } else { // Door, TDD:Diffuser, TDD:DOME
    1344            3 :                         foundBaseSurf.NetAreaShadowCalc -= newSurf.Area;
    1345              :                     }
    1346            6 :                     newSurf.ExtBoundCond = foundBaseSurf.ExtBoundCond;
    1347            6 :                     newSurf.ExtBoundCondName = surfTemp.Name;
    1348            6 :                     newSurf.ExtSolar = foundBaseSurf.ExtSolar;
    1349            6 :                     newSurf.ExtWind = foundBaseSurf.ExtWind;
    1350            6 :                     newSurf.Zone = foundBaseSurf.Zone;
    1351            6 :                     newSurf.ZoneName = foundBaseSurf.ZoneName;
    1352            6 :                     newSurf.spaceNum = foundBaseSurf.spaceNum;
    1353            6 :                     newSurf.OSCPtr = foundBaseSurf.OSCPtr;
    1354              :                     // Debug        write(outputfiledebug,*) ' subsurf, extboundcondname=',TRIM(SurfaceTmp(CurNewSurf)%ExtBoundCondName)
    1355              :                     // Debug        write(outputfiledebug,*) ' subsurf, basesurf=',TRIM('iz-'//SurfaceTmp(SurfNum)%BaseSurfName)
    1356              :                 } else {
    1357            0 :                     ShowSevereError(state,
    1358            0 :                                     format("{}Adding unentered subsurface, could not find base surface=iz-{}", RoutineName, surfTemp.BaseSurfName));
    1359            0 :                     SurfError = true;
    1360              :                 }
    1361              :             }
    1362              :         }
    1363              :         //**********************************************************************************
    1364              :         // After all of the surfaces have been defined then the base surfaces for the
    1365              :         // sub-surfaces can be defined.  Loop through surfaces and match with the sub-surface
    1366              :         // names.
    1367         2484 :         for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    1368         2260 :             auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    1369         2260 :             if (!surfTemp.HeatTransSurf) {
    1370           84 :                 continue;
    1371              :             }
    1372              : 
    1373         2176 :             int Found = 0;
    1374              :             // why are we doing this again?  this should have already been done.
    1375         2176 :             if (Util::SameString(surfTemp.BaseSurfName, surfTemp.Name)) {
    1376         1949 :                 Found = SurfNum;
    1377              :             } else {
    1378          227 :                 Found = Util::FindItemInList(surfTemp.BaseSurfName, state.dataSurfaceGeometry->SurfaceTmp, state.dataSurface->TotSurfaces);
    1379              :             }
    1380         2176 :             if (Found > 0) {
    1381         2176 :                 surfTemp.BaseSurf = Found;
    1382         2176 :                 if (SurfNum != Found) { // for subsurfaces
    1383          227 :                     if (surfTemp.HeatTransSurf) {
    1384          227 :                         ++state.dataSurfaceGeometry->SurfaceTmp(Found).NumSubSurfaces;
    1385              :                     }
    1386          227 :                     if (surfTemp.Class < SurfaceClass::Window || surfTemp.Class > SurfaceClass::TDD_Diffuser) {
    1387            0 :                         if (surfTemp.Class == SurfaceClass::None) {
    1388            0 :                             ShowSevereError(state, format("{}Invalid SubSurface detected, Surface={}", RoutineName, surfTemp.Name));
    1389              :                         } else {
    1390            0 :                             ShowSevereError(state,
    1391            0 :                                             format("{}Invalid SubSurface detected, Surface={}, class={} invalid class for subsurface",
    1392              :                                                    RoutineName,
    1393            0 :                                                    surfTemp.Name,
    1394            0 :                                                    state.dataSurfaceGeometry->BaseSurfCls(int(surfTemp.Class))));
    1395            0 :                             SurfError = true;
    1396              :                         }
    1397              :                     }
    1398              :                 }
    1399              :             }
    1400              : 
    1401              :         } // ...end of the Surface DO loop for finding BaseSurf
    1402              :         //**********************************************************************************
    1403              :         // The surfaces need to be hierarchical by space.  Input is allowed to be in any order.  In
    1404              :         // this section the surfaces are reordered into:
    1405              :         //    All shadowing surfaces (if mirrored, Mir- surface follows immediately after original)
    1406              :         //      Shading:Site
    1407              :         //      Shading:Building
    1408              :         //      Shading:space (and variants)
    1409              :         //    For each space:
    1410              :         //      Walls
    1411              :         //      Floors
    1412              :         //      Roofs/Ceilings
    1413              :         //      Internal Mass
    1414              :         //      Non-Window subsurfaces (including doors)
    1415              :         //      Window subsurfaces (including TubularDaylightingDiffusers)
    1416              :         //      TubularDaylightingDomes
    1417              :         //    After reordering, MovedSurfs should equal TotSurfaces
    1418              : 
    1419              :         // For reporting purposes, the legacy surface order is also saved in DataSurfaces::AllSurfaceListReportOrder:
    1420              :         //    All shadowing surfaces (if mirrored, Mir- surface follows immediately after original)
    1421              :         //      Shading:Site
    1422              :         //      Shading:Building
    1423              :         //      Shading:Zone (and variants)
    1424              :         //    For each zone:
    1425              :         //      Walls
    1426              :         //        subsurfaces for each wall (windows, doors, in input order, not sorted) follow the base surface
    1427              :         //      Floors
    1428              :         //        subsurfaces for each floor (windows, doors, in input order, not sorted) follow the base surface
    1429              :         //      Roofs/Ceilings
    1430              :         //        subsurfaces for each roof/ceiling (windows, doors, in input order, not sorted) follow the base surface
    1431              :         //      Internal Mass
    1432              :         //    After reordering, MovedSurfs should equal TotSurfaces
    1433              : 
    1434          224 :         MovedSurfs = 0;
    1435          224 :         Array1D<bool> SurfaceTmpClassMoved; // Tmp class is moved
    1436          224 :         SurfaceTmpClassMoved.dimension(state.dataSurface->TotSurfaces, false);
    1437          224 :         state.dataSurface->AllSurfaceListReportOrder.reserve(state.dataSurface->TotSurfaces);
    1438              : 
    1439          224 :         CreateMissingSpaces(state, state.dataSurfaceGeometry->SurfaceTmp);
    1440              : 
    1441              :         // Old SurfNum to New SurfNum
    1442              :         // Old = order in state.dataSurfaceGeometry->SurfaceTmp
    1443              :         // New = order in state.dataSurface->Surface
    1444          224 :         EPVector<int> oldToNewSurfNums;
    1445          224 :         oldToNewSurfNums.resize(state.dataSurface->TotSurfaces, -1);
    1446              : 
    1447              :         // Move all shading Surfaces to Front
    1448         2484 :         for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    1449         2260 :             auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    1450         2260 :             if (surfTemp.Class != SurfaceClass::Detached_F && surfTemp.Class != SurfaceClass::Detached_B && surfTemp.Class != SurfaceClass::Shading) {
    1451         2176 :                 continue;
    1452              :             }
    1453              : 
    1454              :             //  A shading surface
    1455           84 :             ++MovedSurfs;
    1456              :             // Store list of moved surface numbers in reporting order
    1457           84 :             state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    1458           84 :             SurfaceTmpClassMoved(SurfNum) = true; //'Moved'
    1459           84 :             state.dataSurface->AllSurfaceListReportOrder.push_back(SurfNum);
    1460           84 :             oldToNewSurfNums(SurfNum) = MovedSurfs;
    1461              :         }
    1462              : 
    1463              :         //  For each zone
    1464              : 
    1465          578 :         for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
    1466          729 :             for (int spaceNum : state.dataHeatBal->Zone(ZoneNum).spaceIndexes) {
    1467              :                 // Group air boundary surfaces first within each space
    1468         6648 :                 for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    1469         6273 :                     auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    1470         6273 :                     if (SurfaceTmpClassMoved(SurfNum)) {
    1471         2196 :                         continue;
    1472              :                     }
    1473         4077 :                     if (surfTemp.spaceNum != spaceNum) {
    1474         1901 :                         continue;
    1475              :                     }
    1476         2176 :                     int constNum = surfTemp.Construction;
    1477         2176 :                     if (constNum == 0) {
    1478            0 :                         continue;
    1479              :                     }
    1480         2176 :                     if (!state.dataConstruction->Construct(constNum).TypeIsAirBoundary) {
    1481         2134 :                         continue;
    1482              :                     }
    1483              : 
    1484              :                     //  An air boundary surface
    1485           42 :                     surfTemp.IsAirBoundarySurf = true;
    1486           42 :                     ++MovedSurfs;
    1487           42 :                     state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    1488              :                     //  If base Surface Type (Wall, Floor, Roof/Ceiling)
    1489           42 :                     if ((surfTemp.Class == state.dataSurfaceGeometry->BaseSurfIDs(1)) ||
    1490           47 :                         (surfTemp.Class == state.dataSurfaceGeometry->BaseSurfIDs(2)) ||
    1491            5 :                         (surfTemp.Class == state.dataSurfaceGeometry->BaseSurfIDs(3))) {
    1492              :                         // Store list of moved surface numbers in reporting order. We use the old position, we'll reconcile later
    1493              :                         // We don't do it for Air Door/Air Windows yet, we want them listed below each base surf they belong to
    1494           38 :                         state.dataSurface->AllSurfaceListReportOrder.push_back(SurfNum);
    1495              :                     }
    1496           42 :                     oldToNewSurfNums(SurfNum) = MovedSurfs;
    1497           42 :                     SurfaceTmpClassMoved(SurfNum) = true; //'Moved'
    1498              :                 }
    1499              : 
    1500              :                 //  For each Base Surface Type (Wall, Floor, Roof/Ceiling) - put these first
    1501              : 
    1502         1500 :                 for (const DataSurfaces::SurfaceClass Loop : state.dataSurfaceGeometry->BaseSurfIDs) {
    1503              : 
    1504        19944 :                     for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    1505        18819 :                         auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    1506              : 
    1507        18819 :                         if (SurfaceTmpClassMoved(SurfNum)) {
    1508         9398 :                             continue;
    1509              :                         }
    1510         9421 :                         if (surfTemp.Zone == 0) {
    1511            0 :                             continue;
    1512              :                         }
    1513              : 
    1514         9421 :                         if (surfTemp.spaceNum != spaceNum) {
    1515         5703 :                             continue;
    1516              :                         }
    1517         3718 :                         if (surfTemp.Class != Loop) {
    1518         1823 :                             continue;
    1519              :                         }
    1520              : 
    1521         1895 :                         ++MovedSurfs;
    1522         1895 :                         state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    1523         1895 :                         oldToNewSurfNums(SurfNum) = MovedSurfs;
    1524         1895 :                         SurfaceTmpClassMoved(SurfNum) = true; // 'Moved'
    1525              :                         // Store list of moved surface numbers in order reporting order (subsurfaces follow their base surface)
    1526         1895 :                         state.dataSurface->AllSurfaceListReportOrder.push_back(SurfNum);
    1527              : 
    1528              :                         //  Find all subsurfaces to this surface - just to update Report them in order
    1529        41187 :                         for (int SubSurfNum = 1; SubSurfNum <= state.dataSurface->TotSurfaces; ++SubSurfNum) {
    1530              :                             // Gotta avoid pushing myself again!
    1531        39292 :                             if (SubSurfNum == SurfNum) {
    1532         1895 :                                 continue;
    1533              :                             }
    1534              :                             // We don't check if already moved, because we didn't add them to AllSurfaceListReportOrder above!
    1535        37397 :                             if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).Zone == 0) {
    1536         1160 :                                 continue;
    1537              :                             }
    1538        36237 :                             if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).BaseSurf != SurfNum) {
    1539        36010 :                                 continue;
    1540              :                             }
    1541              :                             // Add original sub-surface numbers as placeholders in surface list for reporting
    1542          227 :                             state.dataSurface->AllSurfaceListReportOrder.push_back(SubSurfNum);
    1543              :                         }
    1544              :                     }
    1545              :                 }
    1546              : 
    1547              :                 // Internal mass goes next
    1548         6648 :                 for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    1549         6273 :                     if (SurfaceTmpClassMoved(SurfNum)) {
    1550         4133 :                         continue;
    1551              :                     }
    1552              : 
    1553         2140 :                     auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    1554         2140 :                     if (surfTemp.spaceNum != spaceNum) {
    1555         1901 :                         continue;
    1556              :                     }
    1557          239 :                     if (surfTemp.Class != SurfaceClass::IntMass) {
    1558          223 :                         continue;
    1559              :                     }
    1560           16 :                     ++MovedSurfs;
    1561           16 :                     state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    1562           16 :                     oldToNewSurfNums(SurfNum) = MovedSurfs;
    1563           16 :                     SurfaceTmpClassMoved(SurfNum) = true; // 'Moved'
    1564              :                     // Store list of moved surface numbers in reporting order
    1565           16 :                     state.dataSurface->AllSurfaceListReportOrder.push_back(SurfNum);
    1566              :                 }
    1567              : 
    1568              :                 // Opaque door goes next
    1569         6648 :                 for (int SubSurfNum = 1; SubSurfNum <= state.dataSurface->TotSurfaces; ++SubSurfNum) {
    1570              : 
    1571         6273 :                     if (SurfaceTmpClassMoved(SubSurfNum)) {
    1572         4149 :                         continue;
    1573              :                     }
    1574         2124 :                     if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).spaceNum != spaceNum) {
    1575         1901 :                         continue;
    1576              :                     }
    1577          223 :                     if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).Class != SurfaceClass::Door) {
    1578          202 :                         continue;
    1579              :                     }
    1580              : 
    1581           21 :                     ++MovedSurfs;
    1582           21 :                     state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum);
    1583           21 :                     oldToNewSurfNums(SubSurfNum) = MovedSurfs;
    1584           21 :                     SurfaceTmpClassMoved(SubSurfNum) = true; // 'Moved'
    1585              :                 }
    1586              : 
    1587              :                 // The exterior window subsurfaces (includes SurfaceClass::Window and SurfaceClass::GlassDoor) goes next
    1588         6648 :                 for (int SubSurfNum = 1; SubSurfNum <= state.dataSurface->TotSurfaces; ++SubSurfNum) {
    1589              : 
    1590         6273 :                     if (SurfaceTmpClassMoved(SubSurfNum)) {
    1591         4170 :                         continue;
    1592              :                     }
    1593         2103 :                     if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).spaceNum != spaceNum) {
    1594         1901 :                         continue;
    1595              :                     }
    1596          202 :                     if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).ExtBoundCond > 0) {
    1597            0 :                         continue; // Exterior window
    1598              :                     }
    1599          225 :                     if ((state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).Class != SurfaceClass::Window) &&
    1600           23 :                         (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).Class != SurfaceClass::GlassDoor)) {
    1601           13 :                         continue;
    1602              :                     }
    1603              : 
    1604          189 :                     ++MovedSurfs;
    1605          189 :                     state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum);
    1606          189 :                     oldToNewSurfNums(SubSurfNum) = MovedSurfs;
    1607          189 :                     SurfaceTmpClassMoved(SubSurfNum) = true; // 'Moved'
    1608              :                 }
    1609              : 
    1610              :                 // The interior window subsurfaces (includes SurfaceClass::Window and SurfaceClass::GlassDoor) goes next
    1611         6648 :                 for (int SubSurfNum = 1; SubSurfNum <= state.dataSurface->TotSurfaces; ++SubSurfNum) {
    1612              : 
    1613         6273 :                     if (SurfaceTmpClassMoved(SubSurfNum)) {
    1614         4359 :                         continue;
    1615              :                     }
    1616         1914 :                     if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).spaceNum != spaceNum) {
    1617         1901 :                         continue;
    1618              :                     }
    1619           13 :                     if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).ExtBoundCond <= 0) {
    1620           13 :                         continue;
    1621              :                     }
    1622            0 :                     if ((state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).Class != SurfaceClass::Window) &&
    1623            0 :                         (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).Class != SurfaceClass::GlassDoor)) {
    1624            0 :                         continue;
    1625              :                     }
    1626              : 
    1627            0 :                     ++MovedSurfs;
    1628            0 :                     state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum);
    1629            0 :                     oldToNewSurfNums(SubSurfNum) = MovedSurfs;
    1630            0 :                     SurfaceTmpClassMoved(SubSurfNum) = true; // 'Moved'
    1631              :                 }
    1632              : 
    1633              :                 // The SurfaceClass::TDD_Diffuser (OriginalClass = Window) goes next
    1634         6648 :                 for (int SubSurfNum = 1; SubSurfNum <= state.dataSurface->TotSurfaces; ++SubSurfNum) {
    1635              : 
    1636         6273 :                     if (SurfaceTmpClassMoved(SubSurfNum)) {
    1637         4359 :                         continue;
    1638              :                     }
    1639         1914 :                     if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).spaceNum != spaceNum) {
    1640         1901 :                         continue;
    1641              :                     }
    1642           13 :                     if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).Class != SurfaceClass::TDD_Diffuser) {
    1643            7 :                         continue;
    1644              :                     }
    1645              : 
    1646            6 :                     ++MovedSurfs;
    1647            6 :                     state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum);
    1648            6 :                     oldToNewSurfNums(SubSurfNum) = MovedSurfs;
    1649            6 :                     SurfaceTmpClassMoved(SubSurfNum) = true; // 'Moved'
    1650              :                 }
    1651              : 
    1652              :                 // Last but not least, SurfaceClass::TDD_Dome
    1653         6648 :                 for (int SubSurfNum = 1; SubSurfNum <= state.dataSurface->TotSurfaces; ++SubSurfNum) {
    1654              : 
    1655         6273 :                     if (SurfaceTmpClassMoved(SubSurfNum)) {
    1656         4365 :                         continue;
    1657              :                     }
    1658         1908 :                     if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).spaceNum != spaceNum) {
    1659         1901 :                         continue;
    1660              :                     }
    1661            7 :                     if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).Class != SurfaceClass::TDD_Dome) {
    1662            0 :                         continue;
    1663              :                     }
    1664              : 
    1665            7 :                     ++MovedSurfs;
    1666            7 :                     state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum);
    1667            7 :                     oldToNewSurfNums(SubSurfNum) = MovedSurfs;
    1668            7 :                     SurfaceTmpClassMoved(SubSurfNum) = true; // 'Moved'
    1669              :                 }
    1670          354 :             }
    1671              :         }
    1672              : 
    1673              :         // Validity checking
    1674          224 :         assert(state.dataSurface->TotSurfaces == MovedSurfs);
    1675          224 :         assert(state.dataSurface->TotSurfaces == static_cast<int>(state.dataSurface->AllSurfaceListReportOrder.size()));
    1676          224 :         assert(state.dataSurface->TotSurfaces == static_cast<int>(oldToNewSurfNums.size()));
    1677              : 
    1678              :         // Assert validity of indices
    1679         2484 :         assert(std::find_if(state.dataSurface->AllSurfaceListReportOrder.cbegin(), state.dataSurface->AllSurfaceListReportOrder.cend(), [](int i) {
    1680              :                    return i < 1;
    1681              :                }) == state.dataSurface->AllSurfaceListReportOrder.cend());
    1682              : 
    1683         2484 :         assert(std::find_if(oldToNewSurfNums.cbegin(), oldToNewSurfNums.cend(), [](int i) { return i < 1; }) == oldToNewSurfNums.cend());
    1684              : 
    1685          224 :         if (MovedSurfs != state.dataSurface->TotSurfaces) {
    1686            0 :             ShowSevereError(
    1687              :                 state,
    1688            0 :                 format("{}Reordered # of Surfaces ({}) not = Total # of Surfaces ({})", RoutineName, MovedSurfs, state.dataSurface->TotSurfaces));
    1689            0 :             SurfError = true;
    1690            0 :             for (int Loop = 1; Loop <= state.dataSurface->TotSurfaces; ++Loop) {
    1691            0 :                 if (!SurfaceTmpClassMoved(Loop) && state.dataSurfaceGeometry->SurfaceTmp(Loop).Class == SurfaceClass::Invalid) {
    1692            0 :                     ShowSevereError(state,
    1693            0 :                                     format("{}Error in Surface= \"{} indicated Zone=\"{}\"",
    1694              :                                            RoutineName,
    1695            0 :                                            state.dataSurfaceGeometry->SurfaceTmp(Loop).Name,
    1696            0 :                                            state.dataSurfaceGeometry->SurfaceTmp(Loop).ZoneName));
    1697              :                 }
    1698              :             }
    1699            0 :             ShowWarningError(
    1700            0 :                 state, format("{}Remaining surface checks will use \"reordered number of surfaces\", not number of original surfaces", RoutineName));
    1701              :         }
    1702              : 
    1703              :         // Realign the relationship: surface to base surface
    1704         2484 :         for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    1705         2260 :             auto &movedSurf = state.dataSurface->Surface(SurfNum);
    1706         2260 :             if (movedSurf.BaseSurf > 0) {
    1707         2176 :                 int newBaseSurfNum = oldToNewSurfNums(movedSurf.BaseSurf);
    1708         2176 :                 movedSurf.BaseSurf = newBaseSurfNum;
    1709              : 
    1710         2176 :                 if (newBaseSurfNum < 1) {
    1711            0 :                     ShowFatalError(
    1712              :                         state,
    1713            0 :                         format("{}Couldn't find the new Surface Number for surface index {} named '{}'. Looking for BaseSurf old index of {}",
    1714              :                                RoutineName,
    1715              :                                SurfNum,
    1716            0 :                                movedSurf.Name,
    1717            0 :                                movedSurf.BaseSurf));
    1718              :                 }
    1719              :             }
    1720         2260 :             auto &reportOrderNum = state.dataSurface->AllSurfaceListReportOrder[SurfNum - 1];
    1721         2260 :             if (reportOrderNum > 0) {
    1722         2260 :                 int newReportOrderNum = oldToNewSurfNums(reportOrderNum);
    1723         2260 :                 reportOrderNum = newReportOrderNum;
    1724              :             }
    1725              :         }
    1726              : 
    1727          224 :         state.dataSurfaceGeometry->SurfaceTmp.deallocate(); // DeAllocate the Temp Surface derived type
    1728              : 
    1729          224 :         createSpaceSurfaceLists(state);
    1730              : 
    1731              :         //  For each Base Surface Type (Wall, Floor, Roof)
    1732              : 
    1733          896 :         for (const DataSurfaces::SurfaceClass Loop : state.dataSurfaceGeometry->BaseSurfIDs) {
    1734         7452 :             for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    1735              : 
    1736         6780 :                 if (state.dataSurface->Surface(SurfNum).Zone == 0) {
    1737          252 :                     continue;
    1738              :                 }
    1739              : 
    1740         6528 :                 if (state.dataSurface->Surface(SurfNum).Class != Loop) {
    1741         4595 :                     continue;
    1742              :                 }
    1743              : 
    1744              :                 //  Find all subsurfaces to this surface
    1745        41807 :                 for (int SubSurfNum = 1; SubSurfNum <= state.dataSurface->TotSurfaces; ++SubSurfNum) {
    1746              : 
    1747        39874 :                     if (SurfNum == SubSurfNum) {
    1748         1933 :                         continue;
    1749              :                     }
    1750        37941 :                     if (state.dataSurface->Surface(SubSurfNum).Zone == 0) {
    1751         1160 :                         continue;
    1752              :                     }
    1753        36781 :                     if (state.dataSurface->Surface(SubSurfNum).BaseSurf != SurfNum) {
    1754        36554 :                         continue;
    1755              :                     }
    1756              : 
    1757              :                     // Check facing angle of Sub compared to base
    1758          227 :                     checkSubSurfAzTiltNorm(state, state.dataSurface->Surface(SurfNum), state.dataSurface->Surface(SubSurfNum), subSurfaceError);
    1759          227 :                     if (subSurfaceError) {
    1760            0 :                         SurfError = true;
    1761              :                     }
    1762              :                 }
    1763              :             }
    1764              :         }
    1765              : 
    1766              :         //**********************************************************************************
    1767              :         // Now, match up interzone surfaces
    1768          224 :         NonMatch = false;
    1769          224 :         izConstDiffMsg = false;
    1770         2484 :         for (int SurfNum = 1; SurfNum <= MovedSurfs; ++SurfNum) { // TotSurfaces
    1771              :             //  Clean up Shading Surfaces, make sure they don't go through here.
    1772         2260 :             if (!state.dataSurface->Surface(SurfNum).HeatTransSurf) {
    1773           84 :                 continue;
    1774              :             }
    1775              :             //   If other surface, match it up
    1776              :             //  Both interzone and "internal" surfaces have this pointer set
    1777              :             //  Internal surfaces point to themselves, Interzone to another
    1778         2176 :             if (state.dataSurface->Surface(SurfNum).ExtBoundCond == unreconciledZoneSurface) {
    1779          440 :                 if (not_blank(state.dataSurface->Surface(SurfNum).ExtBoundCondName)) {
    1780          440 :                     int Found = 0;
    1781          440 :                     if (state.dataSurface->Surface(SurfNum).ExtBoundCondName == state.dataSurface->Surface(SurfNum).Name) {
    1782          245 :                         Found = SurfNum;
    1783              :                     } else {
    1784          195 :                         Found = Util::FindItemInList(state.dataSurface->Surface(SurfNum).ExtBoundCondName, state.dataSurface->Surface, MovedSurfs);
    1785              :                     }
    1786          440 :                     if (Found != 0) {
    1787          440 :                         state.dataSurface->Surface(SurfNum).ExtBoundCond = Found;
    1788              :                         // Check that matching surface is also "OtherZoneSurface"
    1789          633 :                         if (state.dataSurface->Surface(Found).ExtBoundCond <= 0 &&
    1790          193 :                             state.dataSurface->Surface(Found).ExtBoundCond != unreconciledZoneSurface) {
    1791            0 :                             ShowSevereError(state, format("{}Potential \"OtherZoneSurface\" is not matched correctly:", RoutineName));
    1792              : 
    1793            0 :                             ShowContinueError(state,
    1794            0 :                                               format("Surface={}, Zone={}",
    1795            0 :                                                      state.dataSurface->Surface(SurfNum).Name,
    1796            0 :                                                      state.dataSurface->Surface(SurfNum).ZoneName));
    1797            0 :                             ShowContinueError(state,
    1798            0 :                                               format("Nonmatched Other/InterZone Surface={}, Zone={}",
    1799            0 :                                                      state.dataSurface->Surface(Found).Name,
    1800            0 :                                                      state.dataSurface->Surface(Found).ZoneName));
    1801            0 :                             SurfError = true;
    1802              :                         }
    1803              :                         // Check that matching interzone surface has construction with reversed layers
    1804          440 :                         if (Found != SurfNum) { // Interzone surface
    1805              :                             // Make sure different zones too (CR 4110)
    1806          195 :                             if (state.dataSurface->Surface(SurfNum).spaceNum == state.dataSurface->Surface(Found).spaceNum) {
    1807            1 :                                 ++state.dataSurfaceGeometry->ErrCount2;
    1808            1 :                                 if (state.dataSurfaceGeometry->ErrCount2 == 1 && !state.dataGlobal->DisplayExtraWarnings) {
    1809            2 :                                     ShowWarningError(state,
    1810            2 :                                                      format("{}CAUTION -- Interspace surfaces are occurring in the same space(s).", RoutineName));
    1811            3 :                                     ShowContinueError(
    1812              :                                         state, "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on individual occurrences.");
    1813              :                                 }
    1814            1 :                                 if (state.dataGlobal->DisplayExtraWarnings) {
    1815            0 :                                     ShowWarningError(state, format("{}CAUTION -- Interspace surfaces are usually in different spaces", RoutineName));
    1816            0 :                                     ShowContinueError(state,
    1817            0 :                                                       format("Surface={}, Space={}, Zone={}",
    1818            0 :                                                              state.dataSurface->Surface(SurfNum).Name,
    1819            0 :                                                              state.dataHeatBal->space(state.dataSurface->Surface(SurfNum).spaceNum).Name,
    1820            0 :                                                              state.dataSurface->Surface(SurfNum).ZoneName));
    1821            0 :                                     ShowContinueError(state,
    1822            0 :                                                       format("Surface={}, Space={}, Zone={}",
    1823            0 :                                                              state.dataSurface->Surface(Found).Name,
    1824            0 :                                                              state.dataHeatBal->space(state.dataSurface->Surface(Found).spaceNum).Name,
    1825            0 :                                                              state.dataSurface->Surface(Found).ZoneName));
    1826              :                                 }
    1827              :                             }
    1828          195 :                             int ConstrNum = state.dataSurface->Surface(SurfNum).Construction;
    1829          195 :                             int ConstrNumFound = state.dataSurface->Surface(Found).Construction;
    1830          195 :                             if (ConstrNum <= 0 || ConstrNumFound <= 0) {
    1831            0 :                                 continue;
    1832              :                             }
    1833          195 :                             if (state.dataConstruction->Construct(ConstrNum).ReverseConstructionNumLayersWarning &&
    1834            0 :                                 state.dataConstruction->Construct(ConstrNumFound).ReverseConstructionNumLayersWarning) {
    1835            0 :                                 continue;
    1836              :                             }
    1837          195 :                             if (state.dataConstruction->Construct(ConstrNum).ReverseConstructionLayersOrderWarning &&
    1838            0 :                                 state.dataConstruction->Construct(ConstrNumFound).ReverseConstructionLayersOrderWarning) {
    1839            0 :                                 continue;
    1840              :                             }
    1841          195 :                             TotLay = state.dataConstruction->Construct(ConstrNum).TotLayers;
    1842          195 :                             TotLayFound = state.dataConstruction->Construct(ConstrNumFound).TotLayers;
    1843          195 :                             if (TotLay != TotLayFound) { // Different number of layers
    1844              :                                 // match on like Uvalues (nominal)
    1845            0 :                                 if (std::abs(state.dataHeatBal->NominalU(ConstrNum) - state.dataHeatBal->NominalU(ConstrNumFound)) > 0.001) {
    1846            0 :                                     ShowSevereError(state,
    1847            0 :                                                     format("{}Construction {} of interzone surface {} does not have the same number of layers as the "
    1848              :                                                            "construction {} of adjacent surface {}",
    1849              :                                                            RoutineName,
    1850            0 :                                                            state.dataConstruction->Construct(ConstrNum).Name,
    1851            0 :                                                            state.dataSurface->Surface(SurfNum).Name,
    1852            0 :                                                            state.dataConstruction->Construct(ConstrNumFound).Name,
    1853            0 :                                                            state.dataSurface->Surface(Found).Name));
    1854            0 :                                     if (!state.dataConstruction->Construct(ConstrNum).ReverseConstructionNumLayersWarning ||
    1855            0 :                                         !state.dataConstruction->Construct(ConstrNumFound).ReverseConstructionNumLayersWarning) {
    1856            0 :                                         ShowContinueError(state, "...this problem for this pair will not be reported again.");
    1857            0 :                                         state.dataConstruction->Construct(ConstrNum).ReverseConstructionNumLayersWarning = true;
    1858            0 :                                         state.dataConstruction->Construct(ConstrNumFound).ReverseConstructionNumLayersWarning = true;
    1859              :                                     }
    1860            0 :                                     SurfError = true;
    1861              :                                 }
    1862              :                             } else { // Same number of layers; check for reverse layers
    1863              :                                 // check layers as number of layers is the same
    1864          195 :                                 izConstDiff = false;
    1865              :                                 // ok if same nominal U
    1866          195 :                                 CheckForReversedLayers(state, izConstDiff, ConstrNum, ConstrNumFound, TotLay);
    1867          195 :                                 if (izConstDiff &&
    1868            0 :                                     std::abs(state.dataHeatBal->NominalU(ConstrNum) - state.dataHeatBal->NominalU(ConstrNumFound)) > 0.001) {
    1869            0 :                                     ShowSevereError(state,
    1870            0 :                                                     format("{}Construction {} of interzone surface {} does not have the same materials in the "
    1871              :                                                            "reverse order as the construction {} of adjacent surface {}",
    1872              :                                                            RoutineName,
    1873            0 :                                                            state.dataConstruction->Construct(ConstrNum).Name,
    1874            0 :                                                            state.dataSurface->Surface(SurfNum).Name,
    1875            0 :                                                            state.dataConstruction->Construct(ConstrNumFound).Name,
    1876            0 :                                                            state.dataSurface->Surface(Found).Name));
    1877            0 :                                     ShowContinueError(state,
    1878              :                                                       "or the properties of the reversed layers are not correct due to differing layer front and "
    1879              :                                                       "back side values");
    1880            0 :                                     if (!state.dataConstruction->Construct(ConstrNum).ReverseConstructionLayersOrderWarning ||
    1881            0 :                                         !state.dataConstruction->Construct(ConstrNumFound).ReverseConstructionLayersOrderWarning) {
    1882            0 :                                         ShowContinueError(state, "...this problem for this pair will not be reported again.");
    1883            0 :                                         state.dataConstruction->Construct(ConstrNum).ReverseConstructionLayersOrderWarning = true;
    1884            0 :                                         state.dataConstruction->Construct(ConstrNumFound).ReverseConstructionLayersOrderWarning = true;
    1885              :                                     }
    1886            0 :                                     SurfError = true;
    1887          195 :                                 } else if (izConstDiff) {
    1888            0 :                                     ShowWarningError(state,
    1889            0 :                                                      format("{}Construction {} of interzone surface {} does not have the same materials in the "
    1890              :                                                             "reverse order as the construction {} of adjacent surface {}",
    1891              :                                                             RoutineName,
    1892            0 :                                                             state.dataConstruction->Construct(ConstrNum).Name,
    1893            0 :                                                             state.dataSurface->Surface(SurfNum).Name,
    1894            0 :                                                             state.dataConstruction->Construct(ConstrNumFound).Name,
    1895            0 :                                                             state.dataSurface->Surface(Found).Name));
    1896            0 :                                     ShowContinueError(state,
    1897              :                                                       "or the properties of the reversed layers are not correct due to differing layer front and "
    1898              :                                                       "back side values");
    1899            0 :                                     ShowContinueError(
    1900              :                                         state,
    1901            0 :                                         format("...but Nominal U values are similar, diff=[{:.4R}] ... simulation proceeds.",
    1902            0 :                                                std::abs(state.dataHeatBal->NominalU(ConstrNum) - state.dataHeatBal->NominalU(ConstrNumFound))));
    1903            0 :                                     if (!izConstDiffMsg) {
    1904            0 :                                         ShowContinueError(state,
    1905              :                                                           "...if the two zones are expected to have significantly different temperatures, the proper "
    1906              :                                                           "\"reverse\" construction should be created.");
    1907            0 :                                         izConstDiffMsg = true;
    1908              :                                     }
    1909            0 :                                     if (!state.dataConstruction->Construct(ConstrNum).ReverseConstructionLayersOrderWarning ||
    1910            0 :                                         !state.dataConstruction->Construct(ConstrNumFound).ReverseConstructionLayersOrderWarning) {
    1911            0 :                                         ShowContinueError(state, "...this problem for this pair will not be reported again.");
    1912            0 :                                         state.dataConstruction->Construct(ConstrNum).ReverseConstructionLayersOrderWarning = true;
    1913            0 :                                         state.dataConstruction->Construct(ConstrNumFound).ReverseConstructionLayersOrderWarning = true;
    1914              :                                     }
    1915              :                                 }
    1916              :                             }
    1917              : 
    1918              :                             // If significantly different areas -- this would not be good
    1919          195 :                             MultFound = state.dataHeatBal->Zone(state.dataSurface->Surface(Found).Zone).Multiplier *
    1920          195 :                                         state.dataHeatBal->Zone(state.dataSurface->Surface(Found).Zone).ListMultiplier;
    1921          195 :                             MultSurfNum = state.dataHeatBal->Zone(state.dataSurface->Surface(SurfNum).Zone).Multiplier *
    1922          195 :                                           state.dataHeatBal->Zone(state.dataSurface->Surface(SurfNum).Zone).ListMultiplier;
    1923          195 :                             if (state.dataSurface->Surface(Found).Area > 0.0) {
    1924          195 :                                 if (std::abs((state.dataSurface->Surface(Found).Area * MultFound -
    1925          195 :                                               state.dataSurface->Surface(SurfNum).Area * MultSurfNum) /
    1926          195 :                                              state.dataSurface->Surface(Found).Area * MultFound) > 0.02) { // 2% difference in areas
    1927            0 :                                     ++state.dataSurfaceGeometry->ErrCount4;
    1928            0 :                                     if (state.dataSurfaceGeometry->ErrCount4 == 1 && !state.dataGlobal->DisplayExtraWarnings) {
    1929            0 :                                         ShowWarningError(
    1930              :                                             state,
    1931            0 :                                             format("{}InterZone Surface Areas do not match as expected and might not satisfy conservation of energy:",
    1932              :                                                    RoutineName));
    1933            0 :                                         ShowContinueError(
    1934              :                                             state, "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on individual mismatches.");
    1935              :                                     }
    1936            0 :                                     if (state.dataGlobal->DisplayExtraWarnings) {
    1937            0 :                                         ShowWarningError(
    1938              :                                             state,
    1939            0 :                                             format("{}InterZone Surface Areas do not match as expected and might not satisfy conservation of energy:",
    1940              :                                                    RoutineName));
    1941              : 
    1942            0 :                                         if (MultFound == 1 && MultSurfNum == 1) {
    1943            0 :                                             ShowContinueError(state,
    1944            0 :                                                               format("  Area={:.1T} in Surface={}, Zone={}",
    1945            0 :                                                                      state.dataSurface->Surface(SurfNum).Area,
    1946            0 :                                                                      state.dataSurface->Surface(SurfNum).Name,
    1947            0 :                                                                      state.dataSurface->Surface(SurfNum).ZoneName));
    1948            0 :                                             ShowContinueError(state,
    1949            0 :                                                               format("  Area={:.1T} in Surface={}, Zone={}",
    1950            0 :                                                                      state.dataSurface->Surface(Found).Area,
    1951            0 :                                                                      state.dataSurface->Surface(Found).Name,
    1952            0 :                                                                      state.dataSurface->Surface(Found).ZoneName));
    1953              :                                         } else { // Show multiplier info
    1954            0 :                                             ShowContinueError(state,
    1955            0 :                                                               format("  Area={:.1T}, Multipliers={}, Total Area={:.1T} in Surface={} Zone={}",
    1956            0 :                                                                      state.dataSurface->Surface(SurfNum).Area,
    1957              :                                                                      MultSurfNum,
    1958            0 :                                                                      state.dataSurface->Surface(SurfNum).Area * MultSurfNum,
    1959            0 :                                                                      state.dataSurface->Surface(SurfNum).Name,
    1960            0 :                                                                      state.dataSurface->Surface(SurfNum).ZoneName));
    1961              : 
    1962            0 :                                             ShowContinueError(state,
    1963            0 :                                                               format("  Area={:.1T}, Multipliers={}, Total Area={:.1T} in Surface={} Zone={}",
    1964            0 :                                                                      state.dataSurface->Surface(Found).Area,
    1965              :                                                                      MultFound,
    1966            0 :                                                                      state.dataSurface->Surface(Found).Area * MultFound,
    1967            0 :                                                                      state.dataSurface->Surface(Found).Name,
    1968            0 :                                                                      state.dataSurface->Surface(Found).ZoneName));
    1969              :                                         }
    1970              :                                     }
    1971              :                                 }
    1972              :                             }
    1973              :                             // Check opposites Azimuth and Tilt
    1974              :                             // Tilt
    1975          195 :                             if (std::abs(std::abs(state.dataSurface->Surface(Found).Tilt + state.dataSurface->Surface(SurfNum).Tilt) - 180.0) > 1.0) {
    1976            0 :                                 ShowWarningError(state, format("{}InterZone Surface Tilts do not match as expected.", RoutineName));
    1977            0 :                                 ShowContinueError(state,
    1978            0 :                                                   format("  Tilt={:.1T} in Surface={}, Zone={}",
    1979            0 :                                                          state.dataSurface->Surface(SurfNum).Tilt,
    1980            0 :                                                          state.dataSurface->Surface(SurfNum).Name,
    1981            0 :                                                          state.dataSurface->Surface(SurfNum).ZoneName));
    1982            0 :                                 ShowContinueError(state,
    1983            0 :                                                   format("  Tilt={:.1T} in Surface={}, Zone={}",
    1984            0 :                                                          state.dataSurface->Surface(Found).Tilt,
    1985            0 :                                                          state.dataSurface->Surface(Found).Name,
    1986            0 :                                                          state.dataSurface->Surface(Found).ZoneName));
    1987              :                             }
    1988              :                             // check surface class match.  interzone surface.
    1989              : 
    1990          195 :                             if ((state.dataSurface->Surface(SurfNum).Class == SurfaceClass::Wall &&
    1991          390 :                                  state.dataSurface->Surface(Found).Class != SurfaceClass::Wall) ||
    1992          195 :                                 (state.dataSurface->Surface(SurfNum).Class != SurfaceClass::Wall &&
    1993           71 :                                  state.dataSurface->Surface(Found).Class == SurfaceClass::Wall)) {
    1994            0 :                                 ShowWarningError(state, format("{}InterZone Surface Classes do not match as expected.", RoutineName));
    1995            0 :                                 ShowContinueError(state,
    1996            0 :                                                   format("Surface=\"{}\", surface class={}",
    1997            0 :                                                          state.dataSurface->Surface(SurfNum).Name,
    1998            0 :                                                          cSurfaceClass(state.dataSurface->Surface(SurfNum).Class)));
    1999            0 :                                 ShowContinueError(state,
    2000            0 :                                                   format("Adjacent Surface=\"{}\", surface class={}",
    2001            0 :                                                          state.dataSurface->Surface(Found).Name,
    2002            0 :                                                          cSurfaceClass(state.dataSurface->Surface(Found).Class)));
    2003            0 :                                 ShowContinueError(state, "Other errors/warnings may follow about these surfaces.");
    2004              :                             }
    2005          195 :                             if ((state.dataSurface->Surface(SurfNum).Class == SurfaceClass::Roof &&
    2006          390 :                                  state.dataSurface->Surface(Found).Class != SurfaceClass::Floor) ||
    2007          195 :                                 (state.dataSurface->Surface(SurfNum).Class != SurfaceClass::Roof &&
    2008          170 :                                  state.dataSurface->Surface(Found).Class == SurfaceClass::Floor)) {
    2009            0 :                                 ShowWarningError(state, format("{}InterZone Surface Classes do not match as expected.", RoutineName));
    2010            0 :                                 ShowContinueError(state,
    2011            0 :                                                   format("Surface=\"{}\", surface class={}",
    2012            0 :                                                          state.dataSurface->Surface(SurfNum).Name,
    2013            0 :                                                          cSurfaceClass(state.dataSurface->Surface(SurfNum).Class)));
    2014            0 :                                 ShowContinueError(state,
    2015            0 :                                                   format("Adjacent Surface=\"{}\", surface class={}",
    2016            0 :                                                          state.dataSurface->Surface(Found).Name,
    2017            0 :                                                          cSurfaceClass(state.dataSurface->Surface(Found).Class)));
    2018            0 :                                 ShowContinueError(state, "Other errors/warnings may follow about these surfaces.");
    2019              :                             }
    2020          365 :                             if (state.dataSurface->Surface(SurfNum).Class != SurfaceClass::Roof &&
    2021          170 :                                 state.dataSurface->Surface(SurfNum).Class != SurfaceClass::Floor) {
    2022              :                                 // Walls, Windows, Doors, Glass Doors
    2023          137 :                                 if (state.dataSurface->Surface(SurfNum).Class != SurfaceClass::Wall) {
    2024              :                                     // Surface is a Door, Window or Glass Door
    2025           13 :                                     if (state.dataSurface->Surface(SurfNum).BaseSurf == 0) {
    2026            0 :                                         continue; // error detected elsewhere
    2027              :                                     }
    2028           26 :                                     if (state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Class == SurfaceClass::Roof ||
    2029           13 :                                         state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Class == SurfaceClass::Floor) {
    2030            0 :                                         continue;
    2031              :                                     }
    2032              :                                 }
    2033          137 :                                 if (std::abs(std::abs(state.dataSurface->Surface(SurfNum).Azimuth - state.dataSurface->Surface(Found).Azimuth) -
    2034          137 :                                              180.0) > 1.0) {
    2035           24 :                                     if (std::abs(state.dataSurface->Surface(SurfNum).SinTilt) > 0.5 || state.dataGlobal->DisplayExtraWarnings) {
    2036              :                                         // if horizontal surfaces, then these are windows/doors/etc in those items.
    2037           24 :                                         ShowWarningError(state, format("{}InterZone Surface Azimuths do not match as expected.", RoutineName));
    2038           48 :                                         ShowContinueError(state,
    2039           48 :                                                           format("  Azimuth={:.1T}, Tilt={:.1T}, in Surface={}, Zone={}",
    2040           24 :                                                                  state.dataSurface->Surface(SurfNum).Azimuth,
    2041           24 :                                                                  state.dataSurface->Surface(SurfNum).Tilt,
    2042           24 :                                                                  state.dataSurface->Surface(SurfNum).Name,
    2043           24 :                                                                  state.dataSurface->Surface(SurfNum).ZoneName));
    2044           48 :                                         ShowContinueError(state,
    2045           48 :                                                           format("  Azimuth={:.1T}, Tilt={:.1T}, in Surface={}, Zone={}",
    2046           24 :                                                                  state.dataSurface->Surface(Found).Azimuth,
    2047           24 :                                                                  state.dataSurface->Surface(Found).Tilt,
    2048           24 :                                                                  state.dataSurface->Surface(Found).Name,
    2049           24 :                                                                  state.dataSurface->Surface(Found).ZoneName));
    2050           48 :                                         ShowContinueError(
    2051              :                                             state,
    2052           48 :                                             format("..surface class of first surface={}", cSurfaceClass(state.dataSurface->Surface(SurfNum).Class)));
    2053           48 :                                         ShowContinueError(
    2054              :                                             state,
    2055           48 :                                             format("..surface class of second surface={}", cSurfaceClass(state.dataSurface->Surface(Found).Class)));
    2056              :                                     }
    2057              :                                 }
    2058              :                             }
    2059              : 
    2060              :                             // Make sure exposures (Sun, Wind) are the same.....and are "not"
    2061          195 :                             if (state.dataSurface->Surface(SurfNum).ExtSolar || state.dataSurface->Surface(Found).ExtSolar) {
    2062            0 :                                 ShowWarningError(state, format("{}Interzone surfaces cannot be \"SunExposed\" -- removing SunExposed", RoutineName));
    2063            0 :                                 ShowContinueError(state,
    2064            0 :                                                   format("  Surface={}, Zone={}",
    2065            0 :                                                          state.dataSurface->Surface(SurfNum).Name,
    2066            0 :                                                          state.dataSurface->Surface(SurfNum).ZoneName));
    2067            0 :                                 ShowContinueError(state,
    2068            0 :                                                   format("  Surface={}, Zone={}",
    2069            0 :                                                          state.dataSurface->Surface(Found).Name,
    2070            0 :                                                          state.dataSurface->Surface(Found).ZoneName));
    2071            0 :                                 state.dataSurface->Surface(SurfNum).ExtSolar = false;
    2072            0 :                                 state.dataSurface->Surface(Found).ExtSolar = false;
    2073              :                             }
    2074          195 :                             if (state.dataSurface->Surface(SurfNum).ExtWind || state.dataSurface->Surface(Found).ExtWind) {
    2075            0 :                                 ShowWarningError(state,
    2076            0 :                                                  format("{}Interzone surfaces cannot be \"WindExposed\" -- removing WindExposed", RoutineName));
    2077            0 :                                 ShowContinueError(state,
    2078            0 :                                                   format("  Surface={}, Zone={}",
    2079            0 :                                                          state.dataSurface->Surface(SurfNum).Name,
    2080            0 :                                                          state.dataSurface->Surface(SurfNum).ZoneName));
    2081            0 :                                 ShowContinueError(state,
    2082            0 :                                                   format("  Surface={}, Zone={}",
    2083            0 :                                                          state.dataSurface->Surface(Found).Name,
    2084            0 :                                                          state.dataSurface->Surface(Found).ZoneName));
    2085            0 :                                 state.dataSurface->Surface(SurfNum).ExtWind = false;
    2086            0 :                                 state.dataSurface->Surface(Found).ExtWind = false;
    2087              :                             }
    2088              :                         }
    2089              :                         // Set opposing surface back to this one (regardless of error)
    2090          440 :                         state.dataSurface->Surface(Found).ExtBoundCond = SurfNum;
    2091              :                         // Check subsurfaces...  make sure base surface is also an interzone surface
    2092          440 :                         if (state.dataSurface->Surface(SurfNum).BaseSurf != SurfNum) { // Subsurface
    2093           26 :                             if ((state.dataSurface->Surface(SurfNum).ExtBoundCond != SurfNum) &&
    2094           13 :                                 not_blank(state.dataSurface->Surface(SurfNum).ExtBoundCondName)) {
    2095              :                                 // if not internal subsurface
    2096           13 :                                 if (state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond ==
    2097           13 :                                     state.dataSurface->Surface(SurfNum).BaseSurf) {
    2098              :                                     // base surface is not interzone surface
    2099            0 :                                     ShowSevereError(state,
    2100            0 :                                                     format("{}SubSurface=\"{}\" is an interzone subsurface.",
    2101              :                                                            RoutineName,
    2102            0 :                                                            state.dataSurface->Surface(SurfNum).Name));
    2103            0 :                                     ShowContinueError(state,
    2104            0 :                                                       format("..but the Base Surface is not an interzone surface, Surface=\"{}\".",
    2105            0 :                                                              state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Name));
    2106            0 :                                     SurfError = true;
    2107              :                                 }
    2108              :                             }
    2109              :                         }
    2110              :                     } else {
    2111              :                         //  Seems unlikely that an internal surface would be missing itself, so this message
    2112              :                         //  only indicates for adjacent (interzone) surfaces.
    2113            0 :                         ShowSevereError(state,
    2114            0 :                                         format("{}Adjacent Surface not found: {} adjacent to surface {}",
    2115              :                                                RoutineName,
    2116            0 :                                                state.dataSurface->Surface(SurfNum).ExtBoundCondName,
    2117            0 :                                                state.dataSurface->Surface(SurfNum).Name));
    2118            0 :                         NonMatch = true;
    2119            0 :                         SurfError = true;
    2120              :                     }
    2121            0 :                 } else if (state.dataSurface->Surface(SurfNum).BaseSurf != SurfNum) { // Subsurface
    2122            0 :                     if (state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond > 0 &&
    2123            0 :                         state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond !=
    2124            0 :                             state.dataSurface->Surface(SurfNum).BaseSurf) { // If Interzone surface, subsurface must be also.
    2125            0 :                         ShowSevereError(state, format("{}SubSurface on Interzone Surface must be an Interzone SubSurface.", RoutineName));
    2126            0 :                         ShowContinueError(state,
    2127            0 :                                           format("...OutsideFaceEnvironment is blank, in Surface={}", state.dataSurface->Surface(SurfNum).Name));
    2128            0 :                         SurfError = true;
    2129              :                     } else {
    2130            0 :                         ++state.dataSurfaceGeometry->ErrCount3;
    2131            0 :                         if (state.dataSurfaceGeometry->ErrCount3 == 1 && !state.dataGlobal->DisplayExtraWarnings) {
    2132            0 :                             ShowWarningError(state, format("{}Blank name for Outside Boundary Condition Objects.", RoutineName));
    2133            0 :                             ShowContinueError(state, "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on individual surfaces.");
    2134              :                         }
    2135            0 :                         if (state.dataGlobal->DisplayExtraWarnings) {
    2136            0 :                             ShowWarningError(state,
    2137            0 :                                              format("{}Blank name for Outside Boundary Condition Object, in surface={}",
    2138              :                                                     RoutineName,
    2139            0 :                                                     state.dataSurface->Surface(SurfNum).Name));
    2140            0 :                             ShowContinueError(state,
    2141            0 :                                               format("Resetting this surface to be an internal zone surface, zone={}",
    2142            0 :                                                      state.dataSurface->Surface(SurfNum).ZoneName));
    2143              :                         }
    2144            0 :                         state.dataSurface->Surface(SurfNum).ExtBoundCondName = state.dataSurface->Surface(SurfNum).Name;
    2145            0 :                         state.dataSurface->Surface(SurfNum).ExtBoundCond = SurfNum;
    2146              :                     }
    2147              :                 } else {
    2148            0 :                     ++state.dataSurfaceGeometry->ErrCount3;
    2149            0 :                     if (state.dataSurfaceGeometry->ErrCount3 == 1 && !state.dataGlobal->DisplayExtraWarnings) {
    2150            0 :                         ShowSevereError(state, format("{}Blank name for Outside Boundary Condition Objects.", RoutineName));
    2151            0 :                         ShowContinueError(state, "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on individual surfaces.");
    2152              :                     }
    2153            0 :                     if (state.dataGlobal->DisplayExtraWarnings) {
    2154            0 :                         ShowWarningError(state,
    2155            0 :                                          format("{}Blank name for Outside Boundary Condition Object, in surface={}",
    2156              :                                                 RoutineName,
    2157            0 :                                                 state.dataSurface->Surface(SurfNum).Name));
    2158            0 :                         ShowContinueError(state,
    2159            0 :                                           format("Resetting this surface to be an internal zone (adiabatic) surface, zone={}",
    2160            0 :                                                  state.dataSurface->Surface(SurfNum).ZoneName));
    2161              :                     }
    2162            0 :                     state.dataSurface->Surface(SurfNum).ExtBoundCondName = state.dataSurface->Surface(SurfNum).Name;
    2163            0 :                     state.dataSurface->Surface(SurfNum).ExtBoundCond = SurfNum;
    2164            0 :                     SurfError = true;
    2165              :                 }
    2166              :             }
    2167              : 
    2168              :         } // ...end of the Surface DO loop for finding BaseSurf
    2169          224 :         if (NonMatch) {
    2170            0 :             ShowSevereError(state, format("{}Non matching interzone surfaces found", RoutineName));
    2171              :         }
    2172              : 
    2173              :         //**********************************************************************************
    2174              :         // Warn about interzone surfaces that have adiabatic windows/vice versa
    2175          224 :         SubSurfaceSevereDisplayed = false;
    2176         2484 :         for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    2177         2260 :             if (!state.dataSurface->Surface(SurfNum).HeatTransSurf) {
    2178           84 :                 continue;
    2179              :             }
    2180         2176 :             if (state.dataSurface->Surface(SurfNum).BaseSurf == SurfNum) {
    2181         1949 :                 continue; // base surface
    2182              :             }
    2183              :             // not base surface.  Check it.
    2184          227 :             if (state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond <= 0) { // exterior or other base surface
    2185          195 :                 if (state.dataSurface->Surface(SurfNum).ExtBoundCond !=
    2186          195 :                     state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond) { // should match base surface
    2187            0 :                     if (state.dataSurface->Surface(SurfNum).ExtBoundCond == SurfNum) {
    2188            0 :                         ShowSevereError(
    2189              :                             state,
    2190            0 :                             format("{}Subsurface=\"{}\" exterior condition [adiabatic surface] in a base surface=\"{}\" with exterior condition [{}]",
    2191              :                                    RoutineName,
    2192            0 :                                    state.dataSurface->Surface(SurfNum).Name,
    2193            0 :                                    state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Name,
    2194              :                                    DataSurfaces::cExtBoundCondition(
    2195            0 :                                        state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond)));
    2196            0 :                         SurfError = true;
    2197            0 :                     } else if (state.dataSurface->Surface(SurfNum).ExtBoundCond > 0) {
    2198            0 :                         ShowSevereError(
    2199              :                             state,
    2200            0 :                             format("{}Subsurface=\"{}\" exterior condition [interzone surface] in a base surface=\"{}\" with exterior condition [{}]",
    2201              :                                    RoutineName,
    2202            0 :                                    state.dataSurface->Surface(SurfNum).Name,
    2203            0 :                                    state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Name,
    2204              :                                    DataSurfaces::cExtBoundCondition(
    2205            0 :                                        state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond)));
    2206            0 :                         SurfError = true;
    2207            0 :                     } else if (state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond ==
    2208              :                                DataSurfaces::OtherSideCondModeledExt) {
    2209            0 :                         ShowWarningError(state,
    2210            0 :                                          format("{}Subsurface=\"{}\" exterior condition [{}] in a base surface=\"{}\" with exterior condition [{}]",
    2211              :                                                 RoutineName,
    2212            0 :                                                 state.dataSurface->Surface(SurfNum).Name,
    2213            0 :                                                 DataSurfaces::cExtBoundCondition(state.dataSurface->Surface(SurfNum).ExtBoundCond),
    2214            0 :                                                 state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Name,
    2215              :                                                 DataSurfaces::cExtBoundCondition(
    2216            0 :                                                     state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond)));
    2217            0 :                         ShowContinueError(state, "...SubSurface will not use the exterior condition model of the base surface.");
    2218              :                     } else {
    2219            0 :                         ShowSevereError(state,
    2220            0 :                                         format("{}Subsurface=\"{}\" exterior condition [{}] in a base surface=\"{}\" with exterior condition [{}]",
    2221              :                                                RoutineName,
    2222            0 :                                                state.dataSurface->Surface(SurfNum).Name,
    2223            0 :                                                DataSurfaces::cExtBoundCondition(state.dataSurface->Surface(SurfNum).ExtBoundCond),
    2224            0 :                                                state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Name,
    2225              :                                                DataSurfaces::cExtBoundCondition(
    2226            0 :                                                    state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond)));
    2227            0 :                         SurfError = true;
    2228              :                     }
    2229            0 :                     if (!SubSurfaceSevereDisplayed && SurfError) {
    2230            0 :                         ShowContinueError(state, "...calculations for heat balance would be compromised.");
    2231            0 :                         SubSurfaceSevereDisplayed = true;
    2232              :                     }
    2233              :                 }
    2234           32 :             } else if (state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).BaseSurf ==
    2235           32 :                        state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond) {
    2236              :                 // adiabatic surface. make sure subsurfaces match
    2237            0 :                 if (state.dataSurface->Surface(SurfNum).ExtBoundCond != SurfNum) { // not adiabatic surface
    2238            0 :                     if (state.dataSurface->Surface(SurfNum).ExtBoundCond > 0) {
    2239            0 :                         ShowSevereError(state,
    2240            0 :                                         format("{}Subsurface=\"{}\" exterior condition [interzone surface] in a base surface=\"{}\" with exterior "
    2241              :                                                "condition [adiabatic surface]",
    2242              :                                                RoutineName,
    2243            0 :                                                state.dataSurface->Surface(SurfNum).Name,
    2244            0 :                                                state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Name));
    2245              :                     } else {
    2246            0 :                         ShowSevereError(
    2247              :                             state,
    2248            0 :                             format("{}Subsurface=\"{}\" exterior condition [{}] in a base surface=\"{}\" with exterior condition [adiabatic surface]",
    2249              :                                    RoutineName,
    2250            0 :                                    state.dataSurface->Surface(SurfNum).Name,
    2251            0 :                                    DataSurfaces::cExtBoundCondition(state.dataSurface->Surface(SurfNum).ExtBoundCond),
    2252            0 :                                    state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Name));
    2253              :                     }
    2254            0 :                     if (!SubSurfaceSevereDisplayed) {
    2255            0 :                         ShowContinueError(state, "...calculations for heat balance would be compromised.");
    2256            0 :                         SubSurfaceSevereDisplayed = true;
    2257              :                     }
    2258            0 :                     SurfError = true;
    2259              :                 }
    2260           32 :             } else if (state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond > 0) { // interzone surface
    2261           32 :                 if (state.dataSurface->Surface(SurfNum).ExtBoundCond == SurfNum) {
    2262            0 :                     ShowSevereError(state,
    2263            0 :                                     format("{}Subsurface=\"{}\" is an adiabatic surface in an Interzone base surface=\"{}\"",
    2264              :                                            RoutineName,
    2265            0 :                                            state.dataSurface->Surface(SurfNum).Name,
    2266            0 :                                            state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Name));
    2267            0 :                     if (!SubSurfaceSevereDisplayed) {
    2268            0 :                         ShowContinueError(state, "...calculations for heat balance would be compromised.");
    2269            0 :                         SubSurfaceSevereDisplayed = true;
    2270              :                     }
    2271              :                     //        SurfError=.TRUE.
    2272              :                 }
    2273              :             }
    2274              :         }
    2275              : 
    2276          224 :         setSurfaceFirstLast(state);
    2277              : 
    2278              :         // Set up Floor Areas for Zones and Spaces
    2279          224 :         Real64 constexpr floorAreaTolerance(0.05);
    2280          224 :         Real64 constexpr floorAreaPercentTolerance(floorAreaTolerance * 100.0);
    2281          224 :         if (!SurfError) {
    2282          224 :             int ErrCount = 0;
    2283          599 :             for (auto &thisSpace : state.dataHeatBal->space) {
    2284          375 :                 auto &thisZone = state.dataHeatBal->Zone(thisSpace.zoneNum);
    2285          375 :                 Real64 calcFloorArea = 0.0; // Calculated floor area used for this space
    2286         2509 :                 for (int SurfNum = thisSpace.HTSurfaceFirst; SurfNum <= thisSpace.HTSurfaceLast; ++SurfNum) {
    2287         2134 :                     auto const &thisSurf = state.dataSurface->Surface(SurfNum);
    2288         2134 :                     if (thisSurf.Class == SurfaceClass::Floor) {
    2289          422 :                         thisZone.HasFloor = true;
    2290          422 :                         thisSpace.hasFloor = true;
    2291          422 :                         calcFloorArea += thisSurf.Area;
    2292              :                     }
    2293         2134 :                     if (thisSurf.Class == SurfaceClass::Roof) {
    2294          342 :                         thisZone.CeilingArea += thisSurf.Area;
    2295          342 :                         thisZone.HasRoof = true;
    2296              :                     }
    2297              :                 }
    2298          375 :                 if (thisSpace.userEnteredFloorArea != Constant::AutoCalculate) {
    2299              :                     // Check entered vs calculated
    2300            5 :                     if (thisSpace.userEnteredFloorArea > 0.0) { // User entered Space floor area,
    2301              :                         // produce message if not near calculated
    2302            5 :                         if (calcFloorArea > 0.0) {
    2303            5 :                             Real64 diffp = std::abs(calcFloorArea - thisSpace.userEnteredFloorArea) / thisSpace.userEnteredFloorArea;
    2304            5 :                             if (diffp > floorAreaTolerance) {
    2305            5 :                                 ++ErrCount;
    2306            5 :                                 if (ErrCount == 1 && !state.dataGlobal->DisplayExtraWarnings) {
    2307            6 :                                     ShowWarningError(
    2308              :                                         state,
    2309            6 :                                         format("{}Entered Space Floor Area(s) differ more than {:.0R}% from calculated Space Floor Area(s).",
    2310            6 :                                                std::string(RoutineName),
    2311              :                                                floorAreaPercentTolerance));
    2312            9 :                                     ShowContinueError(state,
    2313              :                                                       "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on individual Spaces.");
    2314              :                                 }
    2315            5 :                                 if (state.dataGlobal->DisplayExtraWarnings) {
    2316              :                                     // Warn user of using specified Space Floor Area
    2317            0 :                                     ShowWarningError(
    2318              :                                         state,
    2319            0 :                                         format("{}Entered Floor Area for Space=\"{}\" is {:.1R}% different from the calculated Floor Area.",
    2320            0 :                                                std::string(RoutineName),
    2321            0 :                                                thisSpace.Name,
    2322            0 :                                                diffp * 100.0));
    2323            0 :                                     ShowContinueError(state,
    2324            0 :                                                       format("Entered Space Floor Area={:.2R}, Calculated Space Floor Area={:.2R}, entered "
    2325              :                                                              "Floor Area will be used.",
    2326            0 :                                                              thisSpace.userEnteredFloorArea,
    2327              :                                                              calcFloorArea));
    2328              :                                 }
    2329              :                             }
    2330              :                         }
    2331            5 :                         thisSpace.FloorArea = thisSpace.userEnteredFloorArea;
    2332            5 :                         thisSpace.hasFloor = true;
    2333              :                     }
    2334              :                 } else {
    2335          370 :                     thisSpace.FloorArea = calcFloorArea;
    2336              :                 }
    2337          224 :             }
    2338          224 :             ErrCount = 0;
    2339          578 :             for (auto &thisZone : state.dataHeatBal->Zone) {
    2340              :                 // Calculate zone floor area as sum of space floor areas
    2341          354 :                 Real64 zoneCalcFloorArea = 0.0; // Calculated floor area excluding air boundary surfaces
    2342          729 :                 for (int spaceNum : thisZone.spaceIndexes) {
    2343          375 :                     zoneCalcFloorArea += state.dataHeatBal->space(spaceNum).FloorArea;
    2344          375 :                     thisZone.HasFloor |= state.dataHeatBal->space(spaceNum).hasFloor;
    2345          354 :                 }
    2346          354 :                 if (thisZone.UserEnteredFloorArea != Constant::AutoCalculate) {
    2347              :                     // Check entered vs calculated
    2348           10 :                     if (thisZone.UserEnteredFloorArea > 0.0) { // User entered zone floor area,
    2349              :                         // produce message if not near calculated
    2350            9 :                         if (zoneCalcFloorArea > 0.0) {
    2351            7 :                             Real64 diffp = std::abs(zoneCalcFloorArea - thisZone.UserEnteredFloorArea) / thisZone.UserEnteredFloorArea;
    2352            7 :                             if (diffp > 0.05) {
    2353            3 :                                 ++ErrCount;
    2354            3 :                                 if (ErrCount == 1 && !state.dataGlobal->DisplayExtraWarnings) {
    2355            4 :                                     ShowWarningError(
    2356              :                                         state,
    2357            4 :                                         format("{}Entered Zone Floor Area(s) differ more than {:.0R}% from the sum of the Space Floor Area(s).",
    2358            4 :                                                std::string(RoutineName),
    2359              :                                                floorAreaPercentTolerance));
    2360            6 :                                     ShowContinueError(state,
    2361              :                                                       "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on individual zones.");
    2362              :                                 }
    2363            3 :                                 if (state.dataGlobal->DisplayExtraWarnings) {
    2364              :                                     // Warn user of using specified Zone Floor Area
    2365            0 :                                     ShowWarningError(state,
    2366            0 :                                                      format("{}Entered Floor Area for Zone=\"{}\" is {:.1R}% different from the sum of the "
    2367              :                                                             "Space Floor Area(s).",
    2368            0 :                                                             std::string(RoutineName),
    2369            0 :                                                             thisZone.Name,
    2370            0 :                                                             diffp * 100.0));
    2371            0 :                                     ShowContinueError(state,
    2372            0 :                                                       format("Entered Zone Floor Area={:.2R}, Sum of Space Floor Area(s)={:.2R}",
    2373            0 :                                                              thisZone.UserEnteredFloorArea,
    2374              :                                                              zoneCalcFloorArea));
    2375            0 :                                     ShowContinueError(
    2376              :                                         state, "Entered Zone Floor Area will be used and Space Floor Area(s) will be adjusted proportionately.");
    2377              :                                 }
    2378              :                             }
    2379              :                         }
    2380            9 :                         thisZone.FloorArea = thisZone.UserEnteredFloorArea;
    2381            9 :                         thisZone.HasFloor = true;
    2382              : 
    2383              :                         // Adjust space floor areas to match zone floor area
    2384            9 :                         if (thisZone.numSpaces == 1) {
    2385              :                             // If the zone contains only one space, then set the Space area to the Zone area
    2386            8 :                             int spaceNum = thisZone.spaceIndexes(1);
    2387            8 :                             state.dataHeatBal->space(spaceNum).FloorArea = thisZone.FloorArea;
    2388            1 :                         } else if (zoneCalcFloorArea > 0.0) {
    2389              :                             // Adjust space areas proportionately
    2390            1 :                             Real64 areaRatio = thisZone.FloorArea / zoneCalcFloorArea;
    2391            3 :                             for (int spaceNum : thisZone.spaceIndexes) {
    2392            2 :                                 state.dataHeatBal->space(spaceNum).FloorArea *= areaRatio;
    2393            1 :                             }
    2394              :                         } else {
    2395            0 :                             if (state.dataGlobal->DisplayExtraWarnings) {
    2396              :                                 // Warn if calculated floor area was zero and there is more than one Space
    2397            0 :                                 ShowWarningError(
    2398              :                                     state,
    2399            0 :                                     format("{}Entered Floor Area entered for Zone=\"{}\" significantly different from sum of Space Floor Areas",
    2400              :                                            RoutineName,
    2401            0 :                                            thisZone.Name));
    2402            0 :                                 ShowContinueError(state,
    2403              :                                                   "But the sum of the Space Floor Areas is zero and there is more than one Space in the zone."
    2404              :                                                   "Unable to apportion the zone floor area. Space Floor Areas are zero.");
    2405              :                             }
    2406              :                         }
    2407              :                     } else {
    2408            1 :                         if (zoneCalcFloorArea > 0.0) {
    2409            1 :                             thisZone.FloorArea = zoneCalcFloorArea;
    2410              :                         }
    2411              :                     }
    2412              :                 } else {
    2413          344 :                     thisZone.FloorArea = zoneCalcFloorArea;
    2414              :                 }
    2415          354 :                 Real64 totSpacesFloorArea = 0.0;
    2416          729 :                 for (int spaceNum : thisZone.spaceIndexes) {
    2417          375 :                     totSpacesFloorArea += state.dataHeatBal->space(spaceNum).FloorArea;
    2418          354 :                 }
    2419          354 :                 if (totSpacesFloorArea > 0.0) {
    2420          673 :                     for (int spaceNum : thisZone.spaceIndexes) {
    2421          347 :                         state.dataHeatBal->space(spaceNum).fracZoneFloorArea = state.dataHeatBal->space(spaceNum).FloorArea / totSpacesFloorArea;
    2422          326 :                     }
    2423              :                 } // else leave fractions at zero
    2424          224 :             }
    2425              :         }
    2426              : 
    2427         2484 :         for (int SurfNum = 1; SurfNum <= MovedSurfs; ++SurfNum) { // TotSurfaces
    2428         2260 :             if (state.dataSurface->Surface(SurfNum).Area < 1.e-06) {
    2429            0 :                 ShowSevereError(state,
    2430            0 :                                 format("{}Zero or negative surface area[{:.5R}], Surface={}",
    2431              :                                        RoutineName,
    2432            0 :                                        state.dataSurface->Surface(SurfNum).Area,
    2433            0 :                                        state.dataSurface->Surface(SurfNum).Name));
    2434            0 :                 SurfError = true;
    2435              :             }
    2436         2260 :             if (state.dataSurface->Surface(SurfNum).Area >= 1.e-06 && state.dataSurface->Surface(SurfNum).Area < 0.001) {
    2437            0 :                 ShowWarningError(state,
    2438            0 :                                  format("{}Very small surface area[{:.5R}], Surface={}",
    2439              :                                         RoutineName,
    2440            0 :                                         state.dataSurface->Surface(SurfNum).Area,
    2441            0 :                                         state.dataSurface->Surface(SurfNum).Name));
    2442              :             }
    2443              :         }
    2444              : 
    2445         2484 :         for (int SurfNum = 1; SurfNum <= MovedSurfs; ++SurfNum) { // TotSurfaces
    2446         2260 :             auto &surf = state.dataSurface->Surface(SurfNum);
    2447              :             // GLASSDOORs and TDD:DIFFUSERs will be treated as windows in the subsequent heat transfer and daylighting
    2448              :             // calculations. Reset class to 'Window' after saving the original designation in SurfaceWindow.
    2449              : 
    2450         2260 :             surf.OriginalClass = surf.Class;
    2451              : 
    2452         2260 :             if (surf.Class == SurfaceClass::GlassDoor || surf.Class == SurfaceClass::TDD_Diffuser) {
    2453           16 :                 surf.Class = SurfaceClass::Window;
    2454              :             }
    2455              : 
    2456         2260 :             if (surf.Class == SurfaceClass::TDD_Dome) {
    2457              :                 // Reset the TDD:DOME subsurface to act as a base surface that can shade and be shaded
    2458              :                 // NOTE: This must be set early so that subsequent shading calculations are done correctly
    2459            7 :                 surf.BaseSurf = SurfNum;
    2460              :             }
    2461              :         }
    2462              : 
    2463          224 :         auto &s_mat = state.dataMaterial;
    2464              : 
    2465              :         // I don't think this entire loop matters
    2466          224 :         errFlag = false;
    2467          224 :         if (!SurfError) {
    2468         2484 :             for (int SurfNum = 1; SurfNum <= MovedSurfs; ++SurfNum) { // TotSurfaces
    2469         2260 :                 auto &surf = state.dataSurface->Surface(SurfNum);
    2470         2260 :                 if (!surf.HasShadeControl) {
    2471         2249 :                     continue;
    2472              :                 }
    2473              : 
    2474           11 :                 int ConstrNumSh = surf.activeShadedConstruction;
    2475           11 :                 if (ConstrNumSh <= 0) {
    2476            0 :                     continue;
    2477              :                 }
    2478              : 
    2479           11 :                 auto &winShadeCtrl = state.dataSurface->WindowShadingControl(surf.activeWindowShadingControl);
    2480           11 :                 if (!ANY_BLIND(winShadeCtrl.ShadingType)) {
    2481            3 :                     continue;
    2482              :                 }
    2483              :                 // use first item since others should be identical
    2484              : 
    2485            8 :                 auto &surfShade = state.dataSurface->surfShades(SurfNum);
    2486              :                 // TH 1/7/2010. CR 7930
    2487              :                 // The old code did not consider between-glass blind. Also there should not be two blinds - both interior and exterior
    2488              :                 // Use the new generic code (assuming only one blind) as follows
    2489           16 :                 for (int iMatNum = 1; iMatNum <= state.dataConstruction->Construct(ConstrNumSh).TotLayers; ++iMatNum) {
    2490           16 :                     auto *mat = s_mat->materials(state.dataConstruction->Construct(ConstrNumSh).LayerPoint(iMatNum));
    2491              : 
    2492           16 :                     if (mat->group != Material::Group::Blind) {
    2493            8 :                         continue;
    2494              :                     }
    2495              : 
    2496            8 :                     auto *matBlind = dynamic_cast<Material::MaterialBlind *>(mat);
    2497            8 :                     assert(matBlind != nullptr);
    2498              : 
    2499            8 :                     surfShade.blind.matNum = mat->Num;
    2500            8 :                     break;
    2501              :                 }
    2502              : 
    2503            8 :                 if (errFlag) {
    2504            0 :                     ErrorsFound = true;
    2505            0 :                     ShowContinueError(state, format("WindowShadingControl {} has errors, program will terminate.", winShadeCtrl.Name));
    2506              :                 }
    2507              : 
    2508            8 :                 if (winShadeCtrl.slatAngleControl != DataSurfaces::SlatAngleControl::Fixed) {
    2509            0 :                     surfShade.blind.movableSlats = true;
    2510            0 :                     state.dataSurface->AnyMovableSlat = true;
    2511            0 :                     state.dataHeatBalSurf->SurfMovSlatsIndexList.push_back(SurfNum);
    2512              :                 }
    2513              :             } // End of surface loop
    2514              : 
    2515              :             // final associate fenestration surfaces referenced in WindowShadingControl
    2516          224 :             FinalAssociateWindowShadingControlFenestration(state, ErrorsFound);
    2517          224 :             CheckWindowShadingControlSimilarForWindow(state, ErrorsFound);
    2518              :         }
    2519              : 
    2520              :         // Check for zones with not enough surfaces
    2521          578 :         for (auto &thisZone : state.dataHeatBal->Zone) {
    2522          354 :             int OpaqueHTSurfs = 0;        // Number of floors, walls and roofs in a zone
    2523          354 :             int OpaqueHTSurfsWithWin = 0; // Number of floors, walls and roofs with windows in a zone
    2524          354 :             int InternalMassSurfs = 0;    // Number of internal mass surfaces in a zone
    2525          354 :             int priorBaseSurfNum = 0;
    2526              : 
    2527          729 :             for (int spaceNum : thisZone.spaceIndexes) {
    2528          375 :                 auto const &thisSpace = state.dataHeatBal->space(spaceNum);
    2529          375 :                 if (thisSpace.HTSurfaceFirst == 0) {
    2530            4 :                     continue; // Zone with no surfaces
    2531              :                 }
    2532         2505 :                 for (int SurfNum = thisSpace.HTSurfaceFirst; SurfNum <= thisSpace.HTSurfaceLast; ++SurfNum) {
    2533         2134 :                     auto const &thisSurf = state.dataSurface->Surface(SurfNum);
    2534         2134 :                     if (thisSurf.Class == SurfaceClass::Floor || thisSurf.Class == SurfaceClass::Wall || thisSurf.Class == SurfaceClass::Roof) {
    2535         1895 :                         ++OpaqueHTSurfs;
    2536              :                     }
    2537         2134 :                     if (thisSurf.Class == SurfaceClass::IntMass) {
    2538           16 :                         ++InternalMassSurfs;
    2539              :                     }
    2540         2134 :                     if (thisSurf.Class == SurfaceClass::Window) {
    2541              :                         // Count base surface only once for multiple windows on a wall
    2542          195 :                         int thisBaseSurfNum = thisSurf.BaseSurf;
    2543          195 :                         if (thisBaseSurfNum != priorBaseSurfNum) {
    2544          144 :                             ++OpaqueHTSurfsWithWin;
    2545          144 :                             priorBaseSurfNum = thisBaseSurfNum;
    2546              :                         }
    2547              :                     }
    2548              :                 }
    2549          354 :             }
    2550          354 :             if (OpaqueHTSurfsWithWin == 1 && OpaqueHTSurfs == 1 && InternalMassSurfs == 0) {
    2551            0 :                 SurfError = true;
    2552            0 :                 ShowSevereError(state,
    2553            0 :                                 format("{}Zone {} has only one floor, wall or roof, and this surface has a window.", RoutineName, thisZone.Name));
    2554            0 :                 ShowContinueError(state, "Add more floors, walls or roofs, or an internal mass surface.");
    2555              :             }
    2556          224 :         }
    2557              : 
    2558              :         // set up vertex of centroid for each surface.
    2559          224 :         CalcSurfaceCentroid(state);
    2560              : 
    2561          224 :         SetupShadeSurfacesForSolarCalcs(state); // if shading surfaces are solar collectors or PV, then we need full solar calc.
    2562              : 
    2563          224 :         GetMovableInsulationData(state, ErrorsFound);
    2564              : 
    2565          224 :         if (state.dataSurface->CalcSolRefl) {
    2566            0 :             GetShadingSurfReflectanceData(state, ErrorsFound);
    2567              :         }
    2568              : 
    2569          224 :         LayNumOutside = 0;
    2570              : 
    2571         2484 :         for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    2572         2260 :             auto &surf = state.dataSurface->Surface(SurfNum);
    2573              :             // Check for EcoRoof and only 1 allowed to be used.
    2574         2260 :             if (surf.Construction > 0) {
    2575         2176 :                 state.dataSurface->SurfExtEcoRoof(SurfNum) = state.dataConstruction->Construct(surf.Construction).TypeIsEcoRoof;
    2576              :             }
    2577         2260 :             if (!state.dataSurface->SurfExtEcoRoof(SurfNum)) {
    2578         2260 :                 continue;
    2579              :             }
    2580            0 :             if (LayNumOutside == 0) {
    2581            0 :                 LayNumOutside = state.dataConstruction->Construct(surf.Construction).LayerPoint(1);
    2582            0 :                 continue;
    2583              :             }
    2584            0 :             if (LayNumOutside != state.dataConstruction->Construct(surf.Construction).LayerPoint(1)) {
    2585            0 :                 ShowSevereError(state, format("{}Only one EcoRoof Material is currently allowed for all constructions.", RoutineName));
    2586            0 :                 ShowContinueError(state, format("... first material={}", s_mat->materials(LayNumOutside)->Name));
    2587            0 :                 ShowContinueError(state,
    2588            0 :                                   format("... conflicting Construction={} uses material={}",
    2589            0 :                                          state.dataConstruction->Construct(surf.Construction).Name,
    2590            0 :                                          s_mat->materials(state.dataConstruction->Construct(surf.Construction).LayerPoint(1))->Name));
    2591            0 :                 ErrorsFound = true;
    2592              :             }
    2593              :         }
    2594              : 
    2595              :         // Reserve space to avoid excess allocations
    2596          224 :         state.dataSurface->AllHTSurfaceList.reserve(state.dataSurface->TotSurfaces);
    2597          224 :         state.dataSurface->AllExtSolarSurfaceList.reserve(state.dataSurface->TotSurfaces);
    2598          224 :         state.dataSurface->AllShadowPossObstrSurfaceList.reserve(state.dataSurface->TotSurfaces);
    2599          224 :         state.dataSurface->AllIZSurfaceList.reserve(state.dataSurface->TotSurfaces);
    2600          224 :         state.dataSurface->AllHTNonWindowSurfaceList.reserve(state.dataSurface->TotSurfaces - state.dataSurface->TotWindows);
    2601          224 :         state.dataSurface->AllHTWindowSurfaceList.reserve(state.dataSurface->TotWindows);
    2602          224 :         state.dataSurface->AllExtSolWindowSurfaceList.reserve(state.dataSurface->TotWindows);
    2603          224 :         state.dataSurface->AllExtSolWinWithFrameSurfaceList.reserve(state.dataSurface->TotWindows);
    2604          224 :         state.dataSurface->AllHTKivaSurfaceList.reserve(state.dataSurface->TotSurfaces);
    2605              : 
    2606              :         // Set flag that determines whether a surface can be an exterior obstruction
    2607              :         // Also set associated surfaces for Kiva foundations and build heat transfer surface lists
    2608         2484 :         for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    2609         2260 :             auto &surf = state.dataSurface->Surface(SurfNum);
    2610         2260 :             surf.IsShadowPossibleObstruction = false;
    2611         2260 :             if (surf.ExtSolar) {
    2612              :                 // This may include some attached shading surfaces
    2613         1408 :                 state.dataSurface->AllExtSolarSurfaceList.push_back(SurfNum);
    2614              :             }
    2615         2260 :             if (surf.HeatTransSurf) {
    2616              :                 // Outside light shelves get tagged later as HeatTransSurf=true but they haven't been processed yet
    2617         2134 :                 state.dataSurface->AllHTSurfaceList.push_back(SurfNum);
    2618         2134 :                 int const zoneNum(surf.Zone);
    2619         2134 :                 auto &surfZone(state.dataHeatBal->Zone(zoneNum));
    2620         2134 :                 surfZone.ZoneHTSurfaceList.push_back(SurfNum);
    2621              :                 // Sort window vs non-window surfaces
    2622         2134 :                 if (surf.Class == DataSurfaces::SurfaceClass::Window) {
    2623          195 :                     state.dataSurface->AllHTWindowSurfaceList.push_back(SurfNum);
    2624          195 :                     surfZone.ZoneHTWindowSurfaceList.push_back(SurfNum);
    2625          195 :                     if (surf.ExtSolar) {
    2626          175 :                         state.dataSurface->AllExtSolWindowSurfaceList.push_back(SurfNum);
    2627          175 :                         if (surf.FrameDivider > 0) {
    2628           22 :                             state.dataSurface->AllExtSolWinWithFrameSurfaceList.push_back(SurfNum);
    2629              :                         }
    2630              :                     }
    2631              :                 } else {
    2632         1939 :                     state.dataSurface->AllHTNonWindowSurfaceList.push_back(SurfNum);
    2633         1939 :                     surfZone.ZoneHTNonWindowSurfaceList.push_back(SurfNum);
    2634              :                 }
    2635         2134 :                 int const surfExtBoundCond(surf.ExtBoundCond);
    2636              :                 // Build zone and interzone surface lists
    2637         2134 :                 if ((surfExtBoundCond > 0) && (surfExtBoundCond != SurfNum)) {
    2638          346 :                     state.dataSurface->AllIZSurfaceList.push_back(SurfNum);
    2639          346 :                     surfZone.ZoneIZSurfaceList.push_back(SurfNum);
    2640          346 :                     auto &adjZone(state.dataHeatBal->Zone(state.dataSurface->Surface(surfExtBoundCond).Zone));
    2641          346 :                     adjZone.ZoneHTSurfaceList.push_back(SurfNum);
    2642          346 :                     adjZone.ZoneIZSurfaceList.push_back(SurfNum);
    2643              :                     // Sort window vs non-window surfaces
    2644          346 :                     if (surf.Class == DataSurfaces::SurfaceClass::Window) {
    2645            6 :                         adjZone.ZoneHTWindowSurfaceList.push_back(SurfNum);
    2646              :                     } else {
    2647          340 :                         adjZone.ZoneHTNonWindowSurfaceList.push_back(SurfNum);
    2648              :                     }
    2649              :                 }
    2650              :             }
    2651              : 
    2652              :             // Exclude non-exterior heat transfer surfaces (but not OtherSideCondModeledExt = -4 CR7640)
    2653         2260 :             if (surf.HeatTransSurf && surf.ExtBoundCond > 0) {
    2654          591 :                 continue;
    2655              :             }
    2656         1669 :             if (surf.HeatTransSurf && surf.ExtBoundCond == DataSurfaces::Ground) {
    2657          118 :                 continue;
    2658              :             }
    2659         1551 :             if (surf.HeatTransSurf && surf.ExtBoundCond == DataSurfaces::KivaFoundation) {
    2660            0 :                 state.dataSurface->AllHTKivaSurfaceList.push_back(SurfNum);
    2661            0 :                 if (!ErrorsFound) {
    2662            0 :                     state.dataSurfaceGeometry->kivaManager.foundationInputs[surf.OSCPtr].surfaces.push_back(SurfNum);
    2663              :                 }
    2664            0 :                 continue;
    2665              :             }
    2666         1551 :             if (surf.HeatTransSurf && surf.ExtBoundCond == DataSurfaces::OtherSideCoefNoCalcExt) {
    2667            0 :                 continue;
    2668              :             }
    2669         1551 :             if (surf.HeatTransSurf && surf.ExtBoundCond == DataSurfaces::OtherSideCoefCalcExt) {
    2670            0 :                 continue;
    2671              :             }
    2672              :             // Exclude windows and doors, i.e., consider only their base surfaces as possible obstructions
    2673         1551 :             if (surf.Class == SurfaceClass::Window || surf.Class == SurfaceClass::Door) {
    2674          198 :                 continue;
    2675              :             }
    2676              :             // Exclude duplicate shading surfaces
    2677         1353 :             if (surf.MirroredSurf) {
    2678           42 :                 continue;
    2679              :             }
    2680              :             // Exclude air boundary surfaces
    2681         1311 :             if (surf.IsAirBoundarySurf) {
    2682           38 :                 continue;
    2683              :             }
    2684              : 
    2685         1273 :             surf.IsShadowPossibleObstruction = true;
    2686         1273 :             state.dataSurface->AllShadowPossObstrSurfaceList.push_back(SurfNum);
    2687              :         } // for (SurfNum)
    2688              : 
    2689              :         // Check for IRT surfaces in invalid places.
    2690          224 :         if (std::any_of(state.dataConstruction->Construct.begin(),
    2691          224 :                         state.dataConstruction->Construct.end(),
    2692          767 :                         [](Construction::ConstructionProps const &e) { return e.TypeIsIRT; })) {
    2693            0 :             int iTmp1 = 0;
    2694            0 :             for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    2695            0 :                 auto &surf = state.dataSurface->Surface(SurfNum);
    2696            0 :                 if (!surf.HeatTransSurf) {
    2697            0 :                     continue; // ignore shading surfaces
    2698              :                 }
    2699            0 :                 if (surf.ExtBoundCond > 0 && surf.ExtBoundCond != SurfNum) {
    2700            0 :                     continue; // interzone, not adiabatic surface
    2701              :                 }
    2702            0 :                 if (!state.dataConstruction->Construct(surf.Construction).TypeIsIRT) {
    2703            0 :                     continue;
    2704              :                 }
    2705            0 :                 if (!state.dataGlobal->DisplayExtraWarnings) {
    2706            0 :                     ++iTmp1;
    2707              :                 } else {
    2708            0 :                     ShowWarningError(state,
    2709            0 :                                      format("{}Surface=\"{}\" uses InfraredTransparent construction in a non-interzone surface. (illegal use)",
    2710              :                                             RoutineName,
    2711            0 :                                             surf.Name));
    2712              :                 }
    2713              :             }
    2714            0 :             if (iTmp1 > 0) {
    2715            0 :                 ShowWarningError(
    2716              :                     state,
    2717            0 :                     format("{}Surfaces use InfraredTransparent constructions {} in non-interzone surfaces. (illegal use)", RoutineName, iTmp1));
    2718            0 :                 ShowContinueError(state, "For explicit details on each use, use Output:Diagnostics,DisplayExtraWarnings;");
    2719              :             }
    2720              :         }
    2721              : 
    2722              :         // Populate SurfaceFilter lists
    2723         2464 :         for (int iSurfaceFilter = 1; iSurfaceFilter < static_cast<int>(DataSurfaces::SurfaceFilter::Num); ++iSurfaceFilter) {
    2724         2240 :             state.dataSurface->SurfaceFilterLists[iSurfaceFilter].reserve(state.dataSurface->TotSurfaces);
    2725              :         }
    2726              : 
    2727         2484 :         for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    2728         2260 :             auto const &surf = state.dataSurface->Surface(SurfNum);
    2729         2260 :             if (!surf.HeatTransSurf) {
    2730          126 :                 continue;
    2731              :             }
    2732         2134 :             if (surf.ExtBoundCond > 0) {
    2733          591 :                 state.dataSurface->SurfaceFilterLists[static_cast<int>(DataSurfaces::SurfaceFilter::AllInteriorSurfaces)].push_back(SurfNum);
    2734          591 :                 if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) {
    2735            6 :                     state.dataSurface->SurfaceFilterLists[static_cast<int>(DataSurfaces::SurfaceFilter::AllInteriorWindows)].push_back(SurfNum);
    2736          585 :                 } else if (surf.Class == SurfaceClass::Wall) {
    2737          306 :                     state.dataSurface->SurfaceFilterLists[static_cast<int>(DataSurfaces::SurfaceFilter::AllInteriorWalls)].push_back(SurfNum);
    2738          279 :                 } else if (surf.Class == SurfaceClass::Floor) {
    2739          185 :                     state.dataSurface->SurfaceFilterLists[static_cast<int>(DataSurfaces::SurfaceFilter::AllInteriorFloors)].push_back(SurfNum);
    2740           94 :                 } else if (surf.Class == SurfaceClass::Roof) {
    2741           62 :                     state.dataSurface->SurfaceFilterLists[static_cast<int>(DataSurfaces::SurfaceFilter::AllInteriorRoofs)].push_back(SurfNum);
    2742           62 :                     state.dataSurface->SurfaceFilterLists[static_cast<int>(DataSurfaces::SurfaceFilter::AllInteriorCeilings)].push_back(SurfNum);
    2743              :                 }
    2744              :             } else {
    2745         1543 :                 state.dataSurface->SurfaceFilterLists[static_cast<int>(DataSurfaces::SurfaceFilter::AllExteriorSurfaces)].push_back(SurfNum);
    2746         1543 :                 if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) {
    2747          196 :                     state.dataSurface->SurfaceFilterLists[static_cast<int>(DataSurfaces::SurfaceFilter::AllExteriorWindows)].push_back(SurfNum);
    2748         1347 :                 } else if (surf.Class == SurfaceClass::Wall) {
    2749          825 :                     state.dataSurface->SurfaceFilterLists[static_cast<int>(DataSurfaces::SurfaceFilter::AllExteriorWalls)].push_back(SurfNum);
    2750          522 :                 } else if (surf.Class == SurfaceClass::Floor) {
    2751          237 :                     state.dataSurface->SurfaceFilterLists[static_cast<int>(DataSurfaces::SurfaceFilter::AllExteriorFloors)].push_back(SurfNum);
    2752          285 :                 } else if (surf.Class == SurfaceClass::Roof) {
    2753          280 :                     state.dataSurface->SurfaceFilterLists[static_cast<int>(DataSurfaces::SurfaceFilter::AllExteriorRoofs)].push_back(SurfNum);
    2754          280 :                     state.dataSurface->SurfaceFilterLists[static_cast<int>(DataSurfaces::SurfaceFilter::AllInteriorCeilings)].push_back(SurfNum);
    2755              :                 }
    2756              :             }
    2757              :         } // for (SurfNum)
    2758              : 
    2759              :         // Note, could do same for Window Area and detecting if Interzone Surface in Zone
    2760              : 
    2761          224 :         if (state.dataSurfaceGeometry->Warning1Count > 0) {
    2762            0 :             ShowWarningMessage(state,
    2763            0 :                                format("{}Window dimensions differ from Window 5/6 data file dimensions, {} times.",
    2764              :                                       RoutineName,
    2765            0 :                                       state.dataSurfaceGeometry->Warning1Count));
    2766            0 :             ShowContinueError(state, "This will affect the frame heat transfer calculation if the frame in the Data File entry");
    2767            0 :             ShowContinueError(state, "is not uniform, i.e., has sections with different geometry and/or thermal properties.");
    2768            0 :             ShowContinueError(state, "For explicit details on each window, use Output:Diagnostics,DisplayExtraWarnings;");
    2769              :         }
    2770          224 :         if (state.dataSurfaceGeometry->Warning2Count > 0) {
    2771            0 :             ShowWarningMessage(state,
    2772            0 :                                format("{}Exterior Windows have been replaced with Window 5/6 two glazing systems, {} times.",
    2773              :                                       RoutineName,
    2774            0 :                                       state.dataSurfaceGeometry->Warning2Count));
    2775            0 :             ShowContinueError(state, "Note that originally entered dimensions are overridden.");
    2776            0 :             ShowContinueError(state, "For explicit details on each window, use Output:Diagnostics,DisplayExtraWarnings;");
    2777              :         }
    2778          224 :         if (state.dataSurfaceGeometry->Warning3Count > 0) {
    2779            0 :             ShowWarningMessage(state,
    2780            0 :                                format("{}Interior Windows have been replaced with Window 5/6 two glazing systems, {} times.",
    2781              :                                       RoutineName,
    2782            0 :                                       state.dataSurfaceGeometry->Warning3Count));
    2783            0 :             ShowContinueError(state, "Note that originally entered dimensions are overridden.");
    2784            0 :             ShowContinueError(state, "For explicit details on each window, use Output:Diagnostics,DisplayExtraWarnings;");
    2785              :         }
    2786              : 
    2787          224 :         if (state.dataErrTracking->TotalMultipliedWindows > 0) {
    2788            0 :             ShowWarningMessage(state,
    2789            0 :                                format("{}There are {} window/glass door(s) that may cause inaccurate shadowing due to Solar Distribution.",
    2790              :                                       RoutineName,
    2791            0 :                                       state.dataErrTracking->TotalMultipliedWindows));
    2792            0 :             ShowContinueError(state, "For explicit details on each window, use Output:Diagnostics,DisplayExtraWarnings;");
    2793            0 :             state.dataErrTracking->TotalWarningErrors += state.dataErrTracking->TotalMultipliedWindows;
    2794              :         }
    2795          224 :         if (state.dataErrTracking->TotalCoincidentVertices > 0) {
    2796            0 :             ShowWarningMessage(state,
    2797            0 :                                format("{}There are {} coincident/collinear vertices; These have been deleted unless the deletion would bring the "
    2798              :                                       "number of surface sides < 3.",
    2799              :                                       RoutineName,
    2800            0 :                                       state.dataErrTracking->TotalCoincidentVertices));
    2801            0 :             ShowContinueError(state, "For explicit details on each problem surface, use Output:Diagnostics,DisplayExtraWarnings;");
    2802            0 :             state.dataErrTracking->TotalWarningErrors += state.dataErrTracking->TotalCoincidentVertices;
    2803              :         }
    2804          224 :         if (state.dataErrTracking->TotalDegenerateSurfaces > 0) {
    2805            0 :             ShowSevereMessage(state,
    2806            0 :                               format("{}There are {} degenerate surfaces; Degenerate surfaces are those with number of sides < 3.",
    2807              :                                      RoutineName,
    2808            0 :                                      state.dataErrTracking->TotalDegenerateSurfaces));
    2809            0 :             ShowContinueError(state, "These surfaces should be deleted.");
    2810            0 :             ShowContinueError(state, "For explicit details on each problem surface, use Output:Diagnostics,DisplayExtraWarnings;");
    2811            0 :             state.dataErrTracking->TotalSevereErrors += state.dataErrTracking->TotalDegenerateSurfaces;
    2812              :         }
    2813              : 
    2814          224 :         GetHTSurfExtVentedCavityData(state, ErrorsFound);
    2815              : 
    2816          224 :         state.dataSurfaceGeometry->exposedFoundationPerimeter.getData(state, ErrorsFound);
    2817              : 
    2818          224 :         GetSurfaceHeatTransferAlgorithmOverrides(state, ErrorsFound);
    2819              : 
    2820              :         // Set up enclosures, process Air Boundaries if any
    2821          224 :         SetupEnclosuresAndAirBoundaries(state, state.dataViewFactor->EnclRadInfo, SurfaceGeometry::enclosureType::RadiantEnclosures, ErrorsFound);
    2822              : 
    2823          224 :         GetSurfaceGroundSurfsData(state, ErrorsFound);
    2824              : 
    2825          224 :         GetSurfaceSrdSurfsData(state, ErrorsFound);
    2826              : 
    2827          224 :         GetSurfaceLocalEnvData(state, ErrorsFound);
    2828              : 
    2829          224 :         if (SurfError || ErrorsFound) {
    2830            0 :             ErrorsFound = true;
    2831            0 :             ShowFatalError(state, format("{}Errors discovered, program terminates.", RoutineName));
    2832              :         }
    2833              : 
    2834          224 :         int TotShadSurf = TotDetachedFixed + TotDetachedBldg + TotRectDetachedFixed + TotRectDetachedBldg + TotShdSubs + TotOverhangs +
    2835          224 :                           TotOverhangsProjection + TotFins + TotFinsProjection;
    2836          224 :         int NumDElightCmplxFen = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Daylighting:DElight:ComplexFenestration");
    2837          224 :         if (TotShadSurf > 0 && (NumDElightCmplxFen > 0 || Dayltg::doesDayLightingUseDElight(state))) {
    2838            0 :             ShowWarningError(state, format("{}When using DElight daylighting the presence of exterior shading surfaces is ignored.", RoutineName));
    2839              :         }
    2840              : 
    2841         2484 :         for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; SurfNum++) {
    2842         2260 :             auto &surf = state.dataSurface->Surface(SurfNum);
    2843              :             // Initialize run time surface arrays
    2844         2260 :             state.dataSurface->SurfActiveConstruction(SurfNum) = surf.Construction;
    2845         2260 :             surf.RepresentativeCalcSurfNum = SurfNum;
    2846              :         }
    2847              : 
    2848              :         // Representative surface calculations: Assign representative heat transfer surfaces
    2849          224 :         if (state.dataSurface->UseRepresentativeSurfaceCalculations &&
    2850          224 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "ZoneProperty:UserViewFactors:BySurfaceName") == 0) {
    2851            0 :             for (int zoneNum = 1; zoneNum <= state.dataGlobal->NumOfZones; ++zoneNum) {
    2852            0 :                 for (int spaceNum : state.dataHeatBal->Zone(zoneNum).spaceIndexes) {
    2853            0 :                     auto const &thisSpace = state.dataHeatBal->space(spaceNum);
    2854            0 :                     for (int surfNum = thisSpace.HTSurfaceFirst; surfNum <= thisSpace.HTSurfaceLast; surfNum++) {
    2855            0 :                         auto &surface(state.dataSurface->Surface(surfNum));
    2856              :                         // Conditions where surface always needs to be unique
    2857            0 :                         bool forceUniqueSurface = surface.HasShadeControl ||
    2858            0 :                                                   state.dataSurface->SurfWinAirflowSource(surfNum) != DataSurfaces::WindowAirFlowSource::Invalid ||
    2859            0 :                                                   state.dataConstruction->Construct(surface.Construction).SourceSinkPresent ||
    2860            0 :                                                   surface.Class == SurfaceClass::TDD_Dome ||
    2861            0 :                                                   (surface.Class == SurfaceClass::Window &&
    2862            0 :                                                    (surface.OriginalClass == SurfaceClass::TDD_Diffuser ||
    2863            0 :                                                     state.dataSurface->SurfWinWindowModelType(surfNum) != DataSurfaces::WindowModel::Detailed ||
    2864            0 :                                                     state.dataWindowManager->inExtWindowModel->isExternalLibraryModel() ||
    2865            0 :                                                     state.dataConstruction->Construct(surface.Construction).isTCWindow));
    2866            0 :                         if (!forceUniqueSurface) {
    2867            0 :                             state.dataSurface->Surface(surfNum).set_representative_surface(state, surfNum);
    2868              :                         }
    2869              :                     }
    2870            0 :                 }
    2871              :             }
    2872              :         }
    2873              : 
    2874          224 :         if (SurfError || ErrorsFound) {
    2875            0 :             ErrorsFound = true;
    2876            0 :             ShowFatalError(state, format("{}Errors discovered, program terminates.", RoutineName));
    2877              :         }
    2878          224 :     }
    2879              : 
    2880          224 :     void CreateMissingSpaces(EnergyPlusData &state, Array1D<SurfaceGeometry::SurfaceData> &Surfaces)
    2881              :     {
    2882              :         static constexpr std::string_view RoutineName = "CreateMissingSpaces: ";
    2883              :         // Scan surfaces to see if Space was assigned in input
    2884          224 :         EPVector<bool> anySurfacesWithSpace;    // True if any surfaces in a zone do not have a space assigned in input
    2885          224 :         EPVector<bool> anySurfacesWithoutSpace; // True if any surfaces in a zone have a space assigned in input
    2886          224 :         anySurfacesWithSpace.resize(state.dataGlobal->NumOfZones, false);
    2887          224 :         anySurfacesWithoutSpace.resize(state.dataGlobal->NumOfZones, false);
    2888              : 
    2889         2484 :         for (int surfNum = 1; surfNum <= state.dataSurface->TotSurfaces; ++surfNum) {
    2890         2260 :             auto &thisSurf = Surfaces(surfNum);
    2891         2260 :             if (!thisSurf.HeatTransSurf) {
    2892           84 :                 continue; // ignore shading surfaces
    2893              :             }
    2894         2176 :             if (thisSurf.Class == DataSurfaces::SurfaceClass::IntMass) {
    2895           16 :                 continue; // skip internal mass surfaces for this check
    2896              :             }
    2897         2160 :             if (thisSurf.BaseSurf != surfNum) {
    2898              :                 // Set space for subsurfaces
    2899          227 :                 thisSurf.spaceNum = Surfaces(thisSurf.BaseSurf).spaceNum;
    2900              :             }
    2901         2160 :             if (thisSurf.spaceNum > 0) {
    2902          163 :                 anySurfacesWithSpace(thisSurf.Zone) = true;
    2903         1997 :             } else if (thisSurf.ExtBoundCond != unreconciledZoneSurface) {
    2904         1446 :                 anySurfacesWithoutSpace(thisSurf.Zone) = true;
    2905          551 :             } else if (thisSurf.Name.substr(0, 3) != "iz-") {
    2906              :                 // Only trigger a new space if the spaceless surface is not an autogenerated interzone surface
    2907          539 :                 anySurfacesWithoutSpace(thisSurf.Zone) = true;
    2908              :             }
    2909              :         }
    2910              : 
    2911              :         // Create any missing Spaces
    2912          578 :         for (int zoneNum = 1; zoneNum <= state.dataGlobal->NumOfZones; ++zoneNum) {
    2913          354 :             auto &thisZone = state.dataHeatBal->Zone(zoneNum);
    2914          354 :             if (anySurfacesWithoutSpace(zoneNum)) {
    2915              :                 // If any surfaces in the zone are not assigned to a space, may need to create a new space
    2916              :                 // Every zone has at least one space, created in HeatBalanceManager::GetSpaceData
    2917              :                 // If no surfaces have a space assigned, then the default space will be used, otherwise, create a new space
    2918          300 :                 if (anySurfacesWithSpace(zoneNum)) {
    2919              :                     // Add new space
    2920            0 :                     ++state.dataGlobal->numSpaces;
    2921            0 :                     assert(state.dataHeatBal->space.size() >= state.dataGlobal->numSpaces);
    2922            0 :                     state.dataHeatBal->space(state.dataGlobal->numSpaces).zoneNum = zoneNum;
    2923              :                     // Add to zone's list of spaces
    2924            0 :                     thisZone.spaceIndexes.emplace_back(state.dataGlobal->numSpaces);
    2925            0 :                     ++state.dataHeatBal->Zone(zoneNum).numSpaces;
    2926            0 :                     assert(state.dataHeatBal->Zone(zoneNum).numSpaces == int(state.dataHeatBal->Zone(zoneNum).spaceIndexes.size()));
    2927              :                     // If some surfaces in the zone are assigned to a space, the new space is the remainder of the zone
    2928            0 :                     state.dataHeatBal->space(state.dataGlobal->numSpaces).Name =
    2929            0 :                         thisZone.Name + "-REMAINDER"; // Make UPPERcase so it can be referenced in input
    2930            0 :                     state.dataHeatBal->space(state.dataGlobal->numSpaces).isRemainderSpace = true;
    2931            0 :                     state.dataHeatBal->space(state.dataGlobal->numSpaces).spaceType = "GENERAL";
    2932            0 :                     state.dataHeatBal->space(state.dataGlobal->numSpaces).spaceTypeNum = HeatBalanceManager::GetGeneralSpaceTypeNum(state);
    2933              :                 }
    2934              :             }
    2935              :         }
    2936              :         // Right-size space vector
    2937          224 :         state.dataHeatBal->space.resize(state.dataGlobal->numSpaces);
    2938              : 
    2939              :         // Assign Spaces to surfaces without one
    2940         2484 :         for (int surfNum = 1; surfNum <= state.dataSurface->TotSurfaces; ++surfNum) {
    2941         2260 :             auto &thisSurf = Surfaces(surfNum);
    2942         2260 :             if (!thisSurf.HeatTransSurf) {
    2943           84 :                 continue; // ignore shading surfaces
    2944              :             }
    2945         2176 :             if (thisSurf.spaceNum == 0) {
    2946         2013 :                 int const numSpaces = state.dataHeatBal->Zone(thisSurf.Zone).numSpaces;
    2947         2013 :                 int const lastSpaceForZone = state.dataHeatBal->Zone(thisSurf.Zone).spaceIndexes(numSpaces);
    2948         2013 :                 thisSurf.spaceNum = lastSpaceForZone;
    2949         2013 :                 if ((thisSurf.ExtBoundCond == unreconciledZoneSurface) && (thisSurf.Name.substr(0, 3) == "iz-")) {
    2950           12 :                     if (state.dataHeatBal->Zone(thisSurf.Zone).numSpaces > 1) {
    2951              :                         // Only trigger warning if the spaceless surface is an autogenerated interzone surface
    2952            4 :                         ShowWarningError(state,
    2953            4 :                                          format("{}Surface=\"{}\" has Outside Boundary Condition=Zone, but Zone=\"{}\" has more than 1 Space.",
    2954              :                                                 RoutineName,
    2955            2 :                                                 thisSurf.Name.substr(3),
    2956            2 :                                                 thisSurf.ZoneName));
    2957            4 :                         ShowContinueError(state,
    2958            4 :                                           format("Auto-generated surface=\"{}\" will be assigned to Space=\"{}\"",
    2959            2 :                                                  thisSurf.Name,
    2960            2 :                                                  state.dataHeatBal->space(thisSurf.spaceNum).Name));
    2961            6 :                         ShowContinueError(state, "Use Outside Boundary Condition = Space to specify the exact Space for the outside boundary.");
    2962              :                     }
    2963              :                 }
    2964              :             }
    2965              :         }
    2966          224 :     }
    2967              : 
    2968          224 :     void createSpaceSurfaceLists(EnergyPlusData &state)
    2969              :     {
    2970              :         static constexpr std::string_view RoutineName("createSpaceSurfaceLists: ");
    2971              :         // Build Space surface lists now that all of the surface sorting is complete
    2972         2484 :         for (int surfNum = 1; surfNum <= state.dataSurface->TotSurfaces; ++surfNum) {
    2973         2260 :             auto &thisSurf = state.dataSurface->Surface(surfNum);
    2974         2260 :             if (!thisSurf.HeatTransSurf) {
    2975           84 :                 continue; // ignore shading surfaces
    2976              :             }
    2977              :             // Add to Space's list of surfaces
    2978         2176 :             state.dataHeatBal->space(thisSurf.spaceNum).surfaces.emplace_back(surfNum);
    2979              :         }
    2980          599 :         for (int spaceNum = 1; spaceNum <= state.dataGlobal->numSpaces; ++spaceNum) {
    2981          375 :             if (int(state.dataHeatBal->space(spaceNum).surfaces.size()) == 0) {
    2982            3 :                 ShowWarningError(state, format("{}Space={} has no surfaces.", RoutineName, state.dataHeatBal->space(spaceNum).Name));
    2983              :             }
    2984              :         }
    2985          224 :     }
    2986              : 
    2987          224 :     void setSurfaceFirstLast(EnergyPlusData &state)
    2988              :     {
    2989              :         // Set Zone and Space Surface First/Last Pointers
    2990              :         // Space surface lists have been built earlier in createSpaceSurfaceLists
    2991          578 :         for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
    2992          729 :             for (int spaceNum : state.dataHeatBal->Zone(ZoneNum).spaceIndexes) {
    2993          375 :                 auto &thisSpace = state.dataHeatBal->space(spaceNum);
    2994         2551 :                 for (int SurfNum : thisSpace.surfaces) {
    2995         2176 :                     auto &surf = state.dataSurface->Surface(SurfNum);
    2996         2176 :                     if (thisSpace.AllSurfaceFirst == 0) {
    2997          372 :                         thisSpace.AllSurfaceFirst = SurfNum;
    2998              :                     }
    2999         2176 :                     thisSpace.AllSurfaceLast = SurfNum;
    3000              : 
    3001         2176 :                     if (surf.IsAirBoundarySurf) {
    3002           42 :                         surf.HeatTransSurf = false;
    3003           42 :                         continue;
    3004              :                     }
    3005              :                     // Non window surfaces are grouped next within each space
    3006         2134 :                     if (thisSpace.HTSurfaceFirst == 0) {
    3007          371 :                         thisSpace.HTSurfaceFirst = SurfNum;
    3008          371 :                         thisSpace.OpaqOrIntMassSurfaceFirst = SurfNum;
    3009          371 :                         thisSpace.OpaqOrWinSurfaceFirst = SurfNum;
    3010              :                     }
    3011         2134 :                     thisSpace.HTSurfaceLast = SurfNum;
    3012              : 
    3013              :                     // Window surfaces are grouped next within each space
    3014         2134 :                     if ((surf.Class == DataSurfaces::SurfaceClass::Window) || (surf.Class == DataSurfaces::SurfaceClass::GlassDoor) ||
    3015         1945 :                         (surf.Class == DataSurfaces::SurfaceClass::TDD_Diffuser)) {
    3016          195 :                         if (thisSpace.WindowSurfaceFirst == 0) {
    3017          112 :                             thisSpace.WindowSurfaceFirst = SurfNum;
    3018              :                         }
    3019          195 :                         thisSpace.WindowSurfaceLast = SurfNum;
    3020         1939 :                     } else if (surf.Class != DataSurfaces::SurfaceClass::TDD_Dome) {
    3021         1932 :                         thisSpace.OpaqOrIntMassSurfaceLast = SurfNum;
    3022              :                     }
    3023              : 
    3024              :                     // TDDDome surfaces are grouped last within each space
    3025         2134 :                     if (surf.Class == DataSurfaces::SurfaceClass::TDD_Dome) {
    3026            7 :                         if (thisSpace.TDDDomeFirst == 0) {
    3027            5 :                             thisSpace.TDDDomeFirst = SurfNum;
    3028              :                         }
    3029            7 :                         thisSpace.TDDDomeLast = SurfNum;
    3030              :                     } else {
    3031         2127 :                         thisSpace.OpaqOrWinSurfaceLast = SurfNum;
    3032              :                     }
    3033          375 :                 }
    3034          375 :                 state.dataHeatBal->Zone(ZoneNum).AllSurfaceLast = thisSpace.AllSurfaceLast;
    3035          354 :             }
    3036          354 :             int firstSpaceNum = state.dataHeatBal->Zone(ZoneNum).spaceIndexes(1);
    3037          354 :             state.dataHeatBal->Zone(ZoneNum).AllSurfaceFirst = state.dataHeatBal->space(firstSpaceNum).AllSurfaceFirst;
    3038              :         }
    3039          224 :     }
    3040              : 
    3041          235 :     void checkSubSurfAzTiltNorm(EnergyPlusData &state,
    3042              :                                 SurfaceData &baseSurface, // Base surface data (in)
    3043              :                                 SurfaceData &subSurface,  // Subsurface data (in)
    3044              :                                 bool &surfaceError        // True if surface azimuths or tilts differ by more than error tolerance
    3045              :     )
    3046              :     {
    3047          235 :         bool sameSurfNormal = false; // True if surface has the same surface normal within tolerance
    3048          235 :         Real64 constexpr warningTolerance = 30.0;
    3049          235 :         Real64 constexpr errorTolerance = 90.0;
    3050              : 
    3051          235 :         surfaceError = false; // True if surface has the same surface normal within tolerance
    3052              : 
    3053              :         // Check if base surface and subsurface have the same normal
    3054          235 :         Vectors::CompareTwoVectors(baseSurface.NewellSurfaceNormalVector, subSurface.NewellSurfaceNormalVector, sameSurfNormal, 0.001);
    3055          235 :         if (sameSurfNormal) { // copy lcs vectors
    3056              :                               // Prior logic tested for azimuth difference < 30 and then skipped this - this caused large diffs in
    3057              :                               // CmplxGlz_MeasuredDeflectionAndShading Restoring that check here but will require further investigation (MJW Dec 2015)
    3058              :                               // if (std::abs(baseSurface.Azimuth - subSurface.Azimuth) > warningTolerance) {
    3059          223 :             subSurface.lcsx = baseSurface.lcsx;
    3060          223 :             subSurface.lcsy = baseSurface.lcsy;
    3061          223 :             subSurface.lcsz = baseSurface.lcsz;
    3062              :             // }
    3063              :         } else {
    3064           12 :             bool baseSurfHoriz = false; // True if base surface is near horizontal
    3065              :             // // Not sure what this does, but keeping for now (MJW Dec 2015)
    3066              :             // if (std::abs(subSurface.Azimuth - 360.0) < 0.01) {
    3067              :             //     subSurface.Azimuth = 360.0 - subSurface.Azimuth;
    3068              :             // }
    3069              :             // if (std::abs(baseSurface.Azimuth - 360.0) < 0.01) {
    3070              :             //     baseSurface.Azimuth = 360.0 - baseSurface.Azimuth;
    3071              :             // }
    3072              : 
    3073              :             // Is base surface horizontal? If so, ignore azimuth differences
    3074           12 :             if (std::abs(baseSurface.Tilt) <= 1.0e-5 || std::abs(baseSurface.Tilt - 180.0) <= 1.0e-5) {
    3075            2 :                 baseSurfHoriz = true;
    3076              :             }
    3077              : 
    3078           24 :             if (((General::rotAzmDiffDeg(baseSurface.Azimuth, subSurface.Azimuth) > errorTolerance) && !baseSurfHoriz) ||
    3079           12 :                 (std::abs(baseSurface.Tilt - subSurface.Tilt) > errorTolerance)) {
    3080            1 :                 surfaceError = true;
    3081            2 :                 ShowSevereError(
    3082              :                     state,
    3083            2 :                     format("checkSubSurfAzTiltNorm: Outward facing angle of subsurface differs more than {:.1R} degrees from base surface.",
    3084              :                            errorTolerance));
    3085            2 :                 ShowContinueError(state,
    3086            2 :                                   format("Subsurface=\"{}\" Tilt = {:.1R}  Azimuth = {:.1R}", subSurface.Name, subSurface.Tilt, subSurface.Azimuth));
    3087            2 :                 ShowContinueError(
    3088            2 :                     state, format("Base surface=\"{}\" Tilt = {:.1R}  Azimuth = {:.1R}", baseSurface.Name, baseSurface.Tilt, baseSurface.Azimuth));
    3089           20 :             } else if (((General::rotAzmDiffDeg(baseSurface.Azimuth, subSurface.Azimuth) > warningTolerance) && !baseSurfHoriz) ||
    3090            9 :                        (std::abs(baseSurface.Tilt - subSurface.Tilt) > warningTolerance)) {
    3091            5 :                 ++state.dataSurfaceGeometry->checkSubSurfAzTiltNormErrCount;
    3092            5 :                 if (state.dataSurfaceGeometry->checkSubSurfAzTiltNormErrCount == 1 && !state.dataGlobal->DisplayExtraWarnings) {
    3093           10 :                     ShowWarningError(state,
    3094           10 :                                      format("checkSubSurfAzTiltNorm: Some Outward Facing angles of subsurfaces differ more than {:.1R} "
    3095              :                                             "degrees from base surface.",
    3096              :                                             warningTolerance));
    3097           15 :                     ShowContinueError(state, "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on individual surfaces.");
    3098              :                 }
    3099            5 :                 if (state.dataGlobal->DisplayExtraWarnings) {
    3100            0 :                     ShowWarningError(
    3101              :                         state,
    3102            0 :                         format("checkSubSurfAzTiltNorm: Outward facing angle of subsurface differs more than {:.1R} degrees from base surface.",
    3103              :                                warningTolerance));
    3104            0 :                     ShowContinueError(
    3105            0 :                         state, format("Subsurface=\"{}\" Tilt = {:.1R}  Azimuth = {:.1R}", subSurface.Name, subSurface.Tilt, subSurface.Azimuth));
    3106            0 :                     ShowContinueError(
    3107              :                         state,
    3108            0 :                         format("Base surface=\"{}\" Tilt = {:.1R}  Azimuth = {:.1R}", baseSurface.Name, baseSurface.Tilt, baseSurface.Azimuth));
    3109              :                 }
    3110              :             }
    3111              :         }
    3112          235 :     }
    3113              : 
    3114          268 :     void GetGeometryParameters(EnergyPlusData &state, bool &ErrorsFound) // set to true if errors found during input
    3115              :     {
    3116              : 
    3117              :         // SUBROUTINE INFORMATION:
    3118              :         //       AUTHOR         Linda Lawrie
    3119              :         //       DATE WRITTEN   May 2000
    3120              : 
    3121              :         // PURPOSE OF THIS SUBROUTINE:
    3122              :         // This subroutine reads in the "Surface Geometry" parameters, verifies them,
    3123              :         // and sets "global" variables that will tell other routines how the surface
    3124              :         // vertices are expected in input.
    3125              : 
    3126              :         // REFERENCES:
    3127              :         // GlobalGeometryRules Definition
    3128              :         // GlobalGeometryRules,
    3129              :         //      \required-object
    3130              :         //      \unique-object
    3131              :         //  A1, \field Starting Vertex Position
    3132              :         //      \required-field
    3133              :         //      \note Specified as entry for a 4 sided surface/rectangle
    3134              :         //      \note Surfaces are specified as viewed from outside the surface
    3135              :         //      \note Shading surfaces as viewed from behind.  (towards what they are shading)
    3136              :         //      \type choice
    3137              :         //      \key UpperLeftCorner
    3138              :         //      \key LowerLeftCorner
    3139              :         //      \key UpperRightCorner
    3140              :         //      \key LowerRightCorner
    3141              :         //  A2, \field Vertex Entry Direction
    3142              :         //      \required-field
    3143              :         //      \type choice
    3144              :         //      \key Counterclockwise
    3145              :         //      \key Clockwise
    3146              :         //  A3, \field Coordinate System
    3147              :         //      \required-field
    3148              :         //      \note relative -- coordinates are entered relative to zone origin
    3149              :         //      \note world -- all coordinates entered are "absolute" for this facility
    3150              :         //      \note absolute -- same as world
    3151              :         //      \type choice
    3152              :         //      \key Relative
    3153              :         //      \key World
    3154              :         //      \key Absolute
    3155              :         //  A4, \field Daylighting Reference Point Coordinate System
    3156              :         //      \type choice
    3157              :         //      \key Relative
    3158              :         //      \default Relative
    3159              :         //      \note Relative -- coordinates are entered relative to zone origin
    3160              :         //      \key World
    3161              :         //      \note World -- all coordinates entered are "absolute" for this facility
    3162              :         //      \key Absolute
    3163              :         //      \note absolute -- same as world
    3164              :         //  A5; \field Rectangular Surface Coordinate System
    3165              :         //      \type choice
    3166              :         //      \key Relative
    3167              :         //      \default Relative
    3168              :         //      \note Relative -- Starting corner is entered relative to zone origin
    3169              :         //      \key World
    3170              :         //      \note World -- Starting corner is entered in "absolute"
    3171              :         //      \key Absolute
    3172              :         //      \note absolute -- same as world
    3173              : 
    3174              :         // SUBROUTINE PARAMETER DEFINITIONS:
    3175          268 :         static Array1D_string const FlCorners(4, {"UpperLeftCorner", "LowerLeftCorner", "LowerRightCorner", "UpperRightCorner"});
    3176              : 
    3177              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    3178          268 :         Array1D_string GAlphas(5);
    3179          268 :         Array1D<Real64> GNum(1);
    3180              : 
    3181          268 :         auto &s_ipsc = state.dataIPShortCut;
    3182              : 
    3183          268 :         s_ipsc->cCurrentModuleObject = "GlobalGeometryRules";
    3184          268 :         int NumStmt = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
    3185          268 :         std::string OutMsg = " Surface Geometry,";
    3186              : 
    3187              :         {
    3188          268 :             int const SELECT_CASE_var = NumStmt;
    3189              : 
    3190          268 :             if (SELECT_CASE_var == 1) {
    3191              :                 int NNum;
    3192              :                 int IOStat;
    3193              :                 int NAlphas;
    3194              :                 // This is the valid case
    3195          804 :                 state.dataInputProcessing->inputProcessor->getObjectItem(state,
    3196          268 :                                                                          s_ipsc->cCurrentModuleObject,
    3197              :                                                                          1,
    3198              :                                                                          GAlphas,
    3199              :                                                                          NAlphas,
    3200              :                                                                          GNum,
    3201              :                                                                          NNum,
    3202              :                                                                          IOStat,
    3203          268 :                                                                          s_ipsc->lNumericFieldBlanks,
    3204          268 :                                                                          s_ipsc->lAlphaFieldBlanks,
    3205          268 :                                                                          s_ipsc->cAlphaFieldNames,
    3206          268 :                                                                          s_ipsc->cNumericFieldNames);
    3207              : 
    3208              :                 // Even though these will be validated, set defaults in case error here -- wont
    3209              :                 // cause aborts in later surface gets (hopefully)
    3210          268 :                 state.dataSurface->Corner = DataSurfaces::UpperLeftCorner;
    3211          268 :                 state.dataSurface->WorldCoordSystem = true;
    3212          268 :                 state.dataSurface->CCW = true;
    3213              : 
    3214          268 :                 int Found = Util::FindItem(GAlphas(1), FlCorners, 4);
    3215          268 :                 if (Found == 0) {
    3216            0 :                     ShowSevereError(state, format("{}: Invalid {}={}", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaFieldNames(1), GAlphas(1)));
    3217            0 :                     ErrorsFound = true;
    3218              :                 } else {
    3219          268 :                     state.dataSurface->Corner = Found;
    3220          268 :                     OutMsg += FlCorners(state.dataSurface->Corner) + ',';
    3221              :                 }
    3222              : 
    3223          268 :                 bool OK = false;
    3224          268 :                 if (Util::SameString(GAlphas(2), "CCW") || Util::SameString(GAlphas(2), "Counterclockwise")) {
    3225          268 :                     state.dataSurface->CCW = true;
    3226          268 :                     OutMsg += "Counterclockwise,";
    3227          268 :                     OK = true;
    3228              :                 }
    3229          268 :                 if (Util::SameString(GAlphas(2), "CW") || Util::SameString(GAlphas(2), "Clockwise")) {
    3230            0 :                     state.dataSurface->CCW = false;
    3231            0 :                     OutMsg += "Clockwise,";
    3232            0 :                     OK = true;
    3233              :                 }
    3234          268 :                 if (!OK) {
    3235            0 :                     ShowSevereError(state, format("{}: Invalid {}={}", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaFieldNames(2), GAlphas(2)));
    3236            0 :                     ErrorsFound = true;
    3237              :                 }
    3238              : 
    3239          268 :                 OK = false;
    3240          268 :                 if (Util::SameString(GAlphas(3), "World") || Util::SameString(GAlphas(3), "Absolute")) {
    3241          102 :                     state.dataSurface->WorldCoordSystem = true;
    3242          102 :                     OutMsg += "WorldCoordinateSystem,";
    3243          102 :                     OK = true;
    3244              :                 }
    3245          268 :                 if (Util::SameString(GAlphas(3), "Relative")) {
    3246          166 :                     state.dataSurface->WorldCoordSystem = false;
    3247          166 :                     OutMsg += "RelativeCoordinateSystem,";
    3248          166 :                     OK = true;
    3249              :                 }
    3250          268 :                 if (!OK) {
    3251            0 :                     ShowWarningError(state, format("{}: Invalid {}={}", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaFieldNames(3), GAlphas(3)));
    3252            0 :                     ShowContinueError(state, format("{} defaults to \"WorldCoordinateSystem\"", s_ipsc->cAlphaFieldNames(3)));
    3253            0 :                     state.dataSurface->WorldCoordSystem = true;
    3254            0 :                     OutMsg += "WorldCoordinateSystem,";
    3255              :                 }
    3256              : 
    3257          268 :                 OK = false;
    3258          268 :                 if (Util::SameString(GAlphas(4), "World") || Util::SameString(GAlphas(4), "Absolute")) {
    3259            8 :                     state.dataSurface->DaylRefWorldCoordSystem = true;
    3260            8 :                     OutMsg += "WorldCoordinateSystem,";
    3261            8 :                     OK = true;
    3262              :                 }
    3263          268 :                 if (Util::SameString(GAlphas(4), "Relative") || GAlphas(4).empty()) {
    3264          260 :                     state.dataSurface->DaylRefWorldCoordSystem = false;
    3265          260 :                     OutMsg += "RelativeCoordinateSystem,";
    3266          260 :                     OK = true;
    3267              :                 }
    3268          268 :                 if (!OK) {
    3269            0 :                     ShowWarningError(state, format("{}: Invalid {}={}", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaFieldNames(4), GAlphas(4)));
    3270            0 :                     ShowContinueError(state, format("{} defaults to \"RelativeToZoneOrigin\"", s_ipsc->cAlphaFieldNames(4)));
    3271            0 :                     state.dataSurface->DaylRefWorldCoordSystem = false;
    3272            0 :                     OutMsg += "RelativeToZoneOrigin,";
    3273              :                 }
    3274              : 
    3275          268 :                 OK = false;
    3276          268 :                 if (Util::SameString(GAlphas(5), "World") || Util::SameString(GAlphas(5), "Absolute")) {
    3277            2 :                     state.dataSurfaceGeometry->RectSurfRefWorldCoordSystem = true;
    3278            2 :                     OutMsg += "WorldCoordinateSystem";
    3279            2 :                     OK = true;
    3280              :                 }
    3281          268 :                 if (Util::SameString(GAlphas(5), "Relative") || GAlphas(5).empty()) {
    3282          266 :                     state.dataSurfaceGeometry->RectSurfRefWorldCoordSystem = false;
    3283          266 :                     OutMsg += "RelativeToZoneOrigin";
    3284          266 :                     OK = true;
    3285              :                 }
    3286          268 :                 if (!OK) {
    3287            0 :                     ShowWarningError(state, format("{}: Invalid {}={}", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaFieldNames(5), GAlphas(5)));
    3288            0 :                     ShowContinueError(state, format("{} defaults to \"RelativeToZoneOrigin\"", s_ipsc->cAlphaFieldNames(5)));
    3289            0 :                     state.dataSurfaceGeometry->RectSurfRefWorldCoordSystem = false;
    3290            0 :                     OutMsg += "RelativeToZoneOrigin";
    3291              :                 }
    3292              : 
    3293            0 :             } else if (SELECT_CASE_var == 0) {
    3294              : 
    3295            0 :                 ShowSevereError(state, format("{}: Required object not found.", s_ipsc->cCurrentModuleObject));
    3296            0 :                 OutMsg += "None found in input";
    3297            0 :                 ErrorsFound = true;
    3298              : 
    3299              :             } else {
    3300              : 
    3301            0 :                 ShowSevereError(state, format("{}: Too many objects entered.  Only one allowed.", s_ipsc->cCurrentModuleObject));
    3302            0 :                 ErrorsFound = true;
    3303              :             }
    3304              :         }
    3305              : 
    3306          268 :         if (!state.dataSurface->WorldCoordSystem) {
    3307          166 :             if (state.dataSurface->DaylRefWorldCoordSystem) {
    3308            0 :                 ShowWarningError(state, format("{}: Potential mismatch of coordinate specifications.", s_ipsc->cCurrentModuleObject));
    3309            0 :                 ShowContinueError(state, format("{}=\"{}\"; while ", s_ipsc->cAlphaFieldNames(3), GAlphas(3)));
    3310            0 :                 ShowContinueError(state, format("{}=\"{}\".", s_ipsc->cAlphaFieldNames(4), GAlphas(4)));
    3311              :             }
    3312          166 :             if (state.dataSurfaceGeometry->RectSurfRefWorldCoordSystem) {
    3313            0 :                 ShowWarningError(state, format("{}: Potential mismatch of coordinate specifications.", s_ipsc->cCurrentModuleObject));
    3314            0 :                 ShowContinueError(state, format("{}=\"{}\"; while ", s_ipsc->cAlphaFieldNames(3), GAlphas(3)));
    3315            0 :                 ShowContinueError(state, format("{}=\"{}\".", s_ipsc->cAlphaFieldNames(5), GAlphas(5)));
    3316              :             }
    3317              :         } else {
    3318          102 :             bool RelWarning = false;
    3319          270 :             for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
    3320          168 :                 if (state.dataHeatBal->Zone(ZoneNum).OriginX != 0.0) {
    3321           10 :                     RelWarning = true;
    3322              :                 }
    3323          168 :                 if (state.dataHeatBal->Zone(ZoneNum).OriginY != 0.0) {
    3324           10 :                     RelWarning = true;
    3325              :                 }
    3326          168 :                 if (state.dataHeatBal->Zone(ZoneNum).OriginZ != 0.0) {
    3327            0 :                     RelWarning = true;
    3328              :                 }
    3329              :             }
    3330          102 :             if (RelWarning && !state.dataSurfaceGeometry->RectSurfRefWorldCoordSystem) {
    3331            4 :                 ShowWarningError(state,
    3332            4 :                                  format("{}: Potential mismatch of coordinate specifications. Note that the rectangular surfaces are relying on the "
    3333              :                                         "default SurfaceGeometry for 'Relative to zone' coordinate.",
    3334            2 :                                         s_ipsc->cCurrentModuleObject));
    3335            2 :                 ShowContinueError(state, format("{}=\"{}\"; while ", s_ipsc->cAlphaFieldNames(3), GAlphas(3)));
    3336            2 :                 if (GAlphas(5) == "RELATIVE") {
    3337            2 :                     ShowContinueError(state, format("{}=\"{}\".", s_ipsc->cAlphaFieldNames(5), GAlphas(5)));
    3338            0 :                 } else if (GAlphas(5) != "ABSOLUTE") {
    3339            0 :                     ShowContinueError(state, format("{}=\"defaults to RELATIVE\".", s_ipsc->cAlphaFieldNames(5)));
    3340              :                 }
    3341              :             }
    3342              :         }
    3343              : 
    3344          268 :         print(state.files.eio,
    3345              :               "! <Surface Geometry>,Starting Corner,Vertex Input Direction,Coordinate System,Daylight Reference "
    3346              :               "Point Coordinate System,Rectangular (Simple) Surface Coordinate System\n");
    3347          268 :         print(state.files.eio, "{}\n", OutMsg);
    3348          268 :     }
    3349              : 
    3350          227 :     void GetDetShdSurfaceData(EnergyPlusData &state,
    3351              :                               bool &ErrorsFound,          // Error flag indicator (true if errors found)
    3352              :                               int &SurfNum,               // Count of Current SurfaceNumber
    3353              :                               int const TotDetachedFixed, // Number of Fixed Detached Shading Surfaces to obtain
    3354              :                               int const TotDetachedBldg   // Number of Building Detached Shading Surfaces to obtain
    3355              :     )
    3356              :     {
    3357              :         // SUBROUTINE INFORMATION:
    3358              :         //       AUTHOR         Linda Lawrie
    3359              :         //       DATE WRITTEN   May 2000
    3360              : 
    3361              :         // PURPOSE OF THIS SUBROUTINE:
    3362              :         // This subroutine gets the Detached Shading Surface Data,
    3363              :         // checks it for errors, etc.
    3364              : 
    3365              :         static constexpr std::string_view routineName = "GetDetShdSurfaceData";
    3366              :         // SUBROUTINE PARAMETER DEFINITIONS:
    3367          227 :         static Array1D_string const cModuleObjects(2, {"Shading:Site:Detailed", "Shading:Building:Detailed"});
    3368              : 
    3369              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    3370              :         int IOStat;     // IO Status when calling get input subroutine
    3371              :         int NumAlphas;  // Number of material alpha names being passed
    3372              :         int NumNumbers; // Number of material properties being passed
    3373              :         int Loop;
    3374              :         int ItemsToGet;
    3375              :         SurfaceClass ClassItem;
    3376              :         int numSides;
    3377              :         Real64 SchedMinValue;
    3378              :         Real64 SchedMaxValue;
    3379              : 
    3380          227 :         auto &s_ipsc = state.dataIPShortCut;
    3381              : 
    3382          227 :         if ((TotDetachedFixed + TotDetachedBldg) > 0 && state.dataHeatBal->SolarDistribution == DataHeatBalance::Shadowing::Minimal) {
    3383            0 :             ShowWarningError(state, "Detached shading effects are ignored when Solar Distribution = MinimalShadowing");
    3384              :         }
    3385              : 
    3386          227 :         if ((TotDetachedFixed + TotDetachedBldg) == 0) {
    3387          218 :             return;
    3388              :         }
    3389              : 
    3390           27 :         for (int Item = 1; Item <= 2; ++Item) {
    3391              : 
    3392           18 :             s_ipsc->cCurrentModuleObject = cModuleObjects(Item);
    3393           18 :             if (Item == 1) {
    3394            9 :                 ItemsToGet = TotDetachedFixed;
    3395            9 :                 ClassItem = SurfaceClass::Detached_F;
    3396              :             } else { // IF (Item == 2) THEN
    3397            9 :                 ItemsToGet = TotDetachedBldg;
    3398            9 :                 ClassItem = SurfaceClass::Detached_B;
    3399              :             }
    3400              : 
    3401           18 :             state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, s_ipsc->cCurrentModuleObject, Loop, NumAlphas, NumNumbers);
    3402           18 :             if (NumAlphas != 2) {
    3403            0 :                 ShowSevereError(
    3404              :                     state,
    3405            0 :                     format("{}: Object Definition indicates not = 2 Alpha Objects, Number Indicated={}", s_ipsc->cCurrentModuleObject, NumAlphas));
    3406            0 :                 ErrorsFound = true;
    3407              :             }
    3408              : 
    3409           35 :             for (Loop = 1; Loop <= ItemsToGet; ++Loop) {
    3410           34 :                 state.dataInputProcessing->inputProcessor->getObjectItem(state,
    3411           17 :                                                                          s_ipsc->cCurrentModuleObject,
    3412              :                                                                          Loop,
    3413           17 :                                                                          s_ipsc->cAlphaArgs,
    3414              :                                                                          NumAlphas,
    3415           17 :                                                                          s_ipsc->rNumericArgs,
    3416              :                                                                          NumNumbers,
    3417              :                                                                          IOStat,
    3418           17 :                                                                          s_ipsc->lNumericFieldBlanks,
    3419           17 :                                                                          s_ipsc->lAlphaFieldBlanks,
    3420           17 :                                                                          s_ipsc->cAlphaFieldNames,
    3421           17 :                                                                          s_ipsc->cNumericFieldNames);
    3422              : 
    3423           17 :                 ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
    3424              : 
    3425           34 :                 if (GlobalNames::VerifyUniqueInterObjectName(state,
    3426           17 :                                                              state.dataSurfaceGeometry->UniqueSurfaceNames,
    3427           17 :                                                              s_ipsc->cAlphaArgs(1),
    3428           17 :                                                              s_ipsc->cCurrentModuleObject,
    3429           17 :                                                              s_ipsc->cAlphaFieldNames(1),
    3430              :                                                              ErrorsFound)) {
    3431            0 :                     continue;
    3432              :                 }
    3433              : 
    3434           17 :                 ++SurfNum;
    3435              : 
    3436           17 :                 auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    3437           17 :                 surfTemp.Name = s_ipsc->cAlphaArgs(1); // Set the Surface Name in the Derived Type
    3438           17 :                 surfTemp.Class = ClassItem;
    3439           17 :                 surfTemp.HeatTransSurf = false;
    3440           17 :                 surfTemp.ExtSolar = true;
    3441              :                 // Base transmittance of a shadowing (sub)surface
    3442              : 
    3443           17 :                 if (s_ipsc->lAlphaFieldBlanks(2)) {
    3444            5 :                     surfTemp.shadowSurfSched =
    3445              :                         nullptr; // Leaving this as nullptr rather than making AlwaysOff because the uses and tests are too varied
    3446           12 :                 } else if ((surfTemp.shadowSurfSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(2))) == nullptr) {
    3447            0 :                     ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2));
    3448            0 :                     ErrorsFound = true;
    3449           12 :                 } else if (!surfTemp.shadowSurfSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 1.0)) {
    3450            1 :                     Sched::ShowSevereBadMinMax(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2), Clusive::In, 0.0, Clusive::In, 1.0);
    3451            1 :                     ErrorsFound = true;
    3452              :                 } else {
    3453           11 :                     SchedMinValue = surfTemp.shadowSurfSched->getMinVal(state);
    3454           11 :                     surfTemp.SchedMinValue = SchedMinValue;
    3455           11 :                     SchedMaxValue = surfTemp.shadowSurfSched->getCurrentVal();
    3456           11 :                     if (SchedMinValue == 1.0) {
    3457              :                         // Set transparent for now, check for EMS actuators later in SolarShading::resetShadingSurfaceTransparency
    3458            1 :                         surfTemp.IsTransparent = true;
    3459              :                     }
    3460           11 :                     if (SchedMinValue < 0.0) {
    3461            0 :                         ShowSevereError(state,
    3462            0 :                                         format("{}=\"{}\", {}=\"{}\", has schedule values < 0.",
    3463            0 :                                                s_ipsc->cCurrentModuleObject,
    3464            0 :                                                surfTemp.Name,
    3465            0 :                                                s_ipsc->cAlphaFieldNames(2),
    3466            0 :                                                s_ipsc->cAlphaArgs(2)));
    3467            0 :                         ShowContinueError(state, "...Schedule values < 0 have no meaning for shading elements.");
    3468              :                     }
    3469           11 :                     if (SchedMaxValue > 0.0) {
    3470            2 :                         state.dataSolarShading->anyScheduledShadingSurface = true;
    3471              :                     }
    3472           11 :                     if (SchedMaxValue > 1.0) {
    3473            0 :                         ShowSevereError(state,
    3474            0 :                                         format("{}=\"{}\", {}=\"{}\", has schedule values > 1.",
    3475            0 :                                                s_ipsc->cCurrentModuleObject,
    3476            0 :                                                surfTemp.Name,
    3477            0 :                                                s_ipsc->cAlphaFieldNames(2),
    3478            0 :                                                s_ipsc->cAlphaArgs(2)));
    3479            0 :                         ShowContinueError(state, "...Schedule values > 1 have no meaning for shading elements.");
    3480              :                     }
    3481           11 :                     if (std::abs(SchedMinValue - SchedMaxValue) > Constant::OneMillionth) {
    3482            0 :                         state.dataSurface->ShadingTransmittanceVaries = true;
    3483              :                     }
    3484              :                 }
    3485           17 :                 if (s_ipsc->lNumericFieldBlanks(1) || s_ipsc->rNumericArgs(1) == Constant::AutoCalculate) {
    3486            0 :                     numSides = (NumNumbers - 1) / 3;
    3487            0 :                     surfTemp.Sides = numSides;
    3488            0 :                     if (mod(NumNumbers - 1, 3) != 0) {
    3489            0 :                         ShowWarningError(state,
    3490            0 :                                          format("{}=\"{}\", {}",
    3491            0 :                                                 s_ipsc->cCurrentModuleObject,
    3492            0 :                                                 surfTemp.Name,
    3493            0 :                                                 format("{} not even multiple of 3. Will read in {}", s_ipsc->cNumericFieldNames(1), surfTemp.Sides)));
    3494              :                     }
    3495            0 :                     if (numSides < 3) {
    3496            0 :                         ShowSevereError(state,
    3497            0 :                                         format("{}=\"{}\", {} (autocalculate) must be >= 3. Only {} provided.",
    3498            0 :                                                s_ipsc->cCurrentModuleObject,
    3499            0 :                                                surfTemp.Name,
    3500            0 :                                                s_ipsc->cNumericFieldNames(1),
    3501            0 :                                                surfTemp.Sides));
    3502            0 :                         ErrorsFound = true;
    3503            0 :                         continue;
    3504              :                     }
    3505              :                 } else {
    3506           17 :                     numSides = (NumNumbers - 1) / 3;
    3507           17 :                     surfTemp.Sides = s_ipsc->rNumericArgs(1);
    3508           17 :                     if (numSides > surfTemp.Sides) {
    3509            0 :                         ShowWarningError(state,
    3510            0 :                                          format("{}=\"{}\", field {}={}",
    3511            0 :                                                 s_ipsc->cCurrentModuleObject,
    3512            0 :                                                 surfTemp.Name,
    3513            0 :                                                 s_ipsc->cNumericFieldNames(1),
    3514            0 :                                                 fmt::to_string(surfTemp.Sides)));
    3515            0 :                         ShowContinueError(
    3516            0 :                             state, format("...but {} were entered. Only the indicated {} will be used.", numSides, s_ipsc->cNumericFieldNames(1)));
    3517              :                     }
    3518              :                 }
    3519           17 :                 surfTemp.Vertex.allocate(surfTemp.Sides);
    3520           68 :                 GetVertices(state, SurfNum, surfTemp.Sides, s_ipsc->rNumericArgs({2, _}));
    3521           17 :                 CheckConvexity(state, SurfNum, surfTemp.Sides);
    3522           17 :                 if (state.dataReportFlag->MakeMirroredDetachedShading) {
    3523           17 :                     MakeMirrorSurface(state, SurfNum);
    3524              :                 }
    3525              :             }
    3526              : 
    3527              :         } // Item Loop
    3528           17 :     }
    3529              : 
    3530          227 :     void GetRectDetShdSurfaceData(EnergyPlusData &state,
    3531              :                                   bool &ErrorsFound,              // Error flag indicator (true if errors found)
    3532              :                                   int &SurfNum,                   // Count of Current SurfaceNumber
    3533              :                                   int const TotRectDetachedFixed, // Number of Fixed Detached Shading Surfaces to obtain
    3534              :                                   int const TotRectDetachedBldg   // Number of Building Detached Shading Surfaces to obtain
    3535              :     )
    3536              :     {
    3537              : 
    3538              :         // SUBROUTINE INFORMATION:
    3539              :         //       AUTHOR         Linda Lawrie
    3540              :         //       DATE WRITTEN   January 2009
    3541              : 
    3542              :         // PURPOSE OF THIS SUBROUTINE:
    3543              :         // Gets the simple, rectangular detached surfaces.
    3544              : 
    3545              :         // SUBROUTINE PARAMETER DEFINITIONS:
    3546          227 :         static Array1D_string const cModuleObjects(2, {"Shading:Site", "Shading:Building"});
    3547              : 
    3548              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    3549              :         int IOStat;     // IO Status when calling get input subroutine
    3550              :         int NumAlphas;  // Number of material alpha names being passed
    3551              :         int NumNumbers; // Number of material properties being passed
    3552              :         int Loop;
    3553              :         int ItemsToGet;
    3554              :         SurfaceClass ClassItem;
    3555              : 
    3556          227 :         auto &s_ipsc = state.dataIPShortCut;
    3557              : 
    3558          227 :         if ((TotRectDetachedFixed + TotRectDetachedBldg) > 0 && state.dataHeatBal->SolarDistribution == DataHeatBalance::Shadowing::Minimal) {
    3559            0 :             ShowWarningError(state, "Detached shading effects are ignored when Solar Distribution = MinimalShadowing");
    3560              :         }
    3561              : 
    3562          227 :         if (TotRectDetachedFixed + TotRectDetachedBldg == 0) {
    3563          226 :             return;
    3564              :         }
    3565            3 :         for (int Item = 1; Item <= 2; ++Item) {
    3566              : 
    3567            2 :             s_ipsc->cCurrentModuleObject = cModuleObjects(Item);
    3568            2 :             if (Item == 1) {
    3569            1 :                 ItemsToGet = TotRectDetachedFixed;
    3570            1 :                 ClassItem = SurfaceClass::Detached_F;
    3571              :             } else { // IF (Item == 2) THEN
    3572            1 :                 ItemsToGet = TotRectDetachedBldg;
    3573            1 :                 ClassItem = SurfaceClass::Detached_B;
    3574              :             }
    3575              : 
    3576            2 :             state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, s_ipsc->cCurrentModuleObject, Loop, NumAlphas, NumNumbers);
    3577            2 :             if (NumAlphas != 1) {
    3578            0 :                 ShowSevereError(
    3579              :                     state,
    3580            0 :                     format("{}: Object Definition indicates not = 1 Alpha Objects, Number Indicated={}", s_ipsc->cCurrentModuleObject, NumAlphas));
    3581            0 :                 ErrorsFound = true;
    3582              :             }
    3583              : 
    3584            4 :             for (Loop = 1; Loop <= ItemsToGet; ++Loop) {
    3585            4 :                 state.dataInputProcessing->inputProcessor->getObjectItem(state,
    3586            2 :                                                                          s_ipsc->cCurrentModuleObject,
    3587              :                                                                          Loop,
    3588            2 :                                                                          s_ipsc->cAlphaArgs,
    3589              :                                                                          NumAlphas,
    3590            2 :                                                                          s_ipsc->rNumericArgs,
    3591              :                                                                          NumNumbers,
    3592              :                                                                          IOStat,
    3593            2 :                                                                          s_ipsc->lNumericFieldBlanks,
    3594            2 :                                                                          s_ipsc->lAlphaFieldBlanks,
    3595            2 :                                                                          s_ipsc->cAlphaFieldNames,
    3596            2 :                                                                          s_ipsc->cNumericFieldNames);
    3597              : 
    3598            4 :                 if (GlobalNames::VerifyUniqueInterObjectName(state,
    3599            2 :                                                              state.dataSurfaceGeometry->UniqueSurfaceNames,
    3600            2 :                                                              s_ipsc->cAlphaArgs(1),
    3601            2 :                                                              s_ipsc->cCurrentModuleObject,
    3602            2 :                                                              s_ipsc->cAlphaFieldNames(1),
    3603              :                                                              ErrorsFound)) {
    3604            0 :                     continue;
    3605              :                 }
    3606              : 
    3607            2 :                 ++SurfNum;
    3608              : 
    3609            2 :                 auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    3610            2 :                 surfTemp.Name = s_ipsc->cAlphaArgs(1); // Set the Surface Name in the Derived Type
    3611            2 :                 surfTemp.Class = ClassItem;
    3612            2 :                 surfTemp.HeatTransSurf = false;
    3613            2 :                 surfTemp.ExtSolar = true;
    3614              : 
    3615            2 :                 surfTemp.Azimuth = s_ipsc->rNumericArgs(1);
    3616            2 :                 if (surfTemp.Class == SurfaceClass::Detached_B && !state.dataSurface->WorldCoordSystem) {
    3617            0 :                     surfTemp.Azimuth += state.dataHeatBal->BuildingAzimuth;
    3618              :                 }
    3619            2 :                 if (surfTemp.Class == SurfaceClass::Detached_B) {
    3620            1 :                     surfTemp.Azimuth += state.dataHeatBal->BuildingRotationAppendixG;
    3621              :                 }
    3622            2 :                 surfTemp.Tilt = s_ipsc->rNumericArgs(2);
    3623            2 :                 surfTemp.convOrientation = Convect::GetSurfConvOrientation(surfTemp.Tilt);
    3624              : 
    3625            2 :                 surfTemp.Sides = 4;
    3626            2 :                 surfTemp.Vertex.allocate(surfTemp.Sides);
    3627              : 
    3628           12 :                 MakeRectangularVertices(state,
    3629              :                                         SurfNum,
    3630            2 :                                         s_ipsc->rNumericArgs(3),
    3631            2 :                                         s_ipsc->rNumericArgs(4),
    3632            2 :                                         s_ipsc->rNumericArgs(5),
    3633            2 :                                         s_ipsc->rNumericArgs(6),
    3634            2 :                                         s_ipsc->rNumericArgs(7),
    3635            2 :                                         state.dataSurfaceGeometry->RectSurfRefWorldCoordSystem);
    3636              : 
    3637            2 :                 if (surfTemp.Area <= 0.0) {
    3638            0 :                     ShowSevereError(
    3639              :                         state,
    3640            0 :                         format("{}=\"{}\", Surface Area <= 0.0; Entered Area={:.2T}", s_ipsc->cCurrentModuleObject, surfTemp.Name, surfTemp.Area));
    3641            0 :                     ErrorsFound = true;
    3642              :                 }
    3643              : 
    3644            2 :                 if (state.dataReportFlag->MakeMirroredDetachedShading) {
    3645            2 :                     MakeMirrorSurface(state, SurfNum);
    3646              :                 }
    3647              :             }
    3648              : 
    3649              :         } // Item Loop
    3650              :     }
    3651              : 
    3652          231 :     void GetHTSurfaceData(EnergyPlusData &state,
    3653              :                           bool &ErrorsFound,                 // Error flag indicator (true if errors found)
    3654              :                           int &SurfNum,                      // Count of Current SurfaceNumber
    3655              :                           int const TotHTSurfs,              // Number of Heat Transfer Base Surfaces to obtain
    3656              :                           int const TotDetailedWalls,        // Number of Wall:Detailed items to obtain
    3657              :                           int const TotDetailedRoofs,        // Number of RoofCeiling:Detailed items to obtain
    3658              :                           int const TotDetailedFloors,       // Number of Floor:Detailed items to obtain
    3659              :                           const Array1D_string &BaseSurfCls, // Valid Classes for Base Surfaces
    3660              :                           const Array1D<SurfaceClass> &BaseSurfIDs,
    3661              :                           int &NeedToAddSurfaces // Number of surfaces to add, based on unentered IZ surfaces
    3662              :     )
    3663              :     {
    3664              : 
    3665              :         // SUBROUTINE INFORMATION:
    3666              :         //       AUTHOR         Linda Lawrie
    3667              :         //       DATE WRITTEN   May 2000
    3668              : 
    3669              :         // PURPOSE OF THIS SUBROUTINE:
    3670              :         // This subroutine gets the HeatTransfer Surface Data, checks it for errors, etc.
    3671              : 
    3672              :         // REFERENCES:
    3673              :         // Heat Transfer Surface Definition
    3674              :         // BuildingSurface:Detailed,
    3675              :         //  \extensible:3 -- duplicate last set of x,y,z coordinates (last 3 fields), remembering to remove ; from "inner" fields.
    3676              :         //  \format vertices
    3677              :         //  A1 , \field Name
    3678              :         //       \required-field
    3679              :         //       \type alpha
    3680              :         //       \reference SurfaceNames
    3681              :         //       \reference SurfAndSubSurfNames
    3682              :         //       \reference AllHeatTranSurfNames
    3683              :         //       \reference HeatTranBaseSurfNames
    3684              :         //       \reference OutFaceEnvNames
    3685              :         //       \reference AllHeatTranAngFacNames
    3686              :         //       \reference RadGroupAndSurfNames
    3687              :         //       \reference SurfGroupAndHTSurfNames
    3688              :         //       \reference AllShadingAndHTSurfNames
    3689              :         //  A2 , \field Surface Type
    3690              :         //       \required-field
    3691              :         //       \type choice
    3692              :         //       \key Floor
    3693              :         //       \key Wall
    3694              :         //       \key Ceiling
    3695              :         //       \key Roof
    3696              :         //  A3 , \field Construction Name
    3697              :         //       \required-field
    3698              :         //       \note To be matched with a construction in this input file
    3699              :         //       \type object-list
    3700              :         //       \object-list ConstructionNames
    3701              :         //  A4 , \field Zone Name
    3702              :         //       \required-field
    3703              :         //       \note Zone the surface is a part of
    3704              :         //       \type object-list
    3705              :         //       \object-list ZoneNames
    3706              :         //  A5 , \field Outside Boundary Condition
    3707              :         //       \required-field
    3708              :         //       \type choice
    3709              :         //       \key Adiabatic
    3710              :         //       \key Surface
    3711              :         //       \key Zone
    3712              :         //       \key Outdoors
    3713              :         //       \key Ground
    3714              :         //       \key GroundFCfactorMethod
    3715              :         //       \key OtherSideCoefficients
    3716              :         //       \key OtherSideConditionsModel
    3717              :         //       \key GroundSlabPreprocessorAverage
    3718              :         //       \key GroundSlabPreprocessorCore
    3719              :         //       \key GroundSlabPreprocessorPerimeter
    3720              :         //       \key GroundBasementPreprocessorAverageWall
    3721              :         //       \key GroundBasementPreprocessorAverageFloor
    3722              :         //       \key GroundBasementPreprocessorUpperWall
    3723              :         //       \key GroundBasementPreprocessorLowerWall
    3724              :         //  A6,  \field Outside Boundary Condition Object
    3725              :         //       \type object-list
    3726              :         //       \object-list OutFaceEnvNames
    3727              :         //       \note Non-blank only if the field Outside Boundary Condition is Surface,
    3728              :         //       \note Zone, OtherSideCoefficients or OtherSideConditionsModel
    3729              :         //       \note If Surface, specify name of corresponding surface in adjacent zone or
    3730              :         //       \note specify current surface name for internal partition separating like zones
    3731              :         //       \note If Zone, specify the name of the corresponding zone and
    3732              :         //       \note the program will generate the corresponding interzone surface
    3733              :         //       \note If OtherSideCoefficients, specify name of SurfaceProperty:OtherSideCoefficients
    3734              :         //       \note If OtherSideConditionsModel, specify name of SurfaceProperty:OtherSideConditionsModel
    3735              :         //  A7 , \field Sun Exposure
    3736              :         //       \required-field
    3737              :         //       \type choice
    3738              :         //       \key SunExposed
    3739              :         //       \key NoSun
    3740              :         //       \default SunExposed
    3741              :         //  A8,  \field Wind Exposure
    3742              :         //       \required-field
    3743              :         //       \type choice
    3744              :         //       \key WindExposed
    3745              :         //       \key NoWind
    3746              :         //       \default WindExposed
    3747              :         //  N1,  \field View Factor to Ground
    3748              :         //       \type real
    3749              :         //       \note From the exterior of the surface
    3750              :         //       \note Unused if one uses the "reflections" options in Solar Distribution in Building input
    3751              :         //       \note unless a DaylightingDevice:Shelf or DaylightingDevice:Tubular object has been specified.
    3752              :         //       \note autocalculate will automatically calculate this value from the tilt of the surface
    3753              :         //       \autocalculatable
    3754              :         //       \minimum 0.0
    3755              :         //       \maximum 1.0
    3756              :         //       \default autocalculate
    3757              :         //  N2 , \field Number of Vertices
    3758              :         //       \note shown with 120 vertex coordinates -- extensible object
    3759              :         //       \note  "extensible" -- duplicate last set of x,y,z coordinates (last 3 fields),
    3760              :         //       \note remembering to remove ; from "inner" fields.
    3761              :         //       \note for clarity in any error messages, renumber the fields as well.
    3762              :         //       \note (and changing z terminator to a comma "," for all but last one which needs a semi-colon ";")
    3763              :         //       \autocalculatable
    3764              :         //       \minimum 3
    3765              :         //       \default autocalculate
    3766              :         //       \note vertices are given in GlobalGeometryRules coordinates -- if relative, all surface coordinates
    3767              :         //       \note are "relative" to the Zone Origin.  If world, then building and zone origins are used
    3768              :         //       \note for some internal calculations, but all coordinates are given in an "absolute" system.
    3769              :         //  N3-xx as indicated by the N3 value
    3770              : 
    3771              :         // Using/Aliasing
    3772              : 
    3773              :         // SUBROUTINE PARAMETER DEFINITIONS:
    3774          231 :         static Array1D_string const cModuleObjects(4, {"BuildingSurface:Detailed", "Wall:Detailed", "Floor:Detailed", "RoofCeiling:Detailed"});
    3775              : 
    3776              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    3777              :         int IOStat;          // IO Status when calling get input subroutine
    3778              :         int SurfaceNumAlpha; // Number of material alpha names being passed
    3779              :         int SurfaceNumProp;  // Number of material properties being passed
    3780              :         int ZoneNum;         // DO loop counter (zones)
    3781              :         int Found;           // For matching interzone surfaces
    3782              :         int Loop;
    3783              :         int ItemsToGet;
    3784              :         int ClassItem;
    3785              :         int ArgPointer;
    3786              :         int numSides;
    3787              : 
    3788          231 :         auto &s_ipsc = state.dataIPShortCut;
    3789              : 
    3790          231 :         GetOSCData(state, ErrorsFound);
    3791          231 :         GetOSCMData(state, ErrorsFound);
    3792          231 :         GetFoundationData(state, ErrorsFound);
    3793              : 
    3794          231 :         NeedToAddSurfaces = 0;
    3795         1155 :         for (int Item = 1; Item <= 4; ++Item) {
    3796              : 
    3797          924 :             s_ipsc->cCurrentModuleObject = cModuleObjects(Item);
    3798          924 :             if (Item == 1) {
    3799          231 :                 ItemsToGet = TotHTSurfs;
    3800          231 :                 ClassItem = 0;
    3801          693 :             } else if (Item == 2) {
    3802          231 :                 ItemsToGet = TotDetailedWalls;
    3803          231 :                 ClassItem = 1;
    3804          462 :             } else if (Item == 3) {
    3805          231 :                 ItemsToGet = TotDetailedFloors;
    3806          231 :                 ClassItem = 2;
    3807              :             } else { // IF (Item == 4) THEN
    3808          231 :                 ItemsToGet = TotDetailedRoofs;
    3809          231 :                 ClassItem = 3;
    3810              :             }
    3811              : 
    3812         1848 :             state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(
    3813          924 :                 state, s_ipsc->cCurrentModuleObject, Loop, SurfaceNumAlpha, SurfaceNumProp);
    3814          924 :             if (Item == 1) {
    3815          231 :                 if (SurfaceNumAlpha != 9) {
    3816            0 :                     ShowSevereError(state,
    3817            0 :                                     format("{}: Object Definition indicates not = 9 Alpha Objects, Number Indicated={}",
    3818            0 :                                            s_ipsc->cCurrentModuleObject,
    3819              :                                            SurfaceNumAlpha));
    3820            0 :                     ErrorsFound = true;
    3821              :                 }
    3822              :             } else {
    3823          693 :                 if (SurfaceNumAlpha != 8) {
    3824            0 :                     ShowSevereError(state,
    3825            0 :                                     format("{}: Object Definition indicates not = 8 Alpha Objects, Number Indicated={}",
    3826            0 :                                            s_ipsc->cCurrentModuleObject,
    3827              :                                            SurfaceNumAlpha));
    3828            0 :                     ErrorsFound = true;
    3829              :                 }
    3830              :             }
    3831              : 
    3832         2861 :             for (Loop = 1; Loop <= ItemsToGet; ++Loop) {
    3833         3874 :                 state.dataInputProcessing->inputProcessor->getObjectItem(state,
    3834         1937 :                                                                          s_ipsc->cCurrentModuleObject,
    3835              :                                                                          Loop,
    3836         1937 :                                                                          s_ipsc->cAlphaArgs,
    3837              :                                                                          SurfaceNumAlpha,
    3838         1937 :                                                                          s_ipsc->rNumericArgs,
    3839              :                                                                          SurfaceNumProp,
    3840              :                                                                          IOStat,
    3841         1937 :                                                                          s_ipsc->lNumericFieldBlanks,
    3842         1937 :                                                                          s_ipsc->lAlphaFieldBlanks,
    3843         1937 :                                                                          s_ipsc->cAlphaFieldNames,
    3844         1937 :                                                                          s_ipsc->cNumericFieldNames);
    3845              : 
    3846         3874 :                 if (GlobalNames::VerifyUniqueInterObjectName(state,
    3847         1937 :                                                              state.dataSurfaceGeometry->UniqueSurfaceNames,
    3848         1937 :                                                              s_ipsc->cAlphaArgs(1),
    3849         1937 :                                                              s_ipsc->cCurrentModuleObject,
    3850         1937 :                                                              s_ipsc->cAlphaFieldNames(1),
    3851              :                                                              ErrorsFound)) {
    3852            0 :                     continue;
    3853              :                 }
    3854              : 
    3855         1937 :                 ++SurfNum;
    3856              : 
    3857         1937 :                 auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    3858         1937 :                 surfTemp.Name = s_ipsc->cAlphaArgs(1); // Set the Surface Name in the Derived Type
    3859         1937 :                 ArgPointer = 2;
    3860         1937 :                 if (Item == 1) {
    3861         1937 :                     if (s_ipsc->cAlphaArgs(2) == "CEILING") {
    3862           92 :                         s_ipsc->cAlphaArgs(2) = "ROOF";
    3863              :                     }
    3864         1937 :                     ClassItem = Util::FindItemInList(s_ipsc->cAlphaArgs(2), BaseSurfCls, 3);
    3865         1937 :                     if (ClassItem == 0) {
    3866            0 :                         ShowSevereError(state,
    3867            0 :                                         format("{}=\"{}\", invalid {}=\"{}",
    3868            0 :                                                s_ipsc->cCurrentModuleObject,
    3869            0 :                                                surfTemp.Name,
    3870            0 :                                                s_ipsc->cAlphaFieldNames(2),
    3871            0 :                                                s_ipsc->cAlphaArgs(2)));
    3872            0 :                         ErrorsFound = true;
    3873              :                     } else {
    3874         1937 :                         surfTemp.Class = BaseSurfIDs(ClassItem);
    3875              :                     }
    3876         1937 :                     ++ArgPointer;
    3877              :                 } else {
    3878            0 :                     surfTemp.Class = BaseSurfIDs(ClassItem);
    3879              :                 }
    3880              : 
    3881         1937 :                 surfTemp.Construction =
    3882         1937 :                     Util::FindItemInList(s_ipsc->cAlphaArgs(ArgPointer), state.dataConstruction->Construct, state.dataHeatBal->TotConstructs);
    3883              : 
    3884         1937 :                 if (surfTemp.Construction == 0) {
    3885            2 :                     ErrorsFound = true;
    3886            4 :                     ShowSevereError(state,
    3887            8 :                                     format("{}=\"{}\", invalid {}=\"{}\".",
    3888            2 :                                            s_ipsc->cCurrentModuleObject,
    3889            2 :                                            surfTemp.Name,
    3890            2 :                                            s_ipsc->cAlphaFieldNames(ArgPointer),
    3891            2 :                                            s_ipsc->cAlphaArgs(ArgPointer)));
    3892         1935 :                 } else if (state.dataConstruction->Construct(surfTemp.Construction).TypeIsWindow) {
    3893            0 :                     ErrorsFound = true;
    3894            0 :                     ShowSevereError(state,
    3895            0 :                                     format("{}=\"{}\", invalid {}=\"{}\" - has Window materials.",
    3896            0 :                                            s_ipsc->cCurrentModuleObject,
    3897            0 :                                            surfTemp.Name,
    3898            0 :                                            s_ipsc->cAlphaFieldNames(ArgPointer),
    3899            0 :                                            s_ipsc->cAlphaArgs(ArgPointer)));
    3900            0 :                     if (Item == 1) {
    3901            0 :                         ShowContinueError(state, format("...because {}={}", s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2)));
    3902              :                     } else {
    3903            0 :                         ShowContinueError(state, format("...because Surface Type={}", BaseSurfCls(ClassItem)));
    3904              :                     }
    3905              :                 } else {
    3906         1935 :                     state.dataConstruction->Construct(surfTemp.Construction).IsUsed = true;
    3907         1935 :                     surfTemp.ConstructionStoredInputValue = surfTemp.Construction;
    3908              :                 }
    3909         1937 :                 surfTemp.HeatTransSurf = true;
    3910         1937 :                 surfTemp.BaseSurf = SurfNum;
    3911         1937 :                 surfTemp.BaseSurfName = surfTemp.Name;
    3912              : 
    3913         1937 :                 ++ArgPointer;
    3914         1937 :                 surfTemp.ZoneName = s_ipsc->cAlphaArgs(ArgPointer);
    3915         1937 :                 ZoneNum = Util::FindItemInList(surfTemp.ZoneName, state.dataHeatBal->Zone, state.dataGlobal->NumOfZones);
    3916              : 
    3917         1937 :                 if (ZoneNum != 0) {
    3918         1937 :                     surfTemp.Zone = ZoneNum;
    3919              :                 } else {
    3920            0 :                     ShowSevereError(state,
    3921            0 :                                     format("{}=\"{}\", invalid {}=\"{}\".",
    3922            0 :                                            s_ipsc->cCurrentModuleObject,
    3923            0 :                                            surfTemp.Name,
    3924            0 :                                            s_ipsc->cAlphaFieldNames(ArgPointer),
    3925            0 :                                            s_ipsc->cAlphaArgs(ArgPointer)));
    3926            0 :                     surfTemp.Class = SurfaceClass::Invalid;
    3927            0 :                     surfTemp.ZoneName = "Unknown Zone";
    3928            0 :                     ErrorsFound = true;
    3929              :                 }
    3930              : 
    3931         1937 :                 ++ArgPointer;
    3932         1937 :                 if (!s_ipsc->lAlphaFieldBlanks(ArgPointer)) {
    3933          154 :                     int spaceNum = Util::FindItemInList(s_ipsc->cAlphaArgs(ArgPointer), state.dataHeatBal->space);
    3934              : 
    3935          154 :                     if (spaceNum != 0) {
    3936          154 :                         surfTemp.spaceNum = spaceNum;
    3937          154 :                         if (surfTemp.Zone != state.dataHeatBal->space(spaceNum).zoneNum) {
    3938            0 :                             ShowSevereError(state,
    3939            0 :                                             format("{}=\"{}\", invalid {}=\"{}\" is not in the same zone as the surface.",
    3940            0 :                                                    s_ipsc->cCurrentModuleObject,
    3941            0 :                                                    surfTemp.Name,
    3942            0 :                                                    s_ipsc->cAlphaFieldNames(ArgPointer),
    3943            0 :                                                    s_ipsc->cAlphaArgs(ArgPointer)));
    3944            0 :                             surfTemp.Class = SurfaceClass::Invalid;
    3945            0 :                             ErrorsFound = true;
    3946              :                         }
    3947              :                     } else {
    3948            0 :                         ShowSevereError(state,
    3949            0 :                                         format("{}=\"{}\", invalid {}=\"{}\" not found.",
    3950            0 :                                                s_ipsc->cCurrentModuleObject,
    3951            0 :                                                surfTemp.Name,
    3952            0 :                                                s_ipsc->cAlphaFieldNames(ArgPointer),
    3953            0 :                                                s_ipsc->cAlphaArgs(ArgPointer)));
    3954            0 :                         surfTemp.Class = SurfaceClass::Invalid;
    3955            0 :                         ErrorsFound = true;
    3956              :                     }
    3957              :                 }
    3958              :                 // Get the ExteriorBoundaryCondition flag from input There are 4 conditions that
    3959              :                 // can take place. The conditions are set with a 0, -1, or -2, or all of the
    3960              :                 // zone names have to be looked at and generate the interzone array number
    3961         1937 :                 ++ArgPointer;
    3962         1937 :                 surfTemp.ExtBoundCondName = s_ipsc->cAlphaArgs(ArgPointer + 1);
    3963              : 
    3964         1937 :                 if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "Outdoors")) {
    3965         1227 :                     surfTemp.ExtBoundCond = DataSurfaces::ExternalEnvironment;
    3966          710 :                 } else if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "Adiabatic")) {
    3967          152 :                     surfTemp.ExtBoundCond = unreconciledZoneSurface;
    3968          152 :                     surfTemp.ExtBoundCondName = surfTemp.Name;
    3969              : 
    3970          558 :                 } else if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "Ground")) {
    3971          118 :                     surfTemp.ExtBoundCond = DataSurfaces::Ground;
    3972          118 :                     if (state.dataSurfaceGeometry->NoGroundTempObjWarning) {
    3973           44 :                         if (!state.dataEnvrn->GroundTempInputs[(int)DataEnvironment::GroundTempType::BuildingSurface]) {
    3974           72 :                             ShowWarningError(state,
    3975              :                                              "GetHTSurfaceData: Surfaces with interface to Ground found but no \"Ground Temperatures\" were input.");
    3976           36 :                             ShowContinueError(state, format("Found first in surface={}", s_ipsc->cAlphaArgs(1)));
    3977           72 :                             ShowContinueError(state,
    3978           72 :                                               format("Defaults, constant throughout the year of ({:.1R}) will be used.",
    3979           36 :                                                      state.dataEnvrn->GroundTemp[(int)DataEnvironment::GroundTempType::BuildingSurface]));
    3980              :                         }
    3981           44 :                         state.dataSurfaceGeometry->NoGroundTempObjWarning = false;
    3982              :                     }
    3983              : 
    3984              :                     // Added for FCfactor method
    3985          440 :                 } else if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "GroundFCfactorMethod")) {
    3986            0 :                     surfTemp.ExtBoundCond = DataSurfaces::GroundFCfactorMethod;
    3987            0 :                     if (state.dataSurfaceGeometry->NoFCGroundTempObjWarning) {
    3988            0 :                         if (!state.dataEnvrn->GroundTempInputs[(int)DataEnvironment::GroundTempType::FCFactorMethod]) {
    3989            0 :                             ShowSevereError(state,
    3990              :                                             "GetHTSurfaceData: Surfaces with interface to GroundFCfactorMethod found but no \"FC Ground "
    3991              :                                             "Temperatures\" were input.");
    3992            0 :                             ShowContinueError(state, format("Found first in surface={}", s_ipsc->cAlphaArgs(1)));
    3993            0 :                             ShowContinueError(state,
    3994              :                                               "Either add a \"Site:GroundTemperature:FCfactorMethod\" object or use a weather file with "
    3995              :                                               "Ground Temperatures.");
    3996            0 :                             ErrorsFound = true;
    3997            0 :                             state.dataSurfaceGeometry->NoFCGroundTempObjWarning = false;
    3998              :                         }
    3999              :                     }
    4000            0 :                     if (surfTemp.Construction > 0) {
    4001            0 :                         if (surfTemp.Class == SurfaceClass::Wall && !state.dataConstruction->Construct(surfTemp.Construction).TypeIsCfactorWall) {
    4002            0 :                             ShowSevereError(
    4003              :                                 state,
    4004            0 :                                 format("{}=\"{}\", invalid {}", s_ipsc->cCurrentModuleObject, surfTemp.Name, s_ipsc->cAlphaFieldNames(ArgPointer)));
    4005            0 :                             ShowContinueError(state,
    4006            0 :                                               format("Construction=\"{}\" is not type Construction:CfactorUndergroundWall.",
    4007            0 :                                                      state.dataConstruction->Construct(surfTemp.Construction).Name));
    4008            0 :                             ErrorsFound = true;
    4009              :                         }
    4010            0 :                         if (surfTemp.Class == SurfaceClass::Floor && !state.dataConstruction->Construct(surfTemp.Construction).TypeIsFfactorFloor) {
    4011            0 :                             ShowSevereError(
    4012              :                                 state,
    4013            0 :                                 format("{}=\"{}\", invalid {}", s_ipsc->cCurrentModuleObject, surfTemp.Name, s_ipsc->cAlphaFieldNames(ArgPointer)));
    4014            0 :                             ShowContinueError(state,
    4015            0 :                                               format("Construction=\"{}\" is not type Construction:FfactorGroundFloor.",
    4016            0 :                                                      state.dataConstruction->Construct(surfTemp.Construction).Name));
    4017            0 :                             ErrorsFound = true;
    4018              :                         }
    4019              :                     }
    4020              : 
    4021          440 :                 } else if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "OtherSideCoefficients")) {
    4022            0 :                     Found = Util::FindItemInList(surfTemp.ExtBoundCondName, state.dataSurface->OSC, state.dataSurface->TotOSC);
    4023            0 :                     if (Found == 0) {
    4024            0 :                         ShowSevereError(state,
    4025            0 :                                         format("{}=\"{}\", invalid {}=\"{}\".",
    4026            0 :                                                s_ipsc->cCurrentModuleObject,
    4027            0 :                                                surfTemp.Name,
    4028            0 :                                                s_ipsc->cAlphaFieldNames(ArgPointer + 1),
    4029            0 :                                                s_ipsc->cAlphaArgs(ArgPointer + 1)));
    4030            0 :                         ShowContinueError(state, " no OtherSideCoefficients of that name.");
    4031            0 :                         ErrorsFound = true;
    4032              :                     } else {
    4033            0 :                         surfTemp.OSCPtr = Found;
    4034            0 :                         if (state.dataSurface->OSC(Found).SurfFilmCoef > 0.0) {
    4035            0 :                             surfTemp.ExtBoundCond = DataSurfaces::OtherSideCoefCalcExt;
    4036              :                         } else {
    4037            0 :                             surfTemp.ExtBoundCond = DataSurfaces::OtherSideCoefNoCalcExt;
    4038              :                         }
    4039              :                     }
    4040              : 
    4041          440 :                 } else if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "Surface")) {
    4042              :                     // it has to be another surface which needs to be found
    4043              :                     // this will be found on the second pass through the surface input
    4044              :                     // for flagging, set the value to UnreconciledZoneSurface
    4045              :                     // name (ExtBoundCondName) will be validated later.
    4046          427 :                     surfTemp.ExtBoundCond = unreconciledZoneSurface;
    4047          427 :                     if (s_ipsc->lAlphaFieldBlanks(ArgPointer + 1)) {
    4048            0 :                         surfTemp.ExtBoundCondName = surfTemp.Name;
    4049            0 :                         ShowSevereError(state,
    4050            0 :                                         format("{}=\"{}\", invalid {}=<blank>.",
    4051            0 :                                                s_ipsc->cCurrentModuleObject,
    4052            0 :                                                surfTemp.Name,
    4053            0 :                                                s_ipsc->cAlphaFieldNames(ArgPointer + 1)));
    4054            0 :                         ShowContinueError(state, format("..{}=\"Surface\" must be non-blank.", s_ipsc->cAlphaFieldNames(ArgPointer)));
    4055            0 :                         ShowContinueError(state, "..This surface will become an adiabatic surface - no doors/windows allowed.");
    4056              :                     }
    4057              : 
    4058           13 :                 } else if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "Zone")) {
    4059              :                     // This is the code for an unmatched "other surface"
    4060              :                     // will be set up later.
    4061            8 :                     surfTemp.ExtBoundCond = unenteredAdjacentZoneSurface;
    4062              :                     // check OutsideFaceEnvironment for legal zone
    4063            8 :                     Found = Util::FindItemInList(surfTemp.ExtBoundCondName, state.dataHeatBal->Zone, state.dataGlobal->NumOfZones);
    4064            8 :                     ++NeedToAddSurfaces;
    4065              : 
    4066            8 :                     if (Found == 0) {
    4067            0 :                         ShowSevereError(state,
    4068            0 :                                         format("{}=\"{}\", invalid {}=\"{}\".",
    4069            0 :                                                s_ipsc->cCurrentModuleObject,
    4070            0 :                                                surfTemp.Name,
    4071            0 :                                                s_ipsc->cAlphaFieldNames(ArgPointer),
    4072            0 :                                                s_ipsc->cAlphaArgs(ArgPointer)));
    4073            0 :                         ShowContinueError(state, "..Referenced as Zone for this surface.");
    4074            0 :                         ErrorsFound = true;
    4075              :                     }
    4076              : 
    4077            5 :                 } else if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "Space")) {
    4078              :                     // This is the code for an unmatched "other surface"
    4079              :                     // will be set up later.
    4080            2 :                     state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond = unenteredAdjacentSpaceSurface;
    4081              :                     // check OutsideFaceEnvironment for legal zone
    4082            2 :                     Found = Util::FindItemInList(
    4083            2 :                         state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCondName, state.dataHeatBal->space, state.dataGlobal->numSpaces);
    4084            2 :                     ++NeedToAddSurfaces;
    4085              : 
    4086            2 :                     if (Found == 0) {
    4087            0 :                         ShowSevereError(state,
    4088            0 :                                         format("{}=\"{}\", invalid {}=\"{}\".",
    4089            0 :                                                s_ipsc->cCurrentModuleObject,
    4090            0 :                                                state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
    4091            0 :                                                s_ipsc->cAlphaFieldNames(ArgPointer),
    4092            0 :                                                s_ipsc->cAlphaArgs(ArgPointer)));
    4093            0 :                         ShowContinueError(state, "..Referenced as Space for this surface.");
    4094            0 :                         ErrorsFound = true;
    4095              :                     }
    4096              : 
    4097            3 :                 } else if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "Foundation")) {
    4098              : 
    4099            0 :                     if (!state.dataWeather->WeatherFileExists) {
    4100            0 :                         ShowSevereError(
    4101              :                             state,
    4102            0 :                             format("{}=\"{}\", using \"Foundation\" type Outside Boundary Condition requires specification of a weather file",
    4103            0 :                                    s_ipsc->cCurrentModuleObject,
    4104            0 :                                    surfTemp.Name));
    4105            0 :                         ShowContinueError(state,
    4106              :                                           "Either place in.epw in the working directory or specify a weather file on the command line using -w "
    4107              :                                           "/path/to/weather.epw");
    4108            0 :                         ErrorsFound = true;
    4109              :                     }
    4110              : 
    4111              :                     // Find foundation object, if blank use default
    4112            0 :                     if (s_ipsc->lAlphaFieldBlanks(ArgPointer + 1)) {
    4113              : 
    4114            0 :                         if (!state.dataSurfaceGeometry->kivaManager.defaultAdded) {
    4115              :                             // Add default foundation if no other foundation object specified
    4116            0 :                             state.dataSurfaceGeometry->kivaManager.addDefaultFoundation();
    4117              :                         }
    4118            0 :                         surfTemp.OSCPtr =
    4119            0 :                             state.dataSurfaceGeometry->kivaManager.defaultIndex; // Reuse OSC pointer...shouldn't be used for non OSC surfaces anyway.
    4120              :                     } else {
    4121            0 :                         Found = state.dataSurfaceGeometry->kivaManager.findFoundation(surfTemp.ExtBoundCondName);
    4122            0 :                         if (Found != (int)state.dataSurfaceGeometry->kivaManager.foundationInputs.size()) {
    4123            0 :                             surfTemp.OSCPtr = Found;
    4124              :                         } else {
    4125            0 :                             ShowSevereError(state,
    4126            0 :                                             format("{}=\"{}\", invalid {}=\"{}\".",
    4127            0 :                                                    s_ipsc->cCurrentModuleObject,
    4128            0 :                                                    surfTemp.Name,
    4129            0 :                                                    s_ipsc->cAlphaFieldNames(ArgPointer + 1),
    4130            0 :                                                    s_ipsc->cAlphaArgs(ArgPointer + 1)));
    4131            0 :                             ErrorsFound = true;
    4132              :                         }
    4133              :                     }
    4134              : 
    4135            0 :                     if (state.dataConstruction->Construct(surfTemp.Construction).SourceSinkPresent) {
    4136            0 :                         ShowSevereError(
    4137              :                             state,
    4138            0 :                             format("{}=\"{}\", construction may not have an internal source/sink", s_ipsc->cCurrentModuleObject, surfTemp.Name));
    4139            0 :                         ErrorsFound = true;
    4140              :                     }
    4141            0 :                     surfTemp.ExtBoundCond = DataSurfaces::KivaFoundation;
    4142            3 :                 } else if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "OtherSideConditionsModel")) {
    4143            3 :                     Found = Util::FindItemInList(surfTemp.ExtBoundCondName, state.dataSurface->OSCM, state.dataSurface->TotOSCM);
    4144            3 :                     if (Found == 0) {
    4145            0 :                         ShowSevereError(state,
    4146            0 :                                         format("{}=\"{}\", invalid {}=\"{}\".",
    4147            0 :                                                s_ipsc->cCurrentModuleObject,
    4148            0 :                                                surfTemp.Name,
    4149            0 :                                                s_ipsc->cAlphaFieldNames(ArgPointer + 1),
    4150            0 :                                                s_ipsc->cAlphaArgs(ArgPointer + 1)));
    4151            0 :                         ErrorsFound = true;
    4152              :                     }
    4153            3 :                     surfTemp.OSCMPtr = Found;
    4154            3 :                     surfTemp.ExtBoundCond = DataSurfaces::OtherSideCondModeledExt;
    4155              : 
    4156            0 :                 } else if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "GroundSlabPreprocessorAverage") ||
    4157            0 :                            Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "GroundSlabPreprocessorCore") ||
    4158            0 :                            Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "GroundSlabPreprocessorPerimeter") ||
    4159            0 :                            Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "GroundBasementPreprocessorAverageFloor") ||
    4160            0 :                            Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "GroundBasementPreprocessorAverageWall") ||
    4161            0 :                            Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "GroundBasementPreprocessorUpperWall") ||
    4162            0 :                            Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "GroundBasementPreprocessorLowerWall")) {
    4163            0 :                     ShowSevereError(state,
    4164            0 :                                     format("{}=\"{}\", invalid {}=\"{}\".",
    4165            0 :                                            s_ipsc->cCurrentModuleObject,
    4166            0 :                                            surfTemp.Name,
    4167            0 :                                            s_ipsc->cAlphaFieldNames(ArgPointer),
    4168            0 :                                            s_ipsc->cAlphaArgs(ArgPointer)));
    4169            0 :                     ShowContinueError(state, "The ExpandObjects program has not been run or is not in your EnergyPlus.exe folder.");
    4170            0 :                     ErrorsFound = true;
    4171              : 
    4172              :                 } else {
    4173            0 :                     ShowSevereError(state,
    4174            0 :                                     format("{}=\"{}\", invalid {}=\"{}\".",
    4175            0 :                                            s_ipsc->cCurrentModuleObject,
    4176            0 :                                            surfTemp.Name,
    4177            0 :                                            s_ipsc->cAlphaFieldNames(ArgPointer),
    4178            0 :                                            s_ipsc->cAlphaArgs(ArgPointer)));
    4179            0 :                     ShowContinueError(state,
    4180              :                                       "Should be one of \"Outdoors\", \"Adiabatic\", Ground\", \"Surface\", \"OtherSideCoefficients\", "
    4181              :                                       "\"OtherSideConditionsModel\" or \"Zone\"");
    4182            0 :                     ErrorsFound = true;
    4183              :                 } // ... End of the ExtBoundCond logical IF Block
    4184              : 
    4185         1937 :                 ArgPointer += 2;
    4186              :                 // Set the logical flag for the exterior solar
    4187         1937 :                 if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "SunExposed")) {
    4188         1149 :                     if ((surfTemp.ExtBoundCond != DataSurfaces::ExternalEnvironment) &&
    4189            3 :                         (surfTemp.ExtBoundCond != DataSurfaces::OtherSideCondModeledExt)) {
    4190            0 :                         ShowWarningError(state,
    4191            0 :                                          format("{}=\"{}\", {}=\"{}\".",
    4192            0 :                                                 s_ipsc->cCurrentModuleObject,
    4193            0 :                                                 surfTemp.Name,
    4194            0 :                                                 s_ipsc->cAlphaFieldNames(ArgPointer),
    4195            0 :                                                 s_ipsc->cAlphaArgs(ArgPointer)));
    4196            0 :                         ShowContinueError(state, "..This surface is not exposed to External Environment.  Sun exposure has no effect.");
    4197              :                     } else {
    4198         1149 :                         surfTemp.ExtSolar = true;
    4199              :                     }
    4200          788 :                 } else if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "NoSun")) {
    4201          788 :                     surfTemp.ExtSolar = false;
    4202              :                 } else {
    4203            0 :                     ShowSevereError(state,
    4204            0 :                                     format("{}=\"{}\", invalid {}=\"{}\".",
    4205            0 :                                            s_ipsc->cCurrentModuleObject,
    4206            0 :                                            surfTemp.Name,
    4207            0 :                                            s_ipsc->cAlphaFieldNames(ArgPointer),
    4208            0 :                                            s_ipsc->cAlphaArgs(ArgPointer)));
    4209            0 :                     ErrorsFound = true;
    4210              :                 }
    4211              : 
    4212         1937 :                 ++ArgPointer;
    4213              :                 // Set the logical flag for the exterior wind
    4214         1937 :                 if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "WindExposed")) {
    4215         1163 :                     surfTemp.ExtWind = true;
    4216          774 :                 } else if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "NoWind")) {
    4217          774 :                     surfTemp.ExtWind = false;
    4218              :                 } else {
    4219            0 :                     ShowSevereError(state,
    4220            0 :                                     format("{}=\"{}\", invalid {}=\"{}\".",
    4221            0 :                                            s_ipsc->cCurrentModuleObject,
    4222            0 :                                            surfTemp.Name,
    4223            0 :                                            s_ipsc->cAlphaFieldNames(ArgPointer),
    4224            0 :                                            s_ipsc->cAlphaArgs(ArgPointer)));
    4225            0 :                     ErrorsFound = true;
    4226              :                 }
    4227              : 
    4228              :                 // Set the logical flag for the EcoRoof presented, this is only based on the flag in the construction type
    4229              :                 //                if (surfTemp.Construction > 0)
    4230              :                 //                    surfTemp.ExtEcoRoof =
    4231              :                 //                        state.dataConstruction->Construct(surfTemp.Construction).TypeIsEcoRoof;
    4232              : 
    4233         1937 :                 surfTemp.ViewFactorGround = s_ipsc->rNumericArgs(1);
    4234         1937 :                 if (s_ipsc->lNumericFieldBlanks(1)) {
    4235          309 :                     surfTemp.ViewFactorGround = Constant::AutoCalculate;
    4236              :                 }
    4237         1937 :                 if (s_ipsc->lNumericFieldBlanks(2) || s_ipsc->rNumericArgs(2) == Constant::AutoCalculate) {
    4238          175 :                     numSides = (SurfaceNumProp - 2) / 3;
    4239          175 :                     surfTemp.Sides = numSides;
    4240          175 :                     if (mod(SurfaceNumProp - 2, 3) != 0) {
    4241            0 :                         ShowWarningError(state,
    4242            0 :                                          format("{}=\"{}\", {}",
    4243            0 :                                                 s_ipsc->cCurrentModuleObject,
    4244            0 :                                                 surfTemp.Name,
    4245            0 :                                                 format("{} not even multiple of 3. Will read in {}", s_ipsc->cNumericFieldNames(2), surfTemp.Sides)));
    4246              :                     }
    4247          175 :                     if (numSides < 3) {
    4248            0 :                         ShowSevereError(state,
    4249            0 :                                         format("{}=\"{}\", {} (autocalculate) must be >= 3. Only {} provided.",
    4250            0 :                                                s_ipsc->cCurrentModuleObject,
    4251            0 :                                                surfTemp.Name,
    4252            0 :                                                s_ipsc->cNumericFieldNames(2),
    4253            0 :                                                surfTemp.Sides));
    4254            0 :                         ErrorsFound = true;
    4255            0 :                         continue;
    4256              :                     }
    4257              :                 } else {
    4258         1762 :                     numSides = (SurfaceNumProp - 2) / 3;
    4259         1762 :                     surfTemp.Sides = s_ipsc->rNumericArgs(2);
    4260         1762 :                     if (numSides > surfTemp.Sides) {
    4261            0 :                         ShowWarningError(state,
    4262            0 :                                          format("{}=\"{}\", field {}={}",
    4263            0 :                                                 s_ipsc->cCurrentModuleObject,
    4264            0 :                                                 surfTemp.Name,
    4265            0 :                                                 s_ipsc->cNumericFieldNames(2),
    4266            0 :                                                 fmt::to_string(surfTemp.Sides)));
    4267            0 :                         ShowContinueError(
    4268            0 :                             state, format("...but {} were entered. Only the indicated {} will be used.", numSides, s_ipsc->cNumericFieldNames(2)));
    4269              :                     }
    4270              :                 }
    4271         1937 :                 surfTemp.Vertex.allocate(surfTemp.Sides);
    4272         1937 :                 surfTemp.NewVertex.allocate(surfTemp.Sides);
    4273         7748 :                 GetVertices(state, SurfNum, surfTemp.Sides, s_ipsc->rNumericArgs({3, _}));
    4274         1937 :                 if (surfTemp.Area <= 0.0) {
    4275            0 :                     ShowSevereError(
    4276              :                         state,
    4277            0 :                         format("{}=\"{}\", Surface Area <= 0.0; Entered Area={:.2T}", s_ipsc->cCurrentModuleObject, surfTemp.Name, surfTemp.Area));
    4278            0 :                     ErrorsFound = true;
    4279              :                 }
    4280              : 
    4281         1937 :                 CheckConvexity(state, SurfNum, surfTemp.Sides);
    4282         1937 :                 if (Util::SameString(s_ipsc->cAlphaArgs(5), "Surface")) {
    4283            0 :                     if (surfTemp.Sides != static_cast<int>(surfTemp.Vertex.size())) {
    4284            0 :                         ShowSevereError(state,
    4285            0 :                                         format("{}=\"{}\", After CheckConvexity, mismatch between Sides ({}) and size of Vertex ({}).",
    4286            0 :                                                s_ipsc->cCurrentModuleObject,
    4287            0 :                                                surfTemp.Name,
    4288            0 :                                                surfTemp.Sides,
    4289            0 :                                                surfTemp.Vertex.size()));
    4290            0 :                         ShowContinueError(state, "CheckConvexity is used to verify the convexity of a surface and detect collinear points.");
    4291            0 :                         ErrorsFound = true;
    4292              :                     }
    4293              :                 }
    4294         1937 :                 if (surfTemp.Construction > 0) {
    4295              :                     // Check wall height for the CFactor walls
    4296              : 
    4297         1935 :                     if (surfTemp.Class == SurfaceClass::Wall && state.dataConstruction->Construct(surfTemp.Construction).TypeIsCfactorWall) {
    4298            0 :                         if (std::abs(surfTemp.Height - state.dataConstruction->Construct(surfTemp.Construction).Height) > 0.05) {
    4299            0 :                             ShowWarningError(
    4300              :                                 state,
    4301            0 :                                 format("{}=\"{}\", underground Wall Height = {:.2T}", s_ipsc->cCurrentModuleObject, surfTemp.Name, surfTemp.Height));
    4302            0 :                             ShowContinueError(state, "..which does not match its construction height.");
    4303              :                         }
    4304              :                     }
    4305              : 
    4306              :                     // Check area and perimeter for the FFactor floors
    4307         1935 :                     if (surfTemp.Class == SurfaceClass::Floor && state.dataConstruction->Construct(surfTemp.Construction).TypeIsFfactorFloor) {
    4308            0 :                         if (std::abs(surfTemp.Area - state.dataConstruction->Construct(surfTemp.Construction).Area) > 0.1) {
    4309            0 :                             ShowWarningError(
    4310              :                                 state,
    4311            0 :                                 format("{}=\"{}\", underground Floor Area = {:.2T}", s_ipsc->cCurrentModuleObject, surfTemp.Name, surfTemp.Area));
    4312            0 :                             ShowContinueError(state, "..which does not match its construction area.");
    4313              :                         }
    4314            0 :                         if (surfTemp.Perimeter < state.dataConstruction->Construct(surfTemp.Construction).PerimeterExposed - 0.1) {
    4315            0 :                             ShowWarningError(state,
    4316            0 :                                              format("{}=\"{}\", underground Floor Perimeter = {:.2T}",
    4317            0 :                                                     s_ipsc->cCurrentModuleObject,
    4318            0 :                                                     surfTemp.Name,
    4319            0 :                                                     surfTemp.Perimeter));
    4320            0 :                             ShowContinueError(state, "..which is less than its construction exposed perimeter.");
    4321              :                         }
    4322              :                     }
    4323              :                 }
    4324              :                 // Not sure if it's better to add this or guard in SolarShading.cc
    4325              :                 // surfTemp.shadowSurfSched = nullptr
    4326              :             }
    4327              :         } // Item Looop
    4328              :         // Check number of Vertex between base surface and Outside Boundary surface
    4329              :         int ExtSurfNum;
    4330         2198 :         for (int i = 1; i <= SurfNum; i++) {
    4331         2546 :             if (state.dataSurfaceGeometry->SurfaceTmp(i).ExtBoundCond == unreconciledZoneSurface &&
    4332          579 :                 state.dataSurfaceGeometry->SurfaceTmp(i).ExtBoundCondName != "") {
    4333          579 :                 ExtSurfNum = Util::FindItemInList(state.dataSurfaceGeometry->SurfaceTmp(i).ExtBoundCondName, state.dataSurfaceGeometry->SurfaceTmp);
    4334              :                 // If we cannot find the referenced surface
    4335          579 :                 if (ExtSurfNum == 0) {
    4336            2 :                     ShowSevereError(state,
    4337            2 :                                     format("{}=\"{}\" references an outside boundary surface that cannot be found:{}",
    4338            1 :                                            s_ipsc->cCurrentModuleObject,
    4339            1 :                                            state.dataSurfaceGeometry->SurfaceTmp(i).Name,
    4340            1 :                                            state.dataSurfaceGeometry->SurfaceTmp(i).ExtBoundCondName));
    4341            1 :                     ErrorsFound = true;
    4342              :                     // If vertex size mismatch
    4343         1156 :                 } else if (state.dataSurfaceGeometry->SurfaceTmp(i).Vertex.size() !=
    4344          578 :                            state.dataSurfaceGeometry->SurfaceTmp(ExtSurfNum).Vertex.size()) {
    4345            4 :                     ShowSevereError(state,
    4346            4 :                                     format("{}=\"{}\", Vertex size mismatch between base surface :{} and outside boundary surface: {}",
    4347            2 :                                            s_ipsc->cCurrentModuleObject,
    4348            2 :                                            state.dataSurfaceGeometry->SurfaceTmp(i).Name,
    4349            2 :                                            state.dataSurfaceGeometry->SurfaceTmp(i).Name,
    4350            2 :                                            state.dataSurfaceGeometry->SurfaceTmp(ExtSurfNum).Name));
    4351            4 :                     ShowContinueError(state,
    4352            4 :                                       format("The vertex sizes are {} for base surface and {} for outside boundary surface. Please check inputs.",
    4353            2 :                                              state.dataSurfaceGeometry->SurfaceTmp(i).Vertex.size(),
    4354            2 :                                              state.dataSurfaceGeometry->SurfaceTmp(ExtSurfNum).Vertex.size()));
    4355            2 :                     ErrorsFound = true;
    4356              :                 }
    4357              :             }
    4358              :         }
    4359         2168 :     }
    4360              : 
    4361          226 :     void GetRectSurfaces(EnergyPlusData &state,
    4362              :                          bool &ErrorsFound,                        // Error flag indicator (true if errors found)
    4363              :                          int &SurfNum,                             // Count of Current SurfaceNumber
    4364              :                          int const TotRectExtWalls,                // Number of Exterior Walls to obtain
    4365              :                          int const TotRectIntWalls,                // Number of Adiabatic Walls to obtain
    4366              :                          int const TotRectIZWalls,                 // Number of Interzone Walls to obtain
    4367              :                          int const TotRectUGWalls,                 // Number of Underground to obtain
    4368              :                          int const TotRectRoofs,                   // Number of Roofs to obtain
    4369              :                          int const TotRectCeilings,                // Number of Adiabatic Ceilings to obtain
    4370              :                          int const TotRectIZCeilings,              // Number of Interzone Ceilings to obtain
    4371              :                          int const TotRectGCFloors,                // Number of Floors with Ground Contact to obtain
    4372              :                          int const TotRectIntFloors,               // Number of Adiabatic Walls to obtain
    4373              :                          int const TotRectIZFloors,                // Number of Interzone Floors to obtain
    4374              :                          const Array1D<SurfaceClass> &BaseSurfIDs, // ID Assignments for valid surface classes
    4375              :                          int &NeedToAddSurfaces                    // Number of surfaces to add, based on unentered IZ surfaces
    4376              :     )
    4377              :     {
    4378              : 
    4379              :         // SUBROUTINE INFORMATION:
    4380              :         //       AUTHOR         Linda Lawrie
    4381              :         //       DATE WRITTEN   December 2008
    4382              : 
    4383              :         // PURPOSE OF THIS SUBROUTINE:
    4384              :         // Get simple (rectangular, LLC corner specified) walls
    4385              : 
    4386              :         // SUBROUTINE PARAMETER DEFINITIONS:
    4387              :         static Array1D_string const cModuleObjects(10,
    4388              :                                                    {"Wall:Exterior",
    4389              :                                                     "Wall:Adiabatic",
    4390              :                                                     "Wall:Interzone",
    4391              :                                                     "Wall:Underground",
    4392              :                                                     "Roof",
    4393              :                                                     "Ceiling:Adiabatic",
    4394              :                                                     "Ceiling:Interzone",
    4395              :                                                     "Floor:GroundContact",
    4396              :                                                     "Floor:Adiabatic",
    4397          226 :                                                     "Floor:Interzone"});
    4398              : 
    4399              :         int ItemsToGet;
    4400              :         int NumAlphas;
    4401              :         int NumNumbers;
    4402              :         int IOStat; // IO Status when calling get input subroutine
    4403              :         int Found;  // For matching base surfaces
    4404              :         bool GettingIZSurfaces;
    4405              :         int OtherSurfaceField;
    4406              :         int ExtBoundCondition;
    4407              :         int ClassItem;
    4408              :         int ZoneNum;
    4409              : 
    4410          226 :         auto &s_ipsc = state.dataIPShortCut;
    4411              : 
    4412         2486 :         for (int Item = 1; Item <= 10; ++Item) {
    4413              : 
    4414         2260 :             s_ipsc->cCurrentModuleObject = cModuleObjects(Item);
    4415         2260 :             if (Item == 1) {
    4416          226 :                 ItemsToGet = TotRectExtWalls;
    4417          226 :                 GettingIZSurfaces = false;
    4418          226 :                 OtherSurfaceField = 0;
    4419          226 :                 ExtBoundCondition = DataSurfaces::ExternalEnvironment;
    4420          226 :                 ClassItem = 1;
    4421         2034 :             } else if (Item == 2) {
    4422          226 :                 ItemsToGet = TotRectIntWalls;
    4423          226 :                 GettingIZSurfaces = false;
    4424          226 :                 OtherSurfaceField = 0;
    4425          226 :                 ExtBoundCondition = unreconciledZoneSurface;
    4426          226 :                 ClassItem = 1;
    4427         1808 :             } else if (Item == 3) {
    4428          226 :                 ItemsToGet = TotRectIZWalls;
    4429          226 :                 GettingIZSurfaces = true;
    4430          226 :                 OtherSurfaceField = 5;
    4431          226 :                 ExtBoundCondition = unreconciledZoneSurface;
    4432          226 :                 ClassItem = 1;
    4433         1582 :             } else if (Item == 4) {
    4434          226 :                 ItemsToGet = TotRectUGWalls;
    4435          226 :                 GettingIZSurfaces = false;
    4436          226 :                 OtherSurfaceField = 0;
    4437          226 :                 ExtBoundCondition = DataSurfaces::Ground;
    4438          226 :                 ClassItem = 1;
    4439         1356 :             } else if (Item == 5) {
    4440          226 :                 ItemsToGet = TotRectRoofs;
    4441          226 :                 GettingIZSurfaces = false;
    4442          226 :                 OtherSurfaceField = 0;
    4443          226 :                 ExtBoundCondition = DataSurfaces::ExternalEnvironment;
    4444          226 :                 ClassItem = 3;
    4445         1130 :             } else if (Item == 6) {
    4446          226 :                 ItemsToGet = TotRectCeilings;
    4447          226 :                 GettingIZSurfaces = false;
    4448          226 :                 OtherSurfaceField = 0;
    4449          226 :                 ExtBoundCondition = unreconciledZoneSurface;
    4450          226 :                 ClassItem = 3;
    4451          904 :             } else if (Item == 7) {
    4452          226 :                 ItemsToGet = TotRectIZCeilings;
    4453          226 :                 GettingIZSurfaces = false;
    4454          226 :                 OtherSurfaceField = 5;
    4455          226 :                 ExtBoundCondition = unreconciledZoneSurface;
    4456          226 :                 ClassItem = 3;
    4457          678 :             } else if (Item == 8) {
    4458          226 :                 ItemsToGet = TotRectGCFloors;
    4459          226 :                 GettingIZSurfaces = false;
    4460          226 :                 OtherSurfaceField = 0;
    4461          226 :                 ExtBoundCondition = DataSurfaces::Ground;
    4462          226 :                 ClassItem = 2;
    4463          452 :             } else if (Item == 9) {
    4464          226 :                 ItemsToGet = TotRectIntFloors;
    4465          226 :                 GettingIZSurfaces = false;
    4466          226 :                 OtherSurfaceField = 0;
    4467          226 :                 ExtBoundCondition = unreconciledZoneSurface;
    4468          226 :                 ClassItem = 2;
    4469              :             } else { // IF (Item == 10) THEN
    4470          226 :                 ItemsToGet = TotRectIZFloors;
    4471          226 :                 GettingIZSurfaces = true;
    4472          226 :                 OtherSurfaceField = 5;
    4473          226 :                 ExtBoundCondition = unreconciledZoneSurface;
    4474          226 :                 ClassItem = 2;
    4475              :             }
    4476              : 
    4477         2261 :             for (int Loop = 1; Loop <= ItemsToGet; ++Loop) {
    4478            2 :                 state.dataInputProcessing->inputProcessor->getObjectItem(state,
    4479            1 :                                                                          s_ipsc->cCurrentModuleObject,
    4480              :                                                                          Loop,
    4481            1 :                                                                          s_ipsc->cAlphaArgs,
    4482              :                                                                          NumAlphas,
    4483            1 :                                                                          s_ipsc->rNumericArgs,
    4484              :                                                                          NumNumbers,
    4485              :                                                                          IOStat,
    4486            1 :                                                                          s_ipsc->lNumericFieldBlanks,
    4487            1 :                                                                          s_ipsc->lAlphaFieldBlanks,
    4488            1 :                                                                          s_ipsc->cAlphaFieldNames,
    4489            1 :                                                                          s_ipsc->cNumericFieldNames);
    4490              : 
    4491            2 :                 if (GlobalNames::VerifyUniqueInterObjectName(state,
    4492            1 :                                                              state.dataSurfaceGeometry->UniqueSurfaceNames,
    4493            1 :                                                              s_ipsc->cAlphaArgs(1),
    4494            1 :                                                              s_ipsc->cCurrentModuleObject,
    4495            1 :                                                              s_ipsc->cAlphaFieldNames(1),
    4496              :                                                              ErrorsFound)) {
    4497            0 :                     continue;
    4498              :                 }
    4499              : 
    4500            1 :                 if (NumNumbers < 7) {
    4501            0 :                     ShowSevereError(
    4502              :                         state,
    4503            0 :                         format("{}=\"{}\", Too few number of numeric args=[{}].", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1), NumNumbers));
    4504            0 :                     ErrorsFound = true;
    4505              :                 }
    4506              : 
    4507            1 :                 ++SurfNum;
    4508              : 
    4509            1 :                 auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    4510            1 :                 surfTemp.Name = s_ipsc->cAlphaArgs(1);   // Set the Surface Name in the Derived Type
    4511            1 :                 surfTemp.Class = BaseSurfIDs(ClassItem); // Set class number
    4512              : 
    4513            1 :                 surfTemp.Construction =
    4514            1 :                     Util::FindItemInList(s_ipsc->cAlphaArgs(2), state.dataConstruction->Construct, state.dataHeatBal->TotConstructs);
    4515              : 
    4516            1 :                 if (surfTemp.Construction == 0) {
    4517            0 :                     ErrorsFound = true;
    4518            0 :                     ShowSevereError(state,
    4519            0 :                                     format("{}=\"{}\", invalid {}=\"{}\".",
    4520            0 :                                            s_ipsc->cCurrentModuleObject,
    4521            0 :                                            surfTemp.Name,
    4522            0 :                                            s_ipsc->cAlphaFieldNames(2),
    4523            0 :                                            s_ipsc->cAlphaArgs(2)));
    4524            1 :                 } else if (state.dataConstruction->Construct(surfTemp.Construction).TypeIsWindow) {
    4525            0 :                     ErrorsFound = true;
    4526            0 :                     ShowSevereError(state,
    4527            0 :                                     format("{}=\"{}\", invalid {}=\"{}\" - has Window materials.",
    4528            0 :                                            s_ipsc->cCurrentModuleObject,
    4529            0 :                                            surfTemp.Name,
    4530            0 :                                            s_ipsc->cAlphaFieldNames(3),
    4531            0 :                                            s_ipsc->cAlphaArgs(2)));
    4532            0 :                     ShowContinueError(state, format("...because {}={}", s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2)));
    4533              :                 } else {
    4534            1 :                     state.dataConstruction->Construct(surfTemp.Construction).IsUsed = true;
    4535            1 :                     surfTemp.ConstructionStoredInputValue = surfTemp.Construction;
    4536              :                 }
    4537            1 :                 surfTemp.HeatTransSurf = true;
    4538            1 :                 surfTemp.BaseSurf = SurfNum;
    4539            1 :                 surfTemp.BaseSurfName = surfTemp.Name;
    4540              : 
    4541            1 :                 surfTemp.ZoneName = s_ipsc->cAlphaArgs(3);
    4542            1 :                 ZoneNum = Util::FindItemInList(surfTemp.ZoneName, state.dataHeatBal->Zone, state.dataGlobal->NumOfZones);
    4543              : 
    4544            1 :                 if (ZoneNum != 0) {
    4545            1 :                     surfTemp.Zone = ZoneNum;
    4546              :                 } else {
    4547            0 :                     ShowSevereError(state,
    4548            0 :                                     format("{}=\"{}\", invalid {}=\"{}\".",
    4549            0 :                                            s_ipsc->cCurrentModuleObject,
    4550            0 :                                            surfTemp.Name,
    4551            0 :                                            s_ipsc->cAlphaFieldNames(3),
    4552            0 :                                            s_ipsc->cAlphaArgs(3)));
    4553            0 :                     surfTemp.Class = SurfaceClass::Invalid;
    4554            0 :                     surfTemp.ZoneName = "Unknown Zone";
    4555            0 :                     ErrorsFound = true;
    4556              :                 }
    4557              : 
    4558            1 :                 if (!s_ipsc->lAlphaFieldBlanks(4)) {
    4559            0 :                     int spaceNum = Util::FindItemInList(s_ipsc->cAlphaArgs(4), state.dataHeatBal->space);
    4560              : 
    4561            0 :                     if (spaceNum != 0) {
    4562            0 :                         surfTemp.spaceNum = spaceNum;
    4563              :                     } else {
    4564            0 :                         ShowSevereError(state,
    4565            0 :                                         format("{}=\"{}\", invalid {}=\"{}\".",
    4566            0 :                                                s_ipsc->cCurrentModuleObject,
    4567            0 :                                                surfTemp.Name,
    4568            0 :                                                s_ipsc->cAlphaFieldNames(4),
    4569            0 :                                                s_ipsc->cAlphaArgs(4)));
    4570            0 :                         surfTemp.Class = SurfaceClass::Invalid;
    4571            0 :                         ErrorsFound = true;
    4572              :                     }
    4573              :                 }
    4574              : 
    4575            1 :                 surfTemp.ExtBoundCond = ExtBoundCondition;
    4576            1 :                 if (surfTemp.Construction > 0) {
    4577            1 :                     if (surfTemp.Class == SurfaceClass::Wall && state.dataConstruction->Construct(surfTemp.Construction).TypeIsCfactorWall &&
    4578            0 :                         surfTemp.ExtBoundCond == DataSurfaces::Ground) {
    4579            0 :                         surfTemp.ExtBoundCond = DataSurfaces::GroundFCfactorMethod;
    4580            1 :                     } else if (state.dataConstruction->Construct(surfTemp.Construction).TypeIsCfactorWall) {
    4581            0 :                         ErrorsFound = true;
    4582            0 :                         ShowSevereError(state,
    4583            0 :                                         format("{}=\"{}\", Construction type is \"Construction:CfactorUndergroundWall\" but invalid for this object.",
    4584            0 :                                                s_ipsc->cCurrentModuleObject,
    4585            0 :                                                surfTemp.Name));
    4586              :                     }
    4587              : 
    4588            1 :                     if (surfTemp.Class == SurfaceClass::Floor && state.dataConstruction->Construct(surfTemp.Construction).TypeIsFfactorFloor &&
    4589            0 :                         surfTemp.ExtBoundCond == DataSurfaces::Ground) {
    4590            0 :                         surfTemp.ExtBoundCond = DataSurfaces::GroundFCfactorMethod;
    4591            1 :                     } else if (state.dataConstruction->Construct(surfTemp.Construction).TypeIsFfactorFloor) {
    4592            0 :                         ErrorsFound = true;
    4593            0 :                         ShowSevereError(state,
    4594            0 :                                         format("{}=\"{}\", Construction type is \"Construction:FfactorGroundFloor\" but invalid for this object.",
    4595            0 :                                                s_ipsc->cCurrentModuleObject,
    4596            0 :                                                surfTemp.Name));
    4597              :                     }
    4598              :                 }
    4599            1 :                 surfTemp.ExtSolar = false;
    4600            1 :                 surfTemp.ExtWind = false;
    4601            1 :                 surfTemp.ViewFactorGround = Constant::AutoCalculate;
    4602              : 
    4603            1 :                 if (surfTemp.ExtBoundCond == DataSurfaces::ExternalEnvironment) {
    4604            0 :                     surfTemp.ExtSolar = true;
    4605            0 :                     surfTemp.ExtWind = true;
    4606              : 
    4607              :                     // Set the logical flag for the EcoRoof presented, this is only based on the flag in the construction type
    4608              :                     //                    if (surfTemp.Construction > 0)
    4609              :                     //                        surfTemp.ExtEcoRoof =
    4610              :                     //                            state.dataConstruction->Construct(surfTemp.Construction).TypeIsEcoRoof;
    4611              : 
    4612            1 :                 } else if (surfTemp.ExtBoundCond == unreconciledZoneSurface) {
    4613            1 :                     if (GettingIZSurfaces) {
    4614            0 :                         surfTemp.ExtBoundCondName = s_ipsc->cAlphaArgs(OtherSurfaceField);
    4615            0 :                         Found = Util::FindItemInList(surfTemp.ExtBoundCondName, state.dataHeatBal->Zone, state.dataGlobal->NumOfZones);
    4616              :                         // see if match to zone, then it's an unentered other surface, else reconciled later
    4617            0 :                         if (Found > 0) {
    4618            0 :                             ++NeedToAddSurfaces;
    4619            0 :                             surfTemp.ExtBoundCond = unenteredAdjacentZoneSurface;
    4620              :                         }
    4621              :                     } else {
    4622            1 :                         surfTemp.ExtBoundCondName = surfTemp.Name;
    4623              :                     }
    4624              : 
    4625            0 :                 } else if (surfTemp.ExtBoundCond == DataSurfaces::Ground) {
    4626            0 :                     if (state.dataSurfaceGeometry->NoGroundTempObjWarning) {
    4627            0 :                         if (!state.dataEnvrn->GroundTempInputs[(int)DataEnvironment::GroundTempType::BuildingSurface]) {
    4628            0 :                             ShowWarningError(state,
    4629              :                                              "GetRectSurfaces: Surfaces with interface to Ground found but no \"Ground Temperatures\" were input.");
    4630            0 :                             ShowContinueError(state, format("Found first in surface={}", s_ipsc->cAlphaArgs(1)));
    4631            0 :                             ShowContinueError(state,
    4632            0 :                                               format("Defaults, constant throughout the year of ({:.1R}) will be used.",
    4633            0 :                                                      state.dataEnvrn->GroundTemp[(int)DataEnvironment::GroundTempType::BuildingSurface]));
    4634              :                         }
    4635            0 :                         state.dataSurfaceGeometry->NoGroundTempObjWarning = false;
    4636              :                     }
    4637              : 
    4638            0 :                 } else if (surfTemp.ExtBoundCond == DataSurfaces::GroundFCfactorMethod) {
    4639            0 :                     if (state.dataSurfaceGeometry->NoFCGroundTempObjWarning) {
    4640            0 :                         if (!state.dataEnvrn->GroundTempInputs[(int)DataEnvironment::GroundTempType::FCFactorMethod]) {
    4641            0 :                             ShowSevereError(state,
    4642              :                                             "GetRectSurfaces: Surfaces with interface to GroundFCfactorMethod found but no \"FC Ground "
    4643              :                                             "Temperatures\" were input.");
    4644            0 :                             ShowContinueError(state, format("Found first in surface={}", s_ipsc->cAlphaArgs(1)));
    4645            0 :                             ShowContinueError(state,
    4646              :                                               "Either add a \"Site:GroundTemperature:FCfactorMethod\" object or use a weather file with "
    4647              :                                               "Ground Temperatures.");
    4648            0 :                             ErrorsFound = true;
    4649            0 :                             state.dataSurfaceGeometry->NoFCGroundTempObjWarning = false;
    4650              :                         }
    4651              :                     }
    4652              : 
    4653              :                 } // ... End of the ExtBoundCond logical IF Block
    4654              : 
    4655            1 :                 surfTemp.Azimuth = s_ipsc->rNumericArgs(1);
    4656            1 :                 surfTemp.Tilt = s_ipsc->rNumericArgs(2);
    4657            1 :                 surfTemp.convOrientation = Convect::GetSurfConvOrientation(surfTemp.Tilt);
    4658            1 :                 if (!state.dataSurface->WorldCoordSystem) {
    4659            1 :                     if (ZoneNum != 0) {
    4660            1 :                         surfTemp.Azimuth += state.dataHeatBal->BuildingAzimuth + state.dataHeatBal->Zone(ZoneNum).RelNorth;
    4661              :                     }
    4662              :                 }
    4663            1 :                 if (ZoneNum != 0) {
    4664            1 :                     surfTemp.Azimuth += state.dataHeatBal->BuildingRotationAppendixG;
    4665              :                 }
    4666              : 
    4667            1 :                 surfTemp.Sides = 4;
    4668            1 :                 surfTemp.Vertex.allocate(surfTemp.Sides);
    4669              : 
    4670            6 :                 MakeRectangularVertices(state,
    4671              :                                         SurfNum,
    4672            1 :                                         s_ipsc->rNumericArgs(3),
    4673            1 :                                         s_ipsc->rNumericArgs(4),
    4674            1 :                                         s_ipsc->rNumericArgs(5),
    4675            1 :                                         s_ipsc->rNumericArgs(6),
    4676            1 :                                         s_ipsc->rNumericArgs(7),
    4677            1 :                                         state.dataSurfaceGeometry->RectSurfRefWorldCoordSystem);
    4678              : 
    4679            1 :                 if (surfTemp.Area <= 0.0) {
    4680            0 :                     ShowSevereError(
    4681              :                         state,
    4682            0 :                         format("{}=\"{}\", Surface Area <= 0.0; Entered Area={:.2T}", s_ipsc->cCurrentModuleObject, surfTemp.Name, surfTemp.Area));
    4683            0 :                     ErrorsFound = true;
    4684              :                 }
    4685              : 
    4686              :                 // Check wall height for the CFactor walls
    4687            1 :                 if (surfTemp.Class == SurfaceClass::Wall && surfTemp.ExtBoundCond == DataSurfaces::GroundFCfactorMethod) {
    4688            0 :                     if (std::abs(surfTemp.Height - state.dataConstruction->Construct(surfTemp.Construction).Height) > 0.05) {
    4689            0 :                         ShowWarningError(
    4690              :                             state,
    4691            0 :                             format("{}=\"{}\", underground Wall Height = {:.2T}", s_ipsc->cCurrentModuleObject, surfTemp.Name, surfTemp.Height));
    4692            0 :                         ShowContinueError(state, "..which deos not match its construction height.");
    4693              :                     }
    4694              :                 }
    4695              : 
    4696              :                 // Check area and perimeter for the FFactor floors
    4697            1 :                 if (surfTemp.Class == SurfaceClass::Floor && surfTemp.ExtBoundCond == DataSurfaces::GroundFCfactorMethod) {
    4698            0 :                     if (std::abs(surfTemp.Area - state.dataConstruction->Construct(surfTemp.Construction).Area) > 0.1) {
    4699            0 :                         ShowWarningError(
    4700            0 :                             state, format("{}=\"{}\", underground Floor Area = {:.2T}", s_ipsc->cCurrentModuleObject, surfTemp.Name, surfTemp.Area));
    4701            0 :                         ShowContinueError(state, "..which does not match its construction area.");
    4702              :                     }
    4703            0 :                     if (surfTemp.Perimeter < state.dataConstruction->Construct(surfTemp.Construction).PerimeterExposed - 0.1) {
    4704            0 :                         ShowWarningError(
    4705              :                             state,
    4706            0 :                             format(
    4707            0 :                                 "{}=\"{}\", underground Floor Perimeter = {:.2T}", s_ipsc->cCurrentModuleObject, surfTemp.Name, surfTemp.Perimeter));
    4708            0 :                         ShowContinueError(state, "..which is less than its construction exposed perimeter.");
    4709              :                     }
    4710              :                 }
    4711              :             } // Getting Items
    4712              :         }
    4713          226 :     }
    4714              : 
    4715            7 :     void MakeRectangularVertices(EnergyPlusData &state,
    4716              :                                  int const SurfNum,
    4717              :                                  Real64 const XCoord,
    4718              :                                  Real64 const YCoord,
    4719              :                                  Real64 const ZCoord,
    4720              :                                  Real64 const Length,
    4721              :                                  Real64 const Height,
    4722              :                                  bool const SurfWorldCoordSystem)
    4723              :     {
    4724              : 
    4725              :         // SUBROUTINE INFORMATION:
    4726              :         //       AUTHOR         Linda Lawrie
    4727              :         //       DATE WRITTEN   December 2008
    4728              : 
    4729              :         // PURPOSE OF THIS SUBROUTINE:
    4730              :         // This routine creates world/3d coordinates for rectangular surfaces using azimuth, tilt, LLC (X,Y,Z), length & height.
    4731              : 
    4732              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    4733              :         Real64 XLLC;
    4734              :         Real64 YLLC;
    4735              :         Real64 ZLLC;
    4736            7 :         Array1D<Real64> XX(4);
    4737            7 :         Array1D<Real64> YY(4);
    4738              :         Real64 Xb;
    4739              :         Real64 Yb;
    4740              :         Real64 Perimeter;
    4741              :         int Vrt;
    4742              : 
    4743            7 :         auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    4744              : 
    4745            7 :         if (surfTemp.Zone == 0 && (surfTemp.Class != SurfaceClass::Detached_F && surfTemp.Class != SurfaceClass::Detached_B)) {
    4746            0 :             return;
    4747              :         }
    4748              : 
    4749            7 :         surfTemp.Height = Height;
    4750            7 :         surfTemp.Width = Length;
    4751              : 
    4752            7 :         Real64 SurfAzimuth = surfTemp.Azimuth;
    4753            7 :         Real64 SurfTilt = surfTemp.Tilt;
    4754            7 :         Real64 CosSurfAzimuth = std::cos(SurfAzimuth * Constant::DegToRad);
    4755            7 :         Real64 SinSurfAzimuth = std::sin(SurfAzimuth * Constant::DegToRad);
    4756            7 :         Real64 CosSurfTilt = std::cos(SurfTilt * Constant::DegToRad);
    4757            7 :         Real64 SinSurfTilt = std::sin(SurfTilt * Constant::DegToRad);
    4758              : 
    4759            7 :         if (!SurfWorldCoordSystem) {
    4760            7 :             if (surfTemp.Zone > 0) {
    4761            5 :                 Xb = XCoord * state.dataSurfaceGeometry->CosZoneRelNorth(surfTemp.Zone) -
    4762            5 :                      YCoord * state.dataSurfaceGeometry->SinZoneRelNorth(surfTemp.Zone) + state.dataHeatBal->Zone(surfTemp.Zone).OriginX;
    4763            5 :                 Yb = XCoord * state.dataSurfaceGeometry->SinZoneRelNorth(surfTemp.Zone) +
    4764            5 :                      YCoord * state.dataSurfaceGeometry->CosZoneRelNorth(surfTemp.Zone) + state.dataHeatBal->Zone(surfTemp.Zone).OriginY;
    4765            5 :                 XLLC = Xb * state.dataSurfaceGeometry->CosBldgRelNorth - Yb * state.dataSurfaceGeometry->SinBldgRelNorth;
    4766            5 :                 YLLC = Xb * state.dataSurfaceGeometry->SinBldgRelNorth + Yb * state.dataSurfaceGeometry->CosBldgRelNorth;
    4767            5 :                 ZLLC = ZCoord + state.dataHeatBal->Zone(surfTemp.Zone).OriginZ;
    4768              :             } else {
    4769            2 :                 if (surfTemp.Class == SurfaceClass::Detached_B) {
    4770            1 :                     Xb = XCoord;
    4771            1 :                     Yb = YCoord;
    4772            1 :                     XLLC = Xb * state.dataSurfaceGeometry->CosBldgRelNorth - Yb * state.dataSurfaceGeometry->SinBldgRelNorth;
    4773            1 :                     YLLC = Xb * state.dataSurfaceGeometry->SinBldgRelNorth + Yb * state.dataSurfaceGeometry->CosBldgRelNorth;
    4774            1 :                     ZLLC = ZCoord;
    4775              :                 } else {
    4776            1 :                     XLLC = XCoord;
    4777            1 :                     YLLC = YCoord;
    4778            1 :                     ZLLC = ZCoord;
    4779              :                 }
    4780              :             }
    4781              :         } else {
    4782              :             // for world coordinates, only rotate for appendix G
    4783            0 :             Xb = XCoord;
    4784            0 :             Yb = YCoord;
    4785            0 :             ZLLC = ZCoord;
    4786            0 :             if (surfTemp.Class != SurfaceClass::Detached_F) {
    4787            0 :                 XLLC = Xb * state.dataSurfaceGeometry->CosBldgRotAppGonly - Yb * state.dataSurfaceGeometry->SinBldgRotAppGonly;
    4788            0 :                 YLLC = Xb * state.dataSurfaceGeometry->SinBldgRotAppGonly + Yb * state.dataSurfaceGeometry->CosBldgRotAppGonly;
    4789              :             } else {
    4790            0 :                 XLLC = Xb;
    4791            0 :                 YLLC = Yb;
    4792              :             }
    4793              :         }
    4794              : 
    4795            7 :         XX(1) = 0.0;
    4796            7 :         XX(2) = 0.0;
    4797            7 :         XX(3) = Length;
    4798            7 :         XX(4) = Length;
    4799            7 :         YY(1) = Height;
    4800            7 :         YY(4) = Height;
    4801            7 :         YY(3) = 0.0;
    4802            7 :         YY(2) = 0.0;
    4803              : 
    4804           35 :         for (int n = 1; n <= surfTemp.Sides; ++n) {
    4805           28 :             Vrt = n;
    4806           28 :             surfTemp.Vertex(Vrt).x = XLLC - XX(n) * CosSurfAzimuth - YY(n) * CosSurfTilt * SinSurfAzimuth;
    4807           28 :             surfTemp.Vertex(Vrt).y = YLLC + XX(n) * SinSurfAzimuth - YY(n) * CosSurfTilt * CosSurfAzimuth;
    4808           28 :             surfTemp.Vertex(Vrt).z = ZLLC + YY(n) * SinSurfTilt;
    4809              :         }
    4810              : 
    4811            7 :         Vectors::CreateNewellAreaVector(surfTemp.Vertex, surfTemp.Sides, surfTemp.NewellAreaVector);
    4812            7 :         surfTemp.GrossArea = Vectors::VecLength(surfTemp.NewellAreaVector);
    4813            7 :         surfTemp.Area = surfTemp.GrossArea;
    4814            7 :         surfTemp.NetAreaShadowCalc = surfTemp.Area;
    4815            7 :         Vectors::CreateNewellSurfaceNormalVector(surfTemp.Vertex, surfTemp.Sides, surfTemp.NewellSurfaceNormalVector);
    4816            7 :         Vectors::DetermineAzimuthAndTilt(
    4817            7 :             surfTemp.Vertex, SurfAzimuth, SurfTilt, surfTemp.lcsx, surfTemp.lcsy, surfTemp.lcsz, surfTemp.NewellSurfaceNormalVector);
    4818            7 :         surfTemp.Azimuth = SurfAzimuth;
    4819            7 :         surfTemp.Tilt = SurfTilt;
    4820            7 :         surfTemp.convOrientation = Convect::GetSurfConvOrientation(surfTemp.Tilt);
    4821              :         // Sine and cosine of azimuth and tilt
    4822            7 :         surfTemp.SinAzim = SinSurfAzimuth;
    4823            7 :         surfTemp.CosAzim = CosSurfAzimuth;
    4824            7 :         surfTemp.SinTilt = SinSurfTilt;
    4825            7 :         surfTemp.CosTilt = CosSurfTilt;
    4826            7 :         surfTemp.ViewFactorGround = 0.5 * (1.0 - surfTemp.CosTilt);
    4827              :         // Outward normal unit vector (pointing away from room)
    4828              : 
    4829            7 :         surfTemp.OutNormVec = surfTemp.NewellSurfaceNormalVector;
    4830           28 :         for (int n = 1; n <= 3; ++n) {
    4831           21 :             if (std::abs(surfTemp.OutNormVec(n) - 1.0) < 1.e-06) {
    4832            2 :                 surfTemp.OutNormVec(n) = +1.0;
    4833              :             }
    4834           21 :             if (std::abs(surfTemp.OutNormVec(n) + 1.0) < 1.e-06) {
    4835            3 :                 surfTemp.OutNormVec(n) = -1.0;
    4836              :             }
    4837           21 :             if (std::abs(surfTemp.OutNormVec(n)) < 1.e-06) {
    4838           10 :                 surfTemp.OutNormVec(n) = 0.0;
    4839              :             }
    4840              :         }
    4841              : 
    4842              :         // Can perform tests on this surface here
    4843            7 :         surfTemp.ViewFactorSky = 0.5 * (1.0 + surfTemp.CosTilt);
    4844              :         // The following IR view factors are modified in subr. SkyDifSolarShading if there are shadowing
    4845              :         // surfaces
    4846            7 :         surfTemp.ViewFactorSkyIR = surfTemp.ViewFactorSky;
    4847            7 :         surfTemp.ViewFactorGroundIR = 0.5 * (1.0 - surfTemp.CosTilt);
    4848              : 
    4849            7 :         Perimeter = distance(surfTemp.Vertex(surfTemp.Sides), surfTemp.Vertex(1));
    4850           28 :         for (Vrt = 2; Vrt <= surfTemp.Sides; ++Vrt) {
    4851           21 :             Perimeter += distance(surfTemp.Vertex(Vrt), surfTemp.Vertex(Vrt - 1));
    4852              :         }
    4853            7 :         surfTemp.Perimeter = Perimeter;
    4854              : 
    4855              :         // Call to transform vertices
    4856              : 
    4857            7 :         TransformVertsByAspect(state, SurfNum, surfTemp.Sides);
    4858            7 :     }
    4859              : 
    4860          226 :     void GetHTSubSurfaceData(EnergyPlusData &state,
    4861              :                              bool &ErrorsFound,                       // Error flag indicator (true if errors found)
    4862              :                              int &SurfNum,                            // Count of Current SurfaceNumber
    4863              :                              int const TotHTSubs,                     // Number of Heat Transfer SubSurfaces to obtain
    4864              :                              const Array1D_string &SubSurfCls,        // Valid Classes for Sub Surfaces
    4865              :                              const Array1D<SurfaceClass> &SubSurfIDs, // ID Assignments for valid sub surface classes
    4866              :                              int &AddedSubSurfaces,                   // Subsurfaces added when windows reference Window5
    4867              :                              int &NeedToAddSurfaces                   // Number of surfaces to add, based on unentered IZ surfaces
    4868              :     )
    4869              :     {
    4870              : 
    4871              :         // SUBROUTINE INFORMATION:
    4872              :         //       AUTHOR         Linda Lawrie
    4873              :         //       DATE WRITTEN   May 2000
    4874              :         //       MODIFIED       August 2012 - line up subsurfaces with base surface types
    4875              : 
    4876              :         // PURPOSE OF THIS SUBROUTINE:
    4877              :         // This subroutine gets the HeatTransfer Sub Surface Data, checks it for errors, etc.
    4878              : 
    4879              :         // REFERENCES:
    4880              :         // Heat Transfer Subsurface Definition
    4881              :         // FenestrationSurface:Detailed,
    4882              :         //        \min-fields 19
    4883              :         //        \memo Used for windows, doors, glass doors, tubular daylighting devices
    4884              :         //        \format vertices
    4885              :         //   A1 , \field Name
    4886              :         //        \required-field
    4887              :         //        \type alpha
    4888              :         //   A2 , \field Surface Type
    4889              :         //        \required-field
    4890              :         //        \type choice
    4891              :         //        \key Window
    4892              :         //        \key Door
    4893              :         //        \key GlassDoor
    4894              :         //        \key TubularDaylightDome
    4895              :         //        \key TubularDaylightDiffuser
    4896              :         //   A3 , \field Construction Name
    4897              :         //        \required-field
    4898              :         //        \note To be matched with a construction in this input file
    4899              :         //        \type object-list
    4900              :         //        \object-list ConstructionNames
    4901              :         //   A4 , \field Building Surface Name
    4902              :         //        \required-field
    4903              :         //        \type object-list
    4904              :         //        \object-list SurfaceNames
    4905              :         //   A5,  \field Outside Boundary Condition Object
    4906              :         //        \type object-list
    4907              :         //        \object-list OutFaceEnvNames
    4908              :         //        \note Non-blank only if base surface field Outside Boundary Condition is
    4909              :         //        \note Surface or OtherSideCoefficients
    4910              :         //        \note If Base Surface's Surface, specify name of corresponding subsurface in adjacent zone or
    4911              :         //        \note specify current subsurface name for internal partition separating like zones
    4912              :         //        \note If OtherSideCoefficients, specify name of SurfaceProperty:OtherSideCoefficients
    4913              :         //        \note  or leave blank to inherit Base Surface's OtherSide Coefficients
    4914              :         //   N1, \field View Factor to Ground
    4915              :         //        \type real
    4916              :         //        \note From the exterior of the surface
    4917              :         //        \note Unused if one uses the "reflections" options in Solar Distribution in Building input
    4918              :         //        \note unless a DaylightingDevice:Shelf or DaylightingDevice:Tubular object has been specified.
    4919              :         //        \note autocalculate will automatically calculate this value from the tilt of the surface
    4920              :         //        \autocalculatable
    4921              :         //        \minimum 0.0
    4922              :         //        \maximum 1.0
    4923              :         //        \default autocalculate
    4924              :         //   A6, \field Frame and Divider Name
    4925              :         //        \note Enter the name of a WindowProperty:FrameAndDivider object
    4926              :         //        \type object-list
    4927              :         //        \object-list WindowFrameAndDividerNames
    4928              :         //        \note Used only for exterior windows (rectangular) and glass doors.
    4929              :         //        \note Unused for triangular windows.
    4930              :         //        \note If not specified (blank), window or glass door has no frame or divider
    4931              :         //        \note and no beam solar reflection from reveal surfaces.
    4932              :         //   N2 , \field Multiplier
    4933              :         //        \note Used only for Surface Type = WINDOW, GLASSDOOR or DOOR
    4934              :         //        \note Non-integer values will be truncated to integer
    4935              :         //        \default 1.0
    4936              :         //        \minimum 1.0
    4937              :         //   N3 , \field Number of Vertices
    4938              :         //        \minimum 3
    4939              :         //        \maximum 4
    4940              :         //        \autocalculatable
    4941              :         //        \default autocalculate
    4942              :         //        \note vertices are given in GlobalGeometryRules coordinates -- if relative, all surface coordinates
    4943              :         //        \note are "relative" to the Zone Origin.  If world, then building and zone origins are used
    4944              :         //        \note for some internal calculations, but all coordinates are given in an "absolute" system.
    4945              :         //  N4-15 as indicated by the N3 value
    4946              : 
    4947              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    4948              :         int IOStat;          // IO Status when calling get input subroutine
    4949              :         int SurfaceNumAlpha; // Number of material alpha names being passed
    4950              :         int SurfaceNumProp;  // Number of material properties being passed
    4951              :         int Found;           // For matching interzone surfaces
    4952              :         int Loop;
    4953              :         int ValidChk;
    4954              :         int numSides;
    4955              : 
    4956          226 :         auto &s_ipsc = state.dataIPShortCut;
    4957              : 
    4958          226 :         GetWindowShadingControlData(state, ErrorsFound);
    4959          226 :         s_ipsc->cCurrentModuleObject = "FenestrationSurface:Detailed";
    4960          226 :         state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, s_ipsc->cCurrentModuleObject, Loop, SurfaceNumAlpha, SurfaceNumProp);
    4961              : 
    4962          226 :         if (SurfaceNumAlpha != 6) {
    4963            0 :             ShowSevereError(
    4964              :                 state,
    4965            0 :                 format("{}: Object Definition indicates not = 6 Alpha Objects, Number Indicated={}", s_ipsc->cCurrentModuleObject, SurfaceNumAlpha));
    4966            0 :             ErrorsFound = true;
    4967              :         }
    4968              : 
    4969          226 :         if (SurfaceNumProp != 15) {
    4970            0 :             ShowSevereError(
    4971              :                 state,
    4972            0 :                 format("{}: Object Definition indicates > 15 Numeric Objects, Number Indicated={}", s_ipsc->cCurrentModuleObject, SurfaceNumAlpha));
    4973            0 :             ErrorsFound = true;
    4974              :         }
    4975          226 :         NeedToAddSurfaces = 0;
    4976              : 
    4977          441 :         for (Loop = 1; Loop <= TotHTSubs; ++Loop) {
    4978          430 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    4979          215 :                                                                      s_ipsc->cCurrentModuleObject,
    4980              :                                                                      Loop,
    4981          215 :                                                                      s_ipsc->cAlphaArgs,
    4982              :                                                                      SurfaceNumAlpha,
    4983          215 :                                                                      s_ipsc->rNumericArgs,
    4984              :                                                                      SurfaceNumProp,
    4985              :                                                                      IOStat,
    4986          215 :                                                                      s_ipsc->lNumericFieldBlanks,
    4987          215 :                                                                      s_ipsc->lAlphaFieldBlanks,
    4988          215 :                                                                      s_ipsc->cAlphaFieldNames,
    4989          215 :                                                                      s_ipsc->cNumericFieldNames);
    4990              : 
    4991          430 :             if (GlobalNames::VerifyUniqueInterObjectName(state,
    4992          215 :                                                          state.dataSurfaceGeometry->UniqueSurfaceNames,
    4993          215 :                                                          s_ipsc->cAlphaArgs(1),
    4994          215 :                                                          s_ipsc->cCurrentModuleObject,
    4995          215 :                                                          s_ipsc->cAlphaFieldNames(1),
    4996              :                                                          ErrorsFound)) {
    4997            0 :                 continue;
    4998              :             }
    4999              : 
    5000          215 :             ++SurfNum;
    5001              : 
    5002          215 :             auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    5003              : 
    5004          215 :             if (SurfaceNumProp < 12) {
    5005            0 :                 ShowSevereError(
    5006            0 :                     state, format("{}=\"{}\", Too few number of numeric args=[{}].", s_ipsc->cCurrentModuleObject, surfTemp.Name, SurfaceNumProp));
    5007            0 :                 ErrorsFound = true;
    5008              :             }
    5009              : 
    5010          215 :             surfTemp.Name = s_ipsc->cAlphaArgs(1); // Set the Surface Name in the Derived Type
    5011          215 :             ValidChk = Util::FindItemInList(s_ipsc->cAlphaArgs(2), SubSurfCls, 6);
    5012          215 :             if (ValidChk == 0) {
    5013            0 :                 ShowSevereError(state,
    5014            0 :                                 format("{}=\"{}\", invalid {}=\"{}",
    5015            0 :                                        s_ipsc->cCurrentModuleObject,
    5016            0 :                                        surfTemp.Name,
    5017            0 :                                        s_ipsc->cAlphaFieldNames(2),
    5018            0 :                                        s_ipsc->cAlphaArgs(2)));
    5019            0 :                 ErrorsFound = true;
    5020              :             } else {
    5021          215 :                 surfTemp.Class = SubSurfIDs(ValidChk); // Set class number
    5022              :             }
    5023              : 
    5024          215 :             surfTemp.Construction = Util::FindItemInList(s_ipsc->cAlphaArgs(3), state.dataConstruction->Construct, state.dataHeatBal->TotConstructs);
    5025              : 
    5026          215 :             if (surfTemp.Construction == 0) {
    5027            2 :                 ShowSevereError(state,
    5028            4 :                                 format("{}=\"{}\", invalid {}=\"{}\".",
    5029            1 :                                        s_ipsc->cCurrentModuleObject,
    5030            1 :                                        surfTemp.Name,
    5031            1 :                                        s_ipsc->cAlphaFieldNames(3),
    5032            1 :                                        s_ipsc->cAlphaArgs(3)));
    5033            1 :                 ErrorsFound = true;
    5034            1 :                 continue;
    5035              :             } else {
    5036          214 :                 state.dataConstruction->Construct(surfTemp.Construction).IsUsed = true;
    5037          214 :                 surfTemp.ConstructionStoredInputValue = surfTemp.Construction;
    5038              :             }
    5039              : 
    5040          214 :             if (surfTemp.Class == SurfaceClass::Window || surfTemp.Class == SurfaceClass::GlassDoor || surfTemp.Class == SurfaceClass::TDD_Diffuser ||
    5041           26 :                 surfTemp.Class == SurfaceClass::TDD_Dome) {
    5042              : 
    5043          195 :                 if (surfTemp.Construction != 0) {
    5044          195 :                     auto const &construction = state.dataConstruction->Construct(surfTemp.Construction);
    5045          195 :                     if (!construction.TypeIsWindow && !construction.TypeIsAirBoundary) {
    5046            0 :                         ErrorsFound = true;
    5047            0 :                         ShowSevereError(state,
    5048            0 :                                         format("{}=\"{}\" has an opaque surface construction; it should have a window construction.",
    5049            0 :                                                s_ipsc->cCurrentModuleObject,
    5050            0 :                                                surfTemp.Name));
    5051              :                     }
    5052          195 :                     if (state.dataConstruction->Construct(surfTemp.Construction).SourceSinkPresent) {
    5053            0 :                         ErrorsFound = true;
    5054            0 :                         ShowSevereError(
    5055              :                             state,
    5056            0 :                             format("{}=\"{}\": Windows are not allowed to have embedded sources/sinks", s_ipsc->cCurrentModuleObject, surfTemp.Name));
    5057              :                     }
    5058              :                 }
    5059              : 
    5060          214 :             } else if (surfTemp.Construction != 0) {
    5061           19 :                 if (state.dataConstruction->Construct(surfTemp.Construction).TypeIsWindow) {
    5062            0 :                     ErrorsFound = true;
    5063            0 :                     ShowSevereError(state,
    5064            0 :                                     format("{}=\"{}\", invalid {}=\"{}\" - has Window materials.",
    5065            0 :                                            s_ipsc->cCurrentModuleObject,
    5066            0 :                                            surfTemp.Name,
    5067            0 :                                            s_ipsc->cAlphaFieldNames(3),
    5068            0 :                                            s_ipsc->cAlphaArgs(3)));
    5069            0 :                     ShowContinueError(state, format("...because {}={}", s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2)));
    5070              :                 }
    5071              :             }
    5072              : 
    5073          214 :             surfTemp.HeatTransSurf = true;
    5074              : 
    5075          214 :             surfTemp.BaseSurfName = s_ipsc->cAlphaArgs(4);
    5076              :             //  The subsurface inherits properties from the base surface
    5077              :             //  Exterior conditions, Zone, etc.
    5078              :             //  We can figure out the base surface though, because they've all been entered
    5079          214 :             Found = Util::FindItemInList(surfTemp.BaseSurfName, state.dataSurfaceGeometry->SurfaceTmp, state.dataSurface->TotSurfaces);
    5080          214 :             if (Found > 0) {
    5081          214 :                 surfTemp.BaseSurf = Found;
    5082          214 :                 surfTemp.ExtBoundCond = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCond;
    5083          214 :                 surfTemp.ExtBoundCondName = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCondName;
    5084          214 :                 surfTemp.ExtSolar = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtSolar;
    5085          214 :                 surfTemp.ExtWind = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtWind;
    5086          214 :                 surfTemp.Zone = state.dataSurfaceGeometry->SurfaceTmp(Found).Zone;
    5087          214 :                 surfTemp.ZoneName = state.dataSurfaceGeometry->SurfaceTmp(Found).ZoneName;
    5088          214 :                 surfTemp.OSCPtr = state.dataSurfaceGeometry->SurfaceTmp(Found).OSCPtr;
    5089          234 :                 if (state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCond == unreconciledZoneSurface &&
    5090           20 :                     state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCondName ==
    5091           20 :                         state.dataSurfaceGeometry->SurfaceTmp(Found).Name) { // Adiabatic surface, no windows or doors allowed
    5092            0 :                     ShowSevereError(state,
    5093            0 :                                     format("{}=\"{}\", invalid {}=\"{}\".",
    5094            0 :                                            s_ipsc->cCurrentModuleObject,
    5095            0 :                                            surfTemp.Name,
    5096            0 :                                            s_ipsc->cAlphaFieldNames(4),
    5097            0 :                                            s_ipsc->cAlphaArgs(4)));
    5098            0 :                     ShowContinueError(state, "... adiabatic surfaces cannot have windows or doors.");
    5099            0 :                     ShowContinueError(state,
    5100              :                                       "... no solar transmission will result for these windows or doors. You must have interior windows or doors on "
    5101              :                                       "Interzone surfaces for transmission to result.");
    5102              :                 }
    5103              :             } else {
    5104            0 :                 ShowSevereError(state,
    5105            0 :                                 format("{}=\"{}\", invalid {}=\"{}",
    5106            0 :                                        s_ipsc->cCurrentModuleObject,
    5107            0 :                                        surfTemp.Name,
    5108            0 :                                        s_ipsc->cAlphaFieldNames(4),
    5109            0 :                                        s_ipsc->cAlphaArgs(4)));
    5110            0 :                 surfTemp.ZoneName = "Unknown Zone";
    5111            0 :                 ErrorsFound = true;
    5112              :             }
    5113          214 :             if (surfTemp.Class == SurfaceClass::TDD_Dome || surfTemp.Class == SurfaceClass::TDD_Diffuser) {
    5114           13 :                 surfTemp.ExtBoundCond = DataSurfaces::ExternalEnvironment;
    5115              :             }
    5116              : 
    5117          214 :             if (surfTemp.ExtBoundCond == DataSurfaces::ExternalEnvironment) {
    5118          194 :                 if (!s_ipsc->lAlphaFieldBlanks(5)) {
    5119            0 :                     ShowWarningError(state,
    5120            0 :                                      format("{}=\"{}\", invalid field {}", s_ipsc->cCurrentModuleObject, surfTemp.Name, s_ipsc->cAlphaFieldNames(5)));
    5121            0 :                     ShowContinueError(
    5122              :                         state,
    5123            0 :                         format("...when Base surface uses \"Outdoors\" as {}, subsurfaces need to be blank to inherit the outdoor characteristics.",
    5124            0 :                                s_ipsc->cAlphaFieldNames(5)));
    5125            0 :                     ShowContinueError(state, "...Surface external characteristics changed to reflect base surface.");
    5126              :                 }
    5127              :             }
    5128              : 
    5129          214 :             if (surfTemp.ExtBoundCond == unreconciledZoneSurface) { // "Surface" Base Surface
    5130           14 :                 if (!s_ipsc->lAlphaFieldBlanks(5)) {
    5131           14 :                     surfTemp.ExtBoundCondName = s_ipsc->cAlphaArgs(5);
    5132              :                 } else {
    5133            0 :                     ShowSevereError(state,
    5134            0 :                                     format("{}=\"{}\", invalid blank {}", s_ipsc->cCurrentModuleObject, surfTemp.Name, s_ipsc->cAlphaFieldNames(5)));
    5135            0 :                     ShowContinueError(
    5136              :                         state,
    5137            0 :                         format("...when Base surface uses \"Surface\" as {}, subsurfaces must also specify specific surfaces in the adjacent zone.",
    5138            0 :                                s_ipsc->cAlphaFieldNames(5)));
    5139            0 :                     surfTemp.ExtBoundCondName = s_ipsc->cAlphaArgs(5); // putting it as blank will not confuse things later.
    5140            0 :                     ErrorsFound = true;
    5141              :                 }
    5142              :             }
    5143              : 
    5144          214 :             if ((surfTemp.ExtBoundCond == unenteredAdjacentZoneSurface) ||
    5145          210 :                 (surfTemp.ExtBoundCond == unenteredAdjacentSpaceSurface)) { // "Zone" - unmatched interior surface
    5146            6 :                 ++NeedToAddSurfaces;
    5147              :                 // ignoring window5datafiles for now -- will need to add.
    5148              :             }
    5149              : 
    5150          214 :             if (surfTemp.ExtBoundCond == DataSurfaces::OtherSideCoefNoCalcExt || surfTemp.ExtBoundCond == DataSurfaces::OtherSideCoefCalcExt) {
    5151            0 :                 if (!s_ipsc->lAlphaFieldBlanks(5)) { // Otherside Coef special Name
    5152            0 :                     Found = Util::FindItemInList(s_ipsc->cAlphaArgs(5), state.dataSurface->OSC, state.dataSurface->TotOSC);
    5153            0 :                     if (Found == 0) {
    5154            0 :                         ShowSevereError(state,
    5155            0 :                                         format("{}=\"{}\", invalid {}=\"{}\".",
    5156            0 :                                                s_ipsc->cCurrentModuleObject,
    5157            0 :                                                surfTemp.Name,
    5158            0 :                                                s_ipsc->cAlphaFieldNames(5),
    5159            0 :                                                s_ipsc->cAlphaArgs(5)));
    5160            0 :                         ShowContinueError(state, "...base surface requires that this subsurface have OtherSideCoefficients -- not found.");
    5161            0 :                         ErrorsFound = true;
    5162              :                     } else { // found
    5163              :                         // The following allows for a subsurface that has different characteristics than
    5164              :                         // the base surface with OtherSide Coeff -- do we want that or is it an error?
    5165            0 :                         surfTemp.OSCPtr = Found;
    5166            0 :                         surfTemp.ExtBoundCondName = s_ipsc->cAlphaArgs(5);
    5167            0 :                         if (state.dataSurface->OSC(Found).SurfFilmCoef > 0.0) {
    5168            0 :                             surfTemp.ExtBoundCond = DataSurfaces::OtherSideCoefCalcExt;
    5169              :                         } else {
    5170            0 :                             surfTemp.ExtBoundCond = DataSurfaces::OtherSideCoefNoCalcExt;
    5171              :                         }
    5172              :                     }
    5173              :                 }
    5174              :             }
    5175              : 
    5176          214 :             if (surfTemp.ExtBoundCond == DataSurfaces::OtherSideCondModeledExt) {
    5177            0 :                 surfTemp.ExtBoundCond = DataSurfaces::ExternalEnvironment;
    5178              :             }
    5179              : 
    5180          214 :             if (surfTemp.ExtBoundCondName == BlankString) {
    5181          188 :                 surfTemp.ExtBoundCondName = surfTemp.Name;
    5182              :             }
    5183          214 :             surfTemp.ViewFactorGround = s_ipsc->rNumericArgs(1);
    5184          214 :             if (s_ipsc->lNumericFieldBlanks(1)) {
    5185           16 :                 surfTemp.ViewFactorGround = Constant::AutoCalculate;
    5186              :             }
    5187              : 
    5188          214 :             if (s_ipsc->lNumericFieldBlanks(3) || s_ipsc->rNumericArgs(3) == Constant::AutoCalculate) {
    5189           14 :                 s_ipsc->rNumericArgs(3) = (SurfaceNumProp - 3) / 3;
    5190           14 :                 surfTemp.Sides = s_ipsc->rNumericArgs(3);
    5191           14 :                 if (mod(SurfaceNumProp - 3, 3) != 0) {
    5192            0 :                     ShowWarningError(state,
    5193            0 :                                      format("{}=\"{}\", {}",
    5194            0 :                                             s_ipsc->cCurrentModuleObject,
    5195            0 :                                             surfTemp.Name,
    5196            0 :                                             format("{} not even multiple of 3. Will read in {}", s_ipsc->cNumericFieldNames(3), surfTemp.Sides)));
    5197              :                 }
    5198           14 :                 if (s_ipsc->rNumericArgs(3) < 3) {
    5199            0 :                     ShowSevereError(state,
    5200            0 :                                     format("{}=\"{}\", {} (autocalculate) must be >= 3. Only {} provided.",
    5201            0 :                                            s_ipsc->cCurrentModuleObject,
    5202            0 :                                            surfTemp.Name,
    5203            0 :                                            s_ipsc->cNumericFieldNames(3),
    5204            0 :                                            surfTemp.Sides));
    5205            0 :                     ErrorsFound = true;
    5206            0 :                     continue;
    5207              :                 }
    5208              :             } else {
    5209          200 :                 numSides = (SurfaceNumProp - 2) / 3;
    5210          200 :                 surfTemp.Sides = s_ipsc->rNumericArgs(3);
    5211          200 :                 if (numSides > surfTemp.Sides) {
    5212            0 :                     ShowWarningError(state,
    5213            0 :                                      format("{}=\"{}\", field {}={}",
    5214            0 :                                             s_ipsc->cCurrentModuleObject,
    5215            0 :                                             surfTemp.Name,
    5216            0 :                                             s_ipsc->cNumericFieldNames(3),
    5217            0 :                                             fmt::to_string(surfTemp.Sides)));
    5218            0 :                     ShowContinueError(state,
    5219            0 :                                       format("...but {} were entered. Only the indicated {} will be used.", numSides, s_ipsc->cNumericFieldNames(3)));
    5220              :                 }
    5221              :             }
    5222          214 :             surfTemp.Vertex.allocate(surfTemp.Sides);
    5223          214 :             if (surfTemp.Class == SurfaceClass::Window || surfTemp.Class == SurfaceClass::GlassDoor || surfTemp.Class == SurfaceClass::Door) {
    5224          201 :                 surfTemp.Multiplier = int(s_ipsc->rNumericArgs(2));
    5225              :             }
    5226              :             // Only windows, glass doors and doors can have Multiplier > 1:
    5227          227 :             if ((surfTemp.Class != SurfaceClass::Window && surfTemp.Class != SurfaceClass::GlassDoor && surfTemp.Class != SurfaceClass::Door) &&
    5228           13 :                 s_ipsc->rNumericArgs(2) > 1.0) {
    5229            0 :                 ShowWarningError(state,
    5230            0 :                                  format("{}=\"{}\", invalid {}=[{:.1T}].",
    5231            0 :                                         s_ipsc->cCurrentModuleObject,
    5232            0 :                                         surfTemp.Name,
    5233            0 :                                         s_ipsc->cNumericFieldNames(2),
    5234            0 :                                         s_ipsc->rNumericArgs(2)));
    5235            0 :                 ShowContinueError(state,
    5236            0 :                                   format("...because {}={} multiplier will be set to 1.0.", s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2)));
    5237            0 :                 surfTemp.Multiplier = 1.0;
    5238              :             }
    5239              : 
    5240          856 :             GetVertices(state, SurfNum, surfTemp.Sides, s_ipsc->rNumericArgs({4, _}));
    5241              : 
    5242          214 :             CheckConvexity(state, SurfNum, surfTemp.Sides);
    5243          214 :             surfTemp.windowShadingControlList.clear();
    5244          214 :             surfTemp.activeWindowShadingControl = 0;
    5245          214 :             surfTemp.HasShadeControl = false;
    5246              : 
    5247          214 :             surfTemp.shadedConstructionList.clear();
    5248          214 :             surfTemp.activeShadedConstruction = 0;
    5249          214 :             surfTemp.shadedStormWinConstructionList.clear();
    5250              : 
    5251          214 :             if (surfTemp.Class == SurfaceClass::Window || surfTemp.Class == SurfaceClass::GlassDoor || surfTemp.Class == SurfaceClass::TDD_Diffuser ||
    5252           26 :                 surfTemp.Class == SurfaceClass::TDD_Dome) {
    5253              : 
    5254          195 :                 if (surfTemp.ExtBoundCond == DataSurfaces::OtherSideCoefNoCalcExt || surfTemp.ExtBoundCond == DataSurfaces::OtherSideCoefCalcExt) {
    5255            0 :                     ShowSevereError(
    5256              :                         state,
    5257            0 :                         format("{}=\"{}\", Other side coefficients are not allowed with windows.", s_ipsc->cCurrentModuleObject, surfTemp.Name));
    5258            0 :                     ErrorsFound = true;
    5259              :                 }
    5260              : 
    5261          195 :                 if (surfTemp.ExtBoundCond == DataSurfaces::Ground) {
    5262            0 :                     ShowSevereError(state,
    5263            0 :                                     format("{}=\"{}\", Exterior boundary condition = Ground is not allowed with windows.",
    5264            0 :                                            s_ipsc->cCurrentModuleObject,
    5265            0 :                                            surfTemp.Name));
    5266            0 :                     ErrorsFound = true;
    5267              :                 }
    5268              : 
    5269          195 :                 if (surfTemp.ExtBoundCond == DataSurfaces::KivaFoundation) {
    5270            0 :                     ShowSevereError(state,
    5271            0 :                                     format("{}=\"{}\", Exterior boundary condition = Foundation is not allowed with windows.",
    5272            0 :                                            s_ipsc->cCurrentModuleObject,
    5273            0 :                                            surfTemp.Name));
    5274            0 :                     ErrorsFound = true;
    5275              :                 }
    5276              : 
    5277          195 :                 InitialAssociateWindowShadingControlFenestration(state, ErrorsFound, SurfNum);
    5278              : 
    5279          195 :                 CheckWindowShadingControlFrameDivider(state, "GetHTSubSurfaceData", ErrorsFound, SurfNum, 6);
    5280              : 
    5281          195 :                 if (surfTemp.Sides == 3) { // Triangular window
    5282            1 :                     if (!s_ipsc->cAlphaArgs(6).empty()) {
    5283            0 :                         ShowWarningError(state,
    5284            0 :                                          format("{}=\"{}\", invalid {}=\"{}\".",
    5285            0 :                                                 s_ipsc->cCurrentModuleObject,
    5286            0 :                                                 surfTemp.Name,
    5287            0 :                                                 s_ipsc->cAlphaFieldNames(6),
    5288            0 :                                                 s_ipsc->cAlphaArgs(6)));
    5289            0 :                         ShowContinueError(state, ".. because it is a triangular window and cannot have a frame or divider or reveal reflection.");
    5290            0 :                         ShowContinueError(state, "Frame, divider and reveal reflection will be ignored for this window.");
    5291              :                     }
    5292            1 :                     surfTemp.FrameDivider = 0;
    5293              :                 } // End of check if window is triangular or rectangular
    5294              : 
    5295              :             } // check on non-opaquedoor subsurfaces
    5296              : 
    5297          214 :             CheckSubSurfaceMiscellaneous(
    5298          214 :                 state, "GetHTSubSurfaceData", ErrorsFound, SurfNum, s_ipsc->cAlphaArgs(1), s_ipsc->cAlphaArgs(3), AddedSubSurfaces);
    5299              : 
    5300              :         } // End of main loop over subsurfaces
    5301          440 :     }
    5302              : 
    5303          226 :     void GetRectSubSurfaces(EnergyPlusData &state,
    5304              :                             bool &ErrorsFound,                       // Error flag indicator (true if errors found)
    5305              :                             int &SurfNum,                            // Count of Current SurfaceNumber
    5306              :                             int const TotWindows,                    // Number of Window SubSurfaces to obtain
    5307              :                             int const TotDoors,                      // Number of Door SubSurfaces to obtain
    5308              :                             int const TotGlazedDoors,                // Number of Glass Door SubSurfaces to obtain
    5309              :                             int const TotIZWindows,                  // Number of Interzone Window SubSurfaces to obtain
    5310              :                             int const TotIZDoors,                    // Number of Interzone Door SubSurfaces to obtain
    5311              :                             int const TotIZGlazedDoors,              // Number of Interzone Glass Door SubSurfaces to obtain
    5312              :                             const Array1D<SurfaceClass> &SubSurfIDs, // ID Assignments for valid sub surface classes
    5313              :                             int &AddedSubSurfaces,                   // Subsurfaces added when windows reference Window5
    5314              :                             int &NeedToAddSubSurfaces                // Number of surfaces to add, based on unentered IZ surfaces
    5315              :     )
    5316              :     {
    5317              : 
    5318              :         // SUBROUTINE INFORMATION:
    5319              :         //       AUTHOR         Linda Lawrie
    5320              :         //       DATE WRITTEN   December 2008
    5321              : 
    5322              :         // PURPOSE OF THIS SUBROUTINE:
    5323              :         // Get simple (rectangular, relative origin to base surface) windows, doors, glazed doors.
    5324              : 
    5325              :         // SUBROUTINE PARAMETER DEFINITIONS:
    5326          226 :         static Array1D_string const cModuleObjects(6, {"Window", "Door", "GlazedDoor", "Window:Interzone", "Door:Interzone", "GlazedDoor:Interzone"});
    5327              : 
    5328              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    5329              :         int ItemsToGet;
    5330              :         int Loop;
    5331              :         int NumAlphas;
    5332              :         int NumNumbers;
    5333              :         int IOStat; // IO Status when calling get input subroutine
    5334              :         int Found;  // For matching base surfaces
    5335              :         bool GettingIZSurfaces;
    5336              :         int FrameField;
    5337              :         int OtherSurfaceField;
    5338              :         int ClassItem;
    5339              :         int IZFound;
    5340              : 
    5341          226 :         auto &s_ipsc = state.dataIPShortCut;
    5342         1582 :         for (int Item = 1; Item <= 6; ++Item) {
    5343              : 
    5344         1356 :             s_ipsc->cCurrentModuleObject = cModuleObjects(Item);
    5345         1356 :             if (Item == 1) {
    5346          226 :                 ItemsToGet = TotWindows;
    5347          226 :                 GettingIZSurfaces = false;
    5348          226 :                 FrameField = 5;
    5349          226 :                 OtherSurfaceField = 0;
    5350          226 :                 ClassItem = 1;
    5351         1130 :             } else if (Item == 2) {
    5352          226 :                 ItemsToGet = TotDoors;
    5353          226 :                 GettingIZSurfaces = false;
    5354          226 :                 FrameField = 0;
    5355          226 :                 OtherSurfaceField = 0;
    5356          226 :                 ClassItem = 2;
    5357          904 :             } else if (Item == 3) {
    5358          226 :                 ItemsToGet = TotGlazedDoors;
    5359          226 :                 GettingIZSurfaces = false;
    5360          226 :                 FrameField = 5;
    5361          226 :                 OtherSurfaceField = 0;
    5362          226 :                 ClassItem = 3;
    5363          678 :             } else if (Item == 4) {
    5364          226 :                 ItemsToGet = TotIZWindows;
    5365          226 :                 GettingIZSurfaces = true;
    5366          226 :                 FrameField = 0;
    5367          226 :                 OtherSurfaceField = 4;
    5368          226 :                 ClassItem = 1;
    5369          452 :             } else if (Item == 5) {
    5370          226 :                 ItemsToGet = TotIZDoors;
    5371          226 :                 GettingIZSurfaces = true;
    5372          226 :                 FrameField = 0;
    5373          226 :                 OtherSurfaceField = 4;
    5374          226 :                 ClassItem = 2;
    5375              :             } else { // Item = 6
    5376          226 :                 ItemsToGet = TotIZGlazedDoors;
    5377          226 :                 GettingIZSurfaces = true;
    5378          226 :                 FrameField = 0;
    5379          226 :                 OtherSurfaceField = 4;
    5380          226 :                 ClassItem = 3;
    5381              :             }
    5382              : 
    5383         1365 :             for (Loop = 1; Loop <= ItemsToGet; ++Loop) {
    5384           18 :                 state.dataInputProcessing->inputProcessor->getObjectItem(state,
    5385            9 :                                                                          s_ipsc->cCurrentModuleObject,
    5386              :                                                                          Loop,
    5387            9 :                                                                          s_ipsc->cAlphaArgs,
    5388              :                                                                          NumAlphas,
    5389            9 :                                                                          s_ipsc->rNumericArgs,
    5390              :                                                                          NumNumbers,
    5391              :                                                                          IOStat,
    5392            9 :                                                                          s_ipsc->lNumericFieldBlanks,
    5393            9 :                                                                          s_ipsc->lAlphaFieldBlanks,
    5394            9 :                                                                          s_ipsc->cAlphaFieldNames,
    5395            9 :                                                                          s_ipsc->cNumericFieldNames);
    5396              : 
    5397           18 :                 if (GlobalNames::VerifyUniqueInterObjectName(state,
    5398            9 :                                                              state.dataSurfaceGeometry->UniqueSurfaceNames,
    5399            9 :                                                              s_ipsc->cAlphaArgs(1),
    5400            9 :                                                              s_ipsc->cCurrentModuleObject,
    5401            9 :                                                              s_ipsc->cAlphaFieldNames(1),
    5402              :                                                              ErrorsFound)) {
    5403            0 :                     continue;
    5404              :                 }
    5405              : 
    5406            9 :                 if (NumNumbers < 5) {
    5407            0 :                     ShowSevereError(
    5408              :                         state,
    5409            0 :                         format("{}=\"{}\", Too few number of numeric args=[{}].", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1), NumNumbers));
    5410            0 :                     ErrorsFound = true;
    5411              :                 }
    5412              : 
    5413            9 :                 ++SurfNum;
    5414            9 :                 auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    5415              : 
    5416            9 :                 surfTemp.Name = s_ipsc->cAlphaArgs(1);  // Set the Surface Name in the Derived Type
    5417            9 :                 surfTemp.Class = SubSurfIDs(ClassItem); // Set class number
    5418              : 
    5419            9 :                 surfTemp.Construction =
    5420            9 :                     Util::FindItemInList(s_ipsc->cAlphaArgs(2), state.dataConstruction->Construct, state.dataHeatBal->TotConstructs);
    5421              : 
    5422            9 :                 if (surfTemp.Construction == 0) {
    5423            0 :                     ErrorsFound = true;
    5424            0 :                     ShowSevereError(state,
    5425            0 :                                     format("{}=\"{}\", invalid {}=\"{}\".",
    5426            0 :                                            s_ipsc->cCurrentModuleObject,
    5427            0 :                                            surfTemp.Name,
    5428            0 :                                            s_ipsc->cAlphaFieldNames(2),
    5429            0 :                                            s_ipsc->cAlphaArgs(2)));
    5430              :                 } else {
    5431            9 :                     state.dataConstruction->Construct(surfTemp.Construction).IsUsed = true;
    5432            9 :                     surfTemp.ConstructionStoredInputValue = surfTemp.Construction;
    5433              :                 }
    5434              : 
    5435            9 :                 if (surfTemp.Class == SurfaceClass::Window || surfTemp.Class == SurfaceClass::GlassDoor) {
    5436              : 
    5437            8 :                     if (surfTemp.Construction != 0) {
    5438            8 :                         auto const &construction = state.dataConstruction->Construct(surfTemp.Construction);
    5439              : 
    5440            8 :                         if (!construction.TypeIsWindow && !construction.TypeIsAirBoundary) {
    5441            0 :                             ErrorsFound = true;
    5442            0 :                             ShowSevereError(state,
    5443            0 :                                             format("{}=\"{}\" has an opaque surface construction; it should have a window construction.",
    5444            0 :                                                    s_ipsc->cCurrentModuleObject,
    5445            0 :                                                    surfTemp.Name));
    5446              :                         }
    5447            8 :                         if (state.dataConstruction->Construct(surfTemp.Construction).SourceSinkPresent) {
    5448            0 :                             ErrorsFound = true;
    5449            0 :                             ShowSevereError(state,
    5450            0 :                                             format("{}=\"{}\": Windows are not allowed to have embedded sources/sinks",
    5451            0 :                                                    s_ipsc->cCurrentModuleObject,
    5452            0 :                                                    surfTemp.Name));
    5453              :                         }
    5454              :                     }
    5455              : 
    5456            9 :                 } else if (surfTemp.Construction != 0) {
    5457            1 :                     if (state.dataConstruction->Construct(surfTemp.Construction).TypeIsWindow) {
    5458            0 :                         ErrorsFound = true;
    5459            0 :                         ShowSevereError(state,
    5460            0 :                                         format("{}=\"{}\", invalid {}=\"{}\" - has Window materials.",
    5461            0 :                                                s_ipsc->cCurrentModuleObject,
    5462            0 :                                                surfTemp.Name,
    5463            0 :                                                s_ipsc->cAlphaFieldNames(2),
    5464            0 :                                                s_ipsc->cAlphaArgs(2)));
    5465              :                     }
    5466              :                 }
    5467              : 
    5468            9 :                 surfTemp.HeatTransSurf = true;
    5469              : 
    5470            9 :                 surfTemp.BaseSurfName = s_ipsc->cAlphaArgs(3);
    5471              :                 //  The subsurface inherits properties from the base surface
    5472              :                 //  Exterior conditions, Zone, etc.
    5473              :                 //  We can figure out the base surface though, because they've all been entered
    5474            9 :                 Found = Util::FindItemInList(surfTemp.BaseSurfName, state.dataSurfaceGeometry->SurfaceTmp, state.dataSurface->TotSurfaces);
    5475            9 :                 if (Found > 0) {
    5476            9 :                     surfTemp.BaseSurf = Found;
    5477            9 :                     surfTemp.ExtBoundCond = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCond;
    5478            9 :                     surfTemp.ExtBoundCondName = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCondName;
    5479            9 :                     surfTemp.ExtSolar = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtSolar;
    5480            9 :                     surfTemp.ExtWind = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtWind;
    5481            9 :                     surfTemp.Tilt = state.dataSurfaceGeometry->SurfaceTmp(Found).Tilt;
    5482            9 :                     surfTemp.convOrientation = Convect::GetSurfConvOrientation(surfTemp.Tilt);
    5483            9 :                     surfTemp.Azimuth = state.dataSurfaceGeometry->SurfaceTmp(Found).Azimuth;
    5484            9 :                     surfTemp.Zone = state.dataSurfaceGeometry->SurfaceTmp(Found).Zone;
    5485            9 :                     surfTemp.ZoneName = state.dataSurfaceGeometry->SurfaceTmp(Found).ZoneName;
    5486            9 :                     surfTemp.OSCPtr = state.dataSurfaceGeometry->SurfaceTmp(Found).OSCPtr;
    5487            9 :                     surfTemp.ViewFactorGround = state.dataSurfaceGeometry->SurfaceTmp(Found).ViewFactorGround;
    5488            9 :                     surfTemp.ViewFactorSky = state.dataSurfaceGeometry->SurfaceTmp(Found).ViewFactorSky;
    5489              :                 } else {
    5490            0 :                     ShowSevereError(state,
    5491            0 :                                     format("{}=\"{}\", invalid {}=\"{}",
    5492            0 :                                            s_ipsc->cCurrentModuleObject,
    5493            0 :                                            surfTemp.Name,
    5494            0 :                                            s_ipsc->cAlphaFieldNames(3),
    5495            0 :                                            s_ipsc->cAlphaArgs(3)));
    5496            0 :                     surfTemp.ZoneName = "Unknown Zone";
    5497            0 :                     ErrorsFound = true;
    5498            0 :                     continue;
    5499              :                 }
    5500            9 :                 if (state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCond == unreconciledZoneSurface &&
    5501            0 :                     state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCondName ==
    5502            0 :                         state.dataSurfaceGeometry->SurfaceTmp(Found).Name) { // Adiabatic surface, no windows or doors allowed
    5503            0 :                     ShowSevereError(state,
    5504            0 :                                     format("{}=\"{}\", invalid {}=\"{}\".",
    5505            0 :                                            s_ipsc->cCurrentModuleObject,
    5506            0 :                                            surfTemp.Name,
    5507            0 :                                            s_ipsc->cAlphaFieldNames(3),
    5508            0 :                                            s_ipsc->cAlphaArgs(3)));
    5509            0 :                     ShowContinueError(state, "... adiabatic surfaces cannot have windows or doors.");
    5510            0 :                     ShowContinueError(state,
    5511              :                                       "... no solar transmission will result for these windows or doors. You must have interior windows or doors on "
    5512              :                                       "Interzone surfaces for transmission to result.");
    5513              :                 }
    5514              : 
    5515            9 :                 if (surfTemp.ExtBoundCond == unreconciledZoneSurface) { // "Surface" Base Surface
    5516            0 :                     if (!GettingIZSurfaces) {
    5517            0 :                         ShowSevereError(state, format("{}=\"{}\", invalid use of object", s_ipsc->cCurrentModuleObject, surfTemp.Name));
    5518            0 :                         ShowContinueError(
    5519              :                             state,
    5520            0 :                             format(
    5521              :                                 "...when Base surface uses \"Surface\" as {}, subsurfaces must also specify specific surfaces in the adjacent zone.",
    5522            0 :                                 s_ipsc->cAlphaFieldNames(5)));
    5523            0 :                         ShowContinueError(state, format("...Please use {}:Interzone to enter this surface.", s_ipsc->cCurrentModuleObject));
    5524            0 :                         surfTemp.ExtBoundCondName = BlankString; // putting it as blank will not confuse things later.
    5525            0 :                         ErrorsFound = true;
    5526              :                     }
    5527              :                 }
    5528              : 
    5529            9 :                 if (surfTemp.ExtBoundCond == unreconciledZoneSurface) { // "Surface" Base Surface
    5530            0 :                     if (GettingIZSurfaces) {
    5531            0 :                         surfTemp.ExtBoundCondName = s_ipsc->cAlphaArgs(OtherSurfaceField);
    5532            0 :                         IZFound = Util::FindItemInList(surfTemp.ExtBoundCondName, state.dataHeatBal->Zone, state.dataGlobal->NumOfZones);
    5533            0 :                         if (IZFound > 0) {
    5534            0 :                             surfTemp.ExtBoundCond = unenteredAdjacentZoneSurface;
    5535              :                         }
    5536              :                     } else { // Interior Window
    5537            0 :                         surfTemp.ExtBoundCondName = surfTemp.Name;
    5538              :                     }
    5539              :                 }
    5540              : 
    5541              :                 // This is the parent's property:
    5542            9 :                 if (surfTemp.ExtBoundCond == unenteredAdjacentZoneSurface) { // OtherZone - unmatched interior surface
    5543            0 :                     if (GettingIZSurfaces) {
    5544            0 :                         ++NeedToAddSubSurfaces;
    5545              :                     } else { // Interior Window
    5546            0 :                         ShowSevereError(state,
    5547            0 :                                         format("{}=\"{}\", invalid Interzone Surface, specify {}:InterZone",
    5548            0 :                                                s_ipsc->cCurrentModuleObject,
    5549            0 :                                                surfTemp.Name,
    5550            0 :                                                s_ipsc->cCurrentModuleObject));
    5551            0 :                         ShowContinueError(state, "...when base surface is an interzone surface, subsurface must also be an interzone surface.");
    5552            0 :                         ++NeedToAddSubSurfaces;
    5553            0 :                         ErrorsFound = true;
    5554              :                     }
    5555              :                 }
    5556              : 
    5557            9 :                 if (GettingIZSurfaces) {
    5558            0 :                     if (s_ipsc->lAlphaFieldBlanks(OtherSurfaceField)) {
    5559              :                         // blank -- set it up for unentered adjacent zone
    5560            0 :                         if (surfTemp.ExtBoundCond == unenteredAdjacentZoneSurface) {                                   // already set but need Zone
    5561            0 :                             surfTemp.ExtBoundCondName = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCondName; // base surface has it
    5562            0 :                         } else if (surfTemp.ExtBoundCond == unreconciledZoneSurface) {
    5563            0 :                             surfTemp.ExtBoundCondName = state.dataSurfaceGeometry->SurfaceTmp(Found).ZoneName; // base surface has it
    5564            0 :                             surfTemp.ExtBoundCond = unenteredAdjacentZoneSurface;
    5565              :                         } else { // not correct boundary condition for interzone subsurface
    5566            0 :                             ShowSevereError(
    5567              :                                 state,
    5568            0 :                                 format("{}=\"{}\", invalid Base Surface type for Interzone Surface", s_ipsc->cCurrentModuleObject, surfTemp.Name));
    5569            0 :                             ShowContinueError(state,
    5570              :                                               "...when base surface is not an interzone surface, subsurface must also not be an interzone surface.");
    5571            0 :                             ErrorsFound = true;
    5572              :                         }
    5573              :                     }
    5574              :                 }
    5575              : 
    5576            9 :                 if (surfTemp.ExtBoundCond == DataSurfaces::OtherSideCondModeledExt) {
    5577            0 :                     surfTemp.ExtBoundCond = DataSurfaces::ExternalEnvironment;
    5578              :                 }
    5579              : 
    5580              :                 //      SurfaceTmp(SurfNum)%ViewFactorGround = AutoCalculate
    5581              : 
    5582            9 :                 surfTemp.Sides = 4;
    5583            9 :                 surfTemp.Vertex.allocate(surfTemp.Sides);
    5584            9 :                 if (surfTemp.Class == SurfaceClass::Window || surfTemp.Class == SurfaceClass::GlassDoor || surfTemp.Class == SurfaceClass::Door) {
    5585            9 :                     surfTemp.Multiplier = int(s_ipsc->rNumericArgs(1));
    5586            0 :                 } else if (s_ipsc->rNumericArgs(1) > 1.0) {
    5587            0 :                     ShowWarningError(state,
    5588            0 :                                      format("{}=\"{}\", invalid {}=[{:.1T}].",
    5589            0 :                                             s_ipsc->cCurrentModuleObject,
    5590            0 :                                             surfTemp.Name,
    5591            0 :                                             s_ipsc->cNumericFieldNames(1),
    5592            0 :                                             s_ipsc->rNumericArgs(1)));
    5593            0 :                     ShowContinueError(state,
    5594            0 :                                       format("...because {}={} multiplier will be set to 1.0.", s_ipsc->cAlphaFieldNames(1), s_ipsc->cAlphaArgs(1)));
    5595            0 :                     surfTemp.Multiplier = 1.0;
    5596              :                 }
    5597              : 
    5598           36 :                 MakeRelativeRectangularVertices(state,
    5599              :                                                 surfTemp.BaseSurf,
    5600              :                                                 SurfNum,
    5601            9 :                                                 s_ipsc->rNumericArgs(2),
    5602            9 :                                                 s_ipsc->rNumericArgs(3),
    5603            9 :                                                 s_ipsc->rNumericArgs(4),
    5604            9 :                                                 s_ipsc->rNumericArgs(5));
    5605              : 
    5606            9 :                 if (surfTemp.Area <= 0.0) {
    5607            0 :                     ShowSevereError(
    5608              :                         state,
    5609            0 :                         format("{}=\"{}\", Surface Area <= 0.0; Entered Area={:.2T}", s_ipsc->cCurrentModuleObject, surfTemp.Name, surfTemp.Area));
    5610            0 :                     ErrorsFound = true;
    5611              :                 }
    5612              : 
    5613            9 :                 surfTemp.windowShadingControlList.clear();
    5614            9 :                 surfTemp.activeWindowShadingControl = 0;
    5615            9 :                 surfTemp.HasShadeControl = false;
    5616              : 
    5617            9 :                 surfTemp.shadedConstructionList.clear();
    5618            9 :                 surfTemp.activeShadedConstruction = 0;
    5619            9 :                 surfTemp.shadedStormWinConstructionList.clear();
    5620              : 
    5621            9 :                 InitialAssociateWindowShadingControlFenestration(state, ErrorsFound, SurfNum);
    5622              : 
    5623            9 :                 if (!GettingIZSurfaces && (surfTemp.Class == SurfaceClass::Window || surfTemp.Class == SurfaceClass::GlassDoor)) {
    5624              : 
    5625            8 :                     if (surfTemp.ExtBoundCond == DataSurfaces::OtherSideCoefNoCalcExt ||
    5626            8 :                         surfTemp.ExtBoundCond == DataSurfaces::OtherSideCoefCalcExt) {
    5627            0 :                         ShowSevereError(
    5628              :                             state,
    5629            0 :                             format("{}=\"{}\", Other side coefficients are not allowed with windows.", s_ipsc->cCurrentModuleObject, surfTemp.Name));
    5630            0 :                         ErrorsFound = true;
    5631              :                     }
    5632              : 
    5633            8 :                     if (surfTemp.ExtBoundCond == DataSurfaces::Ground) {
    5634            0 :                         ShowSevereError(state,
    5635            0 :                                         format("{}=\"{}\", Exterior boundary condition = Ground is not allowed with windows.",
    5636            0 :                                                s_ipsc->cCurrentModuleObject,
    5637            0 :                                                surfTemp.Name));
    5638            0 :                         ErrorsFound = true;
    5639              :                     }
    5640              : 
    5641            8 :                     CheckWindowShadingControlFrameDivider(state, "GetRectSubSurfaces", ErrorsFound, SurfNum, FrameField);
    5642              : 
    5643              :                 } // check on non-opaquedoor subsurfaces
    5644              : 
    5645            9 :                 CheckSubSurfaceMiscellaneous(
    5646            9 :                     state, "GetRectSubSurfaces", ErrorsFound, SurfNum, s_ipsc->cAlphaArgs(1), s_ipsc->cAlphaArgs(2), AddedSubSurfaces);
    5647              : 
    5648              :             } // Getting Items
    5649              :         }
    5650          226 :     }
    5651              : 
    5652          203 :     void CheckWindowShadingControlFrameDivider(EnergyPlusData &state,
    5653              :                                                std::string_view const cRoutineName, // routine name calling this one (for error messages)
    5654              :                                                bool &ErrorsFound,                   // true if errors have been found or are found here
    5655              :                                                int const SurfNum,                   // current surface number
    5656              :                                                int const FrameField                 // field number for frame/divider
    5657              :     )
    5658              :     {
    5659              : 
    5660              :         // SUBROUTINE INFORMATION:
    5661              :         //       AUTHOR         Linda Lawrie
    5662              :         //       DATE WRITTEN   December 2008
    5663              : 
    5664              :         // PURPOSE OF THIS SUBROUTINE:
    5665              :         // This routine performs checks on WindowShadingControl settings and Frame/Divider Settings.
    5666              : 
    5667              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    5668              :         int ConstrNumSh;    // Construction number with Shade
    5669              :         int ShDevNum;       // Shading Device number
    5670              :         int Lay;            // Layer number
    5671              :         int TotGlassLayers; // Number of glass layers in window construction
    5672              :         int TotLayers;      // Number of layers in unshaded construction
    5673              :         int TotShLayers;    // Number of layers in shaded construction
    5674              :         int MatGap;         // Gap material number
    5675              :         int MatGap1;        // Material number of gap to left (outer side) of between-glass shade/blind
    5676              :         int MatGap2;        // Material number of gap to right (inner side) of between-glass shade/blind
    5677              :         int MatSh;          // Between-glass shade/blind material number
    5678              :         Real64 MatGapCalc;  // Calculated MatGap diff for shaded vs non-shaded constructions
    5679              : 
    5680              :         // If WindowShadingControl has been specified for this window --
    5681              :         // Set shaded construction number if shaded construction was specified in WindowShadingControl.
    5682              :         // Otherwise, create shaded construction if WindowShadingControl for this window has
    5683              :         // interior or exterior shade/blind (but not between-glass shade/blind) specified.
    5684              : 
    5685          203 :         auto &s_ipsc = state.dataIPShortCut;
    5686          203 :         auto &s_mat = state.dataMaterial;
    5687              : 
    5688          203 :         auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    5689              : 
    5690          214 :         for (std::size_t shadeControlIndex = 0; shadeControlIndex < surfTemp.windowShadingControlList.size(); ++shadeControlIndex) {
    5691           11 :             int WSCPtr = surfTemp.windowShadingControlList[shadeControlIndex];
    5692           11 :             ConstrNumSh = 0;
    5693           11 :             if (!ErrorsFound && surfTemp.HasShadeControl) {
    5694           11 :                 ConstrNumSh = surfTemp.shadedConstructionList[shadeControlIndex];
    5695           11 :                 if (ConstrNumSh > 0) {
    5696           11 :                     surfTemp.activeShadedConstruction = ConstrNumSh;
    5697            0 :                 } else if (ANY_INTERIOR_SHADE_BLIND(state.dataSurface->WindowShadingControl(WSCPtr).ShadingType) ||
    5698            0 :                            ANY_EXTERIOR_SHADE_BLIND_SCREEN(state.dataSurface->WindowShadingControl(WSCPtr).ShadingType)) {
    5699            0 :                     ShDevNum = state.dataSurface->WindowShadingControl(WSCPtr).ShadingDevice;
    5700            0 :                     if (ShDevNum > 0) {
    5701            0 :                         CreateShadedWindowConstruction(state, SurfNum, WSCPtr, ShDevNum, shadeControlIndex);
    5702            0 :                         ConstrNumSh = surfTemp.activeShadedConstruction;
    5703              :                     }
    5704              :                 }
    5705              :             }
    5706              : 
    5707              :             // Error checks for shades and blinds
    5708              : 
    5709           11 :             int ConstrNum = surfTemp.Construction;
    5710           11 :             if (!ErrorsFound && WSCPtr > 0 && ConstrNum > 0 && ConstrNumSh > 0) {
    5711              : 
    5712           11 :                 if (ANY_INTERIOR_SHADE_BLIND(state.dataSurface->WindowShadingControl(WSCPtr).ShadingType)) {
    5713            9 :                     TotLayers = state.dataConstruction->Construct(ConstrNum).TotLayers;
    5714            9 :                     TotShLayers = state.dataConstruction->Construct(ConstrNumSh).TotLayers;
    5715            9 :                     if (TotShLayers - 1 != TotLayers) {
    5716            0 :                         ShowWarningError(
    5717              :                             state,
    5718              :                             "WindowShadingControl: Interior shade or blind: Potential problem in match of unshaded/shaded constructions, "
    5719              :                             "shaded should have 1 more layers than unshaded.");
    5720            0 :                         ShowContinueError(state, format("Unshaded construction={}", state.dataConstruction->Construct(ConstrNum).Name));
    5721            0 :                         ShowContinueError(state, format("Shaded construction={}", state.dataConstruction->Construct(ConstrNumSh).Name));
    5722            0 :                         ShowContinueError(state,
    5723              :                                           "If preceding two constructions are same name, you have likely specified a WindowShadingControl (Field #3) "
    5724              :                                           "with the Window Construction rather than a shaded construction.");
    5725              :                     }
    5726           18 :                     for (Lay = 1; Lay <= state.dataConstruction->Construct(ConstrNum).TotLayers; ++Lay) {
    5727            9 :                         if (state.dataConstruction->Construct(ConstrNum).LayerPoint(Lay) !=
    5728            9 :                             state.dataConstruction->Construct(ConstrNumSh).LayerPoint(Lay)) {
    5729            0 :                             ErrorsFound = true;
    5730            0 :                             ShowSevereError(state,
    5731            0 :                                             format(" The glass and gas layers in the shaded and unshaded constructions do not match for window={}",
    5732            0 :                                                    surfTemp.Name));
    5733            0 :                             ShowContinueError(state, format("Unshaded construction={}", state.dataConstruction->Construct(ConstrNum).Name));
    5734            0 :                             ShowContinueError(state, format("Shaded construction={}", state.dataConstruction->Construct(ConstrNumSh).Name));
    5735            0 :                             break;
    5736              :                         }
    5737              :                     }
    5738              :                 }
    5739              : 
    5740           11 :                 if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(state.dataSurface->WindowShadingControl(WSCPtr).ShadingType)) {
    5741            0 :                     TotLayers = state.dataConstruction->Construct(ConstrNum).TotLayers;
    5742            0 :                     TotShLayers = state.dataConstruction->Construct(ConstrNumSh).TotLayers;
    5743            0 :                     if (TotShLayers - 1 != TotLayers) {
    5744            0 :                         ShowWarningError(state,
    5745              :                                          "WindowShadingControl: Exterior shade, screen or blind: Potential problem in match of unshaded/shaded "
    5746              :                                          "constructions, shaded should have 1 more layer than unshaded.");
    5747            0 :                         ShowContinueError(state, format("Unshaded construction={}", state.dataConstruction->Construct(ConstrNum).Name));
    5748            0 :                         ShowContinueError(state, format("Shaded construction={}", state.dataConstruction->Construct(ConstrNumSh).Name));
    5749            0 :                         ShowContinueError(
    5750              :                             state,
    5751              :                             "If preceding two constructions have the same name, you have likely specified a WindowShadingControl (Field "
    5752              :                             "#3) with the Window Construction rather than a shaded construction.");
    5753              :                     }
    5754            0 :                     for (Lay = 1; Lay <= state.dataConstruction->Construct(ConstrNum).TotLayers; ++Lay) {
    5755            0 :                         if (state.dataConstruction->Construct(ConstrNum).LayerPoint(Lay) !=
    5756            0 :                             state.dataConstruction->Construct(ConstrNumSh).LayerPoint(Lay + 1)) {
    5757            0 :                             ErrorsFound = true;
    5758            0 :                             ShowSevereError(state,
    5759            0 :                                             format(" The glass and gas layers in the shaded and unshaded constructions do not match for window={}",
    5760            0 :                                                    surfTemp.Name));
    5761            0 :                             ShowContinueError(state, format("Unshaded construction={}", state.dataConstruction->Construct(ConstrNum).Name));
    5762            0 :                             ShowContinueError(state, format("Shaded construction={}", state.dataConstruction->Construct(ConstrNumSh).Name));
    5763            0 :                             break;
    5764              :                         }
    5765              :                     }
    5766              :                 }
    5767              : 
    5768           11 :                 if (ANY_BETWEENGLASS_SHADE_BLIND(state.dataSurface->WindowShadingControl(WSCPtr).ShadingType)) {
    5769              :                     // Divider not allowed with between-glass shade or blind
    5770            0 :                     if (surfTemp.FrameDivider > 0) {
    5771            0 :                         if (state.dataSurface->FrameDivider(surfTemp.FrameDivider).DividerWidth > 0.0) {
    5772            0 :                             ShowWarningError(state, format("A divider cannot be specified for window {}", surfTemp.Name));
    5773            0 :                             ShowContinueError(state, ", which has a between-glass shade or blind.");
    5774            0 :                             ShowContinueError(state, "Calculation will proceed without the divider for this window.");
    5775            0 :                             state.dataSurface->FrameDivider(surfTemp.FrameDivider).DividerWidth = 0.0;
    5776              :                         }
    5777              :                     }
    5778              :                     // Check consistency of gap widths between unshaded and shaded constructions
    5779            0 :                     TotGlassLayers = state.dataConstruction->Construct(ConstrNum).TotGlassLayers;
    5780            0 :                     TotLayers = state.dataConstruction->Construct(ConstrNum).TotLayers;
    5781            0 :                     TotShLayers = state.dataConstruction->Construct(ConstrNumSh).TotLayers;
    5782            0 :                     if (TotShLayers - 2 != TotLayers) {
    5783            0 :                         ShowWarningError(
    5784              :                             state,
    5785              :                             "WindowShadingControl: Between Glass Shade/Blind: Potential problem in match of unshaded/shaded constructions, "
    5786              :                             "shaded should have 2 more layers than unshaded.");
    5787            0 :                         ShowContinueError(state, format("Unshaded construction={}", state.dataConstruction->Construct(ConstrNum).Name));
    5788            0 :                         ShowContinueError(state, format("Shaded construction={}", state.dataConstruction->Construct(ConstrNumSh).Name));
    5789            0 :                         ShowContinueError(state,
    5790              :                                           "If preceding two constructions are same name, you have likely specified a WindowShadingControl (Field #3) "
    5791              :                                           "with the Window Construction rather than a shaded construction.");
    5792              :                     }
    5793            0 :                     if (state.dataConstruction->Construct(ConstrNum).LayerPoint(TotLayers) !=
    5794            0 :                         state.dataConstruction->Construct(ConstrNumSh).LayerPoint(TotShLayers)) {
    5795            0 :                         ShowSevereError(state, format("{}: Mis-match in unshaded/shaded inside layer materials.  These should match.", cRoutineName));
    5796            0 :                         ShowContinueError(state,
    5797            0 :                                           format("Unshaded construction={}, Material={}",
    5798            0 :                                                  state.dataConstruction->Construct(ConstrNum).Name,
    5799            0 :                                                  s_mat->materials(state.dataConstruction->Construct(ConstrNum).LayerPoint(TotLayers))->Name));
    5800            0 :                         ShowContinueError(state,
    5801            0 :                                           format("Shaded construction={}, Material={}",
    5802            0 :                                                  state.dataConstruction->Construct(ConstrNumSh).Name,
    5803            0 :                                                  s_mat->materials(state.dataConstruction->Construct(ConstrNumSh).LayerPoint(TotShLayers))->Name));
    5804            0 :                         ErrorsFound = true;
    5805              :                     }
    5806            0 :                     if (state.dataConstruction->Construct(ConstrNum).LayerPoint(1) != state.dataConstruction->Construct(ConstrNumSh).LayerPoint(1)) {
    5807            0 :                         ShowSevereError(state, format("{}: Mis-match in unshaded/shaded inside layer materials.  These should match.", cRoutineName));
    5808            0 :                         ShowContinueError(state,
    5809            0 :                                           format("Unshaded construction={}, Material={}",
    5810            0 :                                                  state.dataConstruction->Construct(ConstrNum).Name,
    5811            0 :                                                  s_mat->materials(state.dataConstruction->Construct(ConstrNum).LayerPoint(1))->Name));
    5812            0 :                         ShowContinueError(state,
    5813            0 :                                           format("Shaded construction={}, Material={}",
    5814            0 :                                                  state.dataConstruction->Construct(ConstrNumSh).Name,
    5815            0 :                                                  s_mat->materials(state.dataConstruction->Construct(ConstrNumSh).LayerPoint(1))->Name));
    5816            0 :                         ErrorsFound = true;
    5817              :                     }
    5818            0 :                     if (TotGlassLayers == 2 || TotGlassLayers == 3) {
    5819            0 :                         MatGap = state.dataConstruction->Construct(ConstrNum).LayerPoint(2 * TotGlassLayers - 2);
    5820            0 :                         MatGap1 = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(2 * TotGlassLayers - 2);
    5821            0 :                         MatGap2 = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(2 * TotGlassLayers);
    5822            0 :                         MatSh = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(2 * TotGlassLayers - 1);
    5823            0 :                         if (state.dataSurface->WindowShadingControl(WSCPtr).ShadingType == DataSurfaces::WinShadingType::BGBlind) {
    5824            0 :                             MatGapCalc = std::abs(s_mat->materials(MatGap)->Thickness -
    5825            0 :                                                   (s_mat->materials(MatGap1)->Thickness + s_mat->materials(MatGap2)->Thickness));
    5826            0 :                             if (MatGapCalc > 0.001) {
    5827            0 :                                 ShowSevereError(state,
    5828            0 :                                                 format("{}: The gap width(s) for the unshaded window construction {}",
    5829              :                                                        cRoutineName,
    5830            0 :                                                        state.dataConstruction->Construct(ConstrNum).Name));
    5831            0 :                                 ShowContinueError(state,
    5832            0 :                                                   "are inconsistent with the gap widths for shaded window construction " +
    5833            0 :                                                       state.dataConstruction->Construct(ConstrNumSh).Name);
    5834            0 :                                 ShowContinueError(state, "for window " + surfTemp.Name + ", which has a between-glass blind.");
    5835            0 :                                 ShowContinueError(
    5836              :                                     state,
    5837            0 :                                     format("..Material={} thickness={:.3R} -", s_mat->materials(MatGap)->Name, s_mat->materials(MatGap)->Thickness));
    5838            0 :                                 ShowContinueError(state,
    5839            0 :                                                   format("..( Material={} thickness={:.3R} +",
    5840            0 :                                                          s_mat->materials(MatGap1)->Name,
    5841            0 :                                                          s_mat->materials(MatGap1)->Thickness));
    5842            0 :                                 ShowContinueError(state,
    5843            0 :                                                   format("..Material={} thickness={:.3R} )=[{:.3R}] >.001",
    5844            0 :                                                          s_mat->materials(MatGap2)->Name,
    5845            0 :                                                          s_mat->materials(MatGap2)->Thickness,
    5846              :                                                          MatGapCalc));
    5847            0 :                                 ErrorsFound = true;
    5848              :                             }
    5849              :                         } else { // Between-glass shade
    5850            0 :                             MatGapCalc = std::abs(
    5851            0 :                                 s_mat->materials(MatGap)->Thickness -
    5852            0 :                                 (s_mat->materials(MatGap1)->Thickness + s_mat->materials(MatGap2)->Thickness + s_mat->materials(MatSh)->Thickness));
    5853            0 :                             if (MatGapCalc > 0.001) {
    5854            0 :                                 ShowSevereError(state,
    5855            0 :                                                 format("{}: The gap width(s) for the unshaded window construction {}",
    5856              :                                                        cRoutineName,
    5857            0 :                                                        state.dataConstruction->Construct(ConstrNum).Name));
    5858            0 :                                 ShowContinueError(state,
    5859            0 :                                                   "are inconsistent with the gap widths for shaded window construction " +
    5860            0 :                                                       state.dataConstruction->Construct(ConstrNumSh).Name);
    5861            0 :                                 ShowContinueError(state, "for window " + surfTemp.Name + ", which has a between-glass shade.");
    5862            0 :                                 ShowContinueError(
    5863              :                                     state,
    5864            0 :                                     format("..Material={} thickness={:.3R} -", s_mat->materials(MatGap)->Name, s_mat->materials(MatGap)->Thickness));
    5865            0 :                                 ShowContinueError(state,
    5866            0 :                                                   format("...( Material={} thickness={:.3R} +",
    5867            0 :                                                          s_mat->materials(MatGap1)->Name,
    5868            0 :                                                          s_mat->materials(MatGap1)->Thickness));
    5869            0 :                                 ShowContinueError(state,
    5870            0 :                                                   format("..Material={} thickness={:.3R} +",
    5871            0 :                                                          s_mat->materials(MatGap2)->Name,
    5872            0 :                                                          s_mat->materials(MatGap2)->Thickness));
    5873            0 :                                 ShowContinueError(state,
    5874            0 :                                                   format("..Material={} thickness={:.3R} )=[{:.3R}] >.001",
    5875            0 :                                                          s_mat->materials(MatSh)->Name,
    5876            0 :                                                          s_mat->materials(MatSh)->Thickness,
    5877              :                                                          MatGapCalc));
    5878            0 :                                 ErrorsFound = true;
    5879              :                             }
    5880              :                         }
    5881              :                     }
    5882              :                 }
    5883              :             }
    5884              :         }
    5885              : 
    5886          203 :         if (surfTemp.Sides != 3) { // Rectangular Window
    5887              :             // Initialize the FrameDivider number for this window. W5FrameDivider will be positive if
    5888              :             // this window's construction came from the Window5 data file and that construction had an
    5889              :             // associated frame or divider. It will be zero if the window's construction is not from the
    5890              :             // Window5 data file, or the construction is from the data file, but the construction has no
    5891              :             // associated frame or divider. Note that if there is a FrameDivider candidate for this
    5892              :             // window from the Window5 data file it is used instead of the window's input FrameDivider.
    5893              : 
    5894          202 :             if (surfTemp.Construction != 0) {
    5895          202 :                 surfTemp.FrameDivider = state.dataConstruction->Construct(surfTemp.Construction).W5FrameDivider;
    5896              : 
    5897              :                 // Warning if FrameAndDivider for this window is over-ridden by one from Window5 Data File
    5898          202 :                 if (surfTemp.FrameDivider > 0 && !s_ipsc->lAlphaFieldBlanks(FrameField)) {
    5899            0 :                     ShowSevereError(state,
    5900            0 :                                     format("{}=\"{}\", {}=\"{}\"",
    5901            0 :                                            s_ipsc->cCurrentModuleObject,
    5902            0 :                                            surfTemp.Name,
    5903            0 :                                            s_ipsc->cAlphaFieldNames(FrameField),
    5904            0 :                                            s_ipsc->cAlphaArgs(FrameField)));
    5905            0 :                     ShowContinueError(state,
    5906            0 :                                       format("will be replaced with FrameAndDivider from Window5 Data File entry {}",
    5907            0 :                                              state.dataConstruction->Construct(surfTemp.Construction).Name));
    5908              :                 }
    5909              : 
    5910          202 :                 if (!s_ipsc->lAlphaFieldBlanks(FrameField) && surfTemp.FrameDivider == 0) {
    5911           24 :                     surfTemp.FrameDivider = Util::FindItemInList(s_ipsc->cAlphaArgs(FrameField), state.dataSurface->FrameDivider);
    5912           24 :                     if (surfTemp.FrameDivider == 0) {
    5913            0 :                         if (!state.dataConstruction->Construct(surfTemp.Construction).WindowTypeEQL) {
    5914            0 :                             ShowSevereError(state,
    5915            0 :                                             format("{}=\"{}\", invalid {}=\"{}\"",
    5916            0 :                                                    s_ipsc->cCurrentModuleObject,
    5917            0 :                                                    surfTemp.Name,
    5918            0 :                                                    s_ipsc->cAlphaFieldNames(FrameField),
    5919            0 :                                                    s_ipsc->cAlphaArgs(FrameField)));
    5920            0 :                             ErrorsFound = true;
    5921              :                         } else {
    5922            0 :                             ShowSevereError(state,
    5923            0 :                                             format("{}=\"{}\", invalid {}=\"{}\"",
    5924            0 :                                                    s_ipsc->cCurrentModuleObject,
    5925            0 :                                                    surfTemp.Name,
    5926            0 :                                                    s_ipsc->cAlphaFieldNames(FrameField),
    5927            0 :                                                    s_ipsc->cAlphaArgs(FrameField)));
    5928            0 :                             ShowContinueError(state, "...Frame/Divider is not supported in Equivalent Layer Window model.");
    5929              :                         }
    5930              :                     }
    5931              :                     // Divider not allowed with between-glass shade or blind
    5932           26 :                     for (int WSCPtr : surfTemp.windowShadingControlList) {
    5933            2 :                         if (!ErrorsFound && WSCPtr > 0 && ConstrNumSh > 0) {
    5934            2 :                             if (ANY_BETWEENGLASS_SHADE_BLIND(state.dataSurface->WindowShadingControl(WSCPtr).ShadingType)) {
    5935            0 :                                 if (surfTemp.FrameDivider > 0) {
    5936            0 :                                     if (state.dataSurface->FrameDivider(surfTemp.FrameDivider).DividerWidth > 0.0) {
    5937            0 :                                         ShowSevereError(state,
    5938            0 :                                                         format("{}=\"{}\", invalid {}=\"{}\"",
    5939            0 :                                                                s_ipsc->cCurrentModuleObject,
    5940            0 :                                                                surfTemp.Name,
    5941            0 :                                                                s_ipsc->cAlphaFieldNames(FrameField),
    5942            0 :                                                                s_ipsc->cAlphaArgs(FrameField)));
    5943            0 :                                         ShowContinueError(state,
    5944              :                                                           "Divider cannot be specified because the construction has a between-glass shade or blind.");
    5945            0 :                                         ShowContinueError(state, "Calculation will proceed without the divider for this window.");
    5946            0 :                                         ShowContinueError(
    5947              :                                             state,
    5948            0 :                                             format("Divider width = [{:.2R}].", state.dataSurface->FrameDivider(surfTemp.FrameDivider).DividerWidth));
    5949            0 :                                         state.dataSurface->FrameDivider(surfTemp.FrameDivider).DividerWidth = 0.0;
    5950              :                                     }
    5951              :                                 } // End of check if window has divider
    5952              :                             } // End of check if window has a between-glass shade or blind
    5953              :                         } // End of check if window has a shaded construction
    5954           24 :                     } // end of looping through window shading controls of window
    5955              :                 } // End of check if window has an associated FrameAndDivider
    5956              :             } // End of check if window has a construction
    5957              :         }
    5958              : 
    5959          203 :         if (state.dataConstruction->Construct(surfTemp.Construction).WindowTypeEQL) {
    5960            7 :             if (surfTemp.FrameDivider > 0) {
    5961              :                 // Equivalent Layer window does not have frame/divider model
    5962            4 :                 ShowSevereError(state,
    5963            8 :                                 format("{}=\"{}\", invalid {}=\"{}\"",
    5964            2 :                                        s_ipsc->cCurrentModuleObject,
    5965            2 :                                        surfTemp.Name,
    5966            2 :                                        s_ipsc->cAlphaFieldNames(FrameField),
    5967            2 :                                        s_ipsc->cAlphaArgs(FrameField)));
    5968            4 :                 ShowContinueError(state, "Frame/Divider is not supported in Equivalent Layer Window model.");
    5969            2 :                 surfTemp.FrameDivider = 0;
    5970              :             }
    5971              :         }
    5972          203 :     }
    5973              : 
    5974          223 :     void CheckSubSurfaceMiscellaneous(EnergyPlusData &state,
    5975              :                                       std::string_view const cRoutineName,       // routine name calling this one (for error messages)
    5976              :                                       bool &ErrorsFound,                         // true if errors have been found or are found here
    5977              :                                       int const SurfNum,                         // current surface number
    5978              :                                       std::string const &SubSurfaceName,         // name of the surface
    5979              :                                       std::string const &SubSurfaceConstruction, // name of the construction
    5980              :                                       int &AddedSubSurfaces)
    5981              :     {
    5982              : 
    5983              :         // SUBROUTINE INFORMATION:
    5984              :         //       AUTHOR         Linda Lawrie
    5985              :         //       DATE WRITTEN   December 2008
    5986              : 
    5987              :         // PURPOSE OF THIS SUBROUTINE:
    5988              :         // This routine performs miscellaneous checks on subsurfaces: Windows, GlassDoors, Doors, Tubular Devices.
    5989              : 
    5990          223 :         auto &s_mat = state.dataMaterial;
    5991              :         // Warning if window has multiplier > 1 and SolarDistribution = FullExterior or FullInteriorExterior
    5992              : 
    5993          223 :         auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    5994           43 :         if ((surfTemp.Class == SurfaceClass::Window || surfTemp.Class == SurfaceClass::GlassDoor) &&
    5995          449 :             static_cast<int>(state.dataHeatBal->SolarDistribution) > static_cast<int>(DataHeatBalance::Shadowing::Minimal) &&
    5996          183 :             surfTemp.Multiplier > 1.0) {
    5997            0 :             if (state.dataGlobal->DisplayExtraWarnings) {
    5998            0 :                 ShowWarningError(state, format("{}: A Multiplier > 1.0 for window/glass door {}", cRoutineName, surfTemp.Name));
    5999            0 :                 ShowContinueError(state, "in conjunction with SolarDistribution = FullExterior or FullInteriorExterior");
    6000            0 :                 ShowContinueError(state, "can cause inaccurate shadowing on the window and/or");
    6001            0 :                 ShowContinueError(state, "inaccurate interior solar distribution from the window.");
    6002              :             }
    6003            0 :             ++state.dataErrTracking->TotalMultipliedWindows;
    6004              :         }
    6005              : 
    6006              :         //  Require that a construction referenced by a surface that is a window
    6007              :         //  NOT have a shading device layer; use WindowShadingControl to specify a shading device.
    6008              : 
    6009          223 :         int ConstrNum = surfTemp.Construction;
    6010          223 :         if (ConstrNum > 0) {
    6011          223 :             int NumShades = 0;
    6012          595 :             for (int Lay = 1; Lay <= state.dataConstruction->Construct(ConstrNum).TotLayers; ++Lay) {
    6013          372 :                 int LayerPtr = state.dataConstruction->Construct(ConstrNum).LayerPoint(Lay);
    6014          372 :                 if (LayerPtr == 0) {
    6015            0 :                     continue; // Error is caught already, will terminate later
    6016              :                 }
    6017          744 :                 if (s_mat->materials(LayerPtr)->group == Material::Group::Shade || s_mat->materials(LayerPtr)->group == Material::Group::Blind ||
    6018          372 :                     s_mat->materials(LayerPtr)->group == Material::Group::Screen) {
    6019            0 :                     ++NumShades;
    6020              :                 }
    6021              :             }
    6022          223 :             if (NumShades != 0) {
    6023            0 :                 ShowSevereError(state, format("{}: Window \"{}\" must not directly reference", cRoutineName, SubSurfaceName));
    6024            0 :                 ShowContinueError(state, format("a Construction (i.e, \"{}\") with a shading device.", SubSurfaceConstruction));
    6025            0 :                 ShowContinueError(state, "Use WindowShadingControl to specify a shading device for a window.");
    6026            0 :                 ErrorsFound = true;
    6027              :             }
    6028              :         }
    6029              : 
    6030              :         // Disallow glass transmittance dirt factor for interior windows and glass doors
    6031              : 
    6032          223 :         if (surfTemp.ExtBoundCond != DataSurfaces::ExternalEnvironment &&
    6033           20 :             (surfTemp.Class == SurfaceClass::Window || surfTemp.Class == SurfaceClass::GlassDoor)) {
    6034            5 :             ConstrNum = surfTemp.Construction;
    6035            5 :             if (ConstrNum > 0) {
    6036            8 :                 for (int Lay = 1; Lay <= state.dataConstruction->Construct(ConstrNum).TotLayers; ++Lay) {
    6037            3 :                     int LayerPtr = state.dataConstruction->Construct(ConstrNum).LayerPoint(Lay);
    6038            3 :                     auto const *mat = s_mat->materials(LayerPtr);
    6039            3 :                     if (mat->group != Material::Group::Glass) {
    6040            0 :                         continue;
    6041              :                     }
    6042              : 
    6043            3 :                     if (dynamic_cast<Material::MaterialGlass const *>(mat)->GlassTransDirtFactor < 1.0) {
    6044            0 :                         ShowSevereError(state, format("{}: Interior Window or GlassDoor {} has a glass layer with", cRoutineName, SubSurfaceName));
    6045            0 :                         ShowContinueError(state, "Dirt Correction Factor for Solar and Visible Transmittance < 1.0");
    6046            0 :                         ShowContinueError(state, "A value less than 1.0 for this factor is only allowed for exterior windows and glass doors.");
    6047            0 :                         ErrorsFound = true;
    6048              :                     }
    6049              :                 }
    6050              :             }
    6051              :         }
    6052              : 
    6053              :         // If this is a window with a construction from the Window5DataFile, call routine that will
    6054              :         // (1) if one glazing system on Data File, give warning message if window height or width
    6055              :         //     differ by more than 10% from those of the glazing system on the Data File;
    6056              :         // (2) if two glazing systems (separated by a mullion) on Data File, create a second window
    6057              :         //     and adjust the dimensions of the original and second windows to those on the Data File
    6058              : 
    6059          223 :         if (surfTemp.Construction != 0) {
    6060              : 
    6061          223 :             if (state.dataConstruction->Construct(surfTemp.Construction).FromWindow5DataFile) {
    6062              : 
    6063            0 :                 ModifyWindow(state, SurfNum, ErrorsFound, AddedSubSurfaces);
    6064              : 
    6065              :             } else {
    6066              :                 // Calculate net area for base surface (note that ModifyWindow, above, adjusts net area of
    6067              :                 // base surface for case where window construction is from Window5 Data File
    6068              :                 // In case there is in error in this window's base surface (i.e. none)..
    6069          223 :                 if (surfTemp.BaseSurf > 0) {
    6070          223 :                     state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).Area -= surfTemp.Area;
    6071              : 
    6072              :                     // Subtract TDD:DIFFUSER area from other side interzone surface
    6073          229 :                     if ((surfTemp.Class == SurfaceClass::TDD_Diffuser) &&
    6074            6 :                         not_blank(
    6075            6 :                             state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).ExtBoundCondName)) { // Base surface is an interzone surface
    6076              :                         // Lookup interzone surface of the base surface
    6077              :                         // (Interzone surfaces have not been assigned yet, but all base surfaces should already be loaded.)
    6078            6 :                         int Found = Util::FindItemInList(state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).ExtBoundCondName,
    6079            6 :                                                          state.dataSurfaceGeometry->SurfaceTmp,
    6080              :                                                          SurfNum);
    6081            6 :                         if (Found != 0) {
    6082            6 :                             state.dataSurfaceGeometry->SurfaceTmp(Found).Area -= surfTemp.Area;
    6083              :                         }
    6084              :                     }
    6085          223 :                     if (state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).Area <= 0.0) {
    6086            0 :                         ShowSevereError(state,
    6087            0 :                                         format("{}: Surface Openings have too much area for base surface={}",
    6088              :                                                cRoutineName,
    6089            0 :                                                state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).Name));
    6090            0 :                         ShowContinueError(state, format("Opening Surface creating error={}", surfTemp.Name));
    6091            0 :                         ErrorsFound = true;
    6092              :                     }
    6093              :                     // Net area of base surface with unity window multipliers (used in shadowing checks)
    6094              :                     // For Windows, Glass Doors and Doors, just one area is subtracted.  For the rest, should be
    6095              :                     // full area.
    6096          223 :                     if (surfTemp.Class == SurfaceClass::Window || surfTemp.Class == SurfaceClass::GlassDoor) {
    6097          190 :                         state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).NetAreaShadowCalc -= surfTemp.Area / surfTemp.Multiplier;
    6098           33 :                     } else if (surfTemp.Class == SurfaceClass::Door) { // Door, TDD:Diffuser, TDD:DOME
    6099           20 :                         state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).NetAreaShadowCalc -= surfTemp.Area / surfTemp.Multiplier;
    6100              :                     } else {
    6101           13 :                         state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).NetAreaShadowCalc -= surfTemp.Area;
    6102              :                     }
    6103              :                 }
    6104              :             }
    6105              :         }
    6106          223 :     }
    6107              : 
    6108           14 :     void MakeRelativeRectangularVertices(EnergyPlusData &state,
    6109              :                                          int const BaseSurfNum, // Base surface
    6110              :                                          int const SurfNum,
    6111              :                                          Real64 const XCoord,
    6112              :                                          Real64 const ZCoord,
    6113              :                                          Real64 const Length,
    6114              :                                          Real64 const Height)
    6115              :     {
    6116              : 
    6117              :         // SUBROUTINE INFORMATION:
    6118              :         //       AUTHOR         Linda Lawrie
    6119              :         //       DATE WRITTEN   December 2008
    6120              : 
    6121              :         // PURPOSE OF THIS SUBROUTINE:
    6122              :         // This routine creates world/3d coordinates for rectangular surfaces using relative X and Z, length & height.
    6123              : 
    6124              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    6125           14 :         Array1D<Real64> XX(4);
    6126           14 :         Array1D<Real64> YY(4);
    6127              :         Real64 Perimeter;
    6128              :         int Vrt;
    6129              : 
    6130           14 :         if (BaseSurfNum == 0) {
    6131            0 :             return; // invalid base surface, don't bother
    6132              :         }
    6133              : 
    6134              :         // Tilt and Facing (Azimuth) will be same as the Base Surface
    6135              : 
    6136           14 :         auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    6137           14 :         surfTemp.Height = Height;
    6138           14 :         surfTemp.Width = Length;
    6139              : 
    6140           14 :         Real64 SurfAzimuth = surfTemp.Azimuth;
    6141           14 :         Real64 SurfTilt = surfTemp.Tilt;
    6142           14 :         Real64 CosSurfAzimuth = std::cos(SurfAzimuth * Constant::DegToRad);
    6143           14 :         Real64 SinSurfAzimuth = std::sin(SurfAzimuth * Constant::DegToRad);
    6144           14 :         Real64 CosSurfTilt = std::cos(SurfTilt * Constant::DegToRad);
    6145           14 :         Real64 SinSurfTilt = std::sin(SurfTilt * Constant::DegToRad);
    6146           14 :         Real64 BaseCosSurfAzimuth = state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosAzim;
    6147           14 :         Real64 BaseSinSurfAzimuth = state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).SinAzim;
    6148           14 :         Real64 BaseCosSurfTilt = state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosTilt;
    6149           14 :         Real64 BaseSinSurfTilt = state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).SinTilt;
    6150              : 
    6151           14 :         Real64 XLLC = state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).x - XCoord * BaseCosSurfAzimuth -
    6152           14 :                       ZCoord * BaseCosSurfTilt * BaseSinSurfAzimuth;
    6153           14 :         Real64 YLLC = state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).y + XCoord * BaseSinSurfAzimuth -
    6154           14 :                       ZCoord * BaseCosSurfTilt * BaseCosSurfAzimuth;
    6155           14 :         Real64 ZLLC = state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).z + ZCoord * BaseSinSurfTilt;
    6156              : 
    6157           14 :         XX(1) = 0.0;
    6158           14 :         XX(2) = 0.0;
    6159           14 :         XX(3) = Length;
    6160           14 :         XX(4) = Length;
    6161           14 :         YY(1) = Height;
    6162           14 :         YY(4) = Height;
    6163           14 :         YY(3) = 0.0;
    6164           14 :         YY(2) = 0.0;
    6165              : 
    6166           70 :         for (int n = 1; n <= surfTemp.Sides; ++n) {
    6167           56 :             Vrt = n;
    6168           56 :             surfTemp.Vertex(Vrt).x = XLLC - XX(n) * CosSurfAzimuth - YY(n) * CosSurfTilt * SinSurfAzimuth;
    6169           56 :             surfTemp.Vertex(Vrt).y = YLLC + XX(n) * SinSurfAzimuth - YY(n) * CosSurfTilt * CosSurfAzimuth;
    6170           56 :             surfTemp.Vertex(Vrt).z = ZLLC + YY(n) * SinSurfTilt;
    6171              :         }
    6172              : 
    6173           14 :         Vectors::CreateNewellAreaVector(surfTemp.Vertex, surfTemp.Sides, surfTemp.NewellAreaVector);
    6174           14 :         surfTemp.GrossArea = Vectors::VecLength(surfTemp.NewellAreaVector);
    6175           14 :         surfTemp.Area = surfTemp.GrossArea;
    6176           14 :         surfTemp.NetAreaShadowCalc = surfTemp.Area;
    6177           14 :         Vectors::CreateNewellSurfaceNormalVector(surfTemp.Vertex, surfTemp.Sides, surfTemp.NewellSurfaceNormalVector);
    6178           14 :         Vectors::DetermineAzimuthAndTilt(
    6179           14 :             surfTemp.Vertex, SurfAzimuth, SurfTilt, surfTemp.lcsx, surfTemp.lcsy, surfTemp.lcsz, surfTemp.NewellSurfaceNormalVector);
    6180           14 :         surfTemp.Azimuth = SurfAzimuth;
    6181           14 :         surfTemp.Tilt = SurfTilt;
    6182           14 :         surfTemp.convOrientation = Convect::GetSurfConvOrientation(surfTemp.Tilt);
    6183              :         // Sine and cosine of azimuth and tilt
    6184           14 :         surfTemp.SinAzim = SinSurfAzimuth;
    6185           14 :         surfTemp.CosAzim = CosSurfAzimuth;
    6186           14 :         surfTemp.SinTilt = SinSurfTilt;
    6187           14 :         surfTemp.CosTilt = CosSurfTilt;
    6188           14 :         if (surfTemp.Class != SurfaceClass::Window && surfTemp.Class != SurfaceClass::GlassDoor && surfTemp.Class != SurfaceClass::Door) {
    6189            5 :             surfTemp.ViewFactorGround = 0.5 * (1.0 - surfTemp.CosTilt);
    6190              :         }
    6191              :         // Outward normal unit vector (pointing away from room)
    6192           14 :         surfTemp.OutNormVec = surfTemp.NewellSurfaceNormalVector;
    6193           56 :         for (int n = 1; n <= 3; ++n) {
    6194           42 :             if (std::abs(surfTemp.OutNormVec(n) - 1.0) < 1.e-06) {
    6195            5 :                 surfTemp.OutNormVec(n) = +1.0;
    6196              :             }
    6197           42 :             if (std::abs(surfTemp.OutNormVec(n) + 1.0) < 1.e-06) {
    6198            8 :                 surfTemp.OutNormVec(n) = -1.0;
    6199              :             }
    6200           42 :             if (std::abs(surfTemp.OutNormVec(n)) < 1.e-06) {
    6201           27 :                 surfTemp.OutNormVec(n) = 0.0;
    6202              :             }
    6203              :         }
    6204              : 
    6205              :         //  IF (SurfaceTmp(SurfNum)%Class == SurfaceClass::Roof .and. SurfTilt > 80.) THEN
    6206              :         //    WRITE(TiltString,'(F5.1)') SurfTilt
    6207              :         //    TiltString=ADJUSTL(TiltString)
    6208              :         //    CALL ShowWarningError(state, format("Roof/Ceiling Tilt={}{}{}{}{}{}{}{}{}{} for Surface={}{}{}, in
    6209              :         //    Zone={}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}", //TRIM(TiltString)//',,
    6210              :         //    much, greater, than, expected, tilt, of, 0,'//, &, //, //TRIM(SurfaceTmp(SurfNum)%Name)//, &, //, //TRIM(SurfaceTmp(SurfNum)%ZoneName)),
    6211              :         //    //, ENDIF, //, IF, (SurfaceTmp(SurfNum)%Class, ==, SurfaceClass::Floor, .and., SurfTilt, <, 170.), THEN, //, WRITE(TiltString,'(F5.1)'),
    6212              :         //    SurfTilt, //, TiltString=ADJUSTL(TiltString), //, CALL, ShowWarningError(state, 'Floor Tilt='//TRIM(TiltString)//', much less than
    6213              :         //    expected tilt of 180,'//   &
    6214              :         //                          ' for Surface='//TRIM(SurfaceTmp(SurfNum)%Name)//  &
    6215              :         //                          ', in Zone='//TRIM(SurfaceTmp(SurfNum)%ZoneName)), //, ENDIF, if,
    6216              :         //                          (surfTemp.Class, ==, SurfaceClass::Window, ||,
    6217              :         //                          surfTemp.Class, ==, SurfaceClass::GlassDoor, ||,
    6218              :         //                          surfTemp.Class, ==, SurfaceClass::Door),
    6219              :         //                          surfTemp.Area, *=,
    6220              :         //                          surfTemp.Multiplier;, //, Can, perform, tests, on, this, surface, here,
    6221              :         //                          surfTemp.ViewFactorSky, =, 0.5, *, (1.0,
    6222              :         //                          surfTemp.CosTilt));
    6223              :         // The following IR view factors are modified in subr. SkyDifSolarShading if there are shadowing
    6224              :         // surfaces
    6225           14 :         surfTemp.ViewFactorSkyIR = surfTemp.ViewFactorSky;
    6226           14 :         surfTemp.ViewFactorGroundIR = 0.5 * (1.0 - surfTemp.CosTilt);
    6227              : 
    6228           14 :         Perimeter = distance(surfTemp.Vertex(surfTemp.Sides), surfTemp.Vertex(1));
    6229           56 :         for (Vrt = 2; Vrt <= surfTemp.Sides; ++Vrt) {
    6230           42 :             Perimeter += distance(surfTemp.Vertex(Vrt), surfTemp.Vertex(Vrt - 1));
    6231              :         }
    6232           14 :         surfTemp.Perimeter = Perimeter;
    6233              : 
    6234              :         // Call to transform vertices
    6235              : 
    6236           14 :         TransformVertsByAspect(state, SurfNum, surfTemp.Sides);
    6237           14 :     }
    6238              : 
    6239          226 :     void GetAttShdSurfaceData(EnergyPlusData &state,
    6240              :                               bool &ErrorsFound,   // Error flag indicator (true if errors found)
    6241              :                               int &SurfNum,        // Count of Current SurfaceNumber
    6242              :                               int const TotShdSubs // Number of Attached Shading SubSurfaces to obtain
    6243              :     )
    6244              :     {
    6245              :         // SUBROUTINE INFORMATION:
    6246              :         //       AUTHOR         Linda Lawrie
    6247              :         //       DATE WRITTEN   May 2000
    6248              : 
    6249              :         // PURPOSE OF THIS SUBROUTINE:
    6250              :         // This subroutine gets the HeatTransfer Surface Data,
    6251              :         // checks it for errors, etc.
    6252              : 
    6253              :         static constexpr std::string_view routineName = "GetAttShdSurfaceData";
    6254              : 
    6255              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    6256              :         int IOStat;     // IO Status when calling get input subroutine
    6257              :         int NumAlphas;  // Number of alpha names being passed
    6258              :         int NumNumbers; // Number of properties being passed
    6259              :         int Found;      // For matching interzone surfaces
    6260              :         int Loop;
    6261              :         Real64 SchedMinValue;
    6262              :         Real64 SchedMaxValue;
    6263              : 
    6264          226 :         auto &s_ipsc = state.dataIPShortCut;
    6265              : 
    6266          226 :         if (TotShdSubs > 0 && state.dataHeatBal->SolarDistribution == DataHeatBalance::Shadowing::Minimal) {
    6267            0 :             ShowWarningError(state, "Shading effects of Fins and Overhangs are ignored when Solar Distribution = MinimalShadowing");
    6268              :         }
    6269          226 :         s_ipsc->cCurrentModuleObject = "Shading:Zone:Detailed";
    6270          226 :         state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, s_ipsc->cCurrentModuleObject, Loop, NumAlphas, NumNumbers);
    6271          226 :         if (NumAlphas != 3) {
    6272            0 :             ShowSevereError(
    6273            0 :                 state, format("{}: Object Definition indicates not = 3 Alpha Objects, Number Indicated={}", s_ipsc->cCurrentModuleObject, NumAlphas));
    6274            0 :             ErrorsFound = true;
    6275              :         }
    6276              : 
    6277          250 :         for (Loop = 1; Loop <= TotShdSubs; ++Loop) {
    6278           48 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    6279           24 :                                                                      s_ipsc->cCurrentModuleObject,
    6280              :                                                                      Loop,
    6281           24 :                                                                      s_ipsc->cAlphaArgs,
    6282              :                                                                      NumAlphas,
    6283           24 :                                                                      s_ipsc->rNumericArgs,
    6284              :                                                                      NumNumbers,
    6285              :                                                                      IOStat,
    6286           24 :                                                                      s_ipsc->lNumericFieldBlanks,
    6287           24 :                                                                      s_ipsc->lAlphaFieldBlanks,
    6288           24 :                                                                      s_ipsc->cAlphaFieldNames,
    6289           24 :                                                                      s_ipsc->cNumericFieldNames);
    6290              : 
    6291           24 :             ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
    6292              : 
    6293           48 :             if (GlobalNames::VerifyUniqueInterObjectName(state,
    6294           24 :                                                          state.dataSurfaceGeometry->UniqueSurfaceNames,
    6295           24 :                                                          s_ipsc->cAlphaArgs(1),
    6296           24 :                                                          s_ipsc->cCurrentModuleObject,
    6297           24 :                                                          s_ipsc->cAlphaFieldNames(1),
    6298              :                                                          ErrorsFound)) {
    6299            0 :                 continue;
    6300              :             }
    6301              : 
    6302           24 :             ++SurfNum;
    6303           24 :             auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    6304              : 
    6305           24 :             surfTemp.Name = s_ipsc->cAlphaArgs(1); // Set the Surface Name in the Derived Type
    6306           24 :             surfTemp.Class = SurfaceClass::Shading;
    6307           24 :             surfTemp.HeatTransSurf = false;
    6308           24 :             surfTemp.BaseSurfName = s_ipsc->cAlphaArgs(2);
    6309              :             //  The subsurface inherits properties from the base surface
    6310              :             //  Exterior conditions, Zone, etc.
    6311              :             //  We can figure out the base surface though, because they've all been entered
    6312           24 :             Found = Util::FindItemInList(surfTemp.BaseSurfName, state.dataSurfaceGeometry->SurfaceTmp, state.dataSurface->TotSurfaces);
    6313           24 :             if (Found > 0) {
    6314              :                 // SurfaceTmp(SurfNum)%BaseSurf=Found
    6315           24 :                 surfTemp.ExtBoundCond = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCond;
    6316           24 :                 surfTemp.ExtSolar = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtSolar;
    6317           24 :                 surfTemp.ExtWind = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtWind;
    6318           24 :                 surfTemp.Zone = state.dataSurfaceGeometry->SurfaceTmp(Found).Zone; // Necessary to do relative coordinates in GetVertices below
    6319           24 :                 surfTemp.ZoneName = state.dataSurfaceGeometry->SurfaceTmp(Found).ZoneName; // Necessary to have surface drawn in OutputReports
    6320              :             } else {
    6321            0 :                 ShowSevereError(state,
    6322            0 :                                 format("{}=\"{}\", invalid {}=\"{}",
    6323            0 :                                        s_ipsc->cCurrentModuleObject,
    6324            0 :                                        surfTemp.Name,
    6325            0 :                                        s_ipsc->cAlphaFieldNames(2),
    6326            0 :                                        s_ipsc->cAlphaArgs(2)));
    6327            0 :                 ErrorsFound = true;
    6328              :             }
    6329           24 :             if (surfTemp.ExtBoundCond == unenteredAdjacentZoneSurface) {
    6330            0 :                 ShowSevereError(state,
    6331            0 :                                 format("{}=\"{}\", invalid {}=\"{}",
    6332            0 :                                        s_ipsc->cCurrentModuleObject,
    6333            0 :                                        surfTemp.Name,
    6334            0 :                                        s_ipsc->cAlphaFieldNames(2),
    6335            0 :                                        s_ipsc->cAlphaArgs(2)));
    6336            0 :                 ShowContinueError(state, "...trying to attach a shading device to an interzone surface.");
    6337            0 :                 ErrorsFound = true;
    6338              : 
    6339            0 :                 surfTemp.ExtBoundCond = DataSurfaces::ExternalEnvironment; // reset so program won't crash during "add surfaces"
    6340              :             }
    6341           24 :             if (surfTemp.ExtBoundCond == unreconciledZoneSurface) {
    6342            0 :                 ShowSevereError(state,
    6343            0 :                                 format("{}=\"{}\", invalid {}=\"{}",
    6344            0 :                                        s_ipsc->cCurrentModuleObject,
    6345            0 :                                        surfTemp.Name,
    6346            0 :                                        s_ipsc->cAlphaFieldNames(2),
    6347            0 :                                        s_ipsc->cAlphaArgs(2)));
    6348            0 :                 ShowContinueError(state, "...trying to attach a shading device to an interior surface.");
    6349            0 :                 ErrorsFound = true;
    6350              : 
    6351            0 :                 surfTemp.ExtBoundCond = DataSurfaces::ExternalEnvironment; // reset so program won't crash during "add surfaces"
    6352              :             }
    6353              : 
    6354           24 :             if (s_ipsc->lAlphaFieldBlanks(3)) {
    6355              :                 // Defaults to constant-0.0, but leave this as nullptr for now
    6356           23 :             } else if ((surfTemp.shadowSurfSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(3))) == nullptr) {
    6357            0 :                 ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3));
    6358            0 :                 ErrorsFound = true;
    6359           23 :             } else if (!surfTemp.shadowSurfSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 1.0)) {
    6360            1 :                 Sched::ShowSevereBadMinMax(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3), Clusive::In, 0.0, Clusive::In, 1.0);
    6361            1 :                 ErrorsFound = true;
    6362              :             } else {
    6363              : 
    6364           22 :                 SchedMinValue = surfTemp.shadowSurfSched->getMinVal(state);
    6365           22 :                 surfTemp.SchedMinValue = SchedMinValue;
    6366           22 :                 SchedMaxValue = surfTemp.shadowSurfSched->getMaxVal(state);
    6367           22 :                 if (SchedMinValue == 1.0) {
    6368              :                     // Set transparent for now, check for EMS actuators later in SolarShading::resetShadingSurfaceTransparency
    6369            1 :                     surfTemp.IsTransparent = true;
    6370              :                 }
    6371           22 :                 if (SchedMaxValue > 0.0) {
    6372           13 :                     state.dataSolarShading->anyScheduledShadingSurface = true;
    6373              :                 }
    6374           22 :                 if (SchedMaxValue - SchedMinValue > Constant::OneMillionth) {
    6375           11 :                     state.dataSurface->ShadingTransmittanceVaries = true;
    6376              :                 }
    6377              :             }
    6378              : 
    6379           24 :             if (s_ipsc->lNumericFieldBlanks(1) || s_ipsc->rNumericArgs(1) == Constant::AutoCalculate) {
    6380            0 :                 s_ipsc->rNumericArgs(1) = (NumNumbers - 1) / 3;
    6381            0 :                 surfTemp.Sides = s_ipsc->rNumericArgs(1);
    6382            0 :                 if (mod(NumNumbers - 1, 3) != 0) {
    6383            0 :                     ShowWarningError(state,
    6384            0 :                                      format("{}=\"{}\", {}",
    6385            0 :                                             s_ipsc->cCurrentModuleObject,
    6386            0 :                                             surfTemp.Name,
    6387            0 :                                             format("{} not even multiple of 3. Will read in {}", s_ipsc->cNumericFieldNames(1), surfTemp.Sides)));
    6388              :                 }
    6389            0 :                 if (s_ipsc->rNumericArgs(1) < 3) {
    6390            0 :                     ShowSevereError(state,
    6391            0 :                                     format("{}=\"{}\", {} (autocalculate) must be >= 3. Only {} provided.",
    6392            0 :                                            s_ipsc->cCurrentModuleObject,
    6393            0 :                                            surfTemp.Name,
    6394            0 :                                            s_ipsc->cNumericFieldNames(1),
    6395            0 :                                            surfTemp.Sides));
    6396            0 :                     ErrorsFound = true;
    6397            0 :                     continue;
    6398              :                 }
    6399              :             } else {
    6400           24 :                 surfTemp.Sides = s_ipsc->rNumericArgs(1);
    6401              :             }
    6402           24 :             surfTemp.Vertex.allocate(surfTemp.Sides);
    6403           96 :             GetVertices(state, SurfNum, surfTemp.Sides, s_ipsc->rNumericArgs({2, _}));
    6404           24 :             CheckConvexity(state, SurfNum, surfTemp.Sides);
    6405              :             //    IF (SurfaceTmp(SurfNum)%Sides == 3) THEN
    6406              :             //      CALL ShowWarningError(state, TRIM(s_ipsc->cCurrentModuleObject)//'="'//TRIM(SurfaceTmp(SurfNum)%Name)//  &
    6407              :             //                        ' should not be triangular.')
    6408              :             //      CALL ShowContinueError(state, '...Check results carefully.')
    6409              :             //      ErrorsFound=.TRUE.
    6410              :             //    ENDIF
    6411              :             // Reset surface to be "detached"
    6412           24 :             surfTemp.BaseSurf = 0;
    6413              :             //    SurfaceTmp(SurfNum)%BaseSurfName='  '
    6414           24 :             surfTemp.Zone = 0;
    6415              :             // SurfaceTmp(SurfNum)%ZoneName='  '
    6416           24 :             if (state.dataReportFlag->MakeMirroredAttachedShading) {
    6417           24 :                 MakeMirrorSurface(state, SurfNum);
    6418              :             }
    6419              :         }
    6420          250 :     }
    6421              : 
    6422          226 :     void GetSimpleShdSurfaceData(EnergyPlusData &state,
    6423              :                                  bool &ErrorsFound,                // Error flag indicator (true if errors found)
    6424              :                                  int &SurfNum,                     // Count of Current SurfaceNumber
    6425              :                                  int const TotOverhangs,           // Number of Overhangs to obtain
    6426              :                                  int const TotOverhangsProjection, // Number of Overhangs (projection) to obtain
    6427              :                                  int const TotFins,                // Number of Fins to obtain
    6428              :                                  int const TotFinsProjection       // Number of Fins (projection) to obtain
    6429              :     )
    6430              :     {
    6431              : 
    6432              :         // SUBROUTINE INFORMATION:
    6433              :         //       AUTHOR         Linda Lawrie
    6434              :         //       DATE WRITTEN   January 2009
    6435              : 
    6436              :         // PURPOSE OF THIS SUBROUTINE:
    6437              :         // Get simple overhang and fin descriptions.
    6438              : 
    6439              :         // SUBROUTINE PARAMETER DEFINITIONS:
    6440          226 :         static Array1D_string const cModuleObjects(4, {"Shading:Overhang", "Shading:Overhang:Projection", "Shading:Fin", "Shading:Fin:Projection"});
    6441              : 
    6442              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    6443              :         int ItemsToGet;
    6444              :         int NumAlphas;
    6445              :         int NumNumbers;
    6446              :         int IOStat; // IO Status when calling get input subroutine
    6447              :         Real64 Depth;
    6448              :         Real64 Length;
    6449              :         Real64 Xp;
    6450              :         Real64 Yp;
    6451              :         Real64 Zp;
    6452              :         Real64 XLLC;
    6453              :         Real64 YLLC;
    6454              :         int BaseSurfNum;
    6455              :         Real64 TiltAngle;
    6456              :         bool MakeFin;
    6457              : 
    6458          226 :         auto &s_ipsc = state.dataIPShortCut;
    6459              : 
    6460          228 :         if ((TotOverhangs + TotOverhangsProjection + TotFins + TotFinsProjection) > 0 &&
    6461            2 :             state.dataHeatBal->SolarDistribution == DataHeatBalance::Shadowing::Minimal) {
    6462            0 :             ShowWarningError(state, "Shading effects of Fins and Overhangs are ignored when Solar Distribution = MinimalShadowing");
    6463              :         }
    6464         1130 :         for (int Item = 1; Item <= 4; ++Item) {
    6465              : 
    6466          904 :             s_ipsc->cCurrentModuleObject = cModuleObjects(Item);
    6467          904 :             if (Item == 1) {
    6468          226 :                 ItemsToGet = TotOverhangs;
    6469          678 :             } else if (Item == 2) {
    6470          226 :                 ItemsToGet = TotOverhangsProjection;
    6471          452 :             } else if (Item == 3) {
    6472          226 :                 ItemsToGet = TotFins;
    6473              :             } else { // ! (Item == 4) THEN
    6474          226 :                 ItemsToGet = TotFinsProjection;
    6475              :             }
    6476              : 
    6477          909 :             for (int Loop = 1; Loop <= ItemsToGet; ++Loop) {
    6478           10 :                 state.dataInputProcessing->inputProcessor->getObjectItem(state,
    6479            5 :                                                                          s_ipsc->cCurrentModuleObject,
    6480              :                                                                          Loop,
    6481            5 :                                                                          s_ipsc->cAlphaArgs,
    6482              :                                                                          NumAlphas,
    6483            5 :                                                                          s_ipsc->rNumericArgs,
    6484              :                                                                          NumNumbers,
    6485              :                                                                          IOStat,
    6486            5 :                                                                          s_ipsc->lNumericFieldBlanks,
    6487            5 :                                                                          s_ipsc->lAlphaFieldBlanks,
    6488            5 :                                                                          s_ipsc->cAlphaFieldNames,
    6489            5 :                                                                          s_ipsc->cNumericFieldNames);
    6490              : 
    6491           10 :                 if (GlobalNames::VerifyUniqueInterObjectName(state,
    6492            5 :                                                              state.dataSurfaceGeometry->UniqueSurfaceNames,
    6493            5 :                                                              s_ipsc->cAlphaArgs(1),
    6494            5 :                                                              s_ipsc->cCurrentModuleObject,
    6495            5 :                                                              s_ipsc->cAlphaFieldNames(1),
    6496              :                                                              ErrorsFound)) {
    6497            0 :                     continue;
    6498              :                 }
    6499              : 
    6500            5 :                 ++SurfNum;
    6501            5 :                 auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    6502              : 
    6503            5 :                 surfTemp.Name = s_ipsc->cAlphaArgs(1); // Set the Surface Name in the Derived Type
    6504            5 :                 surfTemp.Class = SurfaceClass::Shading;
    6505            5 :                 surfTemp.HeatTransSurf = false;
    6506              :                 // this object references a window or door....
    6507            5 :                 int Found = Util::FindItemInList(s_ipsc->cAlphaArgs(2), state.dataSurfaceGeometry->SurfaceTmp, state.dataSurface->TotSurfaces);
    6508            5 :                 if (Found > 0) {
    6509            5 :                     BaseSurfNum = state.dataSurfaceGeometry->SurfaceTmp(Found).BaseSurf;
    6510            5 :                     surfTemp.BaseSurfName = state.dataSurfaceGeometry->SurfaceTmp(Found).BaseSurfName;
    6511            5 :                     surfTemp.ExtBoundCond = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCond;
    6512            5 :                     surfTemp.ExtSolar = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtSolar;
    6513            5 :                     surfTemp.ExtWind = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtWind;
    6514            5 :                     surfTemp.Zone = state.dataSurfaceGeometry->SurfaceTmp(Found).Zone; // Necessary to do relative coordinates in GetVertices below
    6515            5 :                     surfTemp.ZoneName = state.dataSurfaceGeometry->SurfaceTmp(Found).ZoneName; // Necessary to have surface drawn in OutputReports
    6516              :                 } else {
    6517            0 :                     ShowSevereError(state,
    6518            0 :                                     format("{}=\"{}\", invalid {}=\"{}",
    6519            0 :                                            s_ipsc->cCurrentModuleObject,
    6520            0 :                                            surfTemp.Name,
    6521            0 :                                            s_ipsc->cAlphaFieldNames(2),
    6522            0 :                                            s_ipsc->cAlphaArgs(2)));
    6523            0 :                     ErrorsFound = true;
    6524            0 :                     continue;
    6525              :                 }
    6526            5 :                 if (surfTemp.ExtBoundCond == unenteredAdjacentZoneSurface) {
    6527            0 :                     ShowSevereError(state,
    6528            0 :                                     format("{}=\"{}\", invalid {}=\"{}",
    6529            0 :                                            s_ipsc->cCurrentModuleObject,
    6530            0 :                                            surfTemp.Name,
    6531            0 :                                            s_ipsc->cAlphaFieldNames(2),
    6532            0 :                                            s_ipsc->cAlphaArgs(2)));
    6533            0 :                     ShowContinueError(state, "...trying to attach a shading device to an interzone surface.");
    6534            0 :                     ErrorsFound = true;
    6535            0 :                     surfTemp.ExtBoundCond = DataSurfaces::ExternalEnvironment; // reset so program won't crash during "add surfaces"
    6536              :                 }
    6537            5 :                 if (surfTemp.ExtBoundCond == unreconciledZoneSurface) {
    6538            0 :                     ShowSevereError(state,
    6539            0 :                                     format("{}=\"{}\", invalid {}=\"{}",
    6540            0 :                                            s_ipsc->cCurrentModuleObject,
    6541            0 :                                            surfTemp.Name,
    6542            0 :                                            s_ipsc->cAlphaFieldNames(2),
    6543            0 :                                            s_ipsc->cAlphaArgs(2)));
    6544            0 :                     ShowContinueError(state, "...trying to attach a shading device to an interior surface.");
    6545            0 :                     ErrorsFound = true;
    6546            0 :                     surfTemp.ExtBoundCond = DataSurfaces::ExternalEnvironment; // reset so program won't crash during "add surfaces"
    6547              :                 }
    6548              : 
    6549            5 :                 surfTemp.shadowSurfSched = nullptr;
    6550              : 
    6551              :                 //===== Overhang =====
    6552              : 
    6553            5 :                 if (Item < 3) {
    6554              :                     //  Found is the surface window or door.
    6555              :                     //   N1,  \field Height above Window or Door
    6556              :                     //        \units m
    6557              :                     //   N2,  \field Tilt Angle from Window/Door
    6558              :                     //        \units deg
    6559              :                     //        \default 90
    6560              :                     //        \minimum 0
    6561              :                     //        \maximum 180
    6562              :                     //   N3,  \field Left extension from Window/Door Width
    6563              :                     //        \units m
    6564              :                     //   N4,  \field Right extension from Window/Door Width
    6565              :                     //        \note N3 + N4 + Window/Door Width is Overhang Length
    6566              :                     //        \units m
    6567              :                     //   N5;  \field Depth
    6568              :                     //        \units m
    6569              :                     // for projection option:
    6570              :                     //   N5;  \field Depth as Fraction of Window/Door Height
    6571              :                     //        \units m
    6572            3 :                     Length = s_ipsc->rNumericArgs(3) + s_ipsc->rNumericArgs(4) + state.dataSurfaceGeometry->SurfaceTmp(Found).Width;
    6573            3 :                     if (Item == 1) {
    6574            2 :                         Depth = s_ipsc->rNumericArgs(5);
    6575            1 :                     } else if (Item == 2) {
    6576            1 :                         Depth = s_ipsc->rNumericArgs(5) * state.dataSurfaceGeometry->SurfaceTmp(Found).Height;
    6577              :                     }
    6578              : 
    6579            3 :                     if (Length * Depth <= 0.0) {
    6580            0 :                         ShowSevereError(state,
    6581            0 :                                         format("{}=\"{}\", illegal surface area=[{:.2R}]. Surface will NOT be entered.",
    6582            0 :                                                s_ipsc->cCurrentModuleObject,
    6583            0 :                                                s_ipsc->cAlphaArgs(1),
    6584            0 :                                                Length * Depth));
    6585            0 :                         continue;
    6586              :                     }
    6587              : 
    6588            3 :                     TiltAngle = state.dataSurfaceGeometry->SurfaceTmp(Found).Tilt + s_ipsc->rNumericArgs(2);
    6589            3 :                     surfTemp.Tilt = TiltAngle;
    6590            3 :                     surfTemp.convOrientation = Convect::GetSurfConvOrientation(surfTemp.Tilt);
    6591            3 :                     surfTemp.Azimuth = state.dataSurfaceGeometry->SurfaceTmp(Found).Azimuth;
    6592              : 
    6593              :                     // Make it relative to surface origin.....
    6594            3 :                     Xp = state.dataSurfaceGeometry->SurfaceTmp(Found).Vertex(2).x - state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).x;
    6595            3 :                     Yp = state.dataSurfaceGeometry->SurfaceTmp(Found).Vertex(2).y - state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).y;
    6596            3 :                     Zp = state.dataSurfaceGeometry->SurfaceTmp(Found).Vertex(2).z - state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).z;
    6597              : 
    6598            3 :                     XLLC = -Xp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosAzim +
    6599            3 :                            Yp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).SinAzim;
    6600              : 
    6601            3 :                     YLLC =
    6602            3 :                         -Xp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).SinAzim *
    6603            3 :                             state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosTilt -
    6604            3 :                         Yp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosAzim * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosTilt +
    6605            3 :                         Zp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).SinTilt;
    6606              : 
    6607            3 :                     surfTemp.Sides = 4;
    6608            3 :                     surfTemp.Vertex.allocate(surfTemp.Sides);
    6609              : 
    6610            6 :                     MakeRelativeRectangularVertices(state,
    6611              :                                                     BaseSurfNum,
    6612              :                                                     SurfNum,
    6613            3 :                                                     XLLC - s_ipsc->rNumericArgs(3),
    6614            3 :                                                     YLLC + state.dataSurfaceGeometry->SurfaceTmp(Found).Height + s_ipsc->rNumericArgs(1),
    6615              :                                                     Length,
    6616              :                                                     Depth);
    6617              : 
    6618              :                     // Reset surface to be "detached"
    6619              :                     //    SurfaceTmp(SurfNum)%BaseSurfName='  '
    6620              :                     //    SurfaceTmp(SurfNum)%ZoneName='  '
    6621              : 
    6622            3 :                     surfTemp.BaseSurf = 0;
    6623            3 :                     surfTemp.Zone = 0;
    6624              : 
    6625              :                     // and mirror
    6626            3 :                     if (state.dataReportFlag->MakeMirroredAttachedShading) {
    6627            3 :                         MakeMirrorSurface(state, SurfNum);
    6628              :                     }
    6629              : 
    6630              :                 } else { // Fins
    6631              : 
    6632              :                     //===== Fins =====
    6633              : 
    6634              :                     //===== Left Fin =====
    6635              : 
    6636              :                     //   N1,  \field Left Extension from Window/Door
    6637              :                     //        \units m
    6638              :                     //   N2,  \field Left Distance Above Top of Window
    6639              :                     //        \units m
    6640              :                     //   N3,  \field Left Distance Below Bottom of Window
    6641              :                     //        \units m
    6642              :                     //        \note N2 + N3 + height of Window/Door is height of Fin
    6643              :                     //   N4,  \field Left Tilt Angle from Window/Door
    6644              :                     //        \units deg
    6645              :                     //        \default 90
    6646              :                     //        \minimum 0
    6647              :                     //        \maximum 180
    6648              :                     //   N5,  \field Left Depth
    6649              :                     //        \units m
    6650              :                     // for projection option:
    6651              :                     //   N5,  \field Left Depth as Fraction of Window/Door Width
    6652              :                     //        \units m
    6653            2 :                     surfTemp.Name = surfTemp.Name + " Left";
    6654            2 :                     Length = s_ipsc->rNumericArgs(2) + s_ipsc->rNumericArgs(3) + state.dataSurfaceGeometry->SurfaceTmp(Found).Height;
    6655            2 :                     if (Item == 3) {
    6656            0 :                         Depth = s_ipsc->rNumericArgs(5);
    6657            2 :                     } else if (Item == 4) {
    6658            2 :                         Depth = s_ipsc->rNumericArgs(5) * state.dataSurfaceGeometry->SurfaceTmp(Found).Width;
    6659              :                     }
    6660              : 
    6661            2 :                     MakeFin = true;
    6662            2 :                     if (Length * Depth <= 0.0) {
    6663            2 :                         ShowWarningError(state,
    6664            3 :                                          format("{}=Left Fin of \"{}\", illegal surface area=[{:.2R}]. Surface will NOT be entered.",
    6665            1 :                                                 s_ipsc->cCurrentModuleObject,
    6666            1 :                                                 s_ipsc->cAlphaArgs(1),
    6667            1 :                                                 Length * Depth));
    6668            1 :                         MakeFin = false;
    6669              :                     }
    6670              : 
    6671            2 :                     if (MakeFin) {
    6672            1 :                         TiltAngle = state.dataSurfaceGeometry->SurfaceTmp(Found).Tilt;
    6673            1 :                         surfTemp.Tilt = TiltAngle;
    6674            1 :                         surfTemp.convOrientation = Convect::GetSurfConvOrientation(surfTemp.Tilt);
    6675            1 :                         surfTemp.Azimuth = state.dataSurfaceGeometry->SurfaceTmp(Found).Azimuth - (180.0 - s_ipsc->rNumericArgs(4));
    6676              : 
    6677              :                         // Make it relative to surface origin.....
    6678              : 
    6679            1 :                         Xp =
    6680            1 :                             state.dataSurfaceGeometry->SurfaceTmp(Found).Vertex(2).x - state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).x;
    6681            1 :                         Yp =
    6682            1 :                             state.dataSurfaceGeometry->SurfaceTmp(Found).Vertex(2).y - state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).y;
    6683            1 :                         Zp =
    6684            1 :                             state.dataSurfaceGeometry->SurfaceTmp(Found).Vertex(2).z - state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).z;
    6685              : 
    6686            1 :                         XLLC = -Xp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosAzim +
    6687            1 :                                Yp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).SinAzim;
    6688              : 
    6689            1 :                         YLLC = -Xp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).SinAzim *
    6690            1 :                                    state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosTilt -
    6691            1 :                                Yp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosAzim *
    6692            1 :                                    state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosTilt +
    6693            1 :                                Zp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).SinTilt;
    6694              : 
    6695            1 :                         surfTemp.CosAzim = std::cos(surfTemp.Azimuth * Constant::DegToRad);
    6696            1 :                         surfTemp.SinAzim = std::sin(surfTemp.Azimuth * Constant::DegToRad);
    6697            1 :                         surfTemp.CosTilt = std::cos(surfTemp.Tilt * Constant::DegToRad);
    6698            1 :                         surfTemp.SinTilt = std::sin(surfTemp.Tilt * Constant::DegToRad);
    6699              : 
    6700            1 :                         surfTemp.Sides = 4;
    6701            1 :                         surfTemp.Vertex.allocate(surfTemp.Sides);
    6702              : 
    6703            3 :                         MakeRelativeRectangularVertices(
    6704            1 :                             state, BaseSurfNum, SurfNum, XLLC - s_ipsc->rNumericArgs(1), YLLC - s_ipsc->rNumericArgs(3), -Depth, Length);
    6705              : 
    6706              :                         // Reset surface to be "detached"
    6707              :                         //    SurfaceTmp(SurfNum)%BaseSurfName='  '
    6708              :                         //    SurfaceTmp(SurfNum)%ZoneName='  '
    6709              : 
    6710            1 :                         surfTemp.BaseSurf = 0;
    6711            1 :                         surfTemp.Zone = 0;
    6712              : 
    6713              :                         // and mirror
    6714            1 :                         if (state.dataReportFlag->MakeMirroredAttachedShading) {
    6715            1 :                             MakeMirrorSurface(state, SurfNum);
    6716              :                         }
    6717              :                     } else {
    6718            1 :                         --SurfNum;
    6719              :                     }
    6720              : 
    6721              :                     //===== Right Fin =====
    6722              : 
    6723              :                     //   N6,  \field Right Extension from Window/Door
    6724              :                     //        \units m
    6725              :                     //   N7,  \field Right Distance Above Top of Window
    6726              :                     //        \units m
    6727              :                     //   N8,  \field Right Distance Below Bottom of Window
    6728              :                     //        \note N7 + N8 + height of Window/Door is height of Fin
    6729              :                     //        \units m
    6730              :                     //   N9,  \field Right Tilt Angle from Window/Door
    6731              :                     //        \units deg
    6732              :                     //        \default 90
    6733              :                     //        \minimum 0
    6734              :                     //        \maximum 180
    6735              :                     //   N10; \field Right Depth
    6736              :                     //        \units m
    6737              :                     // for projection option:
    6738              :                     //   N10; \field Right Depth as Fraction of Window/Door Width
    6739              :                     //        \units m
    6740              : 
    6741            2 :                     ++SurfNum;
    6742            2 :                     auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    6743            2 :                     surfTemp.Name = s_ipsc->cAlphaArgs(1) + " Right"; // Set the Surface Name in the Derived Type
    6744            2 :                     surfTemp.Class = SurfaceClass::Shading;
    6745            2 :                     surfTemp.HeatTransSurf = false;
    6746            2 :                     BaseSurfNum = state.dataSurfaceGeometry->SurfaceTmp(Found).BaseSurf;
    6747            2 :                     surfTemp.BaseSurfName = state.dataSurfaceGeometry->SurfaceTmp(Found).BaseSurfName;
    6748            2 :                     surfTemp.ExtBoundCond = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCond;
    6749            2 :                     surfTemp.ExtSolar = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtSolar;
    6750            2 :                     surfTemp.ExtWind = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtWind;
    6751            2 :                     surfTemp.Zone = state.dataSurfaceGeometry->SurfaceTmp(Found).Zone; // Necessary to do relative coordinates in GetVertices below
    6752            2 :                     surfTemp.ZoneName = state.dataSurfaceGeometry->SurfaceTmp(Found).ZoneName; // Necessary to have surface drawn in OutputReports
    6753              : 
    6754            2 :                     surfTemp.shadowSurfSched = nullptr;
    6755            2 :                     Length = s_ipsc->rNumericArgs(7) + s_ipsc->rNumericArgs(8) + state.dataSurfaceGeometry->SurfaceTmp(Found).Height;
    6756            2 :                     if (Item == 3) {
    6757            0 :                         Depth = s_ipsc->rNumericArgs(10);
    6758            2 :                     } else if (Item == 4) {
    6759            2 :                         Depth = s_ipsc->rNumericArgs(10) * state.dataSurfaceGeometry->SurfaceTmp(Found).Width;
    6760              :                     }
    6761              : 
    6762            2 :                     MakeFin = true;
    6763            2 :                     if (Length * Depth <= 0.0) {
    6764            2 :                         ShowWarningError(state,
    6765            3 :                                          format("{}=Right Fin of \"{}\", illegal surface area=[{:.2R}]. Surface will NOT be entered.",
    6766            1 :                                                 s_ipsc->cCurrentModuleObject,
    6767            1 :                                                 s_ipsc->cAlphaArgs(1),
    6768            1 :                                                 Length * Depth));
    6769            1 :                         MakeFin = false;
    6770              :                     }
    6771              : 
    6772            2 :                     if (MakeFin) {
    6773              :                         // Make it relative to surface origin.....
    6774              : 
    6775            1 :                         Xp =
    6776            1 :                             state.dataSurfaceGeometry->SurfaceTmp(Found).Vertex(2).x - state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).x;
    6777            1 :                         Yp =
    6778            1 :                             state.dataSurfaceGeometry->SurfaceTmp(Found).Vertex(2).y - state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).y;
    6779            1 :                         Zp =
    6780            1 :                             state.dataSurfaceGeometry->SurfaceTmp(Found).Vertex(2).z - state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).z;
    6781              : 
    6782            1 :                         XLLC = -Xp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosAzim +
    6783            1 :                                Yp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).SinAzim;
    6784              : 
    6785            1 :                         YLLC = -Xp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).SinAzim *
    6786            1 :                                    state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosTilt -
    6787            1 :                                Yp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosAzim *
    6788            1 :                                    state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosTilt +
    6789            1 :                                Zp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).SinTilt;
    6790              : 
    6791            1 :                         TiltAngle = state.dataSurfaceGeometry->SurfaceTmp(Found).Tilt;
    6792            1 :                         surfTemp.Tilt = TiltAngle;
    6793            1 :                         surfTemp.convOrientation = Convect::GetSurfConvOrientation(surfTemp.Tilt);
    6794            1 :                         surfTemp.Azimuth = state.dataSurfaceGeometry->SurfaceTmp(Found).Azimuth - (180.0 - s_ipsc->rNumericArgs(9));
    6795            1 :                         surfTemp.CosAzim = std::cos(surfTemp.Azimuth * Constant::DegToRad);
    6796            1 :                         surfTemp.SinAzim = std::sin(surfTemp.Azimuth * Constant::DegToRad);
    6797            1 :                         surfTemp.CosTilt = std::cos(surfTemp.Tilt * Constant::DegToRad);
    6798            1 :                         surfTemp.SinTilt = std::sin(surfTemp.Tilt * Constant::DegToRad);
    6799              : 
    6800            1 :                         surfTemp.Sides = 4;
    6801            1 :                         surfTemp.Vertex.allocate(surfTemp.Sides);
    6802              : 
    6803            3 :                         MakeRelativeRectangularVertices(state,
    6804              :                                                         BaseSurfNum,
    6805              :                                                         SurfNum,
    6806            1 :                                                         XLLC + state.dataSurfaceGeometry->SurfaceTmp(Found).Width + s_ipsc->rNumericArgs(6),
    6807            1 :                                                         YLLC - s_ipsc->rNumericArgs(8),
    6808              :                                                         -Depth,
    6809              :                                                         Length);
    6810              : 
    6811              :                         // Reset surface to be "detached"
    6812              :                         //    SurfaceTmp(SurfNum)%BaseSurfName='  '
    6813              :                         //    SurfaceTmp(SurfNum)%ZoneName='  '
    6814              : 
    6815            1 :                         surfTemp.BaseSurf = 0;
    6816            1 :                         surfTemp.Zone = 0;
    6817              : 
    6818              :                         // and mirror
    6819            1 :                         if (state.dataReportFlag->MakeMirroredAttachedShading) {
    6820            1 :                             MakeMirrorSurface(state, SurfNum);
    6821              :                         }
    6822              :                     } else {
    6823            1 :                         --SurfNum;
    6824              :                     }
    6825              :                 }
    6826              :             }
    6827              :         }
    6828          226 :     }
    6829              : 
    6830          227 :     void GetIntMassSurfaceData(EnergyPlusData &state,
    6831              :                                bool &ErrorsFound, // Error flag indicator (true if errors found)
    6832              :                                int &SurfNum       // Count of Current SurfaceNumber
    6833              :     )
    6834              :     {
    6835              : 
    6836              :         // SUBROUTINE INFORMATION:
    6837              :         //       AUTHOR         Linda Lawrie
    6838              :         //       DATE WRITTEN   May 2000
    6839              : 
    6840              :         // PURPOSE OF THIS SUBROUTINE:
    6841              :         // This subroutine gets the Internal Surface Data,
    6842              :         // checks it for errors, etc.
    6843              : 
    6844              :         // REFERENCES:
    6845              :         // Internal Mass Surface Definition
    6846              :         // Surface:HeatTransfer:InternalMass,
    6847              :         //       \note used to describe internal zone surface area that does not need to be part of geometric representation
    6848              :         //  A1 , \field User Supplied Surface Name
    6849              :         //       \type alpha
    6850              :         //       \reference SurfaceNames
    6851              :         //  A2 , \field Construction Name of the Surface
    6852              :         //       \note To be matched with a construction in this input file
    6853              :         //       \type object-list
    6854              :         //       \object-list ConstructionNames
    6855              :         //  A3 , \field Interior Environment
    6856              :         //       \note Zone the surface is a part of
    6857              :         //       \type object-list
    6858              :         //       \object-list ZoneNames
    6859              :         //  N1,  \field View factor to Person (to people?)
    6860              :         //       \type real
    6861              :         //       \note from the interior of the surface
    6862              :         //  N2 ; \field Surface area
    6863              :         //       \units m2
    6864              : 
    6865              :         // SUBROUTINE PARAMETER DEFINITIONS:
    6866              :         static constexpr std::string_view RoutineName("GetIntMassSurfaceData: ");
    6867              : 
    6868              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    6869              :         int IOStat;          // IO Status when calling get input subroutine
    6870              :         int SurfaceNumAlpha; // Number of material alpha names being passed
    6871              :         int SurfaceNumArg;   // Number of material properties being passed
    6872              : 
    6873          227 :         auto &s_ipsc = state.dataIPShortCut;
    6874          227 :         s_ipsc->cCurrentModuleObject = "InternalMass";
    6875          227 :         int TotIntMass = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
    6876          227 :         if (TotIntMass == 0) {
    6877          218 :             return;
    6878              :         }
    6879              : 
    6880            9 :         state.dataSurface->IntMassObjects.allocate(TotIntMass);
    6881              : 
    6882              :         // scan for use of Zone lists in InternalMass objects
    6883            9 :         bool errFlag = false;
    6884            9 :         int NumIntMassSurfaces = 0;
    6885           28 :         for (int Item = 1; Item <= TotIntMass; ++Item) {
    6886           38 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    6887           19 :                                                                      s_ipsc->cCurrentModuleObject,
    6888              :                                                                      Item,
    6889           19 :                                                                      s_ipsc->cAlphaArgs,
    6890              :                                                                      SurfaceNumAlpha,
    6891           19 :                                                                      s_ipsc->rNumericArgs,
    6892              :                                                                      SurfaceNumArg,
    6893              :                                                                      IOStat,
    6894           19 :                                                                      s_ipsc->lNumericFieldBlanks,
    6895           19 :                                                                      s_ipsc->lAlphaFieldBlanks,
    6896           19 :                                                                      s_ipsc->cAlphaFieldNames,
    6897           19 :                                                                      s_ipsc->cNumericFieldNames);
    6898              : 
    6899           38 :             if (GlobalNames::VerifyUniqueInterObjectName(state,
    6900           19 :                                                          state.dataSurfaceGeometry->UniqueSurfaceNames,
    6901           19 :                                                          s_ipsc->cAlphaArgs(1),
    6902           19 :                                                          s_ipsc->cCurrentModuleObject,
    6903           19 :                                                          s_ipsc->cAlphaFieldNames(1),
    6904              :                                                          ErrorsFound)) {
    6905            0 :                 continue;
    6906              :             }
    6907              : 
    6908           19 :             state.dataSurface->IntMassObjects(Item).Name = s_ipsc->cAlphaArgs(1);
    6909           19 :             state.dataSurface->IntMassObjects(Item).GrossArea = s_ipsc->rNumericArgs(1);
    6910           19 :             state.dataSurface->IntMassObjects(Item).Construction =
    6911           19 :                 Util::FindItemInList(s_ipsc->cAlphaArgs(2), state.dataConstruction->Construct, state.dataHeatBal->TotConstructs);
    6912           19 :             state.dataSurface->IntMassObjects(Item).ZoneOrZoneListName = s_ipsc->cAlphaArgs(3);
    6913           19 :             int Item1 = Util::FindItemInList(s_ipsc->cAlphaArgs(3), state.dataHeatBal->Zone, state.dataGlobal->NumOfZones);
    6914           19 :             int ZLItem = 0;
    6915           19 :             if (Item1 == 0 && state.dataHeatBal->NumOfZoneLists > 0) {
    6916            3 :                 ZLItem = Util::FindItemInList(s_ipsc->cAlphaArgs(3), state.dataHeatBal->ZoneList);
    6917              :             }
    6918           19 :             if (Item1 > 0) {
    6919           16 :                 if (s_ipsc->lAlphaFieldBlanks(4)) {
    6920           16 :                     ++NumIntMassSurfaces;
    6921              :                 }
    6922           16 :                 state.dataSurface->IntMassObjects(Item).NumOfZones = 1;
    6923           16 :                 state.dataSurface->IntMassObjects(Item).ZoneListActive = false;
    6924           16 :                 state.dataSurface->IntMassObjects(Item).ZoneOrZoneListPtr = Item1;
    6925            3 :             } else if (ZLItem > 0) {
    6926            3 :                 NumIntMassSurfaces += state.dataHeatBal->ZoneList(ZLItem).NumOfZones;
    6927            3 :                 state.dataSurface->IntMassObjects(Item).NumOfZones = state.dataHeatBal->ZoneList(ZLItem).NumOfZones;
    6928            3 :                 state.dataSurface->IntMassObjects(Item).ZoneListActive = true;
    6929            3 :                 state.dataSurface->IntMassObjects(Item).ZoneOrZoneListPtr = ZLItem;
    6930            0 :             } else if (state.dataIPShortCut->lAlphaFieldBlanks(4)) {
    6931              :                 // If Space or SpaceList Name is blank, then throw error.
    6932            0 :                 ShowSevereError(state,
    6933            0 :                                 format("{}=\"{}\" invalid {}=\"{}\" not found.",
    6934            0 :                                        s_ipsc->cCurrentModuleObject,
    6935            0 :                                        s_ipsc->cAlphaArgs(1),
    6936            0 :                                        s_ipsc->cAlphaFieldNames(3),
    6937            0 :                                        s_ipsc->cAlphaArgs(3)));
    6938            0 :                 ++SurfNum;
    6939            0 :                 auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    6940            0 :                 surfTemp.Class = SurfaceClass::Invalid;
    6941            0 :                 surfTemp.ZoneName = "Unknown Zone";
    6942            0 :                 ErrorsFound = true;
    6943            0 :                 errFlag = true;
    6944              :             }
    6945              : 
    6946           19 :             if (!s_ipsc->lAlphaFieldBlanks(4)) {
    6947            0 :                 state.dataSurface->IntMassObjects(Item).spaceOrSpaceListName = s_ipsc->cAlphaArgs(4);
    6948            0 :                 Item1 = Util::FindItemInList(s_ipsc->cAlphaArgs(4), state.dataHeatBal->space);
    6949            0 :                 int SLItem = 0;
    6950            0 :                 if (Item1 == 0 && int(state.dataHeatBal->spaceList.size()) > 0) {
    6951            0 :                     SLItem = Util::FindItemInList(s_ipsc->cAlphaArgs(4), state.dataHeatBal->spaceList);
    6952              :                 }
    6953            0 :                 if (Item1 > 0) {
    6954            0 :                     ++NumIntMassSurfaces;
    6955            0 :                     state.dataSurface->IntMassObjects(Item).numOfSpaces = 1;
    6956            0 :                     state.dataSurface->IntMassObjects(Item).spaceListActive = false;
    6957            0 :                     state.dataSurface->IntMassObjects(Item).spaceOrSpaceListPtr = Item1;
    6958            0 :                     state.dataSurface->IntMassObjects(Item).NumOfZones = 1;
    6959            0 :                     state.dataSurface->IntMassObjects(Item).ZoneListActive = false;
    6960            0 :                     state.dataSurface->IntMassObjects(Item).ZoneOrZoneListPtr = state.dataHeatBal->space(Item1).zoneNum;
    6961            0 :                 } else if (SLItem > 0) {
    6962            0 :                     int numOfSpaces = int(state.dataHeatBal->spaceList(SLItem).numListSpaces);
    6963            0 :                     NumIntMassSurfaces += numOfSpaces;
    6964            0 :                     state.dataSurface->IntMassObjects(Item).numOfSpaces = numOfSpaces;
    6965            0 :                     state.dataSurface->IntMassObjects(Item).spaceListActive = true;
    6966            0 :                     state.dataSurface->IntMassObjects(Item).spaceOrSpaceListPtr = SLItem;
    6967              :                 } else {
    6968            0 :                     ShowSevereError(state,
    6969            0 :                                     format("{}=\"{}\" invalid {}=\"{}\" not found.",
    6970            0 :                                            s_ipsc->cCurrentModuleObject,
    6971            0 :                                            s_ipsc->cAlphaArgs(1),
    6972            0 :                                            s_ipsc->cAlphaFieldNames(4),
    6973            0 :                                            s_ipsc->cAlphaArgs(4)));
    6974            0 :                     ++SurfNum;
    6975            0 :                     auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    6976            0 :                     surfTemp.Class = SurfaceClass::Invalid;
    6977            0 :                     ErrorsFound = true;
    6978            0 :                     errFlag = true;
    6979              :                 }
    6980              :             }
    6981              : 
    6982           19 :             if (errFlag) {
    6983            0 :                 ShowSevereError(state, format("{}Errors with invalid names in {} objects.", RoutineName, s_ipsc->cCurrentModuleObject));
    6984            0 :                 ShowContinueError(state, "...These will not be read in.  Other errors may occur.");
    6985            0 :                 NumIntMassSurfaces = 0;
    6986              :             }
    6987              : 
    6988           19 :             if (state.dataSurface->IntMassObjects(Item).Construction == 0) {
    6989            0 :                 ErrorsFound = true;
    6990            0 :                 ShowSevereError(state,
    6991            0 :                                 format("{}=\"{}\", {} not found={}",
    6992            0 :                                        s_ipsc->cCurrentModuleObject,
    6993            0 :                                        s_ipsc->cAlphaArgs(1),
    6994            0 :                                        s_ipsc->cAlphaFieldNames(2),
    6995            0 :                                        s_ipsc->cAlphaArgs(2)));
    6996           19 :             } else if (state.dataConstruction->Construct(state.dataSurface->IntMassObjects(Item).Construction).TypeIsWindow) {
    6997            0 :                 ErrorsFound = true;
    6998            0 :                 ShowSevereError(state,
    6999            0 :                                 format("{}=\"{}\", invalid {}=\"{}\" - has Window materials.",
    7000            0 :                                        s_ipsc->cCurrentModuleObject,
    7001            0 :                                        s_ipsc->cAlphaArgs(1),
    7002            0 :                                        s_ipsc->cAlphaFieldNames(2),
    7003            0 :                                        s_ipsc->cAlphaArgs(2)));
    7004              :             } else {
    7005           19 :                 state.dataConstruction->Construct(state.dataSurface->IntMassObjects(Item).Construction).IsUsed = true;
    7006              :             }
    7007              :         }
    7008              : 
    7009            9 :         if (NumIntMassSurfaces > 0) {
    7010           28 :             for (int Loop = 1; Loop <= TotIntMass; ++Loop) {
    7011           19 :                 int numberOfZonesOrSpaces = 1;
    7012           19 :                 if (state.dataSurface->IntMassObjects(Loop).ZoneListActive) {
    7013            3 :                     numberOfZonesOrSpaces = state.dataSurface->IntMassObjects(Loop).NumOfZones;
    7014           16 :                 } else if (state.dataSurface->IntMassObjects(Loop).spaceListActive) {
    7015            0 :                     numberOfZonesOrSpaces = state.dataSurface->IntMassObjects(Loop).numOfSpaces;
    7016              :                 }
    7017              : 
    7018           59 :                 for (int Item1 = 1; Item1 <= numberOfZonesOrSpaces; ++Item1) {
    7019              : 
    7020           40 :                     ++SurfNum;
    7021              : 
    7022           40 :                     auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    7023           40 :                     surfTemp.Construction = state.dataSurface->IntMassObjects(Loop).Construction;
    7024           40 :                     if (!state.dataSurface->IntMassObjects(Loop).ZoneListActive && !state.dataSurface->IntMassObjects(Loop).spaceListActive) {
    7025           16 :                         surfTemp.Zone = state.dataSurface->IntMassObjects(Loop).ZoneOrZoneListPtr;
    7026           16 :                         surfTemp.spaceNum = state.dataSurface->IntMassObjects(Loop).spaceOrSpaceListPtr;
    7027           16 :                         surfTemp.Name = state.dataSurface->IntMassObjects(Loop).Name;
    7028           16 :                         surfTemp.Class = SurfaceClass::IntMass;
    7029           16 :                         surfTemp.ZoneName = state.dataSurface->IntMassObjects(Loop).ZoneOrZoneListName;
    7030           16 :                         surfTemp.HeatTransSurf = true;
    7031              :                     } else {
    7032           24 :                         int ZoneNum = 0; // index to a zone
    7033           24 :                         if (state.dataSurface->IntMassObjects(Loop).ZoneListActive) {
    7034           72 :                             General::CheckCreatedZoneItemName(
    7035              :                                 state,
    7036              :                                 RoutineName,
    7037           24 :                                 s_ipsc->cCurrentModuleObject,
    7038              :                                 state.dataHeatBal
    7039           24 :                                     ->Zone(state.dataHeatBal->ZoneList(state.dataSurface->IntMassObjects(Loop).ZoneOrZoneListPtr).Zone(Item1))
    7040           24 :                                     .Name,
    7041           24 :                                 state.dataHeatBal->ZoneList(state.dataSurface->IntMassObjects(Loop).ZoneOrZoneListPtr).MaxZoneNameLength,
    7042           24 :                                 state.dataSurface->IntMassObjects(Loop).Name,
    7043           24 :                                 state.dataSurfaceGeometry->SurfaceTmp,
    7044           24 :                                 SurfNum - 1,
    7045           24 :                                 surfTemp.Name,
    7046              :                                 errFlag);
    7047              : 
    7048           24 :                             ZoneNum = state.dataHeatBal->ZoneList(state.dataSurface->IntMassObjects(Loop).ZoneOrZoneListPtr).Zone(Item1);
    7049            0 :                         } else if (state.dataSurface->IntMassObjects(Loop).spaceListActive) {
    7050            0 :                             int spaceNum = state.dataHeatBal->spaceList(state.dataSurface->IntMassObjects(Loop).spaceOrSpaceListPtr).spaces(Item1);
    7051            0 :                             ZoneNum = state.dataHeatBal->space(spaceNum).zoneNum;
    7052            0 :                             const std::string spaceName = state.dataHeatBal->space(spaceNum).Name;
    7053            0 :                             surfTemp.Name = spaceName + ' ' + state.dataSurface->IntMassObjects(Loop).Name;
    7054            0 :                             surfTemp.spaceNum = spaceNum;
    7055            0 :                         }
    7056           24 :                         surfTemp.Zone = ZoneNum;
    7057           24 :                         surfTemp.Class = SurfaceClass::IntMass;
    7058           24 :                         surfTemp.ZoneName = state.dataHeatBal->Zone(ZoneNum).Name;
    7059           24 :                         surfTemp.HeatTransSurf = true;
    7060           24 :                         if (errFlag) {
    7061            0 :                             ErrorsFound = true;
    7062              :                         }
    7063              :                     }
    7064              : 
    7065           40 :                     if (state.dataSurface->IntMassObjects(Loop).Construction > 0) {
    7066           40 :                         if (state.dataConstruction->Construct(state.dataSurface->IntMassObjects(Loop).Construction).IsUsed) {
    7067           40 :                             surfTemp.ConstructionStoredInputValue = state.dataSurface->IntMassObjects(Loop).Construction;
    7068              :                         }
    7069              :                     }
    7070           40 :                     surfTemp.GrossArea = state.dataSurface->IntMassObjects(Loop).GrossArea;
    7071           40 :                     surfTemp.Area = surfTemp.GrossArea;
    7072           40 :                     surfTemp.NetAreaShadowCalc = surfTemp.Area;
    7073           40 :                     surfTemp.Width = surfTemp.Area;
    7074           40 :                     surfTemp.Height = 1.0;
    7075           40 :                     surfTemp.Tilt = 90.0;
    7076           40 :                     surfTemp.convOrientation = Convect::GetSurfConvOrientation(surfTemp.Tilt);
    7077           40 :                     surfTemp.CosTilt = 0.0; // Tuned Was std::cos( 90.0 * DegToRadians )
    7078           40 :                     surfTemp.SinTilt = 1.0; // Tuned Was std::sin( 90.0 * DegToRadians )
    7079           40 :                     surfTemp.Azimuth = 0.0;
    7080           40 :                     surfTemp.CosAzim = 1.0; // Tuned Was std::cos( 0.0 )
    7081           40 :                     surfTemp.SinAzim = 0.0; // Tuned Was std::sin( 0.0 )
    7082              :                     // Outward normal unit vector (pointing away from room)
    7083           40 :                     surfTemp.OutNormVec = surfTemp.lcsz;
    7084           40 :                     surfTemp.ViewFactorSky = 0.5;
    7085           40 :                     surfTemp.ExtSolar = false;
    7086           40 :                     surfTemp.ExtWind = false;
    7087           40 :                     surfTemp.BaseSurf = SurfNum;
    7088           40 :                     surfTemp.BaseSurfName = surfTemp.Name;
    7089           40 :                     surfTemp.ExtBoundCondName = surfTemp.Name;
    7090           40 :                     surfTemp.ExtBoundCond = unreconciledZoneSurface;
    7091              :                 }
    7092              :             }
    7093              :         }
    7094              :     }
    7095              : 
    7096          228 :     int GetNumIntMassSurfaces(EnergyPlusData &state) // Number of Internal Mass Surfaces to obtain
    7097              : 
    7098              :     {
    7099              :         // Counts internal mass surfaces applied to zones and zone lists
    7100              : 
    7101              :         int IOStat;          // IO Status when calling get input subroutine
    7102              :         int SurfaceNumAlpha; // Number of material alpha names being passed
    7103              :         int SurfaceNumArg;   // Number of material properties being passed
    7104              : 
    7105          228 :         auto &s_ipsc = state.dataIPShortCut;
    7106          228 :         s_ipsc->cCurrentModuleObject = "InternalMass";
    7107              : 
    7108          228 :         int NumIntMassSurf = 0;
    7109          228 :         int TotIntMass = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "InternalMass");
    7110              : 
    7111          228 :         if (TotIntMass == 0) {
    7112          218 :             return NumIntMassSurf;
    7113              :         }
    7114              :         // scan for zones and zone lists in InternalMass objects
    7115           32 :         for (int Item = 1; Item <= TotIntMass; ++Item) {
    7116           44 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    7117           22 :                                                                      s_ipsc->cCurrentModuleObject,
    7118              :                                                                      Item,
    7119           22 :                                                                      s_ipsc->cAlphaArgs,
    7120              :                                                                      SurfaceNumAlpha,
    7121           22 :                                                                      s_ipsc->rNumericArgs,
    7122              :                                                                      SurfaceNumArg,
    7123              :                                                                      IOStat,
    7124           22 :                                                                      s_ipsc->lNumericFieldBlanks,
    7125           22 :                                                                      s_ipsc->lAlphaFieldBlanks,
    7126           22 :                                                                      s_ipsc->cAlphaFieldNames,
    7127           22 :                                                                      s_ipsc->cNumericFieldNames);
    7128              : 
    7129           22 :             int Item1 = Util::FindItemInList(s_ipsc->cAlphaArgs(3), state.dataHeatBal->Zone, state.dataGlobal->NumOfZones);
    7130           22 :             int ZLItem = 0;
    7131           22 :             if (Item1 == 0 && state.dataHeatBal->NumOfZoneLists > 0) {
    7132            6 :                 ZLItem = Util::FindItemInList(s_ipsc->cAlphaArgs(3), state.dataHeatBal->ZoneList);
    7133              :             }
    7134           22 :             if (Item1 > 0) {
    7135           16 :                 if (s_ipsc->lAlphaFieldBlanks(4)) {
    7136           16 :                     ++NumIntMassSurf;
    7137              :                 }
    7138            6 :             } else if (ZLItem > 0) {
    7139            6 :                 NumIntMassSurf += state.dataHeatBal->ZoneList(ZLItem).NumOfZones;
    7140              :             }
    7141              : 
    7142           22 :             if (!s_ipsc->lAlphaFieldBlanks(4)) {
    7143            0 :                 Item1 = Util::FindItemInList(s_ipsc->cAlphaArgs(4), state.dataHeatBal->space);
    7144            0 :                 int SLItem = 0;
    7145            0 :                 if (Item1 == 0 && int(state.dataHeatBal->spaceList.size()) > 0) {
    7146            0 :                     SLItem = Util::FindItemInList(s_ipsc->cAlphaArgs(4), state.dataHeatBal->spaceList);
    7147              :                 }
    7148            0 :                 if (Item1 > 0) {
    7149            0 :                     ++NumIntMassSurf;
    7150            0 :                 } else if (SLItem > 0) {
    7151            0 :                     int numOfSpaces = int(state.dataHeatBal->spaceList(SLItem).numListSpaces);
    7152            0 :                     NumIntMassSurf += numOfSpaces;
    7153              :                 }
    7154              :             }
    7155              :         }
    7156           10 :         NumIntMassSurf = max(NumIntMassSurf, TotIntMass);
    7157           10 :         return NumIntMassSurf;
    7158              :     }
    7159              : 
    7160            0 :     void GetShadingSurfReflectanceData(EnergyPlusData &state, bool &ErrorsFound) // If errors found in input
    7161              :     {
    7162              : 
    7163              :         // SUBROUTINE INFORMATION:
    7164              :         //       AUTHOR         Fred Winkelmann
    7165              :         //       DATE WRITTEN   Sept 2003
    7166              : 
    7167              :         // PURPOSE OF THIS SUBROUTINE:
    7168              :         // Gets data for a Shading Surface Reflectance object.  This is only called when the
    7169              :         // Solar Distribution is to be calculated for reflectances.
    7170              : 
    7171              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    7172              :         int IOStat;                       // IO Status when calling get input subroutine
    7173              :         int NumAlpha;                     // Number of alpha names being passed
    7174              :         int NumProp;                      // Number of properties being passed
    7175              :         int TotShadingSurfaceReflectance; // Total Shading Surface Reflectance statements
    7176              :         int Loop;                         // DO loop index
    7177              :         int SurfNum;                      // Surface number
    7178              :         int GlConstrNum;                  // Glazing construction number
    7179              :         bool WrongSurfaceType;
    7180              : 
    7181            0 :         auto &s_ipsc = state.dataIPShortCut;
    7182              :         // For shading surfaces, initialize value of reflectance values to default values. These values
    7183              :         // may be overridden below for shading surfaces with an associated Shading Surface Reflectance object.
    7184            0 :         for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    7185            0 :             auto const &surf = state.dataSurface->Surface(SurfNum);
    7186            0 :             if (!(surf.Class == SurfaceClass::Shading || surf.Class == SurfaceClass::Detached_F || surf.Class == SurfaceClass::Detached_B ||
    7187            0 :                   surf.Class == SurfaceClass::Overhang || surf.Class == SurfaceClass::Fin)) {
    7188            0 :                 continue;
    7189              :             }
    7190            0 :             state.dataSurface->SurfShadowDiffuseSolRefl(SurfNum) = 0.2;
    7191            0 :             state.dataSurface->SurfShadowDiffuseVisRefl(SurfNum) = 0.2;
    7192            0 :             state.dataSurface->SurfShadowGlazingFrac(SurfNum) = 0.0;
    7193            0 :             state.dataSurface->SurfShadowGlazingConstruct(SurfNum) = 0;
    7194              :         }
    7195              : 
    7196              :         // Get the total number of Shading Surface Reflectance objects
    7197            0 :         s_ipsc->cCurrentModuleObject = "ShadingProperty:Reflectance";
    7198            0 :         TotShadingSurfaceReflectance = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
    7199              :         //  IF(TotShadingSurfaceReflectance.EQ.0) RETURN
    7200              : 
    7201            0 :         for (Loop = 1; Loop <= TotShadingSurfaceReflectance; ++Loop) {
    7202              : 
    7203            0 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    7204            0 :                                                                      s_ipsc->cCurrentModuleObject,
    7205              :                                                                      Loop,
    7206            0 :                                                                      s_ipsc->cAlphaArgs,
    7207              :                                                                      NumAlpha,
    7208            0 :                                                                      s_ipsc->rNumericArgs,
    7209              :                                                                      NumProp,
    7210              :                                                                      IOStat,
    7211            0 :                                                                      s_ipsc->lNumericFieldBlanks,
    7212            0 :                                                                      s_ipsc->lAlphaFieldBlanks,
    7213            0 :                                                                      s_ipsc->cAlphaFieldNames,
    7214            0 :                                                                      s_ipsc->cNumericFieldNames);
    7215            0 :             SurfNum = Util::FindItemInList(s_ipsc->cAlphaArgs(1), state.dataSurface->Surface, state.dataSurface->TotSurfaces);
    7216            0 :             if (SurfNum == 0) {
    7217            0 :                 ShowWarningError(state, format("{}=\"{}\", invalid specification", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
    7218            0 :                 ShowContinueError(state, format(".. not found {}=\"{}\".", s_ipsc->cAlphaFieldNames(1), s_ipsc->cAlphaArgs(1)));
    7219              :                 //      ErrorsFound =.TRUE.
    7220            0 :                 continue;
    7221              :             }
    7222              : 
    7223              :             // Check that associated surface is a shading surface
    7224            0 :             WrongSurfaceType = false;
    7225            0 :             auto const &surf = state.dataSurface->Surface(SurfNum);
    7226            0 :             if (!(surf.Class == SurfaceClass::Shading || surf.Class == SurfaceClass::Detached_F || surf.Class == SurfaceClass::Detached_B ||
    7227            0 :                   surf.Class == SurfaceClass::Overhang || surf.Class == SurfaceClass::Fin)) {
    7228            0 :                 WrongSurfaceType = true;
    7229              :             }
    7230            0 :             if (WrongSurfaceType) {
    7231            0 :                 ShowSevereError(
    7232              :                     state,
    7233            0 :                     format("GetShadingSurfReflectanceData: {}=\"{}\", surface is not a shading surface.", s_ipsc->cCurrentModuleObject, surf.Name));
    7234            0 :                 ErrorsFound = true;
    7235            0 :                 continue;
    7236              :             }
    7237              : 
    7238              :             // If associated surface is a shading surface, set reflectance values
    7239            0 :             state.dataSurface->SurfShadowGlazingFrac(SurfNum) = s_ipsc->rNumericArgs(3);
    7240            0 :             state.dataSurface->SurfShadowDiffuseSolRefl(SurfNum) = (1.0 - s_ipsc->rNumericArgs(3)) * s_ipsc->rNumericArgs(1);
    7241            0 :             state.dataSurface->SurfShadowDiffuseVisRefl(SurfNum) = (1.0 - s_ipsc->rNumericArgs(3)) * s_ipsc->rNumericArgs(2);
    7242            0 :             if (s_ipsc->rNumericArgs(3) > 0.0) {
    7243            0 :                 GlConstrNum = Util::FindItemInList(s_ipsc->cAlphaArgs(2), state.dataConstruction->Construct, state.dataHeatBal->TotConstructs);
    7244            0 :                 if (GlConstrNum == 0) {
    7245            0 :                     ShowSevereError(state,
    7246            0 :                                     format("{}=\"{}\", {} not found={}",
    7247            0 :                                            s_ipsc->cCurrentModuleObject,
    7248            0 :                                            state.dataSurface->Surface(SurfNum).Name,
    7249            0 :                                            s_ipsc->cAlphaFieldNames(2),
    7250            0 :                                            s_ipsc->cAlphaArgs(2)));
    7251            0 :                     ErrorsFound = true;
    7252              :                 } else {
    7253            0 :                     state.dataConstruction->Construct(GlConstrNum).IsUsed = true;
    7254              :                 }
    7255            0 :                 state.dataSurface->SurfShadowGlazingConstruct(SurfNum) = GlConstrNum;
    7256              :             }
    7257            0 :             SurfNum = Util::FindItemInList("Mir-" + s_ipsc->cAlphaArgs(1), state.dataSurface->Surface, state.dataSurface->TotSurfaces);
    7258            0 :             if (SurfNum == 0) {
    7259            0 :                 continue;
    7260              :             }
    7261            0 :             state.dataSurface->SurfShadowGlazingFrac(SurfNum) = s_ipsc->rNumericArgs(3);
    7262            0 :             state.dataSurface->SurfShadowDiffuseSolRefl(SurfNum) = (1.0 - s_ipsc->rNumericArgs(3)) * s_ipsc->rNumericArgs(1);
    7263            0 :             state.dataSurface->SurfShadowDiffuseVisRefl(SurfNum) = (1.0 - s_ipsc->rNumericArgs(3)) * s_ipsc->rNumericArgs(2);
    7264            0 :             if (s_ipsc->rNumericArgs(3) > 0.0) {
    7265            0 :                 GlConstrNum = Util::FindItemInList(s_ipsc->cAlphaArgs(2), state.dataConstruction->Construct, state.dataHeatBal->TotConstructs);
    7266            0 :                 if (GlConstrNum != 0) {
    7267            0 :                     state.dataConstruction->Construct(GlConstrNum).IsUsed = true;
    7268              :                 }
    7269            0 :                 state.dataSurface->SurfShadowGlazingConstruct(SurfNum) = GlConstrNum;
    7270              :             }
    7271              : 
    7272              :         } // End of loop over Shading Surface Reflectance objects
    7273              : 
    7274              :         // Write reflectance values to .eio file.
    7275            0 :         print(state.files.eio,
    7276              :               "! <ShadingProperty Reflectance>,Shading Surface Name,Shading Type,Diffuse Solar Reflectance, Diffuse "
    7277              :               "Visible Reflectance,Surface Glazing Fraction,Surface Glazing Construction\n");
    7278              : 
    7279            0 :         for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    7280            0 :             auto const &surf = state.dataSurface->Surface(SurfNum);
    7281            0 :             if (!(surf.Class == SurfaceClass::Shading || surf.Class == SurfaceClass::Detached_F || surf.Class == SurfaceClass::Detached_B ||
    7282            0 :                   surf.Class == SurfaceClass::Overhang || surf.Class == SurfaceClass::Fin)) {
    7283            0 :                 continue;
    7284              :             }
    7285              : 
    7286            0 :             constexpr std::string_view fmt = "ShadingProperty Reflectance,{},{},{:.2R},{:.2R},{:.2R}, {}\n";
    7287            0 :             if (state.dataSurface->SurfShadowGlazingConstruct(SurfNum) != 0) {
    7288            0 :                 print(state.files.eio,
    7289              :                       fmt,
    7290            0 :                       surf.Name,
    7291            0 :                       cSurfaceClass(surf.Class),
    7292            0 :                       state.dataSurface->SurfShadowDiffuseSolRefl(SurfNum),
    7293            0 :                       state.dataSurface->SurfShadowDiffuseVisRefl(SurfNum),
    7294            0 :                       state.dataSurface->SurfShadowGlazingFrac(SurfNum),
    7295            0 :                       state.dataConstruction->Construct(state.dataSurface->SurfShadowGlazingConstruct(SurfNum)).Name);
    7296              :             } else {
    7297            0 :                 print(state.files.eio,
    7298              :                       fmt,
    7299            0 :                       surf.Name,
    7300            0 :                       cSurfaceClass(surf.Class),
    7301            0 :                       state.dataSurface->SurfShadowDiffuseSolRefl(SurfNum),
    7302            0 :                       state.dataSurface->SurfShadowDiffuseVisRefl(SurfNum),
    7303            0 :                       state.dataSurface->SurfShadowGlazingFrac(SurfNum),
    7304              :                       "N/A");
    7305              :             }
    7306              :         }
    7307            0 :     }
    7308              : 
    7309          224 :     void GetHTSurfExtVentedCavityData(EnergyPlusData &state, bool &ErrorsFound) // Error flag indicator (true if errors found)
    7310              :     {
    7311              : 
    7312              :         // SUBROUTINE INFORMATION:
    7313              :         //       AUTHOR         BGriffith
    7314              :         //       DATE WRITTEN   January 2005
    7315              : 
    7316              :         // PURPOSE OF THIS SUBROUTINE:
    7317              :         // load input data for Exterior Vented Cavity Special case for heat transfer surfaces
    7318              : 
    7319              :         // METHODOLOGY EMPLOYED:
    7320              :         // usual E+ input processes
    7321              : 
    7322              :         // REFERENCES:
    7323              :         // derived from SUBROUTINE GetTranspiredCollectorInput
    7324              : 
    7325              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    7326              :         int Item;          // Item to be "gotten"
    7327              :         int NumAlphas;     // Number of Alphas for each GetObjectItem call
    7328              :         int NumNumbers;    // Number of Numbers for each GetObjectItem call
    7329              :         int MaxNumAlphas;  // argument for call to GetObjectDefMaxArgs
    7330              :         int MaxNumNumbers; // argument for call to GetObjectDefMaxArgs
    7331              :         int Dummy;         // argument for call to GetObjectDefMaxArgs
    7332              :         int IOStatus;      // Used in GetObjectItem
    7333              :         int Found;
    7334              :         int AlphaOffset; // local temp var
    7335          224 :         std::string Roughness;
    7336              :         int ThisSurf;                   // do loop counter
    7337              :         Real64 AvgAzimuth;              // temp for error checking
    7338              :         Real64 AvgTilt;                 // temp for error checking
    7339          224 :         constexpr Real64 AZITOL = 15.0; // Degree Azimuth Angle Tolerance
    7340          224 :         constexpr Real64 TILTOL = 10.0; // Degree Tilt Angle Tolerance
    7341              :         int SurfID;                     // local surface "pointer"
    7342              : 
    7343          224 :         auto &s_ipsc = state.dataIPShortCut;
    7344          224 :         s_ipsc->cCurrentModuleObject = "SurfaceProperty:ExteriorNaturalVentedCavity";
    7345          224 :         state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, s_ipsc->cCurrentModuleObject, Dummy, MaxNumAlphas, MaxNumNumbers);
    7346              : 
    7347          224 :         if (MaxNumNumbers != 8) {
    7348            0 :             ShowSevereError(
    7349              :                 state,
    7350            0 :                 format("{}: Object Definition indicates not = 8 Number Objects, Number Indicated={}", s_ipsc->cCurrentModuleObject, MaxNumNumbers));
    7351            0 :             ErrorsFound = true;
    7352              :         }
    7353              : 
    7354          224 :         state.dataSurface->TotExtVentCav = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
    7355              : 
    7356          224 :         state.dataHeatBal->ExtVentedCavity.allocate(state.dataSurface->TotExtVentCav);
    7357              : 
    7358          224 :         for (Item = 1; Item <= state.dataSurface->TotExtVentCav; ++Item) {
    7359            0 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    7360            0 :                                                                      s_ipsc->cCurrentModuleObject,
    7361              :                                                                      Item,
    7362            0 :                                                                      s_ipsc->cAlphaArgs,
    7363              :                                                                      NumAlphas,
    7364            0 :                                                                      s_ipsc->rNumericArgs,
    7365              :                                                                      NumNumbers,
    7366              :                                                                      IOStatus,
    7367            0 :                                                                      s_ipsc->lNumericFieldBlanks,
    7368            0 :                                                                      s_ipsc->lAlphaFieldBlanks,
    7369            0 :                                                                      s_ipsc->cAlphaFieldNames,
    7370            0 :                                                                      s_ipsc->cNumericFieldNames);
    7371              :             // first handle cAlphaArgs
    7372            0 :             bool ErrorInName = false;
    7373            0 :             bool IsBlank = false;
    7374              : 
    7375            0 :             Util::VerifyName(state,
    7376            0 :                              s_ipsc->cAlphaArgs(1),
    7377            0 :                              state.dataHeatBal->ExtVentedCavity,
    7378              :                              Item - 1,
    7379              :                              ErrorInName,
    7380              :                              IsBlank,
    7381            0 :                              s_ipsc->cCurrentModuleObject + " Name");
    7382            0 :             if (ErrorInName) {
    7383            0 :                 ShowContinueError(state, "...cannot not duplicate other names");
    7384            0 :                 ErrorsFound = true;
    7385            0 :                 continue;
    7386              :             }
    7387            0 :             state.dataHeatBal->ExtVentedCavity(Item).Name = s_ipsc->cAlphaArgs(1);
    7388              : 
    7389            0 :             state.dataHeatBal->ExtVentedCavity(Item).OSCMName = s_ipsc->cAlphaArgs(2);
    7390            0 :             if (!s_ipsc->lAlphaFieldBlanks(2)) {
    7391            0 :                 Found = Util::FindItemInList(state.dataHeatBal->ExtVentedCavity(Item).OSCMName, state.dataSurface->OSCM, state.dataSurface->TotOSCM);
    7392            0 :                 if (Found == 0) {
    7393            0 :                     ShowSevereError(state,
    7394            0 :                                     format("{}=\"{}\", invalid {}=\"{}\".",
    7395            0 :                                            s_ipsc->cCurrentModuleObject,
    7396            0 :                                            state.dataHeatBal->ExtVentedCavity(Item).Name,
    7397            0 :                                            s_ipsc->cAlphaFieldNames(2),
    7398            0 :                                            s_ipsc->cAlphaArgs(2)));
    7399            0 :                     ErrorsFound = true;
    7400              :                 }
    7401              :             } else {
    7402            0 :                 Found = 0;
    7403            0 :                 ShowSevereError(state,
    7404            0 :                                 format("{}=\"{}\", invalid {} cannot be blank.",
    7405            0 :                                        s_ipsc->cCurrentModuleObject,
    7406            0 :                                        state.dataHeatBal->ExtVentedCavity(Item).Name,
    7407            0 :                                        s_ipsc->cAlphaFieldNames(2)));
    7408            0 :                 ErrorsFound = true;
    7409              :             }
    7410            0 :             state.dataHeatBal->ExtVentedCavity(Item).OSCMPtr = Found;
    7411              : 
    7412            0 :             Roughness = s_ipsc->cAlphaArgs(3);
    7413              :             // Select the correct Number for the associated ascii name for the roughness type
    7414            0 :             if (Util::SameString(Roughness, "VerySmooth")) {
    7415            0 :                 state.dataHeatBal->ExtVentedCavity(Item).BaffleRoughness = Material::SurfaceRoughness::VerySmooth;
    7416            0 :             } else if (Util::SameString(Roughness, "Smooth")) {
    7417            0 :                 state.dataHeatBal->ExtVentedCavity(Item).BaffleRoughness = Material::SurfaceRoughness::Smooth;
    7418            0 :             } else if (Util::SameString(Roughness, "MediumSmooth")) {
    7419            0 :                 state.dataHeatBal->ExtVentedCavity(Item).BaffleRoughness = Material::SurfaceRoughness::MediumSmooth;
    7420            0 :             } else if (Util::SameString(Roughness, "MediumRough")) {
    7421            0 :                 state.dataHeatBal->ExtVentedCavity(Item).BaffleRoughness = Material::SurfaceRoughness::MediumRough;
    7422            0 :             } else if (Util::SameString(Roughness, "Rough")) {
    7423            0 :                 state.dataHeatBal->ExtVentedCavity(Item).BaffleRoughness = Material::SurfaceRoughness::Rough;
    7424            0 :             } else if (Util::SameString(Roughness, "VeryRough")) {
    7425            0 :                 state.dataHeatBal->ExtVentedCavity(Item).BaffleRoughness = Material::SurfaceRoughness::VeryRough;
    7426              :             } // TODO: fix this after creating FindEnumeratedValueIndex()
    7427              : 
    7428              :             // Was it set?
    7429            0 :             if (state.dataHeatBal->ExtVentedCavity(Item).BaffleRoughness == Material::SurfaceRoughness::Invalid) {
    7430            0 :                 ShowSevereError(state,
    7431            0 :                                 format("{}=\"{}\", invalid {}=\"{}",
    7432            0 :                                        s_ipsc->cCurrentModuleObject,
    7433            0 :                                        state.dataHeatBal->ExtVentedCavity(Item).Name,
    7434            0 :                                        s_ipsc->cAlphaFieldNames(3),
    7435            0 :                                        s_ipsc->cAlphaArgs(3)));
    7436            0 :                 ErrorsFound = true;
    7437              :             }
    7438              : 
    7439            0 :             AlphaOffset = 3;
    7440            0 :             state.dataHeatBal->ExtVentedCavity(Item).NumSurfs = NumAlphas - AlphaOffset;
    7441            0 :             if (state.dataHeatBal->ExtVentedCavity(Item).NumSurfs == 0) {
    7442            0 :                 ShowSevereError(state,
    7443            0 :                                 format("{}=\"{}\", no underlying surfaces specified. Must have at least one.",
    7444            0 :                                        s_ipsc->cCurrentModuleObject,
    7445            0 :                                        state.dataHeatBal->ExtVentedCavity(Item).Name));
    7446            0 :                 ErrorsFound = true;
    7447            0 :                 continue;
    7448              :             }
    7449            0 :             state.dataHeatBal->ExtVentedCavity(Item).SurfPtrs.allocate(state.dataHeatBal->ExtVentedCavity(Item).NumSurfs);
    7450            0 :             state.dataHeatBal->ExtVentedCavity(Item).SurfPtrs = 0;
    7451            0 :             for (ThisSurf = 1; ThisSurf <= state.dataHeatBal->ExtVentedCavity(Item).NumSurfs; ++ThisSurf) {
    7452            0 :                 Found = Util::FindItemInList(s_ipsc->cAlphaArgs(ThisSurf + AlphaOffset), state.dataSurface->Surface, state.dataSurface->TotSurfaces);
    7453            0 :                 if (Found == 0) {
    7454            0 :                     ShowSevereError(state,
    7455            0 :                                     format("{}=\"{}\", invalid {}=\"{}",
    7456            0 :                                            s_ipsc->cCurrentModuleObject,
    7457            0 :                                            state.dataHeatBal->ExtVentedCavity(Item).Name,
    7458            0 :                                            s_ipsc->cAlphaFieldNames(ThisSurf + AlphaOffset),
    7459            0 :                                            s_ipsc->cAlphaArgs(ThisSurf + AlphaOffset)));
    7460            0 :                     ErrorsFound = true;
    7461            0 :                     continue;
    7462              :                 }
    7463              :                 // check that surface is appropriate, Heat transfer, Sun, Wind,
    7464            0 :                 if (!state.dataSurface->Surface(Found).HeatTransSurf) {
    7465            0 :                     ShowSevereError(state,
    7466            0 :                                     format("{}=\"{}\", invalid {}=\"{}",
    7467            0 :                                            s_ipsc->cCurrentModuleObject,
    7468            0 :                                            state.dataHeatBal->ExtVentedCavity(Item).Name,
    7469            0 :                                            s_ipsc->cAlphaFieldNames(ThisSurf + AlphaOffset),
    7470            0 :                                            s_ipsc->cAlphaArgs(ThisSurf + AlphaOffset)));
    7471            0 :                     ShowContinueError(state, "...because it is not a Heat Transfer Surface.");
    7472            0 :                     ErrorsFound = true;
    7473            0 :                     continue;
    7474              :                 }
    7475            0 :                 if (!state.dataSurface->Surface(Found).ExtSolar) {
    7476            0 :                     ShowSevereError(state,
    7477            0 :                                     format("{}=\"{}\", invalid {}=\"{}",
    7478            0 :                                            s_ipsc->cCurrentModuleObject,
    7479            0 :                                            state.dataHeatBal->ExtVentedCavity(Item).Name,
    7480            0 :                                            s_ipsc->cAlphaFieldNames(ThisSurf + AlphaOffset),
    7481            0 :                                            s_ipsc->cAlphaArgs(ThisSurf + AlphaOffset)));
    7482            0 :                     ShowContinueError(state, "...because it is not exposed to Sun.");
    7483            0 :                     ErrorsFound = true;
    7484            0 :                     continue;
    7485              :                 }
    7486            0 :                 if (!state.dataSurface->Surface(Found).ExtWind) {
    7487            0 :                     ShowSevereError(state,
    7488            0 :                                     format("{}=\"{}\", invalid {}=\"{}",
    7489            0 :                                            s_ipsc->cCurrentModuleObject,
    7490            0 :                                            state.dataHeatBal->ExtVentedCavity(Item).Name,
    7491            0 :                                            s_ipsc->cAlphaFieldNames(ThisSurf + AlphaOffset),
    7492            0 :                                            s_ipsc->cAlphaArgs(ThisSurf + AlphaOffset)));
    7493            0 :                     ShowContinueError(state, "...because it is not exposed to Wind.");
    7494            0 :                     ErrorsFound = true;
    7495            0 :                     continue;
    7496              :                 }
    7497            0 :                 if (state.dataSurface->Surface(Found).ExtBoundCond != DataSurfaces::OtherSideCondModeledExt) {
    7498            0 :                     ShowSevereError(state,
    7499            0 :                                     format("{}=\"{}\", is invalid", s_ipsc->cCurrentModuleObject, state.dataHeatBal->ExtVentedCavity(Item).Name));
    7500            0 :                     ShowContinueError(state,
    7501            0 :                                       format("...because {}=\"{}\".",
    7502            0 :                                              s_ipsc->cAlphaFieldNames(ThisSurf + AlphaOffset),
    7503            0 :                                              s_ipsc->cAlphaArgs(ThisSurf + AlphaOffset)));
    7504            0 :                     ShowContinueError(state, "...is not an OtherSideConditionedModel surface.");
    7505            0 :                     ErrorsFound = true;
    7506            0 :                     continue;
    7507              :                 }
    7508            0 :                 state.dataHeatBal->ExtVentedCavity(Item).SurfPtrs(ThisSurf) = Found;
    7509              : 
    7510              :                 // now set info in Surface structure
    7511            0 :                 state.dataSurface->SurfExtCavNum(Found) = Item;
    7512            0 :                 state.dataSurface->SurfExtCavityPresent(Found) = true;
    7513              :             }
    7514              : 
    7515            0 :             if (ErrorsFound) {
    7516            0 :                 continue; // previous inner do loop may have detected problems that need to be cycle'd again to avoid crash
    7517              :             }
    7518              : 
    7519              :             // now that we should have all the surfaces, do some preparations and checks.
    7520              : 
    7521              :             // are they all similar tilt and azimuth? Issue warnings so people can do it if they really want
    7522            0 :             Real64 const surfaceArea(sum_sub(state.dataSurface->Surface, &SurfaceData::Area, state.dataHeatBal->ExtVentedCavity(Item).SurfPtrs));
    7523              :             //            AvgAzimuth = sum( Surface( ExtVentedCavity( Item ).SurfPtrs ).Azimuth * Surface( ExtVentedCavity( Item ).SurfPtrs
    7524              :             //).Area
    7525              :             //)
    7526              :             ///  sum(  Surface( ExtVentedCavity( Item ).SurfPtrs ).Area ); //Autodesk:F2C++ Array subscript usage: Replaced by below
    7527            0 :             AvgAzimuth = sum_product_sub(state.dataSurface->Surface,
    7528              :                                          &SurfaceData::Azimuth,
    7529              :                                          &SurfaceData::Area,
    7530            0 :                                          state.dataHeatBal->ExtVentedCavity(Item).SurfPtrs) /
    7531              :                          surfaceArea; // Autodesk:F2C++ Functions handle array subscript usage
    7532              :             //            AvgTilt = sum( Surface( ExtVentedCavity( Item ).SurfPtrs ).Tilt * Surface( ExtVentedCavity( Item ).SurfPtrs ).Area )
    7533              :             //            /
    7534              :             // sum(  Surface( ExtVentedCavity( Item ).SurfPtrs ).Area ); //Autodesk:F2C++ Array subscript usage: Replaced by below
    7535            0 :             AvgTilt = sum_product_sub(
    7536            0 :                           state.dataSurface->Surface, &SurfaceData::Tilt, &SurfaceData::Area, state.dataHeatBal->ExtVentedCavity(Item).SurfPtrs) /
    7537              :                       surfaceArea; // Autodesk:F2C++ Functions handle array subscript usage
    7538            0 :             for (ThisSurf = 1; ThisSurf <= state.dataHeatBal->ExtVentedCavity(Item).NumSurfs; ++ThisSurf) {
    7539            0 :                 SurfID = state.dataHeatBal->ExtVentedCavity(Item).SurfPtrs(ThisSurf);
    7540            0 :                 if (General::rotAzmDiffDeg(state.dataSurface->Surface(SurfID).Azimuth, AvgAzimuth) > AZITOL) {
    7541            0 :                     ShowWarningError(state,
    7542            0 :                                      format("{}=\"{}, Surface {} has Azimuth different from others in the associated group.",
    7543            0 :                                             s_ipsc->cCurrentModuleObject,
    7544            0 :                                             state.dataHeatBal->ExtVentedCavity(Item).Name,
    7545            0 :                                             state.dataSurface->Surface(SurfID).Name));
    7546              :                 }
    7547            0 :                 if (std::abs(state.dataSurface->Surface(SurfID).Tilt - AvgTilt) > TILTOL) {
    7548            0 :                     ShowWarningError(state,
    7549            0 :                                      format("{}=\"{}, Surface {} has Tilt different from others in the associated group.",
    7550            0 :                                             s_ipsc->cCurrentModuleObject,
    7551            0 :                                             state.dataHeatBal->ExtVentedCavity(Item).Name,
    7552            0 :                                             state.dataSurface->Surface(SurfID).Name));
    7553              :                 }
    7554              : 
    7555              :                 // test that there are no windows.  Now allow windows
    7556              :                 // If (Surface(SurfID)%GrossArea >  Surface(SurfID)%Area) Then
    7557              :                 //      Call ShowWarningError(state, 'Surface '//TRIM(Surface(SurfID)%name)//' has a subsurface whose area is not being ' &
    7558              :                 //         //'subtracted in the group of surfaces associated with '//TRIM(ExtVentedCavity(Item)%Name))
    7559              :                 // endif
    7560              :             }
    7561            0 :             state.dataHeatBal->ExtVentedCavity(Item).Tilt = AvgTilt;
    7562            0 :             state.dataHeatBal->ExtVentedCavity(Item).Azimuth = AvgAzimuth;
    7563              : 
    7564              :             // find area weighted centroid.
    7565              :             //            ExtVentedCavity( Item ).Centroid.z = sum( Surface( ExtVentedCavity( Item ).SurfPtrs ).Centroid.z * Surface(
    7566              :             // ExtVentedCavity(  Item
    7567              :             //).SurfPtrs ).Area ) / sum( Surface( ExtVentedCavity( Item ).SurfPtrs ).Area ); //Autodesk:F2C++ Array subscript usage: Replaced
    7568              :             // by below
    7569            0 :             state.dataHeatBal->ExtVentedCavity(Item).Centroid.z = sum_product_sub(state.dataSurface->Surface,
    7570              :                                                                                   &SurfaceData::Centroid,
    7571              :                                                                                   &Vector::z,
    7572            0 :                                                                                   state.dataSurface->Surface,
    7573              :                                                                                   &SurfaceData::Area,
    7574            0 :                                                                                   state.dataHeatBal->ExtVentedCavity(Item).SurfPtrs) /
    7575              :                                                                   surfaceArea; // Autodesk:F2C++ Functions handle array subscript usage
    7576              : 
    7577              :             // now handle rNumericArgs from input object
    7578            0 :             state.dataHeatBal->ExtVentedCavity(Item).Porosity = s_ipsc->rNumericArgs(1);
    7579            0 :             state.dataHeatBal->ExtVentedCavity(Item).LWEmitt = s_ipsc->rNumericArgs(2);
    7580            0 :             state.dataHeatBal->ExtVentedCavity(Item).SolAbsorp = s_ipsc->rNumericArgs(3);
    7581            0 :             state.dataHeatBal->ExtVentedCavity(Item).HdeltaNPL = s_ipsc->rNumericArgs(4);
    7582            0 :             state.dataHeatBal->ExtVentedCavity(Item).PlenGapThick = s_ipsc->rNumericArgs(5);
    7583            0 :             if (state.dataHeatBal->ExtVentedCavity(Item).PlenGapThick <= 0.0) {
    7584            0 :                 ShowSevereError(state, format("{}=\"{}\", invalid .", s_ipsc->cCurrentModuleObject, state.dataHeatBal->ExtVentedCavity(Item).Name));
    7585            0 :                 ErrorsFound = true;
    7586            0 :                 ShowContinueError(
    7587              :                     state,
    7588            0 :                     format("...because field \"{}\" must be greater than Zero=[{:.2T}].", s_ipsc->cNumericFieldNames(5), s_ipsc->rNumericArgs(5)));
    7589            0 :                 continue;
    7590              :             }
    7591            0 :             state.dataHeatBal->ExtVentedCavity(Item).AreaRatio = s_ipsc->rNumericArgs(6);
    7592            0 :             state.dataHeatBal->ExtVentedCavity(Item).Cv = s_ipsc->rNumericArgs(7);
    7593            0 :             state.dataHeatBal->ExtVentedCavity(Item).Cd = s_ipsc->rNumericArgs(8);
    7594              : 
    7595              :             // Fill out data we now know
    7596              :             // sum areas of HT surface areas
    7597              :             //            ExtVentedCavity( Item ).ProjArea = sum( Surface( ExtVentedCavity( Item ).SurfPtrs ).Area ); //Autodesk:F2C++ Array
    7598              :             // subscript  usage: Replaced by below
    7599            0 :             state.dataHeatBal->ExtVentedCavity(Item).ProjArea = surfaceArea;
    7600            0 :             if (state.dataHeatBal->ExtVentedCavity(Item).ProjArea <= 0.0) {
    7601            0 :                 ShowSevereError(state, format("{}=\"{}\", invalid .", s_ipsc->cCurrentModuleObject, state.dataHeatBal->ExtVentedCavity(Item).Name));
    7602            0 :                 ErrorsFound = true;
    7603            0 :                 ShowContinueError(state,
    7604            0 :                                   format("...because gross area of underlying surfaces must be greater than Zero=[{:.2T}].",
    7605            0 :                                          state.dataHeatBal->ExtVentedCavity(Item).ProjArea));
    7606            0 :                 continue;
    7607              :             }
    7608            0 :             state.dataHeatBal->ExtVentedCavity(Item).ActualArea =
    7609            0 :                 state.dataHeatBal->ExtVentedCavity(Item).ProjArea * state.dataHeatBal->ExtVentedCavity(Item).AreaRatio;
    7610              : 
    7611            0 :             SetupOutputVariable(state,
    7612              :                                 "Surface Exterior Cavity Baffle Surface Temperature",
    7613              :                                 Constant::Units::C,
    7614            0 :                                 state.dataHeatBal->ExtVentedCavity(Item).Tbaffle,
    7615              :                                 OutputProcessor::TimeStepType::System,
    7616              :                                 OutputProcessor::StoreType::Average,
    7617            0 :                                 state.dataHeatBal->ExtVentedCavity(Item).Name);
    7618            0 :             SetupOutputVariable(state,
    7619              :                                 "Surface Exterior Cavity Air Drybulb Temperature",
    7620              :                                 Constant::Units::C,
    7621            0 :                                 state.dataHeatBal->ExtVentedCavity(Item).TAirCav,
    7622              :                                 OutputProcessor::TimeStepType::System,
    7623              :                                 OutputProcessor::StoreType::Average,
    7624            0 :                                 state.dataHeatBal->ExtVentedCavity(Item).Name);
    7625            0 :             SetupOutputVariable(state,
    7626              :                                 "Surface Exterior Cavity Total Natural Ventilation Air Change Rate",
    7627              :                                 Constant::Units::ach,
    7628            0 :                                 state.dataHeatBal->ExtVentedCavity(Item).PassiveACH,
    7629              :                                 OutputProcessor::TimeStepType::System,
    7630              :                                 OutputProcessor::StoreType::Average,
    7631            0 :                                 state.dataHeatBal->ExtVentedCavity(Item).Name);
    7632            0 :             SetupOutputVariable(state,
    7633              :                                 "Surface Exterior Cavity Total Natural Ventilation Mass Flow Rate",
    7634              :                                 Constant::Units::kg_s,
    7635            0 :                                 state.dataHeatBal->ExtVentedCavity(Item).PassiveMdotVent,
    7636              :                                 OutputProcessor::TimeStepType::System,
    7637              :                                 OutputProcessor::StoreType::Average,
    7638            0 :                                 state.dataHeatBal->ExtVentedCavity(Item).Name);
    7639            0 :             SetupOutputVariable(state,
    7640              :                                 "Surface Exterior Cavity Natural Ventilation from Wind Mass Flow Rate",
    7641              :                                 Constant::Units::kg_s,
    7642            0 :                                 state.dataHeatBal->ExtVentedCavity(Item).PassiveMdotWind,
    7643              :                                 OutputProcessor::TimeStepType::System,
    7644              :                                 OutputProcessor::StoreType::Average,
    7645            0 :                                 state.dataHeatBal->ExtVentedCavity(Item).Name);
    7646            0 :             SetupOutputVariable(state,
    7647              :                                 "Surface Exterior Cavity Natural Ventilation from Buoyancy Mass Flow Rate",
    7648              :                                 Constant::Units::kg_s,
    7649            0 :                                 state.dataHeatBal->ExtVentedCavity(Item).PassiveMdotTherm,
    7650              :                                 OutputProcessor::TimeStepType::System,
    7651              :                                 OutputProcessor::StoreType::Average,
    7652            0 :                                 state.dataHeatBal->ExtVentedCavity(Item).Name);
    7653              :         }
    7654          224 :     }
    7655              : 
    7656          224 :     void ExposedFoundationPerimeter::getData(EnergyPlusData &state, bool &ErrorsFound)
    7657              :     {
    7658              : 
    7659              :         static constexpr std::string_view routineName = "ExposedFoundationPerimeter::getData";
    7660              :         int IOStatus; // Used in GetObjectItem
    7661              :         int NumAlphas;
    7662              :         int NumNumbers;
    7663              : 
    7664          224 :         Real64 constexpr tolerance = 1e-6;
    7665              : 
    7666          224 :         auto &s_ipsc = state.dataIPShortCut;
    7667              : 
    7668          224 :         s_ipsc->cCurrentModuleObject = "SurfaceProperty:ExposedFoundationPerimeter";
    7669          224 :         int numObjects = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
    7670              : 
    7671          224 :         for (int obj = 1; obj <= numObjects; ++obj) {
    7672            0 :             int alpF = 1;
    7673            0 :             int numF = 1;
    7674            0 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    7675            0 :                                                                      s_ipsc->cCurrentModuleObject,
    7676              :                                                                      obj,
    7677            0 :                                                                      s_ipsc->cAlphaArgs,
    7678              :                                                                      NumAlphas,
    7679            0 :                                                                      s_ipsc->rNumericArgs,
    7680              :                                                                      NumNumbers,
    7681              :                                                                      IOStatus,
    7682            0 :                                                                      s_ipsc->lNumericFieldBlanks,
    7683            0 :                                                                      s_ipsc->lAlphaFieldBlanks,
    7684            0 :                                                                      s_ipsc->cAlphaFieldNames,
    7685            0 :                                                                      s_ipsc->cNumericFieldNames);
    7686              : 
    7687            0 :             ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(alpF)};
    7688              : 
    7689            0 :             int Found = Util::FindItemInList(s_ipsc->cAlphaArgs(alpF), state.dataSurface->Surface, state.dataSurface->TotSurfaces);
    7690            0 :             if (Found == 0) {
    7691            0 :                 ShowSevereError(state, format("{}=\"{}\", did not find matching surface", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
    7692            0 :                 ErrorsFound = true;
    7693              :             }
    7694            0 :             alpF++;
    7695            0 :             if (state.dataSurface->Surface(Found).Class != SurfaceClass::Floor) {
    7696            0 :                 ShowWarningError(
    7697            0 :                     state, format("{}: {}, surface is not a floor surface", s_ipsc->cCurrentModuleObject, state.dataSurface->Surface(Found).Name));
    7698            0 :                 ShowContinueError(state, format("{} will not be used", s_ipsc->cCurrentModuleObject));
    7699            0 :                 continue;
    7700              :             }
    7701              : 
    7702              :             // Choose calculation method
    7703              : 
    7704              :             enum class CalculationMethod
    7705              :             {
    7706              :                 Invalid = -1,
    7707              :                 TotalExposedPerimeter,
    7708              :                 ExposedPerimeterFraction,
    7709              :                 Bysegment,
    7710              :                 Num
    7711              :             };
    7712              : 
    7713            0 :             constexpr std::array<std::string_view, static_cast<int>(CalculationMethod::Num)> CalculationMethodUC = {
    7714              :                 "TOTALEXPOSEDPERIMETER", "EXPOSEDPERIMETERFRACTION", "BYSEGMENT"};
    7715            0 :             CalculationMethod calculationMethod = static_cast<CalculationMethod>(getEnumValue(CalculationMethodUC, s_ipsc->cAlphaArgs(alpF)));
    7716            0 :             if (calculationMethod != CalculationMethod::TotalExposedPerimeter && calculationMethod != CalculationMethod::ExposedPerimeterFraction &&
    7717            0 :                 calculationMethod != CalculationMethod::Bysegment) {
    7718            0 :                 ShowSevereError(state,
    7719            0 :                                 format("{}=\"{}\", {} is not a valid choice for {}",
    7720            0 :                                        s_ipsc->cCurrentModuleObject,
    7721            0 :                                        s_ipsc->cAlphaArgs(1),
    7722              :                                        calculationMethod,
    7723            0 :                                        s_ipsc->cAlphaFieldNames(alpF)));
    7724            0 :                 ErrorsFound = true;
    7725              :             }
    7726            0 :             alpF++;
    7727              : 
    7728            0 :             Data data;
    7729            0 :             data.useDetailedExposedPerimeter = true;
    7730              : 
    7731            0 :             if (!s_ipsc->lNumericFieldBlanks(numF)) {
    7732            0 :                 if (calculationMethod == CalculationMethod::TotalExposedPerimeter) {
    7733            0 :                     data.exposedFraction = s_ipsc->rNumericArgs(numF) / state.dataSurface->Surface(Found).Perimeter;
    7734            0 :                     if (data.exposedFraction > 1 + tolerance) {
    7735            0 :                         ShowWarningError(state,
    7736            0 :                                          format("{}: {}, {} is greater than the perimeter of {}",
    7737            0 :                                                 s_ipsc->cCurrentModuleObject,
    7738            0 :                                                 state.dataSurface->Surface(Found).Name,
    7739            0 :                                                 s_ipsc->cNumericFieldNames(numF),
    7740            0 :                                                 state.dataSurface->Surface(Found).Name));
    7741            0 :                         ShowContinueError(state,
    7742            0 :                                           format("{} perimeter = {}, {} exposed perimeter = {}",
    7743            0 :                                                  state.dataSurface->Surface(Found).Name,
    7744            0 :                                                  state.dataSurface->Surface(Found).Perimeter,
    7745            0 :                                                  s_ipsc->cCurrentModuleObject,
    7746            0 :                                                  s_ipsc->rNumericArgs(numF)));
    7747            0 :                         ShowContinueError(
    7748              :                             state,
    7749            0 :                             format("{} will be set equal to {} perimeter", s_ipsc->cNumericFieldNames(numF), state.dataSurface->Surface(Found).Name));
    7750            0 :                         data.exposedFraction = 1.0;
    7751              :                     }
    7752              : 
    7753            0 :                     data.useDetailedExposedPerimeter = false;
    7754              :                 } else {
    7755            0 :                     ShowWarningError(state,
    7756            0 :                                      format("{}: {}, {} set as calculation method, but a value has been set for {}. This value will be ignored.",
    7757            0 :                                             s_ipsc->cCurrentModuleObject,
    7758            0 :                                             state.dataSurface->Surface(Found).Name,
    7759              :                                             calculationMethod,
    7760            0 :                                             s_ipsc->cNumericFieldNames(numF)));
    7761              :                 }
    7762              :             } else {
    7763            0 :                 if (calculationMethod == CalculationMethod::TotalExposedPerimeter) {
    7764            0 :                     ShowSevereError(state,
    7765            0 :                                     format("{}: {}, {} set as calculation method, but no value has been set for {}",
    7766            0 :                                            s_ipsc->cCurrentModuleObject,
    7767            0 :                                            state.dataSurface->Surface(Found).Name,
    7768              :                                            calculationMethod,
    7769            0 :                                            s_ipsc->cNumericFieldNames(numF)));
    7770            0 :                     ErrorsFound = true;
    7771              :                 }
    7772              :             }
    7773            0 :             numF++;
    7774              : 
    7775            0 :             if (!s_ipsc->lNumericFieldBlanks(numF)) {
    7776            0 :                 if (calculationMethod == CalculationMethod::ExposedPerimeterFraction) {
    7777            0 :                     data.exposedFraction = s_ipsc->rNumericArgs(numF);
    7778            0 :                     data.useDetailedExposedPerimeter = false;
    7779              :                 } else {
    7780            0 :                     ShowWarningError(state,
    7781            0 :                                      format("{}: {}, {} set as calculation method, but a value has been set for {}. This value will be ignored.",
    7782            0 :                                             s_ipsc->cCurrentModuleObject,
    7783            0 :                                             state.dataSurface->Surface(Found).Name,
    7784              :                                             calculationMethod,
    7785            0 :                                             s_ipsc->cNumericFieldNames(numF)));
    7786              :                 }
    7787              :             } else {
    7788            0 :                 if (calculationMethod == CalculationMethod::ExposedPerimeterFraction) {
    7789            0 :                     ShowSevereError(state,
    7790            0 :                                     format("{}: {}, {} set as calculation method, but no value has been set for {}",
    7791            0 :                                            s_ipsc->cCurrentModuleObject,
    7792            0 :                                            state.dataSurface->Surface(Found).Name,
    7793              :                                            calculationMethod,
    7794            0 :                                            s_ipsc->cNumericFieldNames(numF)));
    7795            0 :                     ErrorsFound = true;
    7796              :                 }
    7797              :             }
    7798            0 :             numF++;
    7799              : 
    7800            0 :             int numRemainingFields = NumAlphas - (alpF - 1) + NumNumbers - (numF - 1);
    7801            0 :             if (numRemainingFields > 0) {
    7802            0 :                 if (calculationMethod == CalculationMethod::Bysegment) {
    7803            0 :                     if (numRemainingFields != (int)state.dataSurface->Surface(Found).Vertex.size()) {
    7804            0 :                         ShowSevereError(state,
    7805            0 :                                         format("{}: {}, must have equal number of segments as the floor has vertices.{}\" and \"{}\"",
    7806            0 :                                                s_ipsc->cCurrentModuleObject,
    7807            0 :                                                state.dataSurface->Surface(Found).Name,
    7808            0 :                                                s_ipsc->cAlphaFieldNames(alpF),
    7809            0 :                                                s_ipsc->cNumericFieldNames(numF - 1)));
    7810            0 :                         ShowContinueError(state,
    7811            0 :                                           format("{} number of vertices = {}, {} number of segments = {}",
    7812            0 :                                                  state.dataSurface->Surface(Found).Name,
    7813            0 :                                                  state.dataSurface->Surface(Found).Vertex.size(),
    7814            0 :                                                  s_ipsc->cCurrentModuleObject,
    7815              :                                                  numRemainingFields));
    7816            0 :                         ErrorsFound = true;
    7817              :                     }
    7818            0 :                     for (int segNum = 0; segNum < numRemainingFields; segNum++) {
    7819            0 :                         if (s_ipsc->lAlphaFieldBlanks(alpF)) {
    7820            0 :                             ShowSevereEmptyField(
    7821            0 :                                 state, eoh, s_ipsc->cAlphaFieldNames(alpF), "Calculation Method", CalculationMethodUC[(int)calculationMethod]);
    7822            0 :                             ErrorsFound = true;
    7823            0 :                         } else if (BooleanSwitch bs = getYesNoValue(s_ipsc->cAlphaArgs(alpF)); bs != BooleanSwitch::Invalid) {
    7824            0 :                             data.isExposedPerimeter.push_back(static_cast<bool>(bs));
    7825              :                         } else {
    7826            0 :                             ShowSevereInvalidBool(state, eoh, s_ipsc->cAlphaFieldNames(alpF), s_ipsc->cAlphaArgs(alpF));
    7827            0 :                             ErrorsFound = true;
    7828              :                         }
    7829            0 :                         alpF++;
    7830              :                     }
    7831              :                 }
    7832              :             } else {
    7833            0 :                 if (calculationMethod == CalculationMethod::Bysegment) {
    7834            0 :                     ShowSevereError(state,
    7835            0 :                                     format("{}: {}, {} set as calculation method, but no values have been set for Surface Segments Exposed",
    7836            0 :                                            s_ipsc->cCurrentModuleObject,
    7837            0 :                                            state.dataSurface->Surface(Found).Name,
    7838              :                                            calculationMethod));
    7839            0 :                     ErrorsFound = true;
    7840              :                 }
    7841              :             }
    7842            0 :             surfaceMap[Found] = data;
    7843            0 :         }
    7844          224 :     }
    7845              : 
    7846          224 :     void GetSurfaceLocalEnvData(EnergyPlusData &state, bool &ErrorsFound) // Error flag indicator (true if errors found)
    7847              :     {
    7848              :         // SUBROUTINE INFORMATION:
    7849              :         //       AUTHOR         X LUO
    7850              :         //       DATE WRITTEN   July 2017
    7851              : 
    7852              :         // PURPOSE OF THIS SUBROUTINE:
    7853              :         // load input data for Outdoor Air Node for exterior surfaces
    7854              : 
    7855              :         // SUBROUTINE PARAMETER DEFINITIONS:
    7856              :         static constexpr std::string_view RoutineName("GetSurfaceLocalEnvData: ");
    7857              :         static constexpr std::string_view routineName = "GetSurfaceLocalEnvData";
    7858              : 
    7859          224 :         auto &s_ipsc = state.dataIPShortCut;
    7860              : 
    7861          224 :         s_ipsc->cCurrentModuleObject = "SurfaceProperty:LocalEnvironment";
    7862          224 :         state.dataSurface->TotSurfLocalEnv = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
    7863              : 
    7864          224 :         if (state.dataSurface->TotSurfLocalEnv > 0) {
    7865              :             int NumAlpha;
    7866              :             int NumNumeric;
    7867              :             int IOStat;
    7868              : 
    7869           13 :             state.dataGlobal->AnyLocalEnvironmentsInModel = true;
    7870              : 
    7871           13 :             if (!allocated(state.dataSurface->SurfLocalEnvironment)) {
    7872           13 :                 state.dataSurface->SurfLocalEnvironment.allocate(state.dataSurface->TotSurfLocalEnv);
    7873              :             }
    7874              : 
    7875           36 :             for (int Loop = 1; Loop <= state.dataSurface->TotSurfLocalEnv; ++Loop) {
    7876              : 
    7877           23 :                 auto &SurfLocalEnv = state.dataSurface->SurfLocalEnvironment(Loop);
    7878              : 
    7879           46 :                 state.dataInputProcessing->inputProcessor->getObjectItem(state,
    7880           23 :                                                                          s_ipsc->cCurrentModuleObject,
    7881              :                                                                          Loop,
    7882           23 :                                                                          s_ipsc->cAlphaArgs,
    7883              :                                                                          NumAlpha,
    7884           23 :                                                                          s_ipsc->rNumericArgs,
    7885              :                                                                          NumNumeric,
    7886              :                                                                          IOStat,
    7887           23 :                                                                          s_ipsc->lNumericFieldBlanks,
    7888           23 :                                                                          s_ipsc->lAlphaFieldBlanks,
    7889           23 :                                                                          s_ipsc->cAlphaFieldNames,
    7890           23 :                                                                          s_ipsc->cNumericFieldNames);
    7891              : 
    7892           23 :                 ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
    7893              : 
    7894           23 :                 Util::IsNameEmpty(state, s_ipsc->cAlphaArgs(1), s_ipsc->cCurrentModuleObject, ErrorsFound);
    7895              : 
    7896           23 :                 SurfLocalEnv.Name = s_ipsc->cAlphaArgs(1);
    7897              : 
    7898              :                 // Assign surface number
    7899           23 :                 int SurfNum = Util::FindItemInList(s_ipsc->cAlphaArgs(2), state.dataSurface->Surface);
    7900           23 :                 if (SurfNum == 0) {
    7901            0 :                     ShowSevereError(state,
    7902            0 :                                     format("{} {} = \"{}\", object. Illegal value for \"{}\" has been found.",
    7903              :                                            RoutineName,
    7904            0 :                                            s_ipsc->cCurrentModuleObject,
    7905            0 :                                            SurfLocalEnv.Name,
    7906            0 :                                            s_ipsc->cAlphaFieldNames(2)));
    7907            0 :                     ShowContinueError(state,
    7908            0 :                                       format("{} entered value = \"{}\", no corresponding surface (ref BuildingSurface:Detailed) has been "
    7909              :                                              "found in the input file.",
    7910            0 :                                              s_ipsc->cAlphaFieldNames(2),
    7911            0 :                                              s_ipsc->cAlphaArgs(2)));
    7912            0 :                     ErrorsFound = true;
    7913              :                 } else {
    7914           23 :                     SurfLocalEnv.SurfPtr = SurfNum;
    7915              :                 }
    7916              : 
    7917              :                 // Assign Sunlit Fraction Schedule number
    7918           23 :                 if (s_ipsc->lAlphaFieldBlanks(3)) {
    7919            1 :                 } else if ((SurfLocalEnv.sunlitFracSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(3))) == nullptr) {
    7920            0 :                     ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3));
    7921            0 :                     ErrorsFound = true;
    7922              :                 }
    7923              : 
    7924              :                 // Assign surrounding surfaces object number;
    7925           23 :                 if (!s_ipsc->lAlphaFieldBlanks(4)) {
    7926           21 :                     int SurroundingSurfsNum = Util::FindItemInList(s_ipsc->cAlphaArgs(4), state.dataSurface->SurroundingSurfsProperty);
    7927           21 :                     if (SurroundingSurfsNum == 0) {
    7928            0 :                         ShowSevereError(state,
    7929            0 :                                         format("{} {} = \"{}\", object. Illegal value for \"{}\" has been found.",
    7930              :                                                RoutineName,
    7931            0 :                                                s_ipsc->cCurrentModuleObject,
    7932            0 :                                                SurfLocalEnv.Name,
    7933            0 :                                                s_ipsc->cAlphaFieldNames(4)));
    7934            0 :                         ShowContinueError(state,
    7935            0 :                                           format("{} entered value = \"{}\", no corresponding surrounding surfaces properties has been found "
    7936              :                                                  "in the input file.",
    7937            0 :                                                  s_ipsc->cAlphaFieldNames(4),
    7938            0 :                                                  s_ipsc->cAlphaArgs(4)));
    7939            0 :                         ErrorsFound = true;
    7940              :                     } else {
    7941           21 :                         SurfLocalEnv.SurroundingSurfsPtr = SurroundingSurfsNum;
    7942              :                     }
    7943              :                 }
    7944              : 
    7945              :                 // Assign outdoor air node number;
    7946           23 :                 if (!s_ipsc->lAlphaFieldBlanks(5)) {
    7947            1 :                     int NodeNum = GetOnlySingleNode(state,
    7948            1 :                                                     s_ipsc->cAlphaArgs(5),
    7949              :                                                     ErrorsFound,
    7950              :                                                     DataLoopNode::ConnectionObjectType::SurfacePropertyLocalEnvironment,
    7951            1 :                                                     SurfLocalEnv.Name,
    7952              :                                                     DataLoopNode::NodeFluidType::Air,
    7953              :                                                     DataLoopNode::ConnectionType::Inlet,
    7954              :                                                     NodeInputManager::CompFluidStream::Primary,
    7955              :                                                     DataLoopNode::ObjectIsParent);
    7956            1 :                     if (NodeNum == 0 && OutAirNodeManager::CheckOutAirNodeNumber(state, NodeNum)) {
    7957            0 :                         ShowSevereError(state,
    7958            0 :                                         format("{} {} = \"{}\", object. Illegal value for \"{}\" has been found.",
    7959              :                                                RoutineName,
    7960            0 :                                                s_ipsc->cCurrentModuleObject,
    7961            0 :                                                SurfLocalEnv.Name,
    7962            0 :                                                s_ipsc->cAlphaFieldNames(5)));
    7963            0 :                         ShowContinueError(state,
    7964            0 :                                           format("{} entered value = \"{}\", no corresponding outdoor air node has been found in the input file.",
    7965            0 :                                                  s_ipsc->cAlphaFieldNames(5),
    7966            0 :                                                  s_ipsc->cAlphaArgs(5)));
    7967            0 :                         ErrorsFound = true;
    7968              :                     } else {
    7969            1 :                         SurfLocalEnv.OutdoorAirNodePtr = NodeNum;
    7970              :                     }
    7971              :                 }
    7972              : 
    7973              :                 // get ground surfaces object number;
    7974           23 :                 if (!s_ipsc->lAlphaFieldBlanks(6)) {
    7975           12 :                     int GndSurfsNum = Util::FindItemInList(s_ipsc->cAlphaArgs(6), state.dataSurface->GroundSurfsProperty);
    7976           12 :                     if (GndSurfsNum == 0) {
    7977            0 :                         ShowSevereError(state,
    7978            0 :                                         format("{} {} = \"{}\", object. Illegal value for \"{}\" has been found.",
    7979              :                                                RoutineName,
    7980            0 :                                                s_ipsc->cCurrentModuleObject,
    7981            0 :                                                SurfLocalEnv.Name,
    7982            0 :                                                s_ipsc->cAlphaFieldNames(6)));
    7983            0 :                         ShowContinueError(
    7984              :                             state,
    7985            0 :                             format("{} entered value = \"{}\", no corresponding ground surfaces object has been found in the input file.",
    7986            0 :                                    s_ipsc->cAlphaFieldNames(6),
    7987            0 :                                    s_ipsc->cAlphaArgs(6)));
    7988            0 :                         ErrorsFound = true;
    7989              :                     } else {
    7990           12 :                         SurfLocalEnv.GroundSurfsPtr = GndSurfsNum;
    7991              :                     }
    7992              :                 }
    7993              :             }
    7994              :         }
    7995              :         // Link surface properties to surface object
    7996         2484 :         for (int SurfLoop = 1; SurfLoop <= state.dataSurface->TotSurfaces; ++SurfLoop) {
    7997         2374 :             for (int Loop = 1; Loop <= state.dataSurface->TotSurfLocalEnv; ++Loop) {
    7998          114 :                 auto const &SurfLocalEnv = state.dataSurface->SurfLocalEnvironment(Loop);
    7999          114 :                 if (SurfLocalEnv.SurfPtr == SurfLoop) {
    8000           23 :                     auto &surface = state.dataSurface->Surface(SurfLoop);
    8001           23 :                     if (SurfLocalEnv.OutdoorAirNodePtr != 0) {
    8002            1 :                         surface.SurfLinkedOutAirNode = SurfLocalEnv.OutdoorAirNodePtr;
    8003              :                     }
    8004           23 :                     if (SurfLocalEnv.sunlitFracSched != nullptr) {
    8005            1 :                         surface.SurfSchedExternalShadingFrac = true;
    8006            1 :                         surface.surfExternalShadingSched = SurfLocalEnv.sunlitFracSched;
    8007              :                     }
    8008           23 :                     if (SurfLocalEnv.SurroundingSurfsPtr != 0) {
    8009           21 :                         surface.SurfHasSurroundingSurfProperty = true;
    8010           21 :                         surface.SurfSurroundingSurfacesNum = SurfLocalEnv.SurroundingSurfsPtr;
    8011           21 :                         surface.ViewFactorSrdSurfs =
    8012           21 :                             state.dataSurface->SurroundingSurfsProperty(surface.SurfSurroundingSurfacesNum).SurfsViewFactorSum;
    8013           21 :                         if (surface.ViewFactorSrdSurfs == 0.0) {
    8014            0 :                             surface.SurfHasSurroundingSurfProperty = false;
    8015              :                         }
    8016              :                     }
    8017           23 :                     if (SurfLocalEnv.GroundSurfsPtr != 0) {
    8018           12 :                         surface.IsSurfPropertyGndSurfacesDefined = true;
    8019           12 :                         surface.UseSurfPropertyGndSurfTemp = true;
    8020           12 :                         surface.UseSurfPropertyGndSurfRefl = true;
    8021           12 :                         surface.SurfPropertyGndSurfIndex = SurfLocalEnv.GroundSurfsPtr;
    8022              :                     }
    8023              :                 }
    8024              :             }
    8025              :         }
    8026          224 :     }
    8027              : 
    8028          224 :     void GetSurfaceSrdSurfsData(EnergyPlusData &state, bool &ErrorsFound) // Error flag indicator (true if errors found)
    8029              :     {
    8030              :         // SUBROUTINE INFORMATION:
    8031              :         //       AUTHOR         X LUO
    8032              :         //       DATE WRITTEN   July 2017
    8033              : 
    8034              :         // PURPOSE OF THIS SUBROUTINE:
    8035              :         // load input data for surrounding surfaces properties for exterior surfaces
    8036          224 :         constexpr std::string_view routineName = "GetSurfaceSrdSurfsData";
    8037              : 
    8038          224 :         auto &s_ipsc = state.dataIPShortCut;
    8039              : 
    8040          224 :         s_ipsc->cCurrentModuleObject = "SurfaceProperty:SurroundingSurfaces";
    8041          224 :         int TotSrdSurfProperties = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
    8042              : 
    8043          224 :         if (TotSrdSurfProperties > 0) {
    8044              :             int NumAlpha;
    8045              :             int NumNumeric;
    8046              :             int IOStat;
    8047              : 
    8048           11 :             if (!allocated(state.dataSurface->SurroundingSurfsProperty)) {
    8049           11 :                 state.dataSurface->SurroundingSurfsProperty.allocate(TotSrdSurfProperties);
    8050              :             }
    8051              : 
    8052           32 :             for (int Loop = 1; Loop <= TotSrdSurfProperties; ++Loop) {
    8053              : 
    8054           21 :                 auto &SrdSurfsProp = state.dataSurface->SurroundingSurfsProperty(Loop);
    8055              : 
    8056           42 :                 state.dataInputProcessing->inputProcessor->getObjectItem(state,
    8057           21 :                                                                          s_ipsc->cCurrentModuleObject,
    8058              :                                                                          Loop,
    8059           21 :                                                                          s_ipsc->cAlphaArgs,
    8060              :                                                                          NumAlpha,
    8061           21 :                                                                          s_ipsc->rNumericArgs,
    8062              :                                                                          NumNumeric,
    8063              :                                                                          IOStat,
    8064           21 :                                                                          s_ipsc->lNumericFieldBlanks,
    8065           21 :                                                                          s_ipsc->lAlphaFieldBlanks,
    8066           21 :                                                                          s_ipsc->cAlphaFieldNames,
    8067           21 :                                                                          s_ipsc->cNumericFieldNames);
    8068              : 
    8069           21 :                 ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
    8070              : 
    8071           21 :                 Util::IsNameEmpty(state, s_ipsc->cAlphaArgs(1), s_ipsc->cCurrentModuleObject, ErrorsFound);
    8072              : 
    8073              :                 // A1: Name
    8074           21 :                 SrdSurfsProp.Name = s_ipsc->cAlphaArgs(1);
    8075              : 
    8076              :                 // N1: sky view factor
    8077           21 :                 if (!s_ipsc->lNumericFieldBlanks(1)) {
    8078           16 :                     SrdSurfsProp.SkyViewFactor = s_ipsc->rNumericArgs(1);
    8079           16 :                     SrdSurfsProp.IsSkyViewFactorSet = true;
    8080              :                 }
    8081              : 
    8082              :                 // A2: sky temp sch name
    8083           21 :                 if (s_ipsc->lAlphaFieldBlanks(2)) {
    8084           15 :                 } else if ((SrdSurfsProp.skyTempSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(2))) == nullptr) {
    8085            5 :                     ShowWarningItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2));
    8086              :                 }
    8087              : 
    8088              :                 // N2: ground view factor
    8089           21 :                 if (!s_ipsc->lNumericFieldBlanks(2)) {
    8090            4 :                     SrdSurfsProp.GroundViewFactor = s_ipsc->rNumericArgs(2);
    8091            4 :                     SrdSurfsProp.IsGroundViewFactorSet = true;
    8092              :                 }
    8093              : 
    8094              :                 // A3: ground temp sch name
    8095           21 :                 if (s_ipsc->lAlphaFieldBlanks(3)) {
    8096            2 :                 } else if ((SrdSurfsProp.groundTempSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(3))) == nullptr) {
    8097            1 :                     ShowWarningItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3));
    8098              :                 }
    8099              : 
    8100              :                 // The object requires at least one srd surface input, each surface requires a set of 3 fields (2 Alpha fields Name and Temp
    8101              :                 // Sch Name and 1 Num fields View Factor)
    8102           21 :                 if (NumAlpha < 5) {
    8103            0 :                     ShowSevereError(state, format("{} = \"{}\" is not defined correctly.", s_ipsc->cCurrentModuleObject, SrdSurfsProp.Name));
    8104            0 :                     ShowContinueError(state, "At lease one set of surrounding surface properties should be defined.");
    8105            0 :                     ErrorsFound = true;
    8106            0 :                     continue;
    8107              :                 }
    8108           21 :                 if ((NumAlpha - 3) / 2 != (NumNumeric - 2)) {
    8109            0 :                     ShowSevereError(state, format("{} = \"{}\" is not defined correctly.", s_ipsc->cCurrentModuleObject, SrdSurfsProp.Name));
    8110            0 :                     ShowContinueError(state, "Check number of input fields for each surrounding surface.");
    8111            0 :                     ErrorsFound = true;
    8112            0 :                     continue;
    8113              :                 }
    8114              :                 // Read surrounding surfaces properties
    8115           21 :                 SrdSurfsProp.TotSurroundingSurface = NumNumeric - 2;
    8116           21 :                 SrdSurfsProp.SurroundingSurfs.allocate(SrdSurfsProp.TotSurroundingSurface);
    8117           54 :                 for (int SurfLoop = 1; SurfLoop <= SrdSurfsProp.TotSurroundingSurface; ++SurfLoop) {
    8118           33 :                     auto &surroundSurf = SrdSurfsProp.SurroundingSurfs(SurfLoop);
    8119           33 :                     surroundSurf.Name = s_ipsc->cAlphaArgs(SurfLoop * 2 + 2);
    8120           33 :                     surroundSurf.ViewFactor = s_ipsc->rNumericArgs(SurfLoop + 2);
    8121              : 
    8122              :                     // Added checking
    8123           33 :                     if (s_ipsc->lAlphaFieldBlanks(SurfLoop * 2 + 3)) {
    8124            0 :                         ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(SurfLoop * 2 + 3));
    8125            0 :                         ErrorsFound = true;
    8126           33 :                     } else if ((surroundSurf.tempSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(SurfLoop * 2 + 3))) == nullptr) {
    8127            0 :                         ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(SurfLoop * 2 + 3), s_ipsc->cAlphaArgs(SurfLoop * 2 + 3));
    8128            0 :                         ErrorsFound = true;
    8129              :                     }
    8130           33 :                     SrdSurfsProp.SurfsViewFactorSum += SrdSurfsProp.SurroundingSurfs(SurfLoop).ViewFactor;
    8131              :                 }
    8132              :             }
    8133              :         }
    8134          224 :     }
    8135              : 
    8136          224 :     void GetSurfaceGroundSurfsData(EnergyPlusData &state, bool &ErrorsFound)
    8137              :     {
    8138              :         static constexpr std::string_view routineName = "GetSurfaceGroundSurfsData";
    8139              : 
    8140          224 :         auto &s_ipsc = state.dataIPShortCut;
    8141          224 :         s_ipsc->cCurrentModuleObject = "SurfaceProperty:GroundSurfaces";
    8142          224 :         state.dataSurface->TotSurfPropGndSurfs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
    8143          224 :         auto const instances = state.dataInputProcessing->inputProcessor->epJSON.find(s_ipsc->cCurrentModuleObject);
    8144          224 :         if (instances == state.dataInputProcessing->inputProcessor->epJSON.end()) {
    8145          218 :             if (state.dataSurface->TotSurfPropGndSurfs > 0) {
    8146            0 :                 ErrorsFound = true;
    8147              :             }
    8148          218 :             return;
    8149              :         }
    8150              : 
    8151            6 :         auto &instancesValue = instances.value();
    8152           18 :         for (auto instance = instancesValue.begin(); instance != instancesValue.end(); ++instance) {
    8153           12 :             auto const &fields = instance.value();
    8154           12 :             std::string const &thisObjectName = instance.key();
    8155              : 
    8156           12 :             ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, thisObjectName};
    8157              : 
    8158           12 :             DataSurfaces::GroundSurfacesProperty thisGndSurfsObj;
    8159           12 :             thisGndSurfsObj.Name = Util::makeUPPER(thisObjectName);
    8160           12 :             state.dataInputProcessing->inputProcessor->markObjectAsUsed(s_ipsc->cCurrentModuleObject, thisObjectName);
    8161           12 :             auto groundSurfaces = fields.find("ground_surfaces");
    8162           12 :             if (groundSurfaces != fields.end()) {
    8163           12 :                 auto &groundSurfacesArray = groundSurfaces.value();
    8164           12 :                 thisGndSurfsObj.NumGndSurfs = groundSurfacesArray.size();
    8165           32 :                 for (auto &groundSurface : groundSurfacesArray) {
    8166           20 :                     DataSurfaces::GroundSurfacesData thisGndSurf;
    8167           20 :                     auto GndSurfName = groundSurface.find("ground_surface_name");
    8168           20 :                     if (GndSurfName != groundSurface.end()) {
    8169           20 :                         std::string ground_surf_name = GndSurfName.value().get<std::string>();
    8170           20 :                         if (!ground_surf_name.empty()) {
    8171           20 :                             thisGndSurf.Name = Util::makeUPPER(ground_surf_name);
    8172              :                         }
    8173           20 :                     }
    8174           20 :                     auto groundSurfViewFactor = groundSurface.find("ground_surface_view_factor");
    8175           20 :                     if (groundSurfViewFactor != groundSurface.end()) {
    8176           15 :                         thisGndSurf.ViewFactor = groundSurfViewFactor.value().get<Real64>();
    8177           15 :                         thisGndSurfsObj.IsGroundViewFactorSet = true;
    8178              :                     }
    8179           20 :                     auto TempSchName = groundSurface.find("ground_surface_temperature_schedule_name");
    8180           20 :                     if (TempSchName != groundSurface.end()) {
    8181           20 :                         std::string schedName = TempSchName.value().get<std::string>();
    8182           20 :                         if (schedName.empty()) {
    8183           20 :                         } else if ((thisGndSurf.tempSched = Sched::GetSchedule(state, Util::makeUPPER(schedName))) == nullptr) {
    8184            0 :                             ShowSevereItemNotFound(state, eoh, "Ground Surface Temperature Schedule Name", schedName);
    8185            0 :                             ErrorsFound = true;
    8186              :                         }
    8187           20 :                     }
    8188              : 
    8189           20 :                     auto ReflSchName = groundSurface.find("ground_surface_reflectance_schedule_name");
    8190           20 :                     if (ReflSchName != groundSurface.end()) {
    8191            3 :                         std::string schedName = ReflSchName.value().get<std::string>();
    8192            3 :                         if (schedName.empty()) {
    8193            3 :                         } else if ((thisGndSurf.reflSched = Sched::GetSchedule(state, Util::makeUPPER(schedName))) == nullptr) {
    8194            0 :                             ShowSevereItemNotFound(state, eoh, "Ground Surface Reflectance Schedule Name", schedName);
    8195            0 :                             ErrorsFound = true;
    8196              :                         }
    8197            3 :                     }
    8198           20 :                     thisGndSurfsObj.GndSurfs.push_back(thisGndSurf);
    8199           32 :                 }
    8200              :             }
    8201           32 :             for (int gSurfNum = 1; gSurfNum <= thisGndSurfsObj.NumGndSurfs; gSurfNum++) {
    8202           20 :                 thisGndSurfsObj.SurfsViewFactorSum += thisGndSurfsObj.GndSurfs(gSurfNum).ViewFactor;
    8203              :             }
    8204           12 :             state.dataSurface->GroundSurfsProperty.push_back(thisGndSurfsObj);
    8205           18 :         } // for (instance)
    8206              : 
    8207              :         // set report variables
    8208            6 :         if (state.dataSurface->TotSurfPropGndSurfs > 0) {
    8209           18 :             for (int Loop = 1; Loop <= state.dataSurface->TotSurfPropGndSurfs; Loop++) {
    8210           12 :                 bool SetTempSchReportVar = true;
    8211           12 :                 bool SetReflSchReportVar = true;
    8212           12 :                 auto &thisGndSurfsObj = state.dataSurface->GroundSurfsProperty(Loop);
    8213           32 :                 for (int gSurfNum = 1; gSurfNum <= thisGndSurfsObj.NumGndSurfs; gSurfNum++) {
    8214           20 :                     if (thisGndSurfsObj.GndSurfs(gSurfNum).tempSched != nullptr && SetTempSchReportVar) {
    8215           24 :                         SetupOutputVariable(state,
    8216              :                                             "Surfaces Property Ground Surfaces Average Temperature",
    8217              :                                             Constant::Units::C,
    8218           12 :                                             thisGndSurfsObj.SurfsTempAvg,
    8219              :                                             OutputProcessor::TimeStepType::Zone,
    8220              :                                             OutputProcessor::StoreType::Average,
    8221           12 :                                             thisGndSurfsObj.Name);
    8222           12 :                         SetTempSchReportVar = false;
    8223              :                     }
    8224           20 :                     if (thisGndSurfsObj.GndSurfs(gSurfNum).reflSched != nullptr && SetReflSchReportVar) {
    8225            2 :                         SetupOutputVariable(state,
    8226              :                                             "Surfaces Property Ground Surfaces Average Reflectance",
    8227              :                                             Constant::Units::None,
    8228            1 :                                             thisGndSurfsObj.SurfsReflAvg,
    8229              :                                             OutputProcessor::TimeStepType::Zone,
    8230              :                                             OutputProcessor::StoreType::Average,
    8231            1 :                                             thisGndSurfsObj.Name);
    8232            1 :                         SetReflSchReportVar = false;
    8233              :                     }
    8234              :                 }
    8235              :             }
    8236              :         }
    8237          224 :     }
    8238              : 
    8239          224 :     void GetSurfaceHeatTransferAlgorithmOverrides(EnergyPlusData &state, bool &ErrorsFound)
    8240              :     {
    8241              : 
    8242              :         // SUBROUTINE INFORMATION:
    8243              :         //       AUTHOR         B. Griffith, portions from ApplyConvectionValue by Linda Lawrie
    8244              :         //       DATE WRITTEN   July 2012
    8245              :         static constexpr std::string_view routineName = "GetSurfaceHeatTransferAlgorithmOverrides";
    8246              : 
    8247              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    8248              :         int CountHTAlgoObjectsSingleSurf;
    8249              :         int CountHTAlgoObjectsMultiSurf;
    8250              :         int CountHTAlgoObjectsSurfList;
    8251              :         int IOStatus; // Used in GetObjectItem
    8252              :         DataSurfaces::HeatTransferModel tmpAlgoInput;
    8253              :         int Item;
    8254              :         int Item1;
    8255              :         int NumAlphas;
    8256              :         int NumNumbers;
    8257              :         int Found;
    8258              :         bool SurfacesOfType;
    8259              :         int SurfNum;
    8260              :         //  INTEGER :: Index
    8261              :         int NumEMPDMat;
    8262              :         int NumPCMat;
    8263              :         int NumVTCMat;
    8264              :         int NumHAMTMat1;
    8265              :         int NumHAMTMat2;
    8266              :         int NumHAMTMat3;
    8267              :         int NumHAMTMat4;
    8268              :         int NumHAMTMat5;
    8269              :         int NumHAMTMat6;
    8270              :         int SumHAMTMat;
    8271              :         bool msgneeded;
    8272              : 
    8273          224 :         auto &s_ipsc = state.dataIPShortCut;
    8274          224 :         s_ipsc->cCurrentModuleObject = "SurfaceProperty:HeatBalanceSourceTerm";
    8275          224 :         int CountAddHeatSourceSurf = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
    8276              : 
    8277          226 :         for (Item = 1; Item <= CountAddHeatSourceSurf; ++Item) {
    8278            4 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    8279            2 :                                                                      s_ipsc->cCurrentModuleObject,
    8280              :                                                                      Item,
    8281            2 :                                                                      s_ipsc->cAlphaArgs,
    8282              :                                                                      NumAlphas,
    8283            2 :                                                                      s_ipsc->rNumericArgs,
    8284              :                                                                      NumNumbers,
    8285              :                                                                      IOStatus,
    8286            2 :                                                                      s_ipsc->lNumericFieldBlanks,
    8287            2 :                                                                      s_ipsc->lAlphaFieldBlanks,
    8288            2 :                                                                      s_ipsc->cAlphaFieldNames,
    8289            2 :                                                                      s_ipsc->cNumericFieldNames);
    8290              : 
    8291            2 :             ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
    8292            2 :             Found = Util::FindItemInList(s_ipsc->cAlphaArgs(1), state.dataSurface->Surface, state.dataSurface->TotSurfaces);
    8293              : 
    8294            2 :             if (Found == 0) {
    8295            0 :                 ShowSevereError(state, format("{}=\"{}\", did not find matching surface.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
    8296            0 :                 ErrorsFound = true;
    8297            4 :             } else if (state.dataSurface->Surface(Found).insideHeatSourceTermSched != nullptr ||
    8298            2 :                        state.dataSurface->Surface(Found).outsideHeatSourceTermSched != nullptr) {
    8299            0 :                 ShowSevereError(state,
    8300            0 :                                 format("{}=\"{}\", multiple SurfaceProperty:HeatBalanceSourceTerm objects applied to the same surface.",
    8301            0 :                                        s_ipsc->cCurrentModuleObject,
    8302            0 :                                        s_ipsc->cAlphaArgs(1)));
    8303            0 :                 ErrorsFound = true;
    8304              :             }
    8305              : 
    8306            2 :             if (s_ipsc->lAlphaFieldBlanks(2)) {
    8307            1 :             } else if ((state.dataSurface->Surface(Found).insideHeatSourceTermSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(2))) == nullptr) {
    8308            0 :                 ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2));
    8309            0 :                 ErrorsFound = true;
    8310              :             } else {
    8311            1 :                 state.dataSurface->allInsideSourceSurfaceList.emplace_back(Found);
    8312              :             }
    8313              : 
    8314            2 :             if (s_ipsc->lAlphaFieldBlanks(3)) {
    8315            1 :             } else if ((state.dataSurface->Surface(Found).outsideHeatSourceTermSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(3))) == nullptr) {
    8316            0 :                 ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3));
    8317            0 :                 ErrorsFound = true;
    8318            1 :             } else if (state.dataSurface->Surface(Found).OSCPtr > 0) {
    8319            0 :                 ShowSevereError(state,
    8320            0 :                                 format("{}=\"SurfaceProperty:HeatBalanceSourceTerm\", cannot be specified for OtherSideCoefficient Surface={}",
    8321            0 :                                        s_ipsc->cCurrentModuleObject,
    8322            0 :                                        s_ipsc->cAlphaArgs(1)));
    8323            0 :                 ErrorsFound = true;
    8324              :             } else {
    8325            1 :                 state.dataSurface->allOutsideSourceSurfaceList.emplace_back(Found);
    8326              :             }
    8327              : 
    8328            3 :             if (state.dataSurface->Surface(Found).outsideHeatSourceTermSched == nullptr &&
    8329            1 :                 state.dataSurface->Surface(Found).insideHeatSourceTermSched == nullptr) {
    8330            0 :                 ShowSevereError(
    8331            0 :                     state, format("{}=\"{}\", no schedule defined for additional heat source.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
    8332            0 :                 ErrorsFound = true;
    8333              :             }
    8334              :         }
    8335              : 
    8336              :         // first initialize each heat transfer surface with the overall model type, array assignment
    8337         2484 :         for (auto &e : state.dataSurface->Surface) {
    8338         2260 :             e.HeatTransferAlgorithm = state.dataHeatBal->OverallHeatTransferSolutionAlgo;
    8339          224 :         }
    8340              : 
    8341          224 :         s_ipsc->cCurrentModuleObject = "SurfaceProperty:HeatTransferAlgorithm";
    8342          224 :         CountHTAlgoObjectsSingleSurf = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
    8343              : 
    8344          224 :         s_ipsc->cCurrentModuleObject = "SurfaceProperty:HeatTransferAlgorithm";
    8345          226 :         for (Item = 1; Item <= CountHTAlgoObjectsSingleSurf; ++Item) {
    8346            4 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    8347            2 :                                                                      s_ipsc->cCurrentModuleObject,
    8348              :                                                                      Item,
    8349            2 :                                                                      s_ipsc->cAlphaArgs,
    8350              :                                                                      NumAlphas,
    8351            2 :                                                                      s_ipsc->rNumericArgs,
    8352              :                                                                      NumNumbers,
    8353              :                                                                      IOStatus,
    8354            2 :                                                                      s_ipsc->lNumericFieldBlanks,
    8355            2 :                                                                      s_ipsc->lAlphaFieldBlanks,
    8356            2 :                                                                      s_ipsc->cAlphaFieldNames,
    8357            2 :                                                                      s_ipsc->cNumericFieldNames);
    8358            2 :             bool ErrorsFoundSingleSurf = false;
    8359            2 :             Found = Util::FindItemInList(s_ipsc->cAlphaArgs(1), state.dataSurface->Surface, state.dataSurface->TotSurfaces);
    8360              : 
    8361            2 :             if (Found == 0) {
    8362            0 :                 ShowSevereError(state, format("{}=\"{}\", did not find matching surface.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
    8363            0 :                 ErrorsFoundSingleSurf = true;
    8364              :             }
    8365              : 
    8366              :             {
    8367            2 :                 std::string const &SELECT_CASE_var = s_ipsc->cAlphaArgs(2);
    8368              : 
    8369            2 :                 if (SELECT_CASE_var == "CONDUCTIONTRANSFERFUNCTION") {
    8370            1 :                     tmpAlgoInput = DataSurfaces::HeatTransferModel::CTF;
    8371            1 :                     state.dataHeatBal->AnyCTF = true;
    8372            1 :                 } else if (SELECT_CASE_var == "MOISTUREPENETRATIONDEPTHCONDUCTIONTRANSFERFUNCTION") {
    8373            0 :                     tmpAlgoInput = DataSurfaces::HeatTransferModel::EMPD;
    8374            0 :                     state.dataHeatBal->AnyEMPD = true;
    8375            1 :                 } else if (SELECT_CASE_var == "COMBINEDHEATANDMOISTUREFINITEELEMENT") {
    8376            1 :                     tmpAlgoInput = DataSurfaces::HeatTransferModel::HAMT;
    8377            1 :                     state.dataHeatBal->AnyHAMT = true;
    8378            0 :                 } else if (SELECT_CASE_var == "CONDUCTIONFINITEDIFFERENCE") {
    8379            0 :                     tmpAlgoInput = DataSurfaces::HeatTransferModel::CondFD;
    8380            0 :                     state.dataHeatBal->AnyCondFD = true;
    8381              :                 } else {
    8382            0 :                     ShowSevereError(state,
    8383            0 :                                     format("{}=\"{}\", invalid {}=\"{}",
    8384            0 :                                            s_ipsc->cCurrentModuleObject,
    8385            0 :                                            s_ipsc->cAlphaArgs(1),
    8386            0 :                                            s_ipsc->cAlphaFieldNames(2),
    8387            0 :                                            s_ipsc->cAlphaArgs(2)));
    8388            0 :                     ErrorsFoundSingleSurf = true;
    8389              :                 }
    8390              :             }
    8391              : 
    8392            2 :             if (!ErrorsFoundSingleSurf) {
    8393            2 :                 state.dataSurface->Surface(Found).HeatTransferAlgorithm = tmpAlgoInput;
    8394              :             } else {
    8395            0 :                 ErrorsFound = true;
    8396              :             }
    8397              :         } // single surface heat transfer algorithm override
    8398              : 
    8399          224 :         s_ipsc->cCurrentModuleObject = "SurfaceProperty:HeatTransferAlgorithm:MultipleSurface";
    8400          224 :         CountHTAlgoObjectsMultiSurf = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
    8401              : 
    8402          224 :         for (Item = 1; Item <= CountHTAlgoObjectsMultiSurf; ++Item) {
    8403            0 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    8404            0 :                                                                      s_ipsc->cCurrentModuleObject,
    8405              :                                                                      Item,
    8406            0 :                                                                      s_ipsc->cAlphaArgs,
    8407              :                                                                      NumAlphas,
    8408            0 :                                                                      s_ipsc->rNumericArgs,
    8409              :                                                                      NumNumbers,
    8410              :                                                                      IOStatus,
    8411            0 :                                                                      s_ipsc->lNumericFieldBlanks,
    8412            0 :                                                                      s_ipsc->lAlphaFieldBlanks,
    8413            0 :                                                                      s_ipsc->cAlphaFieldNames,
    8414            0 :                                                                      s_ipsc->cNumericFieldNames);
    8415            0 :             bool ErrorsFoundMultiSurf = false;
    8416              :             {
    8417            0 :                 std::string const &SELECT_CASE_var = s_ipsc->cAlphaArgs(3);
    8418              : 
    8419            0 :                 if (SELECT_CASE_var == "CONDUCTIONTRANSFERFUNCTION") {
    8420            0 :                     tmpAlgoInput = DataSurfaces::HeatTransferModel::CTF;
    8421            0 :                     state.dataHeatBal->AnyCTF = true;
    8422            0 :                 } else if (SELECT_CASE_var == "MOISTUREPENETRATIONDEPTHCONDUCTIONTRANSFERFUNCTION") {
    8423            0 :                     tmpAlgoInput = DataSurfaces::HeatTransferModel::EMPD;
    8424            0 :                     state.dataHeatBal->AnyEMPD = true;
    8425            0 :                 } else if (SELECT_CASE_var == "COMBINEDHEATANDMOISTUREFINITEELEMENT") {
    8426            0 :                     tmpAlgoInput = DataSurfaces::HeatTransferModel::HAMT;
    8427            0 :                     state.dataHeatBal->AnyHAMT = true;
    8428            0 :                 } else if (SELECT_CASE_var == "CONDUCTIONFINITEDIFFERENCE") {
    8429            0 :                     tmpAlgoInput = DataSurfaces::HeatTransferModel::CondFD;
    8430            0 :                     state.dataHeatBal->AnyCondFD = true;
    8431              :                 } else {
    8432            0 :                     ShowSevereError(state,
    8433            0 :                                     format("{}=\"{}\", invalid {}=\"{}",
    8434            0 :                                            s_ipsc->cCurrentModuleObject,
    8435            0 :                                            s_ipsc->cAlphaArgs(1),
    8436            0 :                                            s_ipsc->cAlphaFieldNames(3),
    8437            0 :                                            s_ipsc->cAlphaArgs(3)));
    8438            0 :                     ErrorsFoundMultiSurf = true;
    8439              :                 }
    8440              :             }
    8441              : 
    8442              :             {
    8443            0 :                 std::string const &SELECT_CASE_var = s_ipsc->cAlphaArgs(2);
    8444              : 
    8445            0 :                 if (SELECT_CASE_var == "ALLEXTERIORSURFACES") {
    8446            0 :                     SurfacesOfType = false;
    8447            0 :                     for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    8448            0 :                         auto &surf = state.dataSurface->Surface(SurfNum);
    8449            0 :                         if (!surf.HeatTransSurf) {
    8450            0 :                             continue;
    8451              :                         }
    8452            0 :                         if (surf.ExtBoundCond > 0) {
    8453            0 :                             continue; // Interior surfaces
    8454              :                         }
    8455            0 :                         if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) {
    8456            0 :                             continue;
    8457              :                         }
    8458            0 :                         SurfacesOfType = true;
    8459            0 :                         surf.HeatTransferAlgorithm = tmpAlgoInput;
    8460              :                     }
    8461              : 
    8462            0 :                 } else if (SELECT_CASE_var == "ALLEXTERIORWALLS") {
    8463            0 :                     SurfacesOfType = false;
    8464            0 :                     for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    8465            0 :                         auto &surf = state.dataSurface->Surface(SurfNum);
    8466            0 :                         if (!surf.HeatTransSurf) {
    8467            0 :                             continue;
    8468              :                         }
    8469            0 :                         if (surf.ExtBoundCond > 0) {
    8470            0 :                             continue; // Interior surfaces
    8471              :                         }
    8472              : 
    8473            0 :                         if (surf.Class != SurfaceClass::Wall) {
    8474            0 :                             continue;
    8475              :                         }
    8476            0 :                         if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) {
    8477            0 :                             continue;
    8478              :                         }
    8479            0 :                         SurfacesOfType = true;
    8480            0 :                         surf.HeatTransferAlgorithm = tmpAlgoInput;
    8481              :                     }
    8482              : 
    8483            0 :                 } else if (SELECT_CASE_var == "ALLEXTERIORROOFS") {
    8484            0 :                     SurfacesOfType = false;
    8485            0 :                     for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    8486            0 :                         auto &surf = state.dataSurface->Surface(SurfNum);
    8487            0 :                         if (!surf.HeatTransSurf) {
    8488            0 :                             continue;
    8489              :                         }
    8490            0 :                         if (surf.ExtBoundCond > 0) {
    8491            0 :                             continue; // Interior surfaces
    8492              :                         }
    8493            0 :                         if (surf.Class != SurfaceClass::Roof) {
    8494            0 :                             continue;
    8495              :                         }
    8496            0 :                         if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) {
    8497            0 :                             continue;
    8498              :                         }
    8499            0 :                         SurfacesOfType = true;
    8500            0 :                         surf.HeatTransferAlgorithm = tmpAlgoInput;
    8501              :                     }
    8502              : 
    8503            0 :                 } else if (SELECT_CASE_var == "ALLEXTERIORFLOORS") {
    8504            0 :                     SurfacesOfType = false;
    8505            0 :                     for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    8506            0 :                         auto &surf = state.dataSurface->Surface(SurfNum);
    8507            0 :                         if (!surf.HeatTransSurf) {
    8508            0 :                             continue;
    8509              :                         }
    8510            0 :                         if (surf.ExtBoundCond > 0) {
    8511            0 :                             continue; // Interior surfaces
    8512              :                         }
    8513            0 :                         if (surf.Class != SurfaceClass::Floor) {
    8514            0 :                             continue;
    8515              :                         }
    8516            0 :                         if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) {
    8517            0 :                             continue;
    8518              :                         }
    8519            0 :                         SurfacesOfType = true;
    8520            0 :                         surf.HeatTransferAlgorithm = tmpAlgoInput;
    8521              :                     }
    8522              : 
    8523            0 :                 } else if (SELECT_CASE_var == "ALLGROUNDCONTACTSURFACES") {
    8524            0 :                     SurfacesOfType = false;
    8525            0 :                     for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    8526            0 :                         auto &surf = state.dataSurface->Surface(SurfNum);
    8527            0 :                         if (!surf.HeatTransSurf) {
    8528            0 :                             continue;
    8529              :                         }
    8530            0 :                         if (surf.ExtBoundCond != DataSurfaces::Ground) {
    8531            0 :                             continue; // ground BC
    8532              :                         }
    8533            0 :                         if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) {
    8534            0 :                             continue;
    8535              :                         }
    8536            0 :                         SurfacesOfType = true;
    8537            0 :                         surf.HeatTransferAlgorithm = tmpAlgoInput;
    8538              :                     }
    8539            0 :                 } else if (SELECT_CASE_var == "ALLINTERIORSURFACES") {
    8540            0 :                     SurfacesOfType = false;
    8541            0 :                     for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    8542            0 :                         auto &surf = state.dataSurface->Surface(SurfNum);
    8543            0 :                         if (!surf.HeatTransSurf) {
    8544            0 :                             continue;
    8545              :                         }
    8546            0 :                         if (surf.ExtBoundCond <= 0) {
    8547            0 :                             continue; // Exterior surfaces
    8548              :                         }
    8549            0 :                         if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) {
    8550            0 :                             continue;
    8551              :                         }
    8552            0 :                         SurfacesOfType = true;
    8553            0 :                         surf.HeatTransferAlgorithm = tmpAlgoInput;
    8554              :                     }
    8555              : 
    8556            0 :                 } else if (SELECT_CASE_var == "ALLINTERIORWALLS") {
    8557            0 :                     SurfacesOfType = false;
    8558            0 :                     for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    8559            0 :                         auto &surf = state.dataSurface->Surface(SurfNum);
    8560            0 :                         if (!surf.HeatTransSurf) {
    8561            0 :                             continue;
    8562              :                         }
    8563            0 :                         if (surf.ExtBoundCond <= 0) {
    8564            0 :                             continue; // Exterior surfaces
    8565              :                         }
    8566            0 :                         if (surf.Class != SurfaceClass::Wall) {
    8567            0 :                             continue;
    8568              :                         }
    8569            0 :                         if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) {
    8570            0 :                             continue;
    8571              :                         }
    8572            0 :                         SurfacesOfType = true;
    8573            0 :                         surf.HeatTransferAlgorithm = tmpAlgoInput;
    8574              :                     }
    8575              : 
    8576            0 :                 } else if ((SELECT_CASE_var == "ALLINTERIORROOFS") || (SELECT_CASE_var == "ALLINTERIORCEILINGS")) {
    8577            0 :                     SurfacesOfType = false;
    8578            0 :                     for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    8579            0 :                         auto &surf = state.dataSurface->Surface(SurfNum);
    8580            0 :                         if (!surf.HeatTransSurf) {
    8581            0 :                             continue;
    8582              :                         }
    8583            0 :                         if (surf.ExtBoundCond <= 0) {
    8584            0 :                             continue; // Exterior surfaces
    8585              :                         }
    8586            0 :                         if (surf.Class != SurfaceClass::Roof) {
    8587            0 :                             continue;
    8588              :                         }
    8589            0 :                         if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) {
    8590            0 :                             continue;
    8591              :                         }
    8592            0 :                         SurfacesOfType = true;
    8593            0 :                         surf.HeatTransferAlgorithm = tmpAlgoInput;
    8594              :                     }
    8595              : 
    8596            0 :                 } else if (SELECT_CASE_var == "ALLINTERIORFLOORS") {
    8597            0 :                     SurfacesOfType = false;
    8598            0 :                     for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    8599            0 :                         auto &surf = state.dataSurface->Surface(SurfNum);
    8600            0 :                         if (!surf.HeatTransSurf) {
    8601            0 :                             continue;
    8602              :                         }
    8603            0 :                         if (surf.ExtBoundCond <= 0) {
    8604            0 :                             continue; // Exterior surfaces
    8605              :                         }
    8606            0 :                         if (surf.Class != SurfaceClass::Floor) {
    8607            0 :                             continue;
    8608              :                         }
    8609            0 :                         if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) {
    8610            0 :                             continue;
    8611              :                         }
    8612            0 :                         SurfacesOfType = true;
    8613            0 :                         surf.HeatTransferAlgorithm = tmpAlgoInput;
    8614              :                     }
    8615              :                 } else {
    8616            0 :                     SurfacesOfType = false;
    8617            0 :                     ShowSevereError(state,
    8618            0 :                                     format("{}=\"{}\", invalid {}=\"{}",
    8619            0 :                                            s_ipsc->cCurrentModuleObject,
    8620            0 :                                            s_ipsc->cAlphaArgs(1),
    8621            0 :                                            s_ipsc->cAlphaFieldNames(2),
    8622            0 :                                            s_ipsc->cAlphaArgs(2)));
    8623            0 :                     ErrorsFoundMultiSurf = true;
    8624              :                 }
    8625              :             }
    8626              : 
    8627            0 :             if (!SurfacesOfType) {
    8628            0 :                 ShowWarningError(
    8629              :                     state,
    8630            0 :                     format("In {}=\"{}\", for Multiple Surface Assignment=\"{}\", there were no surfaces of that type found for assignment.",
    8631            0 :                            s_ipsc->cCurrentModuleObject,
    8632            0 :                            s_ipsc->cAlphaArgs(1),
    8633            0 :                            s_ipsc->cAlphaArgs(2)));
    8634              :             }
    8635            0 :             if (ErrorsFoundMultiSurf) {
    8636            0 :                 ErrorsFound = true;
    8637              :             }
    8638              : 
    8639              :         } // multi surface heat transfer algo override
    8640              : 
    8641          224 :         s_ipsc->cCurrentModuleObject = "SurfaceProperty:HeatTransferAlgorithm:SurfaceList";
    8642          224 :         CountHTAlgoObjectsSurfList = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
    8643          224 :         for (Item = 1; Item <= CountHTAlgoObjectsSurfList; ++Item) {
    8644            0 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    8645            0 :                                                                      s_ipsc->cCurrentModuleObject,
    8646              :                                                                      Item,
    8647            0 :                                                                      s_ipsc->cAlphaArgs,
    8648              :                                                                      NumAlphas,
    8649            0 :                                                                      s_ipsc->rNumericArgs,
    8650              :                                                                      NumNumbers,
    8651              :                                                                      IOStatus,
    8652            0 :                                                                      s_ipsc->lNumericFieldBlanks,
    8653            0 :                                                                      s_ipsc->lAlphaFieldBlanks,
    8654            0 :                                                                      s_ipsc->cAlphaFieldNames,
    8655            0 :                                                                      s_ipsc->cNumericFieldNames);
    8656            0 :             bool ErrorsFoundSurfList = false;
    8657              :             {
    8658            0 :                 std::string const &SELECT_CASE_var = s_ipsc->cAlphaArgs(2);
    8659              : 
    8660            0 :                 if (SELECT_CASE_var == "CONDUCTIONTRANSFERFUNCTION") {
    8661            0 :                     tmpAlgoInput = DataSurfaces::HeatTransferModel::CTF;
    8662            0 :                     state.dataHeatBal->AnyCTF = true;
    8663            0 :                 } else if (SELECT_CASE_var == "MOISTUREPENETRATIONDEPTHCONDUCTIONTRANSFERFUNCTION") {
    8664            0 :                     tmpAlgoInput = DataSurfaces::HeatTransferModel::EMPD;
    8665            0 :                     state.dataHeatBal->AnyEMPD = true;
    8666            0 :                 } else if (SELECT_CASE_var == "COMBINEDHEATANDMOISTUREFINITEELEMENT") {
    8667            0 :                     tmpAlgoInput = DataSurfaces::HeatTransferModel::HAMT;
    8668            0 :                     state.dataHeatBal->AnyHAMT = true;
    8669            0 :                 } else if (SELECT_CASE_var == "CONDUCTIONFINITEDIFFERENCE") {
    8670            0 :                     tmpAlgoInput = DataSurfaces::HeatTransferModel::CondFD;
    8671            0 :                     state.dataHeatBal->AnyCondFD = true;
    8672              :                 } else {
    8673            0 :                     ShowSevereError(state,
    8674            0 :                                     format("{}=\"{}\", invalid {}=\"{}",
    8675            0 :                                            s_ipsc->cCurrentModuleObject,
    8676            0 :                                            s_ipsc->cAlphaArgs(1),
    8677            0 :                                            s_ipsc->cAlphaFieldNames(2),
    8678            0 :                                            s_ipsc->cAlphaArgs(2)));
    8679            0 :                     ErrorsFoundSurfList = true;
    8680              :                 }
    8681              :             }
    8682              : 
    8683            0 :             for (Item1 = 3; Item1 <= NumAlphas; ++Item1) {
    8684              : 
    8685            0 :                 Found = Util::FindItemInList(s_ipsc->cAlphaArgs(Item1), state.dataSurface->Surface, state.dataSurface->TotSurfaces);
    8686              : 
    8687            0 :                 if (Found == 0) {
    8688            0 :                     ShowSevereError(state, format("{}=\"{}\", did not find matching surface.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
    8689            0 :                     ShowContinueError(state, format("Name of surface not found = \"{}\"", s_ipsc->cAlphaArgs(Item1)));
    8690            0 :                     ErrorsFoundSurfList = true;
    8691              :                 }
    8692              : 
    8693            0 :                 if (!ErrorsFoundSurfList) {
    8694            0 :                     state.dataSurface->Surface(Found).HeatTransferAlgorithm = tmpAlgoInput;
    8695              :                 } else {
    8696            0 :                     ErrorsFound = true;
    8697              :                 }
    8698              :             }
    8699              :         }
    8700              : 
    8701          224 :         s_ipsc->cCurrentModuleObject = "SurfaceProperty:HeatTransferAlgorithm:Construction";
    8702          224 :         CountHTAlgoObjectsSurfList = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
    8703          225 :         for (Item = 1; Item <= CountHTAlgoObjectsSurfList; ++Item) {
    8704            2 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    8705            1 :                                                                      s_ipsc->cCurrentModuleObject,
    8706              :                                                                      Item,
    8707            1 :                                                                      s_ipsc->cAlphaArgs,
    8708              :                                                                      NumAlphas,
    8709            1 :                                                                      s_ipsc->rNumericArgs,
    8710              :                                                                      NumNumbers,
    8711              :                                                                      IOStatus,
    8712            1 :                                                                      s_ipsc->lNumericFieldBlanks,
    8713            1 :                                                                      s_ipsc->lAlphaFieldBlanks,
    8714            1 :                                                                      s_ipsc->cAlphaFieldNames,
    8715            1 :                                                                      s_ipsc->cNumericFieldNames);
    8716            1 :             bool ErrorsFoundByConstruct = false;
    8717              :             {
    8718            1 :                 std::string const &SELECT_CASE_var = s_ipsc->cAlphaArgs(2);
    8719              : 
    8720            1 :                 if (SELECT_CASE_var == "CONDUCTIONTRANSFERFUNCTION") {
    8721            0 :                     tmpAlgoInput = DataSurfaces::HeatTransferModel::CTF;
    8722            0 :                     state.dataHeatBal->AnyCTF = true;
    8723            1 :                 } else if (SELECT_CASE_var == "MOISTUREPENETRATIONDEPTHCONDUCTIONTRANSFERFUNCTION") {
    8724            0 :                     tmpAlgoInput = DataSurfaces::HeatTransferModel::EMPD;
    8725            0 :                     state.dataHeatBal->AnyEMPD = true;
    8726            1 :                 } else if (SELECT_CASE_var == "COMBINEDHEATANDMOISTUREFINITEELEMENT") {
    8727            0 :                     tmpAlgoInput = DataSurfaces::HeatTransferModel::HAMT;
    8728            0 :                     state.dataHeatBal->AnyHAMT = true;
    8729            1 :                 } else if (SELECT_CASE_var == "CONDUCTIONFINITEDIFFERENCE") {
    8730            1 :                     tmpAlgoInput = DataSurfaces::HeatTransferModel::CondFD;
    8731            1 :                     state.dataHeatBal->AnyCondFD = true;
    8732              :                 } else {
    8733            0 :                     ShowSevereError(state,
    8734            0 :                                     format("{}=\"{}\", invalid {}=\"{}",
    8735            0 :                                            s_ipsc->cCurrentModuleObject,
    8736            0 :                                            s_ipsc->cAlphaArgs(1),
    8737            0 :                                            s_ipsc->cAlphaFieldNames(2),
    8738            0 :                                            s_ipsc->cAlphaArgs(2)));
    8739            0 :                     ErrorsFoundByConstruct = true;
    8740              :                 }
    8741              :             }
    8742              : 
    8743            1 :             Found = Util::FindItemInList(s_ipsc->cAlphaArgs(3), state.dataConstruction->Construct, state.dataHeatBal->TotConstructs);
    8744            1 :             if (Found == 0) {
    8745            0 :                 ShowSevereError(state,
    8746            0 :                                 format("{}=\"{}\", invalid {}=\"{}",
    8747            0 :                                        s_ipsc->cCurrentModuleObject,
    8748            0 :                                        s_ipsc->cAlphaArgs(1),
    8749            0 :                                        s_ipsc->cAlphaFieldNames(3),
    8750            0 :                                        s_ipsc->cAlphaArgs(3)));
    8751            0 :                 ErrorsFoundByConstruct = true;
    8752              :             }
    8753              : 
    8754            1 :             if (!ErrorsFoundByConstruct) {
    8755            5 :                 for (Item1 = 1; Item1 <= state.dataSurface->TotSurfaces; ++Item1) {
    8756            4 :                     if (state.dataSurface->Surface(Item1).Construction == Found) {
    8757            1 :                         state.dataSurface->Surface(Item1).HeatTransferAlgorithm = tmpAlgoInput;
    8758              :                     }
    8759              :                 }
    8760              :             }
    8761              :         }
    8762              : 
    8763              :         // Change algorithm for Kiva and air boundary foundation surfaces
    8764         2484 :         for (auto &surf : state.dataSurface->Surface) {
    8765         2260 :             if (surf.ExtBoundCond == DataSurfaces::KivaFoundation) {
    8766            0 :                 surf.HeatTransferAlgorithm = DataSurfaces::HeatTransferModel::Kiva;
    8767            0 :                 state.dataHeatBal->AnyKiva = true;
    8768              :             }
    8769          224 :         }
    8770              : 
    8771              :         // test for missing materials for algorithms selected
    8772          224 :         NumEMPDMat = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "MaterialProperty:MoisturePenetrationDepth:Settings");
    8773          224 :         NumPCMat = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "MaterialProperty:PhaseChange") +
    8774          224 :                    state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "MaterialProperty:PhaseChangeHysteresis");
    8775          224 :         NumVTCMat = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "MaterialProperty:VariableThermalConductivity");
    8776          224 :         NumHAMTMat1 = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "MaterialProperty:HeatAndMoistureTransfer:Settings");
    8777              :         NumHAMTMat2 =
    8778          224 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "MaterialProperty:HeatAndMoistureTransfer:SorptionIsotherm");
    8779          224 :         NumHAMTMat3 = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "MaterialProperty:HeatAndMoistureTransfer:Suction");
    8780          224 :         NumHAMTMat4 = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "MaterialProperty:HeatAndMoistureTransfer:Redistribution");
    8781          224 :         NumHAMTMat5 = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "MaterialProperty:HeatAndMoistureTransfer:Diffusion");
    8782              :         NumHAMTMat6 =
    8783          224 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "MaterialProperty:HeatAndMoistureTransfer:ThermalConductivity");
    8784          224 :         SumHAMTMat = NumHAMTMat1 + NumHAMTMat2 + NumHAMTMat3 + NumHAMTMat4 + NumHAMTMat5 + NumHAMTMat6;
    8785          224 :         msgneeded = false;
    8786              : 
    8787          224 :         if (NumEMPDMat > 0 && !state.dataHeatBal->AnyEMPD) {
    8788            0 :             ShowWarningError(state,
    8789            0 :                              format("The input file includes {} MaterialProperty:MoisturePenetrationDepth:Settings objects but the moisture "
    8790              :                                     "penetration depth algorithm is not used anywhere.",
    8791              :                                     NumEMPDMat));
    8792            0 :             msgneeded = true;
    8793              :         }
    8794          224 :         if (NumPCMat > 0 && !state.dataHeatBal->AnyCondFD) {
    8795            0 :             ShowWarningError(state,
    8796            0 :                              format("The input file includes {} MaterialProperty:PhaseChange objects but the conduction finite difference algorithm "
    8797              :                                     "is not used anywhere.",
    8798              :                                     NumPCMat));
    8799            0 :             msgneeded = true;
    8800              :         }
    8801          224 :         if (NumVTCMat > 0 && !state.dataHeatBal->AnyCondFD) {
    8802            0 :             ShowWarningError(state,
    8803            0 :                              format("The input file includes {} MaterialProperty:VariableThermalConductivity objects but the conduction finite "
    8804              :                                     "difference algorithm is not used anywhere.",
    8805              :                                     NumVTCMat));
    8806            0 :             msgneeded = true;
    8807              :         }
    8808          224 :         if (SumHAMTMat > 0 && !state.dataHeatBal->AnyHAMT) {
    8809            0 :             ShowWarningError(state,
    8810            0 :                              format("The input file includes {} MaterialProperty:HeatAndMoistureTransfer:* objects but the combined heat and "
    8811              :                                     "moisture finite difference algorithm is not used anywhere.",
    8812              :                                     SumHAMTMat));
    8813            0 :             msgneeded = true;
    8814              :         }
    8815          224 :         if (msgneeded) {
    8816            0 :             ShowContinueError(state, "Previous materials will be ignored due to HeatBalanceAlgorithm choice.");
    8817              :         }
    8818          224 :         msgneeded = false;
    8819          224 :         if (NumEMPDMat == 0 && state.dataHeatBal->AnyEMPD) {
    8820            2 :             ShowWarningError(state,
    8821              :                              "The moisture penetration depth conduction transfer function algorithm is used but the input file includes no "
    8822              :                              "MaterialProperty:MoisturePenetrationDepth:Settings objects.");
    8823            1 :             msgneeded = true;
    8824              :         }
    8825          224 :         if (SumHAMTMat == 0 && state.dataHeatBal->AnyHAMT) {
    8826            2 :             ShowWarningError(state,
    8827              :                              "The combined heat and moisture finite element algorithm is used but the input file includes no "
    8828              :                              "MaterialProperty:HeatAndMoistureTransfer:* objects.");
    8829            1 :             msgneeded = true;
    8830              :         }
    8831          224 :         if (msgneeded) {
    8832            3 :             ShowContinueError(state,
    8833              :                               "Certain materials objects are necessary to achieve proper results with the heat transfer algorithm(s) selected.");
    8834              :         }
    8835              : 
    8836              :         // Write Solution Algorithm to the initialization output file for User Verification
    8837          224 :         print(state.files.eio,
    8838              :               "{}\n",
    8839              :               "! <Surface Heat Transfer Algorithm>, Value {CTF - ConductionTransferFunction | EMPD - "
    8840              :               "MoisturePenetrationDepthConductionTransferFunction | CondFD - ConductionFiniteDifference | HAMT - "
    8841              :               "CombinedHeatAndMoistureFiniteElement} - Description,Inside Surface Max Temperature Limit{C}, Surface "
    8842              :               "Convection Coefficient Lower Limit {W/m2-K}, Surface Convection Coefficient Upper Limit {W/m2-K}");
    8843              : 
    8844          224 :         int numberOfHeatTransferAlgosUsed = 0;
    8845              :         // Formats
    8846              :         static constexpr std::string_view Format_725("Surface Heat Transfer Algorithm, {},{:.0R},{:.2R},{:.1R}\n");
    8847              : 
    8848          224 :         if (state.dataHeatBal->AnyCTF) {
    8849          183 :             constexpr std::string_view AlgoName = "CTF - ConductionTransferFunction";
    8850          183 :             ++numberOfHeatTransferAlgosUsed;
    8851          183 :             print(state.files.eio,
    8852              :                   Format_725,
    8853              :                   AlgoName,
    8854          183 :                   state.dataHeatBalSurf->MaxSurfaceTempLimit,
    8855          183 :                   state.dataHeatBal->LowHConvLimit,
    8856          183 :                   state.dataHeatBal->HighHConvLimit);
    8857              :         }
    8858          224 :         if (state.dataHeatBal->AnyEMPD) {
    8859            1 :             state.dataHeatBal->AllCTF = false;
    8860            1 :             constexpr std::string_view AlgoName = "EMPD - MoisturePenetrationDepthConductionTransferFunction";
    8861            1 :             ++numberOfHeatTransferAlgosUsed;
    8862            1 :             print(state.files.eio,
    8863              :                   Format_725,
    8864              :                   AlgoName,
    8865            1 :                   state.dataHeatBalSurf->MaxSurfaceTempLimit,
    8866            1 :                   state.dataHeatBal->LowHConvLimit,
    8867            1 :                   state.dataHeatBal->HighHConvLimit);
    8868            1 :             if (state.dataHeatBal->doSpaceHeatBalanceSimulation || state.dataHeatBal->doSpaceHeatBalanceSizing) {
    8869            0 :                 ShowSevereError(
    8870              :                     state,
    8871              :                     "MoisturePenetrationDepthConductionTransferFunction is not supported with ZoneAirHeatBalanceAlgorithm Space Heat Balance.");
    8872            0 :                 ErrorsFound = true;
    8873              :             }
    8874              :         }
    8875          224 :         if (state.dataHeatBal->AnyCondFD) {
    8876            3 :             state.dataHeatBal->AllCTF = false;
    8877            3 :             constexpr std::string_view AlgoName = "CondFD - ConductionFiniteDifference";
    8878            3 :             ++numberOfHeatTransferAlgosUsed;
    8879            3 :             print(state.files.eio,
    8880              :                   Format_725,
    8881              :                   AlgoName,
    8882            3 :                   state.dataHeatBalSurf->MaxSurfaceTempLimit,
    8883            3 :                   state.dataHeatBal->LowHConvLimit,
    8884            3 :                   state.dataHeatBal->HighHConvLimit);
    8885              :         }
    8886          224 :         if (state.dataHeatBal->AnyHAMT) {
    8887            1 :             state.dataHeatBal->AllCTF = false;
    8888            1 :             constexpr std::string_view AlgoName = "HAMT - CombinedHeatAndMoistureFiniteElement";
    8889            1 :             ++numberOfHeatTransferAlgosUsed;
    8890            1 :             print(state.files.eio,
    8891              :                   Format_725,
    8892              :                   AlgoName,
    8893            1 :                   state.dataHeatBalSurf->MaxSurfaceTempLimit,
    8894            1 :                   state.dataHeatBal->LowHConvLimit,
    8895            1 :                   state.dataHeatBal->HighHConvLimit);
    8896            1 :             if (state.dataHeatBal->doSpaceHeatBalanceSimulation || state.dataHeatBal->doSpaceHeatBalanceSizing) {
    8897            0 :                 ShowSevereError(state, "CombinedHeatAndMoistureFiniteElement is not supported with ZoneAirHeatBalanceAlgorithm Space Heat Balance.");
    8898            0 :                 ErrorsFound = true;
    8899              :             }
    8900              :         }
    8901          224 :         if (state.dataHeatBal->AnyKiva) {
    8902            0 :             state.dataHeatBal->AllCTF = false;
    8903            0 :             constexpr std::string_view AlgoName = "KivaFoundation - TwoDimensionalFiniteDifference";
    8904            0 :             ++numberOfHeatTransferAlgosUsed;
    8905            0 :             print(state.files.eio,
    8906              :                   Format_725,
    8907              :                   AlgoName,
    8908            0 :                   state.dataHeatBalSurf->MaxSurfaceTempLimit,
    8909            0 :                   state.dataHeatBal->LowHConvLimit,
    8910            0 :                   state.dataHeatBal->HighHConvLimit);
    8911              :         }
    8912              : 
    8913              :         // Check HeatTransferAlgorithm for interior surfaces
    8914          224 :         if (numberOfHeatTransferAlgosUsed > 1) {
    8915              :             int ExtSurfNum;
    8916            5 :             for (Item = 1; Item <= state.dataSurface->TotSurfaces; ++Item) {
    8917            4 :                 auto &surf = state.dataSurface->Surface(Item);
    8918            4 :                 if (surf.ExtBoundCond > 0) {
    8919            2 :                     if ((surf.HeatTransferAlgorithm == DataSurfaces::HeatTransferModel::Invalid) ||
    8920            2 :                         (surf.HeatTransferAlgorithm == DataSurfaces::HeatTransferModel::None)) {
    8921            0 :                         continue;
    8922              :                     }
    8923            2 :                     ExtSurfNum = surf.ExtBoundCond;
    8924            2 :                     auto &extSurf = state.dataSurface->Surface(ExtSurfNum);
    8925            2 :                     if (surf.HeatTransferAlgorithm != extSurf.HeatTransferAlgorithm) {
    8926            2 :                         ShowWarningError(state,
    8927              :                                          "An interior surface is defined as two surfaces with reverse constructions. The HeatTransferAlgorithm in "
    8928              :                                          "both constructions should be same.");
    8929            2 :                         ShowContinueError(state,
    8930            2 :                                           format("The HeatTransferAlgorithm of Surface: {}, is {}",
    8931            1 :                                                  surf.Name,
    8932            1 :                                                  DataSurfaces::HeatTransAlgoStrs[static_cast<int>(surf.HeatTransferAlgorithm)]));
    8933            2 :                         ShowContinueError(state,
    8934            2 :                                           format("The HeatTransferAlgorithm of Surface: {}, is {}",
    8935            1 :                                                  extSurf.Name,
    8936            1 :                                                  DataSurfaces::HeatTransAlgoStrs[static_cast<int>(extSurf.HeatTransferAlgorithm)]));
    8937            1 :                         if (surf.HeatTransferAlgorithm > extSurf.HeatTransferAlgorithm) {
    8938            2 :                             ShowContinueError(state,
    8939            2 :                                               format("The HeatTransferAlgorithm of Surface: {}, is assigned to {}. Simulation continues.",
    8940            1 :                                                      extSurf.Name,
    8941            1 :                                                      DataSurfaces::HeatTransAlgoStrs[static_cast<int>(surf.HeatTransferAlgorithm)]));
    8942            1 :                             extSurf.HeatTransferAlgorithm = surf.HeatTransferAlgorithm;
    8943              :                         } else {
    8944            0 :                             ShowContinueError(state,
    8945            0 :                                               format("The HeatTransferAlgorithm of Surface: {}, is assigned to {}. Simulation continues.",
    8946            0 :                                                      surf.Name,
    8947            0 :                                                      DataSurfaces::HeatTransAlgoStrs[static_cast<int>(extSurf.HeatTransferAlgorithm)]));
    8948            0 :                             surf.HeatTransferAlgorithm = extSurf.HeatTransferAlgorithm;
    8949              :                         }
    8950              :                     }
    8951              :                 }
    8952              :             }
    8953              :         }
    8954              : 
    8955              :         // Assign model type to windows, shading surfaces, and TDDs
    8956         2484 :         for (Item = 1; Item <= state.dataSurface->TotSurfaces; ++Item) {
    8957         2260 :             if (state.dataSurface->Surface(Item).Class == SurfaceClass::Window || state.dataSurface->Surface(Item).Class == SurfaceClass::GlassDoor) {
    8958              :                 // todo, add complex fenestration switch  HeatTransferModel_ComplexFenestration
    8959          197 :                 if (state.dataSurface->SurfWinWindowModelType(Item) == DataSurfaces::WindowModel::BSDF) {
    8960            0 :                     state.dataSurface->Surface(Item).HeatTransferAlgorithm = DataSurfaces::HeatTransferModel::ComplexFenestration;
    8961              :                 } else {
    8962          197 :                     state.dataSurface->Surface(Item).HeatTransferAlgorithm = DataSurfaces::HeatTransferModel::Window5;
    8963              :                 }
    8964              :             }
    8965         2260 :             if (state.dataSurface->Surface(Item).Class == SurfaceClass::Detached_B ||
    8966         2240 :                 state.dataSurface->Surface(Item).Class == SurfaceClass::Detached_F ||
    8967         6676 :                 state.dataSurface->Surface(Item).Class == SurfaceClass::Shading || state.dataSurface->Surface(Item).Class == SurfaceClass::Overhang ||
    8968         2176 :                 state.dataSurface->Surface(Item).Class == SurfaceClass::Fin) {
    8969           84 :                 state.dataSurface->Surface(Item).HeatTransferAlgorithm = DataSurfaces::HeatTransferModel::None;
    8970              :             }
    8971         4520 :             if (state.dataSurface->Surface(Item).Class == SurfaceClass::TDD_Diffuser ||
    8972         2260 :                 state.dataSurface->Surface(Item).Class == SurfaceClass::TDD_Dome) {
    8973            7 :                 state.dataSurface->Surface(Item).HeatTransferAlgorithm = DataSurfaces::HeatTransferModel::TDD;
    8974              :             }
    8975              : 
    8976         2563 :             if (state.dataSurface->Surface(Item).HeatTransferAlgorithm == DataSurfaces::HeatTransferModel::CTF ||
    8977          303 :                 state.dataSurface->Surface(Item).HeatTransferAlgorithm == DataSurfaces::HeatTransferModel::EMPD) {
    8978         1957 :                 state.dataConstruction->Construct(state.dataSurface->Surface(Item).Construction).IsUsedCTF = true;
    8979              :             }
    8980              :         }
    8981          224 :     }
    8982              : 
    8983              :     struct PopCoincidentVertexReturn
    8984              :     {
    8985              :         double perimeter;
    8986              :         int poppedVertexPos = -1; // This is a STL vector position, 0-indexed
    8987              :         int keptVertexPos = -1;
    8988              :     };
    8989              : 
    8990         2199 :     PopCoincidentVertexReturn checkPopCoincidentVertex(const Array1D<Vector> &vertices)
    8991              :     {
    8992              : 
    8993         2199 :         size_t const nSides = vertices.size();
    8994              : 
    8995              :         // Pass one: Vector of distance from this vertex to the next one
    8996         2199 :         std::vector<Real64> distances(nSides);
    8997         2199 :         size_t index = 0;
    8998         2199 :         double min_distance = std::numeric_limits<Real64>::max();
    8999         2199 :         double perimeter = 0.0;
    9000        10999 :         for (auto it = vertices.begin(); it != vertices.end(); ++it) {
    9001         8800 :             auto itnext = std::next(it);
    9002         8800 :             if (itnext == std::end(vertices)) {
    9003         2199 :                 itnext = std::begin(vertices);
    9004              :             }
    9005         8800 :             const auto dist = distance(*it, *itnext);
    9006         8800 :             distances[index++] = dist;
    9007         8800 :             min_distance = std::min(min_distance, dist);
    9008         8800 :             perimeter += dist;
    9009              :         }
    9010              :         // Return early if nothing to be popped
    9011         2199 :         if (min_distance >= Constant::OneCentimeter) {
    9012         2191 :             return {perimeter};
    9013              :         }
    9014              : 
    9015              :         // Pass two: figure out the vertex that is coincident with its previous and/or next vertex and
    9016              :         // that minimizes the (distanceThisToNext + distanceThisToPrev).
    9017            8 :         Real64 min_weight = std::numeric_limits<Real64>::max();
    9018            8 :         int poppedVertexPos = -1;
    9019            8 :         int keptVertexPos = -1;
    9020              : 
    9021           49 :         for (index = 0; index < nSides; ++index) {
    9022           41 :             size_t const prevIndex = (index == 0) ? nSides - 1 : index - 1;
    9023           41 :             Real64 const &distanceThisToNext = distances[index];
    9024           41 :             Real64 const &distanceThisToPrev = distances[prevIndex];
    9025           41 :             if ((distanceThisToNext >= Constant::OneCentimeter) && (distanceThisToPrev >= Constant::OneCentimeter)) {
    9026           19 :                 continue;
    9027              :             }
    9028           22 :             Real64 const weight = distanceThisToNext + distanceThisToPrev;
    9029           22 :             if (weight < min_weight) {
    9030           13 :                 min_weight = weight;
    9031           13 :                 poppedVertexPos = static_cast<int>(index);
    9032           13 :                 if (distanceThisToPrev < distanceThisToNext) {
    9033            4 :                     keptVertexPos = prevIndex;
    9034              :                 } else {
    9035            9 :                     keptVertexPos = static_cast<int>((index == nSides - 1) ? 0 : index + 1);
    9036              :                 }
    9037              :             }
    9038              :         }
    9039              : 
    9040              :         // Return the keptVertexPos (which can be the previous or the next), so we can print the displayExtraWarning correctly
    9041            8 :         return {perimeter, poppedVertexPos, keptVertexPos};
    9042         2199 :     }
    9043              : 
    9044         2192 :     void GetVertices(EnergyPlusData &state,
    9045              :                      int const SurfNum,             // Current surface number
    9046              :                      int const NSides,              // Number of sides to figure
    9047              :                      Array1S<Real64> const Vertices // Vertices, in specified order
    9048              :     )
    9049              :     {
    9050              : 
    9051              :         // SUBROUTINE INFORMATION:
    9052              :         //       AUTHOR         Linda Lawrie
    9053              :         //       DATE WRITTEN   May 2000
    9054              : 
    9055              :         // PURPOSE OF THIS SUBROUTINE:
    9056              :         // This subroutine gets the surface vertices from the arrays
    9057              :         // passed by the calling routine.  These had previously been obtained
    9058              :         // from the InputProcessor (GetObjectItem).  This routine will provide
    9059              :         // a standard place for determining various properties of the surface
    9060              :         // from the vertices.
    9061              : 
    9062              :         // SUBROUTINE PARAMETER DEFINITIONS:
    9063              :         static constexpr std::string_view RoutineName("GetVertices: ");
    9064              : 
    9065              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    9066              :         int n;    // Loop counter
    9067              :         int NSrc; // Used for CW -> CCW transformation
    9068              :         int NTar; // Used for CW -> CCW transformation
    9069              :         Real64 SurfWorldAz;
    9070              :         Real64 SurfTilt;
    9071              :         Real64 Perimeter; // Perimeter length of the surface
    9072              :         Real64 Xb;        // Intermediate calculation
    9073              :         Real64 Yb;        // Intermediate calculation
    9074              :         int ZoneNum;
    9075              :         int ThisCorner;
    9076              :         Real64 ThisWidth;
    9077              :         Real64 ThisHeight;
    9078              :         // unused    REAL(r64) :: ccwtest
    9079              :         // unused    LOGICAL   :: SurfaceCCW
    9080              :         Real64 dotp;
    9081              : 
    9082              :         // Object Data
    9083         2192 :         Vector const TestVector(0.0, 0.0, 1.0);
    9084         2192 :         Vector temp;
    9085              : 
    9086         2192 :         auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    9087              : 
    9088         2192 :         if (NSides > state.dataSurface->MaxVerticesPerSurface) {
    9089           11 :             state.dataSurface->MaxVerticesPerSurface = NSides;
    9090              :         }
    9091         2192 :         int Ptr = 1;
    9092        10961 :         for (n = 1; n <= NSides; ++n) {
    9093         8769 :             surfTemp.Vertex(n).x = Vertices(Ptr);
    9094         8769 :             ++Ptr;
    9095         8769 :             surfTemp.Vertex(n).y = Vertices(Ptr);
    9096         8769 :             ++Ptr;
    9097         8769 :             surfTemp.Vertex(n).z = Vertices(Ptr);
    9098         8769 :             ++Ptr;
    9099              :         }
    9100              : 
    9101              :         // Address changing vertices if they were put in in CW order rather than CCW
    9102         2192 :         if (!state.dataSurface->CCW) {
    9103              :             // If even number of sides, this will transfer appropriately
    9104              :             // If odd number, will leave the "odd" one, which is what you want.
    9105            2 :             NSrc = NSides;
    9106            2 :             NTar = 2;
    9107            4 :             for (n = 1; n <= (NSides - 1) / 2; ++n) {
    9108            2 :                 temp = surfTemp.Vertex(NSrc);
    9109            2 :                 surfTemp.Vertex(NSrc) = surfTemp.Vertex(NTar);
    9110            2 :                 surfTemp.Vertex(NTar) = temp;
    9111            2 :                 --NSrc;
    9112            2 :                 ++NTar;
    9113              :             }
    9114              :         }
    9115              :         // Now address which "Corner" has been put in first.  Note: the azimuth and tilt and area
    9116              :         // calculations do not care which corner is put in first.
    9117              :         // 2/2011 - don't think the shading calculations have a corner preference.  Will keep this for
    9118              :         // consistency (for now)
    9119         2192 :         ThisCorner = state.dataSurface->Corner;
    9120         2646 :         while (ThisCorner != DataSurfaces::UpperLeftCorner) {
    9121          454 :             if (NSides < 4) {
    9122            4 :                 if (ThisCorner == DataSurfaces::UpperRightCorner) {
    9123            0 :                     break;
    9124              :                 }
    9125              :             }
    9126          454 :             NTar = ThisCorner;
    9127          454 :             NSrc = ThisCorner + 1;
    9128          454 :             if (NSrc > NSides) {
    9129          152 :                 NSrc = 1;
    9130              :             }
    9131         1812 :             for (n = 1; n <= NSides - 1; ++n) {
    9132         1358 :                 temp = surfTemp.Vertex(NTar);
    9133         1358 :                 surfTemp.Vertex(NTar) = surfTemp.Vertex(NSrc);
    9134         1358 :                 surfTemp.Vertex(NSrc) = temp;
    9135         1358 :                 ++NTar;
    9136         1358 :                 ++NSrc;
    9137         1358 :                 if (NTar > NSides) {
    9138          454 :                     NTar = 1;
    9139              :                 }
    9140         1358 :                 if (NSrc > NSides) {
    9141          302 :                     NSrc = 1;
    9142              :                 }
    9143              :             }
    9144          454 :             ++ThisCorner;
    9145          454 :             if (ThisCorner > NSides) {
    9146          152 :                 ThisCorner = 1;
    9147              :             }
    9148              :         } // Corners
    9149         2192 :         if (!state.dataSurface->WorldCoordSystem) {
    9150              :             // Input in "relative" coordinates, use Building and Zone North Axes and Origins
    9151              :             //                                  to translate each point (including rotation for Appendix G)
    9152         1223 :             ZoneNum = surfTemp.Zone;
    9153         1223 :             if (ZoneNum > 0) {
    9154         6067 :                 for (n = 1; n <= NSides; ++n) {
    9155         4857 :                     Xb = surfTemp.Vertex(n).x * state.dataSurfaceGeometry->CosZoneRelNorth(ZoneNum) -
    9156         4857 :                          surfTemp.Vertex(n).y * state.dataSurfaceGeometry->SinZoneRelNorth(ZoneNum) + state.dataHeatBal->Zone(ZoneNum).OriginX;
    9157         4857 :                     Yb = surfTemp.Vertex(n).x * state.dataSurfaceGeometry->SinZoneRelNorth(ZoneNum) +
    9158         4857 :                          surfTemp.Vertex(n).y * state.dataSurfaceGeometry->CosZoneRelNorth(ZoneNum) + state.dataHeatBal->Zone(ZoneNum).OriginY;
    9159         4857 :                     surfTemp.Vertex(n).x = Xb * state.dataSurfaceGeometry->CosBldgRelNorth - Yb * state.dataSurfaceGeometry->SinBldgRelNorth;
    9160         4857 :                     surfTemp.Vertex(n).y = Xb * state.dataSurfaceGeometry->SinBldgRelNorth + Yb * state.dataSurfaceGeometry->CosBldgRelNorth;
    9161         4857 :                     surfTemp.Vertex(n).z += state.dataHeatBal->Zone(ZoneNum).OriginZ;
    9162              :                 }
    9163           13 :             } else if (surfTemp.Class == SurfaceClass::Detached_B) {
    9164           50 :                 for (n = 1; n <= NSides; ++n) {
    9165           40 :                     Xb = surfTemp.Vertex(n).x;
    9166           40 :                     Yb = surfTemp.Vertex(n).y;
    9167           40 :                     surfTemp.Vertex(n).x = Xb * state.dataSurfaceGeometry->CosBldgRelNorth - Yb * state.dataSurfaceGeometry->SinBldgRelNorth;
    9168           40 :                     surfTemp.Vertex(n).y = Xb * state.dataSurfaceGeometry->SinBldgRelNorth + Yb * state.dataSurfaceGeometry->CosBldgRelNorth;
    9169              :                 }
    9170              :             }
    9171              :         } else {
    9172              :             // if world coordinate only need to rotate for Appendix G
    9173          969 :             ZoneNum = surfTemp.Zone;
    9174          969 :             if (ZoneNum > 0) {
    9175         4809 :                 for (n = 1; n <= NSides; ++n) {
    9176         3844 :                     Xb = surfTemp.Vertex(n).x;
    9177         3844 :                     Yb = surfTemp.Vertex(n).y;
    9178         3844 :                     surfTemp.Vertex(n).x = Xb * state.dataSurfaceGeometry->CosBldgRotAppGonly - Yb * state.dataSurfaceGeometry->SinBldgRotAppGonly;
    9179         3844 :                     surfTemp.Vertex(n).y = Xb * state.dataSurfaceGeometry->SinBldgRotAppGonly + Yb * state.dataSurfaceGeometry->CosBldgRotAppGonly;
    9180              :                 }
    9181            4 :             } else if (surfTemp.Class == SurfaceClass::Detached_B) {
    9182           10 :                 for (n = 1; n <= NSides; ++n) {
    9183            8 :                     Xb = surfTemp.Vertex(n).x;
    9184            8 :                     Yb = surfTemp.Vertex(n).y;
    9185            8 :                     surfTemp.Vertex(n).x = Xb * state.dataSurfaceGeometry->CosBldgRotAppGonly - Yb * state.dataSurfaceGeometry->SinBldgRotAppGonly;
    9186            8 :                     surfTemp.Vertex(n).y = Xb * state.dataSurfaceGeometry->SinBldgRotAppGonly + Yb * state.dataSurfaceGeometry->CosBldgRotAppGonly;
    9187              :                 }
    9188              :             }
    9189              :         }
    9190              : 
    9191         2192 :         if (NSides > 2) {
    9192         2192 :             auto &surface = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    9193         2192 :             auto &vertices = surface.Vertex;
    9194         2192 :             auto &nSides = surface.Sides;
    9195         2192 :             std::string TiltString;
    9196              : 
    9197              :             while (true) {
    9198         2199 :                 PopCoincidentVertexReturn const popResult = checkPopCoincidentVertex(vertices);
    9199         2199 :                 Perimeter = popResult.perimeter;
    9200         2199 :                 if (popResult.poppedVertexPos < 0) {
    9201              :                     // No pop needed, we're done
    9202         2191 :                     break;
    9203              :                 }
    9204              : 
    9205              :                 // Grab the popped one, and the kept one (regardless of whether it's previous or next)
    9206            8 :                 auto it = vertices.begin();
    9207            8 :                 std::advance(it, popResult.poppedVertexPos);
    9208            8 :                 int const poppedVertexIndex = popResult.poppedVertexPos + 1;
    9209              : 
    9210            8 :                 auto itKept = vertices.begin();
    9211            8 :                 std::advance(itKept, popResult.keptVertexPos);
    9212            8 :                 int const keptVertexIndex = popResult.keptVertexPos + 1;
    9213              : 
    9214            8 :                 if (state.dataGlobal->DisplayExtraWarnings) {
    9215           12 :                     ShowWarningError(state,
    9216           12 :                                      format("{}Distance between two vertices < .01, possibly coincident. for Surface={}, in Zone={}",
    9217              :                                             RoutineName,
    9218            6 :                                             surfTemp.Name,
    9219            6 :                                             surfTemp.ZoneName));
    9220              : 
    9221            9 :                     bool const printPoppedFirst = (poppedVertexIndex < keptVertexIndex) ? !(poppedVertexIndex == 1 && keptVertexIndex == nSides)
    9222            3 :                                                                                         : (poppedVertexIndex == nSides && keptVertexIndex == 1);
    9223              : 
    9224            6 :                     if (printPoppedFirst) {
    9225            5 :                         ShowContinueError(state, format("Vertex [{}]=({:.2R},{:.2R},{:.2R})", poppedVertexIndex, it->x, it->y, it->z));
    9226            5 :                         ShowContinueError(state, format("Vertex [{}]=({:.2R},{:.2R},{:.2R})", keptVertexIndex, itKept->x, itKept->y, itKept->z));
    9227              :                     } else {
    9228            1 :                         ShowContinueError(state, format("Vertex [{}]=({:.2R},{:.2R},{:.2R})", keptVertexIndex, itKept->x, itKept->y, itKept->z));
    9229            1 :                         ShowContinueError(state, format("Vertex [{}]=({:.2R},{:.2R},{:.2R})", poppedVertexIndex, it->x, it->y, it->z));
    9230              :                     }
    9231              :                 }
    9232            8 :                 ++state.dataErrTracking->TotalCoincidentVertices;
    9233            8 :                 if (nSides <= 3) {
    9234            1 :                     if (state.dataGlobal->DisplayExtraWarnings) {
    9235            0 :                         ShowContinueError(state,
    9236            0 :                                           format("Cannot Drop Vertex [{}]; Number of Surface Sides at minimum. This surface is now a "
    9237              :                                                  "degenerate surface.",
    9238              :                                                  poppedVertexIndex));
    9239              :                     }
    9240            1 :                     ++state.dataErrTracking->TotalDegenerateSurfaces;
    9241              :                     // If degenerate, we won't be able to pop now nor later, so exit
    9242              :                     // mark degenerate surface?
    9243            1 :                     break;
    9244              :                 }
    9245              : 
    9246            7 :                 if (state.dataGlobal->DisplayExtraWarnings) {
    9247            6 :                     ShowContinueError(state, format("Dropping Vertex [{}].", poppedVertexIndex));
    9248              :                 }
    9249            7 :                 --nSides;
    9250            7 :                 vertices.erase(it);
    9251              :                 // No need to recompute perimeter, because it'll be done in the next iteration, until no popping or degenerate happens
    9252            7 :             }
    9253              : 
    9254         2192 :             surfTemp.Perimeter = Perimeter;
    9255              : 
    9256         2192 :             Vectors::CreateNewellSurfaceNormalVector(surfTemp.Vertex, surfTemp.Sides, surfTemp.NewellSurfaceNormalVector);
    9257         2192 :             Vectors::CreateNewellAreaVector(surfTemp.Vertex, surfTemp.Sides, surfTemp.NewellAreaVector);
    9258              :             // For surfaces with subsurfaces, the following two areas are turned into net areas later by
    9259              :             // subtracting subsurface areas
    9260         2192 :             surfTemp.GrossArea = Vectors::VecLength(surfTemp.NewellAreaVector);
    9261         2192 :             surfTemp.Area = surfTemp.GrossArea;
    9262         2192 :             surfTemp.NetAreaShadowCalc = surfTemp.Area;
    9263         2192 :             Vectors::DetermineAzimuthAndTilt(
    9264         2192 :                 surfTemp.Vertex, SurfWorldAz, SurfTilt, surfTemp.lcsx, surfTemp.lcsy, surfTemp.lcsz, surfTemp.NewellSurfaceNormalVector);
    9265         2192 :             dotp = dot(surfTemp.NewellSurfaceNormalVector, TestVector);
    9266         2192 :             if (surfTemp.Class == SurfaceClass::Roof && dotp < -0.000001) {
    9267           16 :                 TiltString = format("{:.1R}", SurfTilt);
    9268           32 :                 ShowWarningError(state,
    9269           32 :                                  format("{}Roof/Ceiling is upside down! Tilt angle=[{}], should be near 0, Surface=\"{}\", in Zone=\"{}\".",
    9270              :                                         RoutineName,
    9271              :                                         TiltString,
    9272           16 :                                         surfTemp.Name,
    9273           16 :                                         surfTemp.ZoneName));
    9274           32 :                 ShowContinueError(state, "Automatic fix is attempted.");
    9275           16 :                 ReverseAndRecalculate(state, SurfNum, surfTemp.Sides, SurfWorldAz, SurfTilt);
    9276         2176 :             } else if (surfTemp.Class == SurfaceClass::Roof && SurfTilt > 80.0) {
    9277            8 :                 TiltString = format("{:.1R}", SurfTilt);
    9278           16 :                 ShowWarningError(
    9279              :                     state,
    9280           16 :                     format("{}Roof/Ceiling is not oriented correctly! Tilt angle=[{}], should be near 0, Surface=\"{}\", in Zone=\"{}\".",
    9281              :                            RoutineName,
    9282              :                            TiltString,
    9283            8 :                            surfTemp.Name,
    9284            8 :                            surfTemp.ZoneName));
    9285              :             }
    9286         2192 :             if (surfTemp.Class == SurfaceClass::Floor && dotp > 0.000001) {
    9287           41 :                 TiltString = format("{:.1R}", SurfTilt);
    9288           82 :                 ShowWarningError(state,
    9289           82 :                                  format("{}Floor is upside down! Tilt angle=[{}], should be near 180, Surface=\"{}\", in Zone=\"{}\".",
    9290              :                                         RoutineName,
    9291              :                                         TiltString,
    9292           41 :                                         surfTemp.Name,
    9293           41 :                                         surfTemp.ZoneName));
    9294           82 :                 ShowContinueError(state, "Automatic fix is attempted.");
    9295           41 :                 ReverseAndRecalculate(state, SurfNum, surfTemp.Sides, SurfWorldAz, SurfTilt);
    9296         2151 :             } else if (surfTemp.Class == SurfaceClass::Floor && SurfTilt < 158.2) { // slope/grade = 40%!
    9297           16 :                 TiltString = format("{:.1R}", SurfTilt);
    9298           32 :                 ShowWarningError(state,
    9299           32 :                                  format("{}Floor is not oriented correctly! Tilt angle=[{}], should be near 180, Surface=\"{}\", in Zone=\"{}\".",
    9300              :                                         RoutineName,
    9301              :                                         TiltString,
    9302           16 :                                         surfTemp.Name,
    9303           16 :                                         surfTemp.ZoneName));
    9304              :             }
    9305         2192 :             surfTemp.Azimuth = SurfWorldAz;
    9306         2192 :             surfTemp.Tilt = SurfTilt;
    9307         2192 :             surfTemp.convOrientation = Convect::GetSurfConvOrientation(surfTemp.Tilt);
    9308              : 
    9309              :             // Sine and cosine of azimuth and tilt
    9310         2192 :             surfTemp.SinAzim = std::sin(SurfWorldAz * Constant::DegToRad);
    9311         2192 :             surfTemp.CosAzim = std::cos(SurfWorldAz * Constant::DegToRad);
    9312         2192 :             surfTemp.SinTilt = std::sin(SurfTilt * Constant::DegToRad);
    9313         2192 :             surfTemp.CosTilt = std::cos(SurfTilt * Constant::DegToRad);
    9314         2192 :             if (surfTemp.ViewFactorGround == Constant::AutoCalculate) {
    9315          477 :                 surfTemp.ViewFactorGround = 0.5 * (1.0 - surfTemp.CosTilt);
    9316              :             }
    9317              :             // Outward normal unit vector (pointing away from room)
    9318         2192 :             surfTemp.OutNormVec = surfTemp.NewellSurfaceNormalVector;
    9319         8768 :             for (n = 1; n <= 3; ++n) {
    9320         6576 :                 if (std::abs(surfTemp.OutNormVec(n) - 1.0) < 1.e-06) {
    9321          848 :                     surfTemp.OutNormVec(n) = +1.0;
    9322              :                 }
    9323         6576 :                 if (std::abs(surfTemp.OutNormVec(n) + 1.0) < 1.e-06) {
    9324         1022 :                     surfTemp.OutNormVec(n) = -1.0;
    9325              :                 }
    9326         6576 :                 if (std::abs(surfTemp.OutNormVec(n)) < 1.e-06) {
    9327         4064 :                     surfTemp.OutNormVec(n) = 0.0;
    9328              :                 }
    9329              :             }
    9330              : 
    9331         2192 :             if (surfTemp.Class == SurfaceClass::Window || surfTemp.Class == SurfaceClass::GlassDoor || surfTemp.Class == SurfaceClass::Door) {
    9332          201 :                 surfTemp.Area *= surfTemp.Multiplier;
    9333              :             }
    9334              :             // Can perform tests on this surface here
    9335         2192 :             surfTemp.ViewFactorSky = 0.5 * (1.0 + surfTemp.CosTilt);
    9336              :             // The following IR view factors are modified in subr. SkyDifSolarShading if there are shadowing
    9337              :             // surfaces
    9338         2192 :             surfTemp.ViewFactorSkyIR = surfTemp.ViewFactorSky;
    9339         2192 :             surfTemp.ViewFactorGroundIR = 0.5 * (1.0 - surfTemp.CosTilt);
    9340              : 
    9341              :             // Call to transform vertices
    9342              : 
    9343         2192 :             TransformVertsByAspect(state, SurfNum, surfTemp.Sides);
    9344              : 
    9345         2192 :         } else {
    9346            0 :             ShowFatalError(state, format("{}Called with less than 2 sides, Surface={}", RoutineName, surfTemp.Name));
    9347              :         }
    9348              : 
    9349              :         // Preliminary Height/Width
    9350         2192 :         temp = surfTemp.Vertex(3) - surfTemp.Vertex(2);
    9351         2192 :         ThisWidth = Vectors::VecLength(temp);
    9352         2192 :         temp = surfTemp.Vertex(2) - surfTemp.Vertex(1);
    9353         2192 :         ThisHeight = Vectors::VecLength(temp);
    9354         2192 :         surfTemp.Height = ThisHeight;
    9355         2192 :         surfTemp.Width = ThisWidth;
    9356         2192 :     }
    9357              : 
    9358           57 :     void ReverseAndRecalculate(EnergyPlusData &state,
    9359              :                                int const SurfNum,   // Surface number for the surface
    9360              :                                int const NSides,    // number of sides to surface
    9361              :                                Real64 &SurfAzimuth, // Surface Facing angle (will be 0 for roofs/floors)
    9362              :                                Real64 &SurfTilt     // Surface tilt (
    9363              :     )
    9364              :     {
    9365              : 
    9366              :         // SUBROUTINE INFORMATION:
    9367              :         //       AUTHOR         Linda Lawrie
    9368              :         //       DATE WRITTEN   February 2011
    9369              : 
    9370              :         // PURPOSE OF THIS SUBROUTINE:
    9371              :         // This routine reverses the vertices for a surface (needed when roof/floor is upside down)
    9372              :         // and recalculates the azimuth, etc for the surface.
    9373              : 
    9374              :         // SUBROUTINE PARAMETER DEFINITIONS:
    9375              :         static constexpr std::string_view RoutineName("ReverseAndRecalculate: ");
    9376              : 
    9377              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    9378              :         int n;      // Loop Control
    9379              :         int RevPtr; // pointer for reversing vertices
    9380           57 :         std::string TiltString;
    9381              : 
    9382              :         // Object Data
    9383           57 :         Array1D<Vector> Vertices(NSides); // Vertices, in specified order
    9384              : 
    9385           57 :         auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    9386              : 
    9387          284 :         for (n = 1; n <= NSides; ++n) {
    9388          227 :             Vertices(n) = surfTemp.Vertex(n);
    9389              :         }
    9390           57 :         RevPtr = NSides;
    9391          284 :         for (n = 1; n <= NSides; ++n) {
    9392          227 :             surfTemp.Vertex(n) = Vertices(RevPtr);
    9393          227 :             --RevPtr;
    9394              :         }
    9395              : 
    9396           57 :         print(state.files.debug, "Reversing Surface Name={}\n", surfTemp.Name);
    9397          284 :         for (n = 1; n <= NSides; ++n) {
    9398          227 :             print(state.files.debug,
    9399              :                   "side={:5} abs coord vertex= {:18.13F} {:18.13F} {:18.13F}\n",
    9400              :                   n,
    9401          227 :                   surfTemp.Vertex(n).x,
    9402          227 :                   surfTemp.Vertex(n).y,
    9403          227 :                   surfTemp.Vertex(n).z);
    9404              :         }
    9405              : 
    9406           57 :         Vectors::CreateNewellSurfaceNormalVector(surfTemp.Vertex, surfTemp.Sides, surfTemp.NewellSurfaceNormalVector);
    9407           57 :         Vectors::DetermineAzimuthAndTilt(
    9408           57 :             surfTemp.Vertex, SurfAzimuth, SurfTilt, surfTemp.lcsx, surfTemp.lcsy, surfTemp.lcsz, surfTemp.NewellSurfaceNormalVector);
    9409           57 :         if (surfTemp.Class == SurfaceClass::Roof && SurfTilt > 80.0) {
    9410            0 :             TiltString = format("{:.1R}", SurfTilt);
    9411            0 :             ShowWarningError(
    9412              :                 state,
    9413            0 :                 format("{}Roof/Ceiling is still upside down! Tilt angle=[{}], should be near 0, please fix manually.", RoutineName, TiltString));
    9414              :         }
    9415           57 :         if (surfTemp.Class == SurfaceClass::Floor && SurfTilt < 158.2) { // 40% grade!
    9416           16 :             ShowWarningError(
    9417           16 :                 state, format("{}Floor is still upside down! Tilt angle=[{}], should be near 180, please fix manually.", RoutineName, TiltString));
    9418              :         }
    9419           57 :     }
    9420              : 
    9421           49 :     void MakeMirrorSurface(EnergyPlusData &state, int &SurfNum) // In=>Surface to Mirror, Out=>new Surface index // This is not good
    9422              :     {
    9423              : 
    9424              :         // SUBROUTINE INFORMATION:
    9425              :         //       AUTHOR         Linda Lawrie
    9426              :         //       DATE WRITTEN   June 2002
    9427              : 
    9428              :         // PURPOSE OF THIS SUBROUTINE:
    9429              :         // This subroutine creates a "mirror" surface using the indicated surface.
    9430              :         // This is the simple approach for bi-directional shading devices.  If, perchance,
    9431              :         // the user has already taken care of this (e.g. fins in middle of wall), there will
    9432              :         // be extra shading devices shown.
    9433              : 
    9434           49 :         auto &origSurface = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    9435           49 :         auto &newSurface = state.dataSurfaceGeometry->SurfaceTmp(SurfNum + 1);
    9436           49 :         newSurface = origSurface;
    9437              : 
    9438           49 :         auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    9439              : 
    9440           49 :         int nVert = origSurface.Sides;
    9441              :         // Reverse the vertices in the original surface.  Add "MIR-" to name.
    9442          244 :         for (int Vert = 1; Vert <= surfTemp.Sides; ++Vert) {
    9443          195 :             newSurface.Vertex(Vert) = origSurface.Vertex(nVert);
    9444          195 :             --nVert;
    9445              :         }
    9446           49 :         newSurface.Name = "Mir-" + origSurface.Name;
    9447           49 :         newSurface.MirroredSurf = true;
    9448              : 
    9449           49 :         if (newSurface.Sides > 2) {
    9450           49 :             Vectors::CreateNewellAreaVector(newSurface.Vertex, newSurface.Sides, newSurface.NewellAreaVector);
    9451           49 :             newSurface.GrossArea = Vectors::VecLength(newSurface.NewellAreaVector);
    9452           49 :             newSurface.Area = newSurface.GrossArea;
    9453           49 :             newSurface.NetAreaShadowCalc = newSurface.Area;
    9454           49 :             Vectors::CreateNewellSurfaceNormalVector(newSurface.Vertex, newSurface.Sides, newSurface.NewellSurfaceNormalVector);
    9455           49 :             Real64 SurfWorldAz = 0.0;
    9456           49 :             Real64 SurfTilt = 0.0;
    9457           49 :             Vectors::DetermineAzimuthAndTilt(
    9458           49 :                 newSurface.Vertex, SurfWorldAz, SurfTilt, newSurface.lcsx, newSurface.lcsy, newSurface.lcsz, newSurface.NewellSurfaceNormalVector);
    9459           49 :             newSurface.Azimuth = SurfWorldAz;
    9460           49 :             newSurface.Tilt = SurfTilt;
    9461           49 :             newSurface.convOrientation = Convect::GetSurfConvOrientation(newSurface.Tilt);
    9462              : 
    9463              :             // Sine and cosine of azimuth and tilt
    9464           49 :             newSurface.SinAzim = std::sin(SurfWorldAz * Constant::DegToRad);
    9465           49 :             newSurface.CosAzim = std::cos(SurfWorldAz * Constant::DegToRad);
    9466           49 :             newSurface.SinTilt = std::sin(SurfTilt * Constant::DegToRad);
    9467           49 :             newSurface.CosTilt = std::cos(SurfTilt * Constant::DegToRad);
    9468              :             // Outward normal unit vector (pointing away from room)
    9469           49 :             newSurface.OutNormVec = newSurface.NewellSurfaceNormalVector;
    9470          196 :             for (int n = 1; n <= 3; ++n) {
    9471          147 :                 if (std::abs(newSurface.OutNormVec(n) - 1.0) < 1.e-06) {
    9472           20 :                     newSurface.OutNormVec(n) = +1.0;
    9473              :                 }
    9474          147 :                 if (std::abs(newSurface.OutNormVec(n) + 1.0) < 1.e-06) {
    9475           21 :                     newSurface.OutNormVec(n) = -1.0;
    9476              :                 }
    9477          147 :                 if (std::abs(newSurface.OutNormVec(n)) < 1.e-06) {
    9478           90 :                     newSurface.OutNormVec(n) = 0.0;
    9479              :                 }
    9480              :             }
    9481              : 
    9482              :             // Can perform tests on this surface here
    9483           49 :             newSurface.ViewFactorSky = 0.5 * (1.0 + newSurface.CosTilt);
    9484              :             // The following IR view factors are modified in subr. SkyDifSolarShading if there are shadowing surfaces
    9485           49 :             newSurface.ViewFactorSkyIR = newSurface.ViewFactorSky;
    9486           49 :             newSurface.ViewFactorGroundIR = 0.5 * (1.0 - newSurface.CosTilt);
    9487           49 :             ++SurfNum; // Calling function expects incremented argument on return
    9488              :         }
    9489           49 :     }
    9490              : 
    9491          226 :     void GetWindowShadingControlData(EnergyPlusData &state, bool &ErrorsFound) // If errors found in input
    9492              :     {
    9493              : 
    9494              :         // SUBROUTINE INFORMATION:
    9495              :         //       AUTHOR         Fred Winkelmann
    9496              :         //       DATE WRITTEN   November 1998
    9497              :         //       MODIFIED       Aug 2001 (FW): add handling of new ShadingControlIsScheduled
    9498              :         //                      and GlareControlIsActive fields
    9499              :         //                      Nov 2001 (FW): add ShadingDevice as alternative to ShadedConstruction
    9500              :         //                      Dec 2001 (FW): add slat angle controls for blinds
    9501              :         //                      Aug 2002 (FW): add Setpoint2; check that specified control type is legal
    9502              :         //                      Feb 2003 (FW): add error if Material Name of Shading Device is used with
    9503              :         //                        Shading Type = BetweenGlassShade or BetweenGlassBlind
    9504              :         //                      Dec 2003 (FW): improve BetweenGlassBlind error messages
    9505              :         //                      Feb 2009 (BG): improve error checking for OnIfScheduleAllows
    9506              : 
    9507              :         // PURPOSE OF THIS SUBROUTINE:
    9508              :         // Reads in the window shading control information
    9509              :         // from the input data file, interprets it and puts it in the derived type
    9510              : 
    9511              :         // SUBROUTINE PARAMETER DEFINITIONS:
    9512              :         static constexpr std::string_view routineName = "GetWindowShadingControlData";
    9513              : 
    9514          226 :         int constexpr NumValidShadingTypes(9);
    9515              :         static Array1D_string const cValidShadingTypes(NumValidShadingTypes,
    9516              :                                                        {
    9517              :                                                            "SHADEOFF",          // 1
    9518              :                                                            "INTERIORSHADE",     // 2
    9519              :                                                            "SWITCHABLEGLAZING", // 3
    9520              :                                                            "EXTERIORSHADE",     // 4
    9521              :                                                            "EXTERIORSCREEN",    // 5
    9522              :                                                            "INTERIORBLIND",     // 6
    9523              :                                                            "EXTERIORBLIND",     // 7
    9524              :                                                            "BETWEENGLASSSHADE", // 8
    9525              :                                                            "BETWEENGLASSBLIND"  // 9
    9526          226 :                                                        });
    9527              : 
    9528          226 :         constexpr std::array<std::string_view, static_cast<int>(DataSurfaces::WindowShadingControlType::Num)> WindowShadingControlTypeNamesUC{
    9529              :             "ALWAYSON",
    9530              :             "ALWAYSOFF",
    9531              :             "ONIFSCHEDULEALLOWS",
    9532              :             "ONIFHIGHSOLARONWINDOW",
    9533              :             "ONIFHIGHHORIZONTALSOLAR",
    9534              :             "ONIFHIGHOUTDOORAIRTEMPERATURE",
    9535              :             "ONIFHIGHZONEAIRTEMPERATURE",
    9536              :             "ONIFHIGHZONECOOLING",
    9537              :             "ONIFHIGHGLARE",
    9538              :             "MEETDAYLIGHTILLUMINANCESETPOINT",
    9539              :             "ONNIGHTIFLOWOUTDOORTEMPANDOFFDAY",
    9540              :             "ONNIGHTIFLOWINSIDETEMPANDOFFDAY",
    9541              :             "ONNIGHTIFHEATINGANDOFFDAY",
    9542              :             "ONNIGHTIFLOWOUTDOORTEMPANDONDAYIFCOOLING",
    9543              :             "ONNIGHTIFHEATINGANDONDAYIFCOOLING",
    9544              :             "OFFNIGHTANDONDAYIFCOOLINGANDHIGHSOLARONWINDOW",
    9545              :             "ONNIGHTANDONDAYIFCOOLINGANDHIGHSOLARONWINDOW",
    9546              :             "ONIFHIGHOUTDOORAIRTEMPANDHIGHSOLARONWINDOW",
    9547              :             "ONIFHIGHOUTDOORAIRTEMPANDHIGHHORIZONTALSOLAR",
    9548              :             "ONIFHIGHZONEAIRTEMPANDHIGHSOLARONWINDOW",
    9549              :             "ONIFHIGHZONEAIRTEMPANDHIGHHORIZONTALSOLAR",
    9550              :             "ONIFHIGHSOLARORHIGHLUMINANCETILLMIDNIGHT",
    9551              :             "ONIFHIGHSOLARORHIGHLUMINANCETILLSUNSET",
    9552              :             "ONIFHIGHSOLARORHIGHLUMINANCETILLNEXTMORNING"};
    9553              : 
    9554          226 :         constexpr std::array<std::string_view, static_cast<int>(DataSurfaces::SlatAngleControl::Num)> SlatAngleNamesUC{
    9555              :             "FIXEDSLATANGLE", "SCHEDULEDSLATANGLE", "BLOCKBEAMSOLAR"};
    9556              : 
    9557          226 :         constexpr std::array<std::string_view, static_cast<int>(DataSurfaces::MultiSurfaceControl::Num)> MultiSurfaceControlNamesUC = {"SEQUENTIAL",
    9558              :                                                                                                                                        "GROUP"};
    9559              : 
    9560              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    9561              :         int IOStat;          // IO Status when calling get input subroutine
    9562              :         int ControlNumAlpha; // Number of control alpha names being passed
    9563              :         int ControlNumProp;  // Number of control properties being passed
    9564              :         int ControlNum;      // DO loop counter/index for window shading control number
    9565              :         int IShadedConst;    // Construction number of shaded construction
    9566              :         int IShadingDevice;  // Material number of shading device
    9567              :         int NLayers;         // Layers in shaded construction
    9568              :         int Loop;
    9569              :         bool BGShadeBlindError; // True if problem with construction that is supposed to have between-glass
    9570              :         // shade or blind
    9571              :         int Found;
    9572              : 
    9573          226 :         auto &s_mat = state.dataMaterial;
    9574          226 :         auto &s_ipsc = state.dataIPShortCut;
    9575              :         // Get the total number of window shading control blocks
    9576          226 :         s_ipsc->cCurrentModuleObject = "WindowShadingControl";
    9577          226 :         state.dataSurface->TotWinShadingControl = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
    9578          226 :         if (state.dataSurface->TotWinShadingControl == 0) {
    9579          222 :             return;
    9580              :         }
    9581              : 
    9582            4 :         state.dataSurface->WindowShadingControl.allocate(state.dataSurface->TotWinShadingControl);
    9583              : 
    9584            4 :         ControlNum = 0;
    9585            8 :         for (Loop = 1; Loop <= state.dataSurface->TotWinShadingControl; ++Loop) {
    9586              : 
    9587            8 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    9588            4 :                                                                      s_ipsc->cCurrentModuleObject,
    9589              :                                                                      Loop,
    9590            4 :                                                                      s_ipsc->cAlphaArgs,
    9591              :                                                                      ControlNumAlpha,
    9592            4 :                                                                      s_ipsc->rNumericArgs,
    9593              :                                                                      ControlNumProp,
    9594              :                                                                      IOStat,
    9595            4 :                                                                      s_ipsc->lNumericFieldBlanks,
    9596            4 :                                                                      s_ipsc->lAlphaFieldBlanks,
    9597            4 :                                                                      s_ipsc->cAlphaFieldNames,
    9598            4 :                                                                      s_ipsc->cNumericFieldNames);
    9599              : 
    9600            4 :             ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
    9601              : 
    9602            4 :             bool ErrorInName = false;
    9603            4 :             bool IsBlank = false;
    9604              : 
    9605            4 :             Util::VerifyName(state,
    9606            4 :                              s_ipsc->cAlphaArgs(1),
    9607            4 :                              state.dataSurface->WindowShadingControl,
    9608              :                              ControlNum,
    9609              :                              ErrorInName,
    9610              :                              IsBlank,
    9611            8 :                              s_ipsc->cCurrentModuleObject + " Name");
    9612            4 :             if (ErrorInName) {
    9613            0 :                 ErrorsFound = true;
    9614            0 :                 continue;
    9615              :             }
    9616              : 
    9617            4 :             ++ControlNum;
    9618              : 
    9619            4 :             auto &windowShadingControl = state.dataSurface->WindowShadingControl(ControlNum);
    9620              : 
    9621            4 :             windowShadingControl.Name = s_ipsc->cAlphaArgs(1); // Set the Control Name in the Derived Type
    9622              : 
    9623            4 :             windowShadingControl.ZoneIndex = Util::FindItemInList(s_ipsc->cAlphaArgs(2), state.dataHeatBal->Zone);
    9624            4 :             if (windowShadingControl.ZoneIndex == 0) {
    9625            0 :                 ShowSevereError(state,
    9626            0 :                                 format("{}=\"{}\" invalid {}=\"{}\" not found.",
    9627            0 :                                        s_ipsc->cCurrentModuleObject,
    9628            0 :                                        s_ipsc->cAlphaArgs(1),
    9629            0 :                                        s_ipsc->cAlphaFieldNames(2),
    9630            0 :                                        s_ipsc->cAlphaArgs(2)));
    9631            0 :                 ErrorsFound = true;
    9632              :             }
    9633              : 
    9634            4 :             windowShadingControl.SequenceNumber = int(s_ipsc->rNumericArgs(1));
    9635              : 
    9636              :             // For upward compatibility change old "noninsulating" and "insulating" shade types to
    9637              :             // INTERIORSHADE or EXTERIORSHADE
    9638            4 :             if (s_ipsc->cAlphaArgs(3) == "INTERIORNONINSULATINGSHADE" || s_ipsc->cAlphaArgs(3) == "INTERIORINSULATINGSHADE") {
    9639            0 :                 ShowWarningError(state,
    9640            0 :                                  format("{}=\"{}\" is using obsolete {}=\"{}\", changing to \"InteriorShade\"",
    9641            0 :                                         s_ipsc->cCurrentModuleObject,
    9642            0 :                                         windowShadingControl.Name,
    9643            0 :                                         s_ipsc->cAlphaFieldNames(3),
    9644            0 :                                         s_ipsc->cAlphaArgs(3)));
    9645            0 :                 windowShadingControl.ShadingType = DataSurfaces::WinShadingType::IntShade;
    9646            0 :                 s_ipsc->cAlphaArgs(3) = "INTERIORSHADE";
    9647              :             }
    9648            4 :             if (s_ipsc->cAlphaArgs(3) == "EXTERIORNONINSULATINGSHADE" || s_ipsc->cAlphaArgs(3) == "EXTERIORINSULATINGSHADE") {
    9649            0 :                 ShowWarningError(state,
    9650            0 :                                  format("{}=\"{}\" is using obsolete {}=\"{}\", changing to \"ExteriorShade\"",
    9651            0 :                                         s_ipsc->cCurrentModuleObject,
    9652            0 :                                         windowShadingControl.Name,
    9653            0 :                                         s_ipsc->cAlphaFieldNames(3),
    9654            0 :                                         s_ipsc->cAlphaArgs(3)));
    9655            0 :                 windowShadingControl.ShadingType = DataSurfaces::WinShadingType::ExtShade;
    9656            0 :                 s_ipsc->cAlphaArgs(3) = "EXTERIORSHADE";
    9657              :             }
    9658              : 
    9659              :             // Check for illegal shading type name
    9660            4 :             Found = Util::FindItemInList(s_ipsc->cAlphaArgs(3), cValidShadingTypes, NumValidShadingTypes);
    9661            4 :             if (Found <= 1) {
    9662            0 :                 ErrorsFound = true;
    9663            0 :                 ShowSevereError(state,
    9664            0 :                                 format("{}=\"{}\" invalid {}=\"{}\".",
    9665            0 :                                        s_ipsc->cCurrentModuleObject,
    9666            0 :                                        windowShadingControl.Name,
    9667            0 :                                        s_ipsc->cAlphaFieldNames(3),
    9668            0 :                                        s_ipsc->cAlphaArgs(3)));
    9669              :             } else {
    9670            4 :                 windowShadingControl.ShadingType = DataSurfaces::WinShadingType(Found);
    9671              :             }
    9672              : 
    9673              :             // WindowShadingControl().getInputShadedConstruction is only used during GetInput process and is ultimately stored in
    9674              :             // Surface().shadedConstructionList
    9675            4 :             windowShadingControl.getInputShadedConstruction =
    9676            4 :                 Util::FindItemInList(s_ipsc->cAlphaArgs(4), state.dataConstruction->Construct, state.dataHeatBal->TotConstructs);
    9677            4 :             windowShadingControl.ShadingDevice = Material::GetMaterialNum(state, s_ipsc->cAlphaArgs(9));
    9678              : 
    9679            4 :             if (s_ipsc->lAlphaFieldBlanks(6)) {
    9680            3 :                 windowShadingControl.sched = Sched::GetScheduleAlwaysOn(state); // Not an availability schedule, but the default is constant-1.0
    9681            1 :             } else if ((windowShadingControl.sched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(6))) == nullptr) {
    9682            0 :                 ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(6), s_ipsc->cAlphaArgs(6));
    9683            0 :                 ErrorsFound = true;
    9684              :             }
    9685              : 
    9686            4 :             windowShadingControl.SetPoint = s_ipsc->rNumericArgs(2);
    9687            4 :             windowShadingControl.SetPoint2 = s_ipsc->rNumericArgs(3);
    9688            4 :             windowShadingControl.ShadingControlIsScheduled = getYesNoValue(s_ipsc->cAlphaArgs(7)) == BooleanSwitch::Yes;
    9689            4 :             windowShadingControl.GlareControlIsActive = getYesNoValue(s_ipsc->cAlphaArgs(8)) == BooleanSwitch::Yes;
    9690              : 
    9691            4 :             if (windowShadingControl.ShadingType != DataSurfaces::WinShadingType::IntBlind &&
    9692            3 :                 windowShadingControl.ShadingType != DataSurfaces::WinShadingType::ExtBlind &&
    9693            3 :                 windowShadingControl.ShadingType != DataSurfaces::WinShadingType::BGBlind) {
    9694            1 :             } else if (s_ipsc->cAlphaArgs(10).empty()) {
    9695            0 :                 ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(10), s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3));
    9696            0 :                 ErrorsFound = true;
    9697            1 :             } else if ((windowShadingControl.slatAngleControl = static_cast<DataSurfaces::SlatAngleControl>(
    9698            1 :                             getEnumValue(SlatAngleNamesUC, s_ipsc->cAlphaArgs(10)))) == DataSurfaces::SlatAngleControl::Invalid) {
    9699            0 :                 ShowSevereInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(10), s_ipsc->cAlphaArgs(10));
    9700            0 :                 ErrorsFound = true;
    9701            1 :             } else if (windowShadingControl.slatAngleControl != DataSurfaces::SlatAngleControl::Scheduled) {
    9702            0 :             } else if (s_ipsc->lAlphaFieldBlanks(11)) {
    9703            0 :                 ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(11), s_ipsc->cAlphaFieldNames(10), s_ipsc->cAlphaArgs(10));
    9704            0 :                 ErrorsFound = true;
    9705            0 :             } else if ((windowShadingControl.slatAngleSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(11))) == nullptr) {
    9706            0 :                 ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(11), s_ipsc->cAlphaArgs(11));
    9707            0 :                 ErrorsFound = true;
    9708              :             }
    9709              : 
    9710              :             // store the string for now and associate it after daylighting control objects are read
    9711            4 :             windowShadingControl.DaylightingControlName = s_ipsc->cAlphaArgs(12);
    9712              : 
    9713            4 :             windowShadingControl.multiSurfaceControl =
    9714            4 :                 static_cast<DataSurfaces::MultiSurfaceControl>(getEnumValue(MultiSurfaceControlNamesUC, s_ipsc->cAlphaArgs(13)));
    9715              : 
    9716            4 :             if (windowShadingControl.multiSurfaceControl == DataSurfaces::MultiSurfaceControl::Invalid) {
    9717            0 :                 windowShadingControl.multiSurfaceControl = DataSurfaces::MultiSurfaceControl::Sequential;
    9718            0 :                 ShowWarningError(state,
    9719            0 :                                  format("{}=\"{}\" should be either SEQUENTIAL or GROUP {}=\"{}\", defaulting to \"SEQUENTIAL\"",
    9720            0 :                                         s_ipsc->cCurrentModuleObject,
    9721            0 :                                         windowShadingControl.Name,
    9722            0 :                                         s_ipsc->cAlphaFieldNames(13),
    9723            0 :                                         s_ipsc->cAlphaArgs(13)));
    9724              :             }
    9725              : 
    9726            4 :             if (ControlNumAlpha >= 14) {
    9727            4 :                 windowShadingControl.FenestrationCount = ControlNumAlpha - 13;
    9728            4 :                 windowShadingControl.FenestrationName.allocate(windowShadingControl.FenestrationCount);
    9729            4 :                 windowShadingControl.FenestrationIndex.allocate(windowShadingControl.FenestrationCount);
    9730           15 :                 for (int i = 1; i <= windowShadingControl.FenestrationCount; i++) {
    9731           11 :                     windowShadingControl.FenestrationName(i) = s_ipsc->cAlphaArgs(i + 13);
    9732              :                 }
    9733              :             } else {
    9734            0 :                 ShowSevereError(state,
    9735            0 :                                 format("{}=\"{}\" invalid. Must reference at least one Fenestration Surface object name.",
    9736            0 :                                        s_ipsc->cCurrentModuleObject,
    9737            0 :                                        s_ipsc->cAlphaArgs(1)));
    9738              :             }
    9739              : 
    9740            4 :             windowShadingControl.shadingControlType = static_cast<DataSurfaces::WindowShadingControlType>(
    9741            4 :                 getEnumValue(WindowShadingControlTypeNamesUC, Util::makeUPPER(s_ipsc->cAlphaArgs(5))));
    9742              : 
    9743            4 :             if (windowShadingControl.ShadingDevice > 0) {
    9744            0 :                 if (s_mat->materials(windowShadingControl.ShadingDevice)->group == Material::Group::Screen &&
    9745            0 :                     !(windowShadingControl.shadingControlType == DataSurfaces::WindowShadingControlType::AlwaysOn ||
    9746            0 :                       windowShadingControl.shadingControlType == DataSurfaces::WindowShadingControlType::AlwaysOff ||
    9747            0 :                       windowShadingControl.shadingControlType == DataSurfaces::WindowShadingControlType::OnIfScheduled)) {
    9748            0 :                     ErrorsFound = true;
    9749            0 :                     ShowSevereError(state,
    9750            0 :                                     format("{}=\"{}\" invalid {}=\"{}\" for exterior screens.",
    9751            0 :                                            s_ipsc->cCurrentModuleObject,
    9752            0 :                                            windowShadingControl.Name,
    9753            0 :                                            s_ipsc->cAlphaFieldNames(5),
    9754            0 :                                            s_ipsc->cAlphaArgs(5)));
    9755            0 :                     ShowContinueError(state,
    9756              :                                       "Valid shading control types for exterior window screens are ALWAYSON, ALWAYSOFF, or ONIFSCHEDULEALLOWS.");
    9757              :                 }
    9758              :             } else {
    9759            4 :                 if (windowShadingControl.getInputShadedConstruction > 0) {
    9760            4 :                     state.dataConstruction->Construct(windowShadingControl.getInputShadedConstruction).IsUsed = true;
    9761            4 :                     if (s_mat->materials(state.dataConstruction->Construct(windowShadingControl.getInputShadedConstruction).LayerPoint(1))->group ==
    9762            4 :                             Material::Group::Screen &&
    9763            0 :                         !(windowShadingControl.shadingControlType == DataSurfaces::WindowShadingControlType::AlwaysOn ||
    9764            0 :                           windowShadingControl.shadingControlType == DataSurfaces::WindowShadingControlType::AlwaysOff ||
    9765            0 :                           windowShadingControl.shadingControlType == DataSurfaces::WindowShadingControlType::OnIfScheduled)) {
    9766            0 :                         ErrorsFound = true;
    9767            0 :                         ShowSevereError(state,
    9768            0 :                                         format("{}=\"{}\" invalid {}=\"{}\" for exterior screens.",
    9769            0 :                                                s_ipsc->cCurrentModuleObject,
    9770            0 :                                                windowShadingControl.Name,
    9771            0 :                                                s_ipsc->cAlphaFieldNames(5),
    9772            0 :                                                s_ipsc->cAlphaArgs(5)));
    9773            0 :                         ShowContinueError(state,
    9774              :                                           "Valid shading control types for exterior window screens are ALWAYSON, ALWAYSOFF, or ONIFSCHEDULEALLOWS.");
    9775              :                     }
    9776            0 :                 } else if (s_ipsc->lAlphaFieldBlanks(4)) {
    9777            0 :                     ShowSevereError(
    9778              :                         state,
    9779            0 :                         format("{}=\"{}\", {} is blank.", s_ipsc->cCurrentModuleObject, windowShadingControl.Name, s_ipsc->cAlphaFieldNames(4)));
    9780            0 :                     ShowContinueError(state, "A valid construction is required.");
    9781            0 :                     ErrorsFound = true;
    9782              :                 } else {
    9783            0 :                     ShowSevereError(
    9784              :                         state,
    9785            0 :                         format("{}=\"{}\", {} is invalid.", s_ipsc->cCurrentModuleObject, windowShadingControl.Name, s_ipsc->cAlphaFieldNames(4)));
    9786            0 :                     ShowContinueError(state, format("Construction=\"{}\" was used. A valid construction is required.", s_ipsc->cAlphaArgs(4)));
    9787            0 :                     ErrorsFound = true;
    9788              :                 }
    9789              :             }
    9790              : 
    9791              :             // Warning if setpoint is unintentionally zero
    9792            4 :             if (windowShadingControl.SetPoint == 0 && windowShadingControl.shadingControlType != DataSurfaces::WindowShadingControlType::AlwaysOn &&
    9793            2 :                 windowShadingControl.shadingControlType != DataSurfaces::WindowShadingControlType::AlwaysOff &&
    9794            2 :                 windowShadingControl.shadingControlType != DataSurfaces::WindowShadingControlType::OnIfScheduled &&
    9795            1 :                 windowShadingControl.shadingControlType != DataSurfaces::WindowShadingControlType::HiGlare) {
    9796            0 :                 ShowWarningError(state, format("{}=\"{}\", The first SetPoint is zero.", s_ipsc->cCurrentModuleObject, windowShadingControl.Name));
    9797            0 :                 ShowContinueError(state, "..You may have forgotten to specify that setpoint.");
    9798              :             }
    9799              : 
    9800              :             // Error checks
    9801            4 :             if (BooleanSwitch bs = getYesNoValue(s_ipsc->cAlphaArgs(7)); bs == BooleanSwitch::Invalid) { // Shading Control is Schedule field
    9802            0 :                 ShowSevereInvalidBool(state, eoh, s_ipsc->cAlphaFieldNames(7), s_ipsc->cAlphaArgs(7));
    9803            0 :                 ErrorsFound = true;
    9804              :             }
    9805              : 
    9806            4 :             if (BooleanSwitch bs = getYesNoValue(s_ipsc->cAlphaArgs(8)); bs == BooleanSwitch::Invalid) { // Shading Control is Schedule field
    9807            0 :                 ShowSevereInvalidBool(state, eoh, s_ipsc->cAlphaFieldNames(8), s_ipsc->cAlphaArgs(8));
    9808            0 :                 ErrorsFound = true;
    9809              :             }
    9810              : 
    9811            4 :             if ((windowShadingControl.shadingControlType == DataSurfaces::WindowShadingControlType::OnIfScheduled) &&
    9812            1 :                 (!windowShadingControl.ShadingControlIsScheduled)) { // CR 7709 BG
    9813            0 :                 ErrorsFound = true;
    9814            0 :                 ShowSevereError(state,
    9815            0 :                                 format("{} = \"{}\" invalid, {} must be set to \"Yes\" for {} = OnIfScheduleAllows",
    9816            0 :                                        s_ipsc->cCurrentModuleObject,
    9817            0 :                                        windowShadingControl.Name,
    9818            0 :                                        s_ipsc->cAlphaFieldNames(7),
    9819            0 :                                        s_ipsc->cAlphaFieldNames(5)));
    9820              :             }
    9821              : 
    9822            4 :             if (windowShadingControl.shadingControlType == DataSurfaces::WindowShadingControlType::MeetDaylIlumSetp &&
    9823            0 :                 windowShadingControl.ShadingType != DataSurfaces::WinShadingType::SwitchableGlazing) {
    9824            0 :                 ErrorsFound = true;
    9825            0 :                 ShowSevereError(state,
    9826            0 :                                 format("{}=\"{}\" invalid {}=\"{}\".",
    9827            0 :                                        s_ipsc->cCurrentModuleObject,
    9828            0 :                                        windowShadingControl.Name,
    9829            0 :                                        s_ipsc->cAlphaFieldNames(3),
    9830            0 :                                        s_ipsc->cAlphaArgs(3)));
    9831            0 :                 ShowContinueError(state,
    9832            0 :                                   format("...{} must be SwitchableGlazing for this control, but entered type=\"{}\".",
    9833            0 :                                          s_ipsc->cAlphaFieldNames(3),
    9834            0 :                                          s_ipsc->cAlphaArgs(3)));
    9835              :             }
    9836              : 
    9837            4 :             DataSurfaces::WinShadingType ShTyp = windowShadingControl.ShadingType;
    9838            4 :             IShadedConst = windowShadingControl.getInputShadedConstruction;
    9839            4 :             IShadingDevice = windowShadingControl.ShadingDevice;
    9840              : 
    9841            4 :             if (IShadedConst == 0 && IShadingDevice == 0) {
    9842            0 :                 ShowSevereError(state,
    9843            0 :                                 format("{}=\"{}\" has no matching shaded construction or shading device.",
    9844            0 :                                        s_ipsc->cCurrentModuleObject,
    9845            0 :                                        windowShadingControl.Name));
    9846            0 :                 ErrorsFound = true;
    9847            4 :             } else if (IShadedConst == 0 && IShadingDevice > 0) {
    9848            0 :                 if (ShTyp == DataSurfaces::WinShadingType::SwitchableGlazing) {
    9849            0 :                     ShowSevereError(state,
    9850            0 :                                     format("{}=\"{}\" has {}= SwitchableGlazing but no matching shaded construction",
    9851            0 :                                            s_ipsc->cCurrentModuleObject,
    9852            0 :                                            windowShadingControl.Name,
    9853            0 :                                            s_ipsc->cAlphaArgs(3)));
    9854            0 :                     ErrorsFound = true;
    9855              :                 }
    9856            0 :                 if ((ShTyp == DataSurfaces::WinShadingType::IntShade || ShTyp == DataSurfaces::WinShadingType::ExtShade) &&
    9857            0 :                     s_mat->materials(IShadingDevice)->group != Material::Group::Shade) {
    9858            0 :                     ShowSevereError(state,
    9859            0 :                                     format("{}=\"{}\" has {}= InteriorShade or ExteriorShade but matching shading device is not a window shade",
    9860            0 :                                            s_ipsc->cCurrentModuleObject,
    9861            0 :                                            windowShadingControl.Name,
    9862            0 :                                            s_ipsc->cAlphaArgs(3)));
    9863            0 :                     ShowContinueError(state, format("{} in error=\"{}\".", s_ipsc->cAlphaFieldNames(8), s_mat->materials(IShadingDevice)->Name));
    9864            0 :                     ErrorsFound = true;
    9865              :                 }
    9866            0 :                 if ((ShTyp == DataSurfaces::WinShadingType::ExtScreen) && s_mat->materials(IShadingDevice)->group != Material::Group::Screen) {
    9867            0 :                     ShowSevereError(state,
    9868            0 :                                     format("{}=\"{}\" has {}= ExteriorScreen but matching shading device is not a window screen",
    9869            0 :                                            s_ipsc->cCurrentModuleObject,
    9870            0 :                                            windowShadingControl.Name,
    9871            0 :                                            s_ipsc->cAlphaArgs(3)));
    9872            0 :                     ShowContinueError(state, format("{} in error=\"{}\".", s_ipsc->cAlphaFieldNames(8), s_mat->materials(IShadingDevice)->Name));
    9873            0 :                     ErrorsFound = true;
    9874              :                 }
    9875            0 :                 if ((ShTyp == DataSurfaces::WinShadingType::IntBlind || ShTyp == DataSurfaces::WinShadingType::ExtBlind) &&
    9876            0 :                     s_mat->materials(IShadingDevice)->group != Material::Group::Blind) {
    9877            0 :                     ShowSevereError(state,
    9878            0 :                                     format("{}=\"{}\" has {}= InteriorBlind or ExteriorBlind but matching shading device is not a window blind",
    9879            0 :                                            s_ipsc->cCurrentModuleObject,
    9880            0 :                                            windowShadingControl.Name,
    9881            0 :                                            s_ipsc->cAlphaArgs(3)));
    9882            0 :                     ShowContinueError(state, format("{} in error=\"{}\".", s_ipsc->cAlphaFieldNames(8), s_mat->materials(IShadingDevice)->Name));
    9883            0 :                     ErrorsFound = true;
    9884              :                 }
    9885            0 :                 if (ShTyp == DataSurfaces::WinShadingType::BGShade || ShTyp == DataSurfaces::WinShadingType::BGBlind) {
    9886            0 :                     ShowSevereError(state,
    9887            0 :                                     format("{}=\"{}\" has {}= BetweenGlassShade or BetweenGlassBlind and",
    9888            0 :                                            s_ipsc->cCurrentModuleObject,
    9889            0 :                                            windowShadingControl.Name,
    9890            0 :                                            s_ipsc->cAlphaArgs(3)));
    9891            0 :                     ShowContinueError(state,
    9892            0 :                                       format("{} is specified. This is illegal. Specify shaded construction instead.", s_ipsc->cAlphaFieldNames(8)));
    9893            0 :                     ErrorsFound = true;
    9894              :                 }
    9895            4 :             } else if (IShadedConst > 0 && IShadingDevice > 0) {
    9896            0 :                 IShadingDevice = 0;
    9897            0 :                 ShowWarningError(state,
    9898            0 :                                  format("{}=\"{}\" Both {} and {} are specified.",
    9899            0 :                                         s_ipsc->cCurrentModuleObject,
    9900            0 :                                         windowShadingControl.Name,
    9901            0 :                                         s_ipsc->cAlphaFieldNames(4),
    9902            0 :                                         s_ipsc->cAlphaFieldNames(9)));
    9903            0 :                 ShowContinueError(
    9904            0 :                     state, format("The {}=\"{}\" will be used.", s_ipsc->cAlphaFieldNames(4), state.dataConstruction->Construct(IShadedConst).Name));
    9905              :             }
    9906              : 
    9907              :             // If type = interior or exterior shade or blind require that the shaded construction
    9908              :             // have a shade layer in the correct position
    9909            4 :             if (IShadedConst != 0) {
    9910              : 
    9911            4 :                 NLayers = state.dataConstruction->Construct(IShadedConst).TotLayers;
    9912            4 :                 BGShadeBlindError = false;
    9913            4 :                 IShadingDevice = 0;
    9914            4 :                 if (state.dataConstruction->Construct(IShadedConst).LayerPoint(NLayers) != 0) {
    9915            4 :                     if (windowShadingControl.ShadingType == DataSurfaces::WinShadingType::IntShade) {
    9916            1 :                         IShadingDevice = state.dataConstruction->Construct(IShadedConst).LayerPoint(NLayers);
    9917            1 :                         if (s_mat->materials(state.dataConstruction->Construct(IShadedConst).LayerPoint(NLayers))->group != Material::Group::Shade) {
    9918            0 :                             ErrorsFound = true;
    9919            0 :                             ShowSevereError(state,
    9920            0 :                                             format("{}=\"{}\" the {}=\"{}\"",
    9921            0 :                                                    s_ipsc->cCurrentModuleObject,
    9922            0 :                                                    windowShadingControl.Name,
    9923            0 :                                                    s_ipsc->cAlphaFieldNames(4),
    9924            0 :                                                    s_ipsc->cAlphaArgs(4)));
    9925            0 :                             ShowContinueError(state,
    9926            0 :                                               format("of {}=\"{}\" should have a shade layer on the inside of the window.",
    9927            0 :                                                      s_ipsc->cAlphaFieldNames(3),
    9928            0 :                                                      s_ipsc->cAlphaArgs(3)));
    9929              :                         }
    9930            3 :                     } else if (windowShadingControl.ShadingType == DataSurfaces::WinShadingType::ExtShade) {
    9931            0 :                         IShadingDevice = state.dataConstruction->Construct(IShadedConst).LayerPoint(1);
    9932            0 :                         if (s_mat->materials(state.dataConstruction->Construct(IShadedConst).LayerPoint(1))->group != Material::Group::Shade) {
    9933            0 :                             ErrorsFound = true;
    9934            0 :                             ShowSevereError(state,
    9935            0 :                                             format("{}=\"{}\" the {}=\"{}\"",
    9936            0 :                                                    s_ipsc->cCurrentModuleObject,
    9937            0 :                                                    windowShadingControl.Name,
    9938            0 :                                                    s_ipsc->cAlphaFieldNames(43),
    9939            0 :                                                    s_ipsc->cAlphaArgs(4)));
    9940            0 :                             ShowContinueError(state,
    9941            0 :                                               format("of {}=\"{}\" should have a shade layer on the outside of the window.",
    9942            0 :                                                      s_ipsc->cAlphaFieldNames(3),
    9943            0 :                                                      s_ipsc->cAlphaArgs(3)));
    9944              :                         }
    9945            3 :                     } else if (windowShadingControl.ShadingType == DataSurfaces::WinShadingType::ExtScreen) {
    9946            0 :                         IShadingDevice = state.dataConstruction->Construct(IShadedConst).LayerPoint(1);
    9947            0 :                         if (s_mat->materials(state.dataConstruction->Construct(IShadedConst).LayerPoint(1))->group != Material::Group::Screen) {
    9948            0 :                             ErrorsFound = true;
    9949            0 :                             ShowSevereError(state,
    9950            0 :                                             format("{}=\"{}\" the {}=\"{}\"",
    9951            0 :                                                    s_ipsc->cCurrentModuleObject,
    9952            0 :                                                    windowShadingControl.Name,
    9953            0 :                                                    s_ipsc->cAlphaFieldNames(4),
    9954            0 :                                                    s_ipsc->cAlphaArgs(4)));
    9955            0 :                             ShowContinueError(state,
    9956            0 :                                               format("of {}=\"{}\" should have a screen layer on the outside of the window.",
    9957            0 :                                                      s_ipsc->cAlphaFieldNames(3),
    9958            0 :                                                      s_ipsc->cAlphaArgs(3)));
    9959              :                         }
    9960            3 :                     } else if (windowShadingControl.ShadingType == DataSurfaces::WinShadingType::IntBlind) {
    9961            1 :                         IShadingDevice = state.dataConstruction->Construct(IShadedConst).LayerPoint(NLayers);
    9962            1 :                         if (s_mat->materials(state.dataConstruction->Construct(IShadedConst).LayerPoint(NLayers))->group != Material::Group::Blind) {
    9963            0 :                             ErrorsFound = true;
    9964            0 :                             ShowSevereError(state,
    9965            0 :                                             format("{}=\"{}\" the {}=\"{}\"",
    9966            0 :                                                    s_ipsc->cCurrentModuleObject,
    9967            0 :                                                    windowShadingControl.Name,
    9968            0 :                                                    s_ipsc->cAlphaFieldNames(4),
    9969            0 :                                                    s_ipsc->cAlphaArgs(4)));
    9970            0 :                             ShowContinueError(state,
    9971            0 :                                               format("of {}=\"{}\" should have a blind layer on the inside of the window.",
    9972            0 :                                                      s_ipsc->cAlphaFieldNames(3),
    9973            0 :                                                      s_ipsc->cAlphaArgs(3)));
    9974              :                         }
    9975            2 :                     } else if (windowShadingControl.ShadingType == DataSurfaces::WinShadingType::ExtBlind) {
    9976            0 :                         IShadingDevice = state.dataConstruction->Construct(IShadedConst).LayerPoint(1);
    9977            0 :                         if (s_mat->materials(state.dataConstruction->Construct(IShadedConst).LayerPoint(1))->group != Material::Group::Blind) {
    9978            0 :                             ErrorsFound = true;
    9979            0 :                             ShowSevereError(state,
    9980            0 :                                             format("{}=\"{}\" the {}=\"{}\"",
    9981            0 :                                                    s_ipsc->cCurrentModuleObject,
    9982            0 :                                                    windowShadingControl.Name,
    9983            0 :                                                    s_ipsc->cAlphaFieldNames(4),
    9984            0 :                                                    s_ipsc->cAlphaArgs(4)));
    9985            0 :                             ShowContinueError(state,
    9986            0 :                                               format("of {}=\"{}\" should have a blind layer on the outside of the window.",
    9987            0 :                                                      s_ipsc->cAlphaFieldNames(3),
    9988            0 :                                                      s_ipsc->cAlphaArgs(3)));
    9989              :                         }
    9990            2 :                     } else if (windowShadingControl.ShadingType == DataSurfaces::WinShadingType::BGShade) {
    9991            0 :                         if (NLayers != 5 && NLayers != 7) {
    9992            0 :                             BGShadeBlindError = true;
    9993              :                         }
    9994            0 :                         if (NLayers == 5) {
    9995            0 :                             if (s_mat->materials(state.dataConstruction->Construct(IShadedConst).LayerPoint(3))->group != Material::Group::Shade) {
    9996            0 :                                 BGShadeBlindError = true;
    9997              :                             }
    9998              :                         }
    9999            0 :                         if (NLayers == 7) {
   10000            0 :                             if (s_mat->materials(state.dataConstruction->Construct(IShadedConst).LayerPoint(5))->group != Material::Group::Shade) {
   10001            0 :                                 BGShadeBlindError = true;
   10002              :                             }
   10003              :                         }
   10004            0 :                         if (BGShadeBlindError) {
   10005            0 :                             ErrorsFound = true;
   10006            0 :                             ShowSevereError(state,
   10007            0 :                                             format("{}=\"{}\" the {}=\"{}\"",
   10008            0 :                                                    s_ipsc->cCurrentModuleObject,
   10009            0 :                                                    windowShadingControl.Name,
   10010            0 :                                                    s_ipsc->cAlphaFieldNames(4),
   10011            0 :                                                    s_ipsc->cAlphaArgs(4)));
   10012            0 :                             ShowContinueError(state,
   10013            0 :                                               format("of {}=\"{}\" should have two or three glass layers and a",
   10014            0 :                                                      s_ipsc->cAlphaFieldNames(3),
   10015            0 :                                                      s_ipsc->cAlphaArgs(3)));
   10016            0 :                             ShowContinueError(state, "between-glass shade layer with a gas layer on each side.");
   10017              :                         }
   10018            2 :                     } else if (windowShadingControl.ShadingType == DataSurfaces::WinShadingType::BGBlind) {
   10019            0 :                         if (NLayers != 5 && NLayers != 7) {
   10020            0 :                             BGShadeBlindError = true;
   10021              :                         }
   10022            0 :                         if (NLayers == 5) {
   10023            0 :                             if (s_mat->materials(state.dataConstruction->Construct(IShadedConst).LayerPoint(3))->group != Material::Group::Blind) {
   10024            0 :                                 BGShadeBlindError = true;
   10025              :                             }
   10026              :                         }
   10027            0 :                         if (NLayers == 7) {
   10028            0 :                             if (s_mat->materials(state.dataConstruction->Construct(IShadedConst).LayerPoint(5))->group != Material::Group::Blind) {
   10029            0 :                                 BGShadeBlindError = true;
   10030              :                             }
   10031              :                         }
   10032            0 :                         if (BGShadeBlindError) {
   10033            0 :                             ErrorsFound = true;
   10034            0 :                             ShowSevereError(state,
   10035            0 :                                             format("{}=\"{}\" the {}=\"{}\"",
   10036            0 :                                                    s_ipsc->cCurrentModuleObject,
   10037            0 :                                                    windowShadingControl.Name,
   10038            0 :                                                    s_ipsc->cAlphaFieldNames(4),
   10039            0 :                                                    s_ipsc->cAlphaArgs(4)));
   10040            0 :                             ShowContinueError(state,
   10041            0 :                                               format("of {}=\"{}\" should have two or three glass layers and a",
   10042            0 :                                                      s_ipsc->cAlphaFieldNames(3),
   10043            0 :                                                      s_ipsc->cAlphaArgs(3)));
   10044            0 :                             ShowContinueError(state, "between-glass blind layer with a gas layer on each side.");
   10045              :                         }
   10046              :                     }
   10047              :                 }
   10048            4 :                 if (IShadingDevice > 0) {
   10049            3 :                     if ((ShTyp == DataSurfaces::WinShadingType::IntShade || ShTyp == DataSurfaces::WinShadingType::ExtShade) &&
   10050            1 :                         s_mat->materials(IShadingDevice)->group != Material::Group::Shade) {
   10051            0 :                         ShowSevereError(state,
   10052            0 :                                         format("{}=\"{}\" has {}= InteriorShade or ExteriorShade but matching shading device is not a window shade",
   10053            0 :                                                s_ipsc->cCurrentModuleObject,
   10054            0 :                                                windowShadingControl.Name,
   10055            0 :                                                s_ipsc->cAlphaFieldNames(3)));
   10056            0 :                         ShowContinueError(state, format("Shading Device in error=\"{}\".", s_mat->materials(IShadingDevice)->Name));
   10057            0 :                         ErrorsFound = true;
   10058              :                     }
   10059            2 :                     if ((ShTyp == DataSurfaces::WinShadingType::ExtScreen) && s_mat->materials(IShadingDevice)->group != Material::Group::Screen) {
   10060            0 :                         ShowSevereError(state,
   10061            0 :                                         format("{}=\"{}\" has {}= ExteriorScreen but matching shading device is not an exterior window screen.",
   10062            0 :                                                s_ipsc->cCurrentModuleObject,
   10063            0 :                                                windowShadingControl.Name,
   10064            0 :                                                s_ipsc->cAlphaFieldNames(3)));
   10065            0 :                         ShowContinueError(state, format("Shading Device in error=\"{}\".", s_mat->materials(IShadingDevice)->Name));
   10066            0 :                         ErrorsFound = true;
   10067              :                     }
   10068            3 :                     if ((ShTyp == DataSurfaces::WinShadingType::IntBlind || ShTyp == DataSurfaces::WinShadingType::ExtBlind) &&
   10069            1 :                         s_mat->materials(IShadingDevice)->group != Material::Group::Blind) {
   10070            0 :                         ShowSevereError(state,
   10071            0 :                                         format("{}=\"{}\" has {}= InteriorBlind or ExteriorBlind but matching shading device is not a window blind.",
   10072            0 :                                                s_ipsc->cCurrentModuleObject,
   10073            0 :                                                windowShadingControl.Name,
   10074            0 :                                                s_ipsc->cAlphaFieldNames(3)));
   10075            0 :                         ShowContinueError(state, format("Shading Device in error=\"{}\".", s_mat->materials(IShadingDevice)->Name));
   10076            0 :                         ErrorsFound = true;
   10077              :                     }
   10078              :                 }
   10079              :             }
   10080              :         } // End of loop over window shading controls
   10081              :     }
   10082              : 
   10083          218 :     void InitialAssociateWindowShadingControlFenestration(EnergyPlusData &state, bool &ErrorsFound, int SurfNum)
   10084              :     {
   10085          218 :         auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
   10086              :         // J.Glazer 2018 - operates on SurfaceTmp array before final indices are known for windows and sets the activeWindowShadingControl
   10087          273 :         for (int iShadeCtrl = 1; iShadeCtrl <= state.dataSurface->TotWinShadingControl; ++iShadeCtrl) {
   10088           55 :             int curShadedConstruction = state.dataSurface->WindowShadingControl(iShadeCtrl).getInputShadedConstruction;
   10089          257 :             for (int jFeneRef = 1; jFeneRef <= state.dataSurface->WindowShadingControl(iShadeCtrl).FenestrationCount; ++jFeneRef) {
   10090          202 :                 if (Util::SameString(state.dataSurface->WindowShadingControl(iShadeCtrl).FenestrationName(jFeneRef), surfTemp.Name)) {
   10091           29 :                     state.dataGlobal->AndShadingControlInModel = true;
   10092           29 :                     surfTemp.HasShadeControl = true;
   10093           29 :                     surfTemp.windowShadingControlList.push_back(iShadeCtrl);
   10094           29 :                     surfTemp.activeWindowShadingControl = iShadeCtrl;
   10095           29 :                     surfTemp.shadedConstructionList.push_back(curShadedConstruction);
   10096           29 :                     surfTemp.activeShadedConstruction = curShadedConstruction;
   10097              : 
   10098              :                     // check to make the window refenced is an exterior window
   10099           29 :                     if (surfTemp.ExtBoundCond != DataSurfaces::ExternalEnvironment) {
   10100            0 :                         ErrorsFound = true;
   10101            0 :                         ShowSevereError(
   10102              :                             state,
   10103            0 :                             format("InitialAssociateWindowShadingControlFenestration: \"{}\", invalid  because it is not an exterior window.",
   10104            0 :                                    surfTemp.Name));
   10105            0 :                         ShowContinueError(
   10106              :                             state,
   10107            0 :                             format(".. It appears on WindowShadingControl object: \"{}", state.dataSurface->WindowShadingControl(iShadeCtrl).Name));
   10108              :                     }
   10109              :                     // check to make sure the window is not using equivalent layer window construction
   10110           29 :                     if (state.dataConstruction->Construct(surfTemp.Construction).WindowTypeEQL) {
   10111            0 :                         ErrorsFound = true;
   10112            0 :                         ShowSevereError(state, format("InitialAssociateWindowShadingControlFenestration: =\"{}\", invalid \".", surfTemp.Name));
   10113            0 :                         ShowContinueError(state, ".. equivalent layer window model does not use shading control object.");
   10114            0 :                         ShowContinueError(state, ".. Shading control is set to none or zero, and simulation continues.");
   10115            0 :                         ShowContinueError(
   10116              :                             state,
   10117            0 :                             format(".. It appears on WindowShadingControl object: \"{}", state.dataSurface->WindowShadingControl(iShadeCtrl).Name));
   10118            0 :                         surfTemp.activeWindowShadingControl = 0;
   10119              :                     }
   10120              :                 }
   10121              :             }
   10122              :         }
   10123          218 :     }
   10124              : 
   10125          225 :     void FinalAssociateWindowShadingControlFenestration(EnergyPlusData &state, bool &ErrorsFound)
   10126              :     {
   10127              :         // J.Glazer 2018 - operates on Surface array after final indices are known for windows and checks to make sure it is correct
   10128          232 :         for (int iShadeCtrl = 1; iShadeCtrl <= state.dataSurface->TotWinShadingControl; ++iShadeCtrl) {
   10129           27 :             for (int jFeneRef = 1; jFeneRef <= state.dataSurface->WindowShadingControl(iShadeCtrl).FenestrationCount; ++jFeneRef) {
   10130           20 :                 int fenestrationIndex = Util::FindItemInList(state.dataSurface->WindowShadingControl(iShadeCtrl).FenestrationName(jFeneRef),
   10131           20 :                                                              state.dataSurface->Surface,
   10132           20 :                                                              state.dataSurface->TotSurfaces);
   10133           40 :                 if (std::find(state.dataSurface->Surface(fenestrationIndex).windowShadingControlList.begin(),
   10134           40 :                               state.dataSurface->Surface(fenestrationIndex).windowShadingControlList.end(),
   10135           60 :                               iShadeCtrl) != state.dataSurface->Surface(fenestrationIndex).windowShadingControlList.end()) {
   10136           20 :                     state.dataSurface->WindowShadingControl(iShadeCtrl).FenestrationIndex(jFeneRef) = fenestrationIndex;
   10137              :                 } else {
   10138              :                     // this error condition should not occur since the rearrangement of Surface() from SurfureTmp() is reliable.
   10139            0 :                     ErrorsFound = true;
   10140            0 :                     ShowSevereError(state,
   10141            0 :                                     format("FinalAssociateWindowShadingControlFenestration: Fenestration surface named \"{}\" has "
   10142              :                                            "WindowShadingContol index that does not match the initial index assigned.",
   10143            0 :                                            state.dataSurface->Surface(fenestrationIndex).Name));
   10144            0 :                     ShowContinueError(state,
   10145            0 :                                       format("This occurs while WindowShadingControl object: \"{}\" is being evaluated. ",
   10146            0 :                                              state.dataSurface->WindowShadingControl(iShadeCtrl).Name));
   10147              :                 }
   10148              :             }
   10149              :         }
   10150          225 :     }
   10151              : 
   10152          226 :     void CheckWindowShadingControlSimilarForWindow(EnergyPlusData &state, bool &ErrorsFound)
   10153              :     {
   10154              :         // For each window check if all window shading controls on list are the same except for name, schedule name, construction, and
   10155              :         // material
   10156         2488 :         for (auto &theSurf : state.dataSurface->Surface) {
   10157         2262 :             if (theSurf.HasShadeControl) {
   10158           13 :                 if (theSurf.windowShadingControlList.size() > 1) {
   10159            2 :                     int firstWindowShadingControl = theSurf.windowShadingControlList.front();
   10160            8 :                     for (auto wsc = std::next(theSurf.windowShadingControlList.begin()); wsc != theSurf.windowShadingControlList.end(); ++wsc) {
   10161            4 :                         if (!isWindowShadingControlSimilar(state, firstWindowShadingControl, *wsc)) {
   10162            1 :                             ErrorsFound = true;
   10163            2 :                             ShowSevereError(state,
   10164            2 :                                             format("CheckWindowShadingControlSimilarForWindow: Fenestration surface named \"{}\" has multiple "
   10165              :                                                    "WindowShadingContols that are not similar.",
   10166            1 :                                                    theSurf.Name));
   10167            2 :                             ShowContinueError(state,
   10168            2 :                                               format("for: \"{} and: {}",
   10169            1 :                                                      state.dataSurface->WindowShadingControl(firstWindowShadingControl).Name,
   10170            1 :                                                      state.dataSurface->WindowShadingControl(*wsc).Name));
   10171              :                         }
   10172            2 :                     }
   10173              :                 }
   10174              :             }
   10175          226 :         }
   10176          226 :     }
   10177              : 
   10178           24 :     bool isWindowShadingControlSimilar(EnergyPlusData &state, int a, int b)
   10179              :     {
   10180              :         // Compares two window shading controls are the same except for the name, schedule name, construction, and material
   10181           24 :         auto const &WindowShadingControlA = state.dataSurface->WindowShadingControl(a);
   10182           24 :         auto const &WindowShadingControlB = state.dataSurface->WindowShadingControl(b);
   10183           47 :         return (WindowShadingControlA.ZoneIndex == WindowShadingControlB.ZoneIndex &&
   10184           23 :                 WindowShadingControlA.ShadingType == WindowShadingControlB.ShadingType &&
   10185           22 :                 WindowShadingControlA.shadingControlType == WindowShadingControlB.shadingControlType &&
   10186           21 :                 WindowShadingControlA.SetPoint == WindowShadingControlB.SetPoint &&
   10187           19 :                 WindowShadingControlA.ShadingControlIsScheduled == WindowShadingControlB.ShadingControlIsScheduled &&
   10188           18 :                 WindowShadingControlA.GlareControlIsActive == WindowShadingControlB.GlareControlIsActive &&
   10189           17 :                 WindowShadingControlA.slatAngleControl == WindowShadingControlB.slatAngleControl &&
   10190           31 :                 WindowShadingControlA.SetPoint2 == WindowShadingControlB.SetPoint2 &&
   10191           15 :                 WindowShadingControlA.DaylightingControlName == WindowShadingControlB.DaylightingControlName &&
   10192           60 :                 WindowShadingControlA.DaylightControlIndex == WindowShadingControlB.DaylightControlIndex &&
   10193           37 :                 WindowShadingControlA.multiSurfaceControl == WindowShadingControlB.multiSurfaceControl);
   10194              :     }
   10195              : 
   10196          192 :     void GetStormWindowData(EnergyPlusData &state, bool &ErrorsFound) // If errors found in input
   10197              :     {
   10198              : 
   10199              :         // SUBROUTINE INFORMATION:
   10200              :         //       AUTHOR         Fred Winkelmann
   10201              :         //       DATE WRITTEN   December 2003
   10202              : 
   10203              :         // PURPOSE OF THIS SUBROUTINE:
   10204              :         // Reads in the storm window data from the input file, interprets it and puts it in the derived type
   10205              : 
   10206              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
   10207              :         int IOStat;           // IO Status when calling get input subroutine
   10208              :         int StormWinNumAlpha; // Number of alpha names being passed
   10209              :         int StormWinNumProp;  // Number of properties being passed
   10210              :         int loop;             // Do loop counter
   10211              : 
   10212          192 :         auto &s_ipsc = state.dataIPShortCut;
   10213          192 :         auto &s_mat = state.dataMaterial;
   10214              : 
   10215              :         // Get the total number of storm window input objects
   10216          192 :         s_ipsc->cCurrentModuleObject = "WindowProperty:StormWindow";
   10217          192 :         state.dataSurface->TotStormWin = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
   10218          192 :         if (state.dataSurface->TotStormWin == 0) {
   10219          192 :             return;
   10220              :         }
   10221              : 
   10222            0 :         state.dataSurface->StormWindow.allocate(state.dataSurface->TotStormWin);
   10223              : 
   10224            0 :         int StormWinNum = 0;
   10225            0 :         for (loop = 1; loop <= state.dataSurface->TotStormWin; ++loop) {
   10226              : 
   10227            0 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
   10228            0 :                                                                      s_ipsc->cCurrentModuleObject,
   10229              :                                                                      loop,
   10230            0 :                                                                      s_ipsc->cAlphaArgs,
   10231              :                                                                      StormWinNumAlpha,
   10232            0 :                                                                      s_ipsc->rNumericArgs,
   10233              :                                                                      StormWinNumProp,
   10234              :                                                                      IOStat,
   10235            0 :                                                                      s_ipsc->lNumericFieldBlanks,
   10236            0 :                                                                      s_ipsc->lAlphaFieldBlanks,
   10237            0 :                                                                      s_ipsc->cAlphaFieldNames,
   10238            0 :                                                                      s_ipsc->cNumericFieldNames);
   10239            0 :             ++StormWinNum;
   10240            0 :             state.dataSurface->StormWindow(StormWinNum).BaseWindowNum =
   10241            0 :                 Util::FindItemInList(s_ipsc->cAlphaArgs(1), state.dataSurface->Surface, state.dataSurface->TotSurfaces);
   10242            0 :             state.dataSurface->StormWindow(StormWinNum).StormWinMaterialNum = Material::GetMaterialNum(state, s_ipsc->cAlphaArgs(2));
   10243            0 :             state.dataSurface->StormWindow(StormWinNum).StormWinDistance = s_ipsc->rNumericArgs(1);
   10244            0 :             state.dataSurface->StormWindow(StormWinNum).MonthOn = s_ipsc->rNumericArgs(2);
   10245            0 :             state.dataSurface->StormWindow(StormWinNum).DayOfMonthOn = s_ipsc->rNumericArgs(3);
   10246            0 :             state.dataSurface->StormWindow(StormWinNum).DateOn =
   10247            0 :                 General::OrdinalDay(state.dataSurface->StormWindow(StormWinNum).MonthOn, state.dataSurface->StormWindow(StormWinNum).DayOfMonthOn, 1);
   10248            0 :             state.dataSurface->StormWindow(StormWinNum).MonthOff = s_ipsc->rNumericArgs(4);
   10249            0 :             state.dataSurface->StormWindow(StormWinNum).DayOfMonthOff = s_ipsc->rNumericArgs(5);
   10250            0 :             state.dataSurface->StormWindow(StormWinNum).DateOff = General::OrdinalDay(
   10251            0 :                 state.dataSurface->StormWindow(StormWinNum).MonthOff, state.dataSurface->StormWindow(StormWinNum).DayOfMonthOff, 1);
   10252              : 
   10253            0 :             if (state.dataSurface->StormWindow(StormWinNum).DateOn == state.dataSurface->StormWindow(StormWinNum).DateOff) {
   10254            0 :                 ShowSevereError(state,
   10255            0 :                                 format("{}: Date On = Date Off -- not allowed, occurred in WindowProperty:StormWindow Input #{}",
   10256            0 :                                        s_ipsc->cCurrentModuleObject,
   10257              :                                        StormWinNum));
   10258            0 :                 ErrorsFound = true;
   10259              :             }
   10260              : 
   10261              :             enum Month
   10262              :             {
   10263              :                 January = 1,
   10264              :                 February,
   10265              :                 March,
   10266              :                 April,
   10267              :                 May,
   10268              :                 June,
   10269              :                 July,
   10270              :                 August,
   10271              :                 September,
   10272              :                 October,
   10273              :                 November,
   10274              :                 December
   10275              :             };
   10276            0 :             constexpr std::array<int, 13> oneBasedDaysInMonth = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
   10277              : 
   10278            0 :             int const monthOn = state.dataSurface->StormWindow(StormWinNum).MonthOn;
   10279            0 :             if (monthOn >= January && monthOn <= December) {
   10280            0 :                 if (state.dataSurface->StormWindow(StormWinNum).DayOfMonthOn >
   10281            0 :                     oneBasedDaysInMonth[state.dataSurface->StormWindow(StormWinNum).MonthOn]) {
   10282            0 :                     ShowSevereError(state,
   10283            0 :                                     format("{}: Date On (Day of Month) [{}], invalid for WindowProperty:StormWindow Input #{}",
   10284            0 :                                            s_ipsc->cCurrentModuleObject,
   10285            0 :                                            state.dataSurface->StormWindow(StormWinNum).DayOfMonthOn,
   10286              :                                            StormWinNum));
   10287            0 :                     ErrorsFound = true;
   10288              :                 }
   10289            0 :                 break;
   10290              :             } else {
   10291            0 :                 ShowSevereError(state,
   10292            0 :                                 format("{}: Date On Month [{}], invalid for WindowProperty:StormWindow Input #{}",
   10293            0 :                                        s_ipsc->cCurrentModuleObject,
   10294            0 :                                        state.dataSurface->StormWindow(StormWinNum).MonthOn,
   10295              :                                        StormWinNum));
   10296            0 :                 ErrorsFound = true;
   10297              :             }
   10298              : 
   10299            0 :             int const monthOff = state.dataSurface->StormWindow(StormWinNum).MonthOff;
   10300            0 :             if (monthOff >= January && monthOff <= December) {
   10301            0 :                 if (state.dataSurface->StormWindow(StormWinNum).DayOfMonthOff >
   10302            0 :                     oneBasedDaysInMonth[state.dataSurface->StormWindow(StormWinNum).MonthOff]) {
   10303            0 :                     ShowSevereError(state,
   10304            0 :                                     format("{}: Date Off (Day of Month) [{}], invalid for WindowProperty:StormWindow Input #{}",
   10305            0 :                                            s_ipsc->cCurrentModuleObject,
   10306            0 :                                            state.dataSurface->StormWindow(StormWinNum).DayOfMonthOff,
   10307              :                                            StormWinNum));
   10308            0 :                     ErrorsFound = true;
   10309              :                 }
   10310            0 :                 break;
   10311              :             } else {
   10312            0 :                 ShowSevereError(state,
   10313            0 :                                 format("{}: Date Off Month [{}], invalid for WindowProperty:StormWindow Input #{}",
   10314            0 :                                        s_ipsc->cCurrentModuleObject,
   10315            0 :                                        state.dataSurface->StormWindow(StormWinNum).MonthOff,
   10316              :                                        StormWinNum));
   10317            0 :                 ErrorsFound = true;
   10318              :             }
   10319              :         }
   10320              : 
   10321              :         // Error checks
   10322              : 
   10323            0 :         for (StormWinNum = 1; StormWinNum <= state.dataSurface->TotStormWin; ++StormWinNum) {
   10324              :             // Require BaseWindowNum be that of an exterior window
   10325            0 :             int SurfNum = state.dataSurface->StormWindow(StormWinNum).BaseWindowNum;
   10326            0 :             if (SurfNum == 0) {
   10327            0 :                 ShowSevereError(state, format("{}=\"{}\" invalid.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
   10328            0 :                 ErrorsFound = true;
   10329              :             } else {
   10330            0 :                 auto const &surf = state.dataSurface->Surface(SurfNum);
   10331            0 :                 if (surf.Class != SurfaceClass::Window || surf.ExtBoundCond != 0) {
   10332            0 :                     ShowSevereError(state, format("{}=\"{}\"", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
   10333            0 :                     ShowSevereError(state, format("cannot be used with surface={}", surf.Name));
   10334            0 :                     ShowContinueError(state, "because that surface is not an exterior window.");
   10335            0 :                     ErrorsFound = true;
   10336              :                 }
   10337              :             }
   10338              : 
   10339              :             // Require that storm window material be glass
   10340            0 :             int MatNum = state.dataSurface->StormWindow(StormWinNum).StormWinMaterialNum;
   10341            0 :             if (SurfNum > 0) {
   10342            0 :                 if (MatNum == 0) {
   10343            0 :                     ShowSevereError(state, format("{}=\"{}\"", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
   10344            0 :                     ShowContinueError(state,
   10345            0 :                                       format("{}=\"{}\" not found as storm window layer.", s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2)));
   10346            0 :                     ErrorsFound = true;
   10347              :                 } else {
   10348            0 :                     if (s_mat->materials(MatNum)->group != Material::Group::Glass) {
   10349            0 :                         ShowSevereError(state, format("{}=\"{}\"", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
   10350            0 :                         ShowContinueError(state,
   10351            0 :                                           format("{}=\"{}must be a WindowMaterial:Glazing or WindowMaterial:Glazing:RefractionExtinctionMethod",
   10352            0 :                                                  s_ipsc->cAlphaFieldNames(2),
   10353            0 :                                                  s_ipsc->cAlphaArgs(2)));
   10354            0 :                         ErrorsFound = true;
   10355              :                     }
   10356              :                 }
   10357              :                 // Error if base window has airflow control
   10358            0 :                 if (state.dataSurface->SurfWinAirflowControlType(SurfNum) != DataSurfaces::WindowAirFlowControlType::Invalid) {
   10359            0 :                     ShowSevereError(
   10360              :                         state,
   10361            0 :                         format("{}=\"{} cannot be used because it is an airflow window (i.e., has WindowProperty:AirflowControl specified)",
   10362            0 :                                s_ipsc->cCurrentModuleObject,
   10363            0 :                                s_ipsc->cAlphaArgs(1)));
   10364            0 :                     ErrorsFound = true;
   10365              :                 }
   10366              :             }
   10367              : 
   10368              :             // Check for reversal of on and off times
   10369            0 :             if (SurfNum > 0) {
   10370            0 :                 if ((state.dataEnvrn->Latitude > 0.0 &&
   10371            0 :                      (state.dataSurface->StormWindow(StormWinNum).MonthOn < state.dataSurface->StormWindow(StormWinNum).MonthOff)) ||
   10372            0 :                     (state.dataEnvrn->Latitude <= 0.0 &&
   10373            0 :                      (state.dataSurface->StormWindow(StormWinNum).MonthOn > state.dataSurface->StormWindow(StormWinNum).MonthOff))) {
   10374            0 :                     ShowWarningError(state, format("{}=\"{}\" check times that storm window", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
   10375            0 :                     ShowContinueError(state,
   10376            0 :                                       format("is put on (month={}, day={}) and taken off (month={}, day={});",
   10377            0 :                                              state.dataSurface->StormWindow(StormWinNum).MonthOn,
   10378            0 :                                              state.dataSurface->StormWindow(StormWinNum).DayOfMonthOn,
   10379            0 :                                              state.dataSurface->StormWindow(StormWinNum).MonthOff,
   10380            0 :                                              state.dataSurface->StormWindow(StormWinNum).DayOfMonthOff));
   10381            0 :                     ShowContinueError(state, format("these times may be reversed for your building latitude={:.2R} deg.", state.dataEnvrn->Latitude));
   10382              :                 }
   10383              :             }
   10384              :         }
   10385              :     }
   10386              : 
   10387          192 :     void GetWindowGapAirflowControlData(EnergyPlusData &state, bool &ErrorsFound) // If errors found in input
   10388              :     {
   10389              : 
   10390              :         // SUBROUTINE INFORMATION:
   10391              :         //       AUTHOR         Fred Winkelmann
   10392              :         //       DATE WRITTEN   Feb 2003
   10393              :         //       MODIFIED       June 2003, FCW: add destination = return air;
   10394              :         //                        more error messages
   10395              : 
   10396              :         // PURPOSE OF THIS SUBROUTINE:
   10397              :         // Reads in the window airflow control information from the input data file,
   10398              :         // interprets it and puts it in the SurfaceWindow derived type
   10399              : 
   10400              :         static constexpr std::string_view routineName = "GetWindowGapAirflowControlData";
   10401              : 
   10402              :         int IOStat;               // IO Status when calling get input subroutine
   10403              :         int ControlNumAlpha;      // Number of control alpha names being passed
   10404              :         int ControlNumProp;       // Number of control properties being passed
   10405              :         int TotWinAirflowControl; // Total window airflow control statements
   10406              :         int Loop;
   10407          192 :         int ConstrNum(0); // Construction number
   10408              :         int ConstrNumSh;  // Shaded Construction number
   10409              :         int MatGapFlow;   // Material number of gas in airflow gap of window's construction
   10410              :         int MatGapFlow1;  // Material number of gas on either side of a between-glass shade/blind
   10411              :         int MatGapFlow2;
   10412              : 
   10413          192 :         constexpr std::array<std::string_view, static_cast<int>(DataSurfaces::WindowAirFlowSource::Num)> WindowAirFlowSourceNamesUC{"INDOORAIR",
   10414              :                                                                                                                                     "OUTDOORAIR"};
   10415          192 :         constexpr std::array<std::string_view, static_cast<int>(DataSurfaces::WindowAirFlowDestination::Num)> WindowAirFlowDestinationNamesUC{
   10416              :             "INDOORAIR", "OUTDOORAIR", "RETURNAIR"};
   10417              : 
   10418              :         // of the shaded construction of airflow window
   10419          192 :         auto &s_ipsc = state.dataIPShortCut;
   10420          192 :         auto &s_mat = state.dataMaterial;
   10421              : 
   10422              :         // Get the total number of window airflow control statements
   10423          192 :         s_ipsc->cCurrentModuleObject = "WindowProperty:AirflowControl";
   10424          192 :         TotWinAirflowControl = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
   10425          192 :         if (TotWinAirflowControl == 0) {
   10426          192 :             return;
   10427              :         }
   10428              : 
   10429            0 :         for (Loop = 1; Loop <= TotWinAirflowControl; ++Loop) { // Loop through all surfaces in the input...
   10430              : 
   10431            0 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
   10432            0 :                                                                      s_ipsc->cCurrentModuleObject,
   10433              :                                                                      Loop,
   10434            0 :                                                                      s_ipsc->cAlphaArgs,
   10435              :                                                                      ControlNumAlpha,
   10436            0 :                                                                      s_ipsc->rNumericArgs,
   10437              :                                                                      ControlNumProp,
   10438              :                                                                      IOStat,
   10439            0 :                                                                      s_ipsc->lNumericFieldBlanks,
   10440            0 :                                                                      s_ipsc->lAlphaFieldBlanks,
   10441            0 :                                                                      s_ipsc->cAlphaFieldNames,
   10442            0 :                                                                      s_ipsc->cNumericFieldNames);
   10443              : 
   10444            0 :             ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
   10445              : 
   10446            0 :             int SurfNum = Util::FindItemInList(s_ipsc->cAlphaArgs(1), state.dataSurface->Surface, state.dataSurface->TotSurfaces);
   10447            0 :             if (SurfNum == 0) {
   10448            0 :                 ShowSevereError(state, format("{}=\"{}\" not found.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
   10449            0 :                 ErrorsFound = true;
   10450              :             }
   10451              :             // Check that associated surface is a 2- or 3-pane exterior window
   10452            0 :             if (SurfNum != 0) {
   10453            0 :                 bool WrongSurfaceType = false;
   10454            0 :                 auto const &surf = state.dataSurface->Surface(SurfNum);
   10455            0 :                 if (surf.Class != SurfaceClass::Window) {
   10456            0 :                     WrongSurfaceType = true;
   10457              :                 }
   10458            0 :                 if (surf.Class == SurfaceClass::Window) {
   10459            0 :                     ConstrNum = surf.Construction;
   10460            0 :                     if (state.dataConstruction->Construct(ConstrNum).TotGlassLayers != 2 &&
   10461            0 :                         state.dataConstruction->Construct(ConstrNum).TotGlassLayers != 3) {
   10462            0 :                         WrongSurfaceType = true;
   10463              :                     }
   10464            0 :                     if (surf.ExtBoundCond != DataSurfaces::ExternalEnvironment) {
   10465            0 :                         WrongSurfaceType = true;
   10466              :                     }
   10467              :                 }
   10468            0 :                 if (WrongSurfaceType) {
   10469            0 :                     ShowSevereError(
   10470              :                         state,
   10471            0 :                         format("{}=\"{}\" is not an exterior window with 2 or 3 glass layers.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
   10472            0 :                     ErrorsFound = true;
   10473              :                 }
   10474              :             }
   10475              : 
   10476              :             // Error if illegal airflow source
   10477            0 :             if (s_ipsc->cAlphaArgs(2) != "INDOORAIR" && s_ipsc->cAlphaArgs(2) != "OUTDOORAIR") {
   10478            0 :                 ErrorsFound = true;
   10479            0 :                 ShowSevereError(state,
   10480            0 :                                 format("{}=\"{}\" invalid {}=\"{}\"",
   10481            0 :                                        s_ipsc->cCurrentModuleObject,
   10482            0 :                                        s_ipsc->cAlphaArgs(1),
   10483            0 :                                        s_ipsc->cAlphaFieldNames(2),
   10484            0 :                                        s_ipsc->cAlphaArgs(2)));
   10485              :             }
   10486              : 
   10487              :             // Error if illegal airflow destination
   10488            0 :             if (s_ipsc->cAlphaArgs(3) != "INDOORAIR" && s_ipsc->cAlphaArgs(3) != "OUTDOORAIR" && s_ipsc->cAlphaArgs(3) != "RETURNAIR") {
   10489            0 :                 ErrorsFound = true;
   10490            0 :                 ShowSevereError(state,
   10491            0 :                                 format("{}=\"{}\" invalid {}=\"{}\"",
   10492            0 :                                        s_ipsc->cCurrentModuleObject,
   10493            0 :                                        s_ipsc->cAlphaArgs(1),
   10494            0 :                                        s_ipsc->cAlphaFieldNames(3),
   10495            0 :                                        s_ipsc->cAlphaArgs(3)));
   10496              :             }
   10497              : 
   10498              :             // Error if source = OutsideAir and destination = ReturnAir
   10499            0 :             if (s_ipsc->cAlphaArgs(2) == "OUTDOORAIR" && s_ipsc->cAlphaArgs(3) == "RETURNAIR") {
   10500            0 :                 ErrorsFound = true;
   10501            0 :                 ShowSevereError(state,
   10502            0 :                                 format("{}=\"{}\" invalid {}=\"{}\"",
   10503            0 :                                        s_ipsc->cCurrentModuleObject,
   10504            0 :                                        s_ipsc->cAlphaArgs(1),
   10505            0 :                                        s_ipsc->cAlphaFieldNames(2),
   10506            0 :                                        s_ipsc->cAlphaArgs(2)));
   10507            0 :                 ShowContinueError(state, format("..when {}=\"{}\"", s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3)));
   10508              :             }
   10509              : 
   10510              :             // Error if illegal airflow control type
   10511            0 :             if (s_ipsc->cAlphaArgs(4) != "ALWAYSONATMAXIMUMFLOW" && s_ipsc->cAlphaArgs(4) != "ALWAYSOFF" &&
   10512            0 :                 s_ipsc->cAlphaArgs(4) != "SCHEDULEDONLY") {
   10513            0 :                 ErrorsFound = true;
   10514            0 :                 ShowSevereError(state,
   10515            0 :                                 format("{}=\"{}\" invalid {}=\"{}\"",
   10516            0 :                                        s_ipsc->cCurrentModuleObject,
   10517            0 :                                        s_ipsc->cAlphaArgs(1),
   10518            0 :                                        s_ipsc->cAlphaFieldNames(4),
   10519            0 :                                        s_ipsc->cAlphaArgs(4)));
   10520              :             }
   10521              : 
   10522              :             // Error if illegal value for Airflow Has Multiplier Schedule
   10523            0 :             if (s_ipsc->cAlphaArgs(5) != "YES" && s_ipsc->cAlphaArgs(5) != "NO") {
   10524            0 :                 ErrorsFound = true;
   10525            0 :                 ShowSevereError(state,
   10526            0 :                                 format("{}=\"{}\" invalid {}=\"{}\"",
   10527            0 :                                        s_ipsc->cCurrentModuleObject,
   10528            0 :                                        s_ipsc->cAlphaArgs(1),
   10529            0 :                                        s_ipsc->cAlphaFieldNames(5),
   10530            0 :                                        s_ipsc->cAlphaArgs(5)));
   10531              :             }
   10532              : 
   10533              :             // Error if Airflow Control Type = ScheduledOnly and Airflow Has Multiplier Schedule = No
   10534            0 :             if (s_ipsc->cAlphaArgs(4) == "SCHEDULEDONLY" && s_ipsc->cAlphaArgs(5) == "NO") {
   10535            0 :                 ErrorsFound = true;
   10536            0 :                 ShowSevereError(state,
   10537            0 :                                 format("{}=\"{}\" invalid {}=\"{}\"",
   10538            0 :                                        s_ipsc->cCurrentModuleObject,
   10539            0 :                                        s_ipsc->cAlphaArgs(1),
   10540            0 :                                        s_ipsc->cAlphaFieldNames(4),
   10541            0 :                                        s_ipsc->cAlphaArgs(4)));
   10542            0 :                 ShowContinueError(state, format("..when {}=\"{}\"", s_ipsc->cAlphaFieldNames(5), s_ipsc->cAlphaArgs(5)));
   10543              :             }
   10544              : 
   10545              :             // Warning if Airflow Control Type = AlwaysOnAtMaxFlow and Airflow Has Multiplier Schedule = Yes
   10546            0 :             if (s_ipsc->cAlphaArgs(4) == "ALWAYSONATMAXIMUMFLOW" && s_ipsc->cAlphaArgs(5) == "YES") {
   10547            0 :                 ShowWarningError(state,
   10548            0 :                                  format("{}=\"{}has {}=\"{}\"",
   10549            0 :                                         s_ipsc->cCurrentModuleObject,
   10550            0 :                                         s_ipsc->cAlphaArgs(1),
   10551            0 :                                         s_ipsc->cAlphaFieldNames(4),
   10552            0 :                                         s_ipsc->cAlphaArgs(4)));
   10553            0 :                 ShowContinueError(state,
   10554            0 :                                   format("..but {}=\"{}If specified, the {} will be ignored.",
   10555            0 :                                          s_ipsc->cAlphaFieldNames(5),
   10556            0 :                                          s_ipsc->cAlphaArgs(5),
   10557            0 :                                          s_ipsc->cAlphaFieldNames(5)));
   10558              :             }
   10559              : 
   10560              :             // Warning if Airflow Control Type = AlwaysOff and Airflow Has Multiplier Schedule = Yes
   10561            0 :             if (s_ipsc->cAlphaArgs(4) == "ALWAYSOFF" && s_ipsc->cAlphaArgs(5) == "YES") {
   10562            0 :                 ShowWarningError(state,
   10563            0 :                                  format("{}=\"{}has {}=\"{}\"",
   10564            0 :                                         s_ipsc->cCurrentModuleObject,
   10565            0 :                                         s_ipsc->cAlphaArgs(1),
   10566            0 :                                         s_ipsc->cAlphaFieldNames(4),
   10567            0 :                                         s_ipsc->cAlphaArgs(4)));
   10568            0 :                 ShowContinueError(state,
   10569            0 :                                   format("..but {}=\"{}\". If specified, the {} will be ignored.",
   10570            0 :                                          s_ipsc->cAlphaFieldNames(5),
   10571            0 :                                          s_ipsc->cAlphaArgs(5),
   10572            0 :                                          s_ipsc->cAlphaFieldNames(5)));
   10573              :             }
   10574              : 
   10575            0 :             if (SurfNum > 0) {
   10576            0 :                 auto const &surf = state.dataSurface->Surface(SurfNum);
   10577            0 :                 state.dataSurface->AirflowWindows = true;
   10578            0 :                 state.dataSurface->SurfWinAirflowSource(SurfNum) =
   10579            0 :                     static_cast<DataSurfaces::WindowAirFlowSource>(getEnumValue(WindowAirFlowSourceNamesUC, s_ipsc->cAlphaArgs(2)));
   10580              : 
   10581            0 :                 state.dataSurface->SurfWinAirflowDestination(SurfNum) =
   10582            0 :                     static_cast<DataSurfaces::WindowAirFlowDestination>(getEnumValue(WindowAirFlowDestinationNamesUC, s_ipsc->cAlphaArgs(3)));
   10583              : 
   10584            0 :                 if (state.dataSurface->SurfWinAirflowDestination(SurfNum) == DataSurfaces::WindowAirFlowDestination::Return) {
   10585            0 :                     int controlledZoneNum = DataZoneEquipment::GetControlledZoneIndex(state, surf.ZoneName);
   10586            0 :                     if (controlledZoneNum > 0) {
   10587            0 :                         state.dataHeatBal->Zone(surf.Zone).HasAirFlowWindowReturn = true;
   10588              :                     }
   10589              : 
   10590              :                     // Set return air node number
   10591            0 :                     state.dataSurface->SurfWinAirflowReturnNodePtr(SurfNum) = 0;
   10592            0 :                     std::string retNodeName = "";
   10593            0 :                     if (!s_ipsc->lAlphaFieldBlanks(7)) {
   10594            0 :                         retNodeName = s_ipsc->cAlphaArgs(7);
   10595              :                     }
   10596            0 :                     std::string callDescription = s_ipsc->cCurrentModuleObject + "=" + surf.Name;
   10597            0 :                     state.dataSurface->SurfWinAirflowReturnNodePtr(SurfNum) =
   10598            0 :                         DataZoneEquipment::GetReturnAirNodeForZone(state, surf.Zone, retNodeName, callDescription);
   10599            0 :                     if (state.dataSurface->SurfWinAirflowReturnNodePtr(SurfNum) == 0) {
   10600            0 :                         ShowSevereError(state,
   10601            0 :                                         format("{}{}=\"{}\", airflow window return air node not found for {} = {}",
   10602              :                                                routineName,
   10603            0 :                                                s_ipsc->cCurrentModuleObject,
   10604            0 :                                                surf.Name,
   10605            0 :                                                s_ipsc->cAlphaFieldNames(3),
   10606            0 :                                                s_ipsc->cAlphaArgs(3)));
   10607            0 :                         if (!s_ipsc->lAlphaFieldBlanks(7)) {
   10608            0 :                             ShowContinueError(
   10609              :                                 state,
   10610            0 :                                 format("{}=\"{}\" did not find a matching return air node.", s_ipsc->cAlphaFieldNames(7), s_ipsc->cAlphaArgs(7)));
   10611              :                         }
   10612            0 :                         ShowContinueError(state,
   10613              :                                           "..Airflow windows with Airflow Destination = ReturnAir must reference a controlled Zone (appear in a "
   10614              :                                           "ZoneHVAC:EquipmentConnections object) with at least one return air node.");
   10615            0 :                         ErrorsFound = true;
   10616              :                     }
   10617            0 :                 }
   10618            0 :                 if (Util::SameString(s_ipsc->cAlphaArgs(4), "AlwaysOnAtMaximumFlow")) {
   10619            0 :                     state.dataSurface->SurfWinAirflowControlType(SurfNum) = DataSurfaces::WindowAirFlowControlType::MaxFlow;
   10620            0 :                 } else if (Util::SameString(s_ipsc->cAlphaArgs(4), "AlwaysOff")) {
   10621            0 :                     state.dataSurface->SurfWinAirflowControlType(SurfNum) = DataSurfaces::WindowAirFlowControlType::AlwaysOff;
   10622            0 :                 } else if (Util::SameString(s_ipsc->cAlphaArgs(4), "ScheduledOnly")) {
   10623            0 :                     state.dataSurface->SurfWinAirflowControlType(SurfNum) = DataSurfaces::WindowAirFlowControlType::Schedule;
   10624              :                 }
   10625            0 :                 state.dataSurface->SurfWinMaxAirflow(SurfNum) = s_ipsc->rNumericArgs(1);
   10626            0 :                 if (s_ipsc->cAlphaArgs(4) == "SCHEDULEDONLY" && s_ipsc->cAlphaArgs(5) == "YES") {
   10627            0 :                     if (s_ipsc->lAlphaFieldBlanks(6)) {
   10628            0 :                         ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(6), s_ipsc->cAlphaFieldNames(4), s_ipsc->cAlphaArgs(4));
   10629            0 :                         ErrorsFound = true;
   10630            0 :                     } else if ((state.dataSurface->SurfWinAirflowScheds(SurfNum) = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(6))) == nullptr) {
   10631            0 :                         ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(6), s_ipsc->cAlphaArgs(6));
   10632            0 :                         ErrorsFound = true;
   10633            0 :                         ShowSevereError(state,
   10634            0 :                                         format("{}=\"{}\", has {}=\"{}\"",
   10635            0 :                                                s_ipsc->cCurrentModuleObject,
   10636            0 :                                                s_ipsc->cAlphaArgs(1),
   10637            0 :                                                s_ipsc->cAlphaFieldNames(4),
   10638            0 :                                                s_ipsc->cAlphaArgs(4)));
   10639            0 :                         ShowContinueError(state,
   10640            0 :                                           format("..and {}=\"{}\", but no {} specified.",
   10641            0 :                                                  s_ipsc->cAlphaFieldNames(5),
   10642            0 :                                                  s_ipsc->cAlphaArgs(5),
   10643            0 :                                                  s_ipsc->cAlphaFieldNames(6)));
   10644              :                     } else {
   10645            0 :                         state.dataSurface->SurfWinAirflowHasSchedule(SurfNum) = true;
   10646            0 :                         if ((state.dataSurface->SurfWinAirflowScheds(SurfNum) = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(6))) == nullptr) {
   10647            0 :                             ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(6), s_ipsc->cAlphaArgs(6));
   10648            0 :                             ErrorsFound = true;
   10649              :                         }
   10650              :                     }
   10651              :                 }
   10652              :                 // Warning if associated window is an interior window
   10653            0 :                 if (surf.ExtBoundCond != DataSurfaces::ExternalEnvironment && !ErrorsFound) {
   10654            0 :                     ShowWarningError(state,
   10655            0 :                                      format("{}=\"{}\", is an Interior window; cannot be an airflow window.",
   10656            0 :                                             s_ipsc->cCurrentModuleObject,
   10657            0 :                                             s_ipsc->cAlphaArgs(1)));
   10658              :                 }
   10659            0 :                 if (!ErrorsFound) {
   10660              :                     // Require that gas in airflow gap has type = air
   10661            0 :                     MatGapFlow = state.dataConstruction->Construct(ConstrNum).LayerPoint(2);
   10662            0 :                     if (state.dataConstruction->Construct(ConstrNum).TotGlassLayers == 3) {
   10663            0 :                         MatGapFlow = state.dataConstruction->Construct(ConstrNum).LayerPoint(4);
   10664              :                     }
   10665            0 :                     if (dynamic_cast<Material::MaterialGasMix const *>(s_mat->materials(MatGapFlow))->gases[0].type != Material::GasType::Air) {
   10666            0 :                         ErrorsFound = true;
   10667            0 :                         ShowSevereError(state,
   10668            0 :                                         format("{}=\"{}\", Gas type not air in airflow gap of construction {}",
   10669            0 :                                                s_ipsc->cCurrentModuleObject,
   10670            0 :                                                s_ipsc->cAlphaArgs(1),
   10671            0 :                                                state.dataConstruction->Construct(ConstrNum).Name));
   10672              :                     }
   10673              :                     // Require that gas be air in airflow gaps on either side of a between glass shade/blind
   10674            0 :                     if (surf.HasShadeControl) {
   10675            0 :                         for (std::size_t listIndex = 0; listIndex < surf.windowShadingControlList.size(); ++listIndex) {
   10676            0 :                             int WSCPtr = surf.windowShadingControlList[listIndex];
   10677            0 :                             if (ANY_BETWEENGLASS_SHADE_BLIND(state.dataSurface->WindowShadingControl(WSCPtr).ShadingType)) {
   10678            0 :                                 ConstrNumSh = surf.shadedConstructionList[listIndex];
   10679            0 :                                 if (state.dataConstruction->Construct(ConstrNum).TotGlassLayers == 2) {
   10680            0 :                                     MatGapFlow1 = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(2);
   10681            0 :                                     MatGapFlow2 = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(4);
   10682              :                                 } else {
   10683            0 :                                     MatGapFlow1 = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(4);
   10684            0 :                                     MatGapFlow2 = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(6);
   10685              :                                 }
   10686            0 :                                 if (dynamic_cast<Material::MaterialGasMix const *>(s_mat->materials(MatGapFlow1))->gases[0].type !=
   10687            0 :                                         Material::GasType::Air ||
   10688            0 :                                     dynamic_cast<Material::MaterialGasMix const *>(s_mat->materials(MatGapFlow2))->gases[0].type !=
   10689              :                                         Material::GasType::Air) {
   10690            0 :                                     ErrorsFound = true;
   10691            0 :                                     ShowSevereError(state,
   10692            0 :                                                     format("{}=\"{}\", gas type must be air on either side of the shade/blind",
   10693            0 :                                                            s_ipsc->cCurrentModuleObject,
   10694            0 :                                                            s_ipsc->cAlphaArgs(1)));
   10695              :                                 }
   10696            0 :                                 break; // only need the first window shading control since they should be the same
   10697              :                             }
   10698              :                         }
   10699              :                     }
   10700              :                 }
   10701              :             }
   10702              : 
   10703              :         } // End of loop over window airflow controls
   10704              :     }
   10705              : 
   10706          234 :     void GetFoundationData(EnergyPlusData &state, bool &ErrorsFound)
   10707              :     {
   10708              : 
   10709              :         int NumAlphas;
   10710              :         int NumProps;
   10711              :         int IOStat;
   10712              : 
   10713              :         static constexpr std::string_view routineName = "GetFoundationData";
   10714              : 
   10715          234 :         auto &s_ipsc = state.dataIPShortCut;
   10716              : 
   10717              :         // Read Kiva Settings
   10718          234 :         s_ipsc->cCurrentModuleObject = "Foundation:Kiva:Settings";
   10719          234 :         int TotKivaStgs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
   10720              : 
   10721          234 :         if (TotKivaStgs > 1) {
   10722            0 :             ErrorsFound = true;
   10723            0 :             ShowSevereError(state, format("Multiple {} objects found. Only one is allowed.", s_ipsc->cCurrentModuleObject));
   10724              :         }
   10725              : 
   10726          234 :         if (TotKivaStgs == 1) {
   10727            4 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
   10728            2 :                                                                      s_ipsc->cCurrentModuleObject,
   10729              :                                                                      1,
   10730            2 :                                                                      s_ipsc->cAlphaArgs,
   10731              :                                                                      NumAlphas,
   10732            2 :                                                                      s_ipsc->rNumericArgs,
   10733              :                                                                      NumProps,
   10734              :                                                                      IOStat,
   10735            2 :                                                                      s_ipsc->lNumericFieldBlanks,
   10736            2 :                                                                      s_ipsc->lAlphaFieldBlanks,
   10737            2 :                                                                      s_ipsc->cAlphaFieldNames,
   10738            2 :                                                                      s_ipsc->cNumericFieldNames);
   10739              : 
   10740            2 :             int numF = 1;
   10741            2 :             int alpF = 1;
   10742              : 
   10743            2 :             if (!s_ipsc->lNumericFieldBlanks(numF)) {
   10744            2 :                 state.dataSurfaceGeometry->kivaManager.settings.soilK = s_ipsc->rNumericArgs(numF);
   10745              :             }
   10746            2 :             numF++;
   10747            2 :             if (!s_ipsc->lNumericFieldBlanks(numF)) {
   10748            2 :                 state.dataSurfaceGeometry->kivaManager.settings.soilRho = s_ipsc->rNumericArgs(numF);
   10749              :             }
   10750            2 :             numF++;
   10751            2 :             if (!s_ipsc->lNumericFieldBlanks(numF)) {
   10752            2 :                 state.dataSurfaceGeometry->kivaManager.settings.soilCp = s_ipsc->rNumericArgs(numF);
   10753              :             }
   10754            2 :             numF++;
   10755            2 :             if (!s_ipsc->lNumericFieldBlanks(numF)) {
   10756            2 :                 state.dataSurfaceGeometry->kivaManager.settings.groundSolarAbs = s_ipsc->rNumericArgs(numF);
   10757              :             }
   10758            2 :             numF++;
   10759            2 :             if (!s_ipsc->lNumericFieldBlanks(numF)) {
   10760            2 :                 state.dataSurfaceGeometry->kivaManager.settings.groundThermalAbs = s_ipsc->rNumericArgs(numF);
   10761              :             }
   10762            2 :             numF++;
   10763            2 :             if (!s_ipsc->lNumericFieldBlanks(numF)) {
   10764            2 :                 state.dataSurfaceGeometry->kivaManager.settings.groundRoughness = s_ipsc->rNumericArgs(numF);
   10765              :             }
   10766            2 :             numF++;
   10767            2 :             if (!s_ipsc->lNumericFieldBlanks(numF)) {
   10768            2 :                 state.dataSurfaceGeometry->kivaManager.settings.farFieldWidth = s_ipsc->rNumericArgs(numF);
   10769              :             }
   10770            2 :             numF++;
   10771              : 
   10772            2 :             if (!s_ipsc->lAlphaFieldBlanks(alpF)) {
   10773            2 :                 if (Util::SameString(s_ipsc->cAlphaArgs(alpF), "ZeroFlux")) {
   10774            1 :                     state.dataSurfaceGeometry->kivaManager.settings.deepGroundBoundary = HeatBalanceKivaManager::KivaManager::Settings::ZERO_FLUX;
   10775            1 :                 } else if (Util::SameString(s_ipsc->cAlphaArgs(alpF), "GroundWater")) {
   10776            0 :                     state.dataSurfaceGeometry->kivaManager.settings.deepGroundBoundary = HeatBalanceKivaManager::KivaManager::Settings::GROUNDWATER;
   10777            1 :                 } else if (Util::SameString(s_ipsc->cAlphaArgs(alpF), "Autoselect")) {
   10778            1 :                     state.dataSurfaceGeometry->kivaManager.settings.deepGroundBoundary = HeatBalanceKivaManager::KivaManager::Settings::AUTO;
   10779              :                 } else {
   10780            0 :                     ErrorsFound = true;
   10781            0 :                     ShowSevereError(state,
   10782            0 :                                     format("{}, {} is not a valid choice for {}",
   10783            0 :                                            s_ipsc->cCurrentModuleObject,
   10784            0 :                                            s_ipsc->cAlphaArgs(alpF),
   10785            0 :                                            s_ipsc->cAlphaFieldNames(alpF)));
   10786              :                 }
   10787              :             }
   10788            2 :             alpF++;
   10789              : 
   10790            2 :             if (s_ipsc->lNumericFieldBlanks(numF) || s_ipsc->rNumericArgs(numF) == Constant::AutoCalculate) {
   10791              :                 // Autocalculate deep-ground depth (see KivaManager::defineDefaultFoundation() for actual calculation)
   10792            1 :                 state.dataSurfaceGeometry->kivaManager.settings.deepGroundDepth = 40.0;
   10793            1 :                 state.dataSurfaceGeometry->kivaManager.settings.autocalculateDeepGroundDepth = true;
   10794            1 :                 if (state.dataSurfaceGeometry->kivaManager.settings.deepGroundBoundary != HeatBalanceKivaManager::KivaManager::Settings::AUTO) {
   10795            1 :                     ErrorsFound = true;
   10796            2 :                     ShowSevereError(state,
   10797            4 :                                     format("{}, {} should not be set to Autocalculate unless {} is set to Autoselect",
   10798            1 :                                            s_ipsc->cCurrentModuleObject,
   10799            1 :                                            s_ipsc->cNumericFieldNames(numF),
   10800            1 :                                            s_ipsc->cAlphaFieldNames(alpF - 1)));
   10801              :                 }
   10802              :             } else {
   10803            1 :                 state.dataSurfaceGeometry->kivaManager.settings.deepGroundDepth = s_ipsc->rNumericArgs(numF);
   10804            1 :                 state.dataSurfaceGeometry->kivaManager.settings.autocalculateDeepGroundDepth = false;
   10805              :             }
   10806            2 :             numF++;
   10807            2 :             if (!s_ipsc->lNumericFieldBlanks(numF)) {
   10808            0 :                 state.dataSurfaceGeometry->kivaManager.settings.minCellDim = s_ipsc->rNumericArgs(numF);
   10809              :             }
   10810            2 :             numF++;
   10811            2 :             if (!s_ipsc->lNumericFieldBlanks(numF)) {
   10812            0 :                 state.dataSurfaceGeometry->kivaManager.settings.maxGrowthCoeff = s_ipsc->rNumericArgs(numF);
   10813              :             }
   10814            2 :             numF++;
   10815              : 
   10816            2 :             if (!s_ipsc->lAlphaFieldBlanks(alpF)) {
   10817            0 :                 if (Util::SameString(s_ipsc->cAlphaArgs(alpF), "Hourly")) {
   10818            0 :                     state.dataSurfaceGeometry->kivaManager.settings.timestepType = HeatBalanceKivaManager::KivaManager::Settings::HOURLY;
   10819            0 :                     state.dataSurfaceGeometry->kivaManager.timestep = 3600.; // seconds
   10820              :                 } else {                                                     // if (Util::SameString(s_ipsc->cAlphaArgs( alpF ), "Timestep"))
   10821            0 :                     state.dataSurfaceGeometry->kivaManager.settings.timestepType = HeatBalanceKivaManager::KivaManager::Settings::TIMESTEP;
   10822            0 :                     state.dataSurfaceGeometry->kivaManager.timestep = state.dataGlobal->MinutesInTimeStep * 60.;
   10823              :                 }
   10824              :             }
   10825            2 :             alpF++;
   10826              :         }
   10827              : 
   10828              :         // Set default foundation (probably doesn't need to be called if there are no Kiva
   10829              :         // surfaces, but we don't know that yet). We call this here so that the default
   10830              :         // foundation is available for 1) the starting copy for user-defined Foundation:Kiva
   10831              :         // object default inputs, and 2) the actual default Foundation object if a
   10832              :         // user-defined Foundation:Kiva name is not referenced by a surface.
   10833          234 :         state.dataSurfaceGeometry->kivaManager.defineDefaultFoundation(state);
   10834              : 
   10835              :         // Read Foundation objects
   10836          234 :         s_ipsc->cCurrentModuleObject = "Foundation:Kiva";
   10837          234 :         int TotKivaFnds = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
   10838              : 
   10839          234 :         if (TotKivaFnds > 0) {
   10840            1 :             auto &s_mat = state.dataMaterial;
   10841            2 :             for (int Loop = 1; Loop <= TotKivaFnds; ++Loop) {
   10842            2 :                 state.dataInputProcessing->inputProcessor->getObjectItem(state,
   10843            1 :                                                                          s_ipsc->cCurrentModuleObject,
   10844              :                                                                          Loop,
   10845            1 :                                                                          s_ipsc->cAlphaArgs,
   10846              :                                                                          NumAlphas,
   10847            1 :                                                                          s_ipsc->rNumericArgs,
   10848              :                                                                          NumProps,
   10849              :                                                                          IOStat,
   10850            1 :                                                                          s_ipsc->lNumericFieldBlanks,
   10851            1 :                                                                          s_ipsc->lAlphaFieldBlanks,
   10852            1 :                                                                          s_ipsc->cAlphaFieldNames,
   10853            1 :                                                                          s_ipsc->cNumericFieldNames);
   10854              : 
   10855            1 :                 ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
   10856              : 
   10857            1 :                 int numF = 1;
   10858            1 :                 int alpF = 1;
   10859              : 
   10860            1 :                 bool ErrorInName = false;
   10861              : 
   10862            1 :                 HeatBalanceKivaManager::FoundationKiva fndInput;
   10863              : 
   10864            1 :                 fndInput.name = s_ipsc->cAlphaArgs(alpF);
   10865            1 :                 alpF++;
   10866            1 :                 Util::IsNameEmpty(state, fndInput.name, s_ipsc->cCurrentModuleObject, ErrorInName);
   10867            1 :                 if (ErrorInName) {
   10868            0 :                     ErrorsFound = true;
   10869            0 :                     continue;
   10870              :                 }
   10871              : 
   10872              :                 // Start with copy of default
   10873            1 :                 auto &fnd = fndInput.foundation;
   10874            1 :                 fnd = state.dataSurfaceGeometry->kivaManager.defaultFoundation.foundation;
   10875              : 
   10876              :                 // Indoor temperature
   10877            1 :                 if (!s_ipsc->lNumericFieldBlanks(numF)) {
   10878            1 :                     fndInput.assumedIndoorTemperature = s_ipsc->rNumericArgs(numF);
   10879              :                 } else {
   10880            0 :                     fndInput.assumedIndoorTemperature = -9999;
   10881              :                 }
   10882            1 :                 numF++;
   10883              : 
   10884              :                 // Interior horizontal insulation
   10885            1 :                 if (!s_ipsc->lAlphaFieldBlanks(alpF)) {
   10886            0 :                     int index = Material::GetMaterialNum(state, s_ipsc->cAlphaArgs(alpF));
   10887            0 :                     if (index == 0) {
   10888            0 :                         ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(alpF), s_ipsc->cAlphaArgs(alpF));
   10889            0 :                         ErrorsFound = true;
   10890            0 :                         continue;
   10891              :                     }
   10892            0 :                     auto *m = s_mat->materials(index);
   10893            0 :                     if (m->group != Material::Group::Regular || m->ROnly) {
   10894            0 :                         ErrorsFound = true;
   10895            0 :                         ShowSevereError(state,
   10896            0 :                                         format("{}=\"{}\", invalid {}=\"{}",
   10897            0 :                                                s_ipsc->cCurrentModuleObject,
   10898              :                                                fndInput.name,
   10899            0 :                                                s_ipsc->cAlphaFieldNames(alpF),
   10900            0 :                                                s_ipsc->cAlphaArgs(alpF)));
   10901            0 :                         ShowContinueError(state, "Must be of type \"Material\"");
   10902            0 :                         continue;
   10903              :                     }
   10904            0 :                     fndInput.intHIns.x = 0.0;
   10905            0 :                     fndInput.intHIns.material = Kiva::Material(m->Conductivity, m->Density, m->SpecHeat);
   10906            0 :                     fndInput.intHIns.depth = m->Thickness;
   10907              :                 }
   10908            1 :                 alpF++;
   10909              : 
   10910            1 :                 if (!s_ipsc->lAlphaFieldBlanks(alpF - 1)) {
   10911            0 :                     if (s_ipsc->lNumericFieldBlanks(numF)) {
   10912            0 :                         fndInput.intHIns.z = 0.0;
   10913              :                     } else {
   10914            0 :                         fndInput.intHIns.z = s_ipsc->rNumericArgs(numF);
   10915              :                     }
   10916            0 :                     numF++;
   10917            0 :                     if (s_ipsc->lNumericFieldBlanks(numF)) {
   10918            0 :                         ErrorsFound = true;
   10919            0 :                         ShowSevereError(state,
   10920            0 :                                         format("{}=\"{}\", {} defined, but no {}provided",
   10921            0 :                                                s_ipsc->cCurrentModuleObject,
   10922              :                                                fndInput.name,
   10923            0 :                                                s_ipsc->cAlphaFieldNames(alpF - 1),
   10924            0 :                                                s_ipsc->cNumericFieldNames(numF)));
   10925            0 :                         continue;
   10926              :                     } else {
   10927            0 :                         fndInput.intHIns.width = -s_ipsc->rNumericArgs(numF);
   10928              :                     }
   10929            0 :                     numF++;
   10930              :                 } else {
   10931            1 :                     if (!s_ipsc->lNumericFieldBlanks(numF)) {
   10932            0 :                         ShowWarningError(
   10933              :                             state,
   10934            0 :                             format("{}=\"{}\", no {} defined", s_ipsc->cCurrentModuleObject, fndInput.name, s_ipsc->cAlphaFieldNames(alpF - 1)));
   10935            0 :                         ShowContinueError(state, format("{} will not be used.", s_ipsc->cNumericFieldNames(numF)));
   10936              :                     }
   10937            1 :                     numF++;
   10938            1 :                     if (!s_ipsc->lNumericFieldBlanks(numF)) {
   10939            0 :                         ShowWarningError(
   10940              :                             state,
   10941            0 :                             format("{}=\"{}\", no {} defined", s_ipsc->cCurrentModuleObject, fndInput.name, s_ipsc->cAlphaFieldNames(alpF - 1)));
   10942            0 :                         ShowContinueError(state, format("{} will not be used.", s_ipsc->cNumericFieldNames(numF)));
   10943              :                     }
   10944            1 :                     numF++;
   10945              :                 }
   10946              : 
   10947              :                 // Interior vertical insulation
   10948            1 :                 if (!s_ipsc->lAlphaFieldBlanks(alpF)) {
   10949            0 :                     int index = Material::GetMaterialNum(state, s_ipsc->cAlphaArgs(alpF));
   10950            0 :                     if (index == 0) {
   10951            0 :                         ErrorsFound = true;
   10952            0 :                         ShowSevereError(state,
   10953            0 :                                         format("Did not find matching material for {}=\"{}\", {}, missing material = {}",
   10954            0 :                                                s_ipsc->cCurrentModuleObject,
   10955              :                                                fndInput.name,
   10956            0 :                                                s_ipsc->cAlphaFieldNames(alpF),
   10957            0 :                                                s_ipsc->cAlphaArgs(alpF)));
   10958            0 :                         continue;
   10959              :                     }
   10960            0 :                     auto *m = s_mat->materials(index);
   10961            0 :                     if (m->group != Material::Group::Regular || m->ROnly) {
   10962            0 :                         ErrorsFound = true;
   10963            0 :                         ShowSevereError(state,
   10964            0 :                                         format("{}=\"{}\", invalid {}=\"{}",
   10965            0 :                                                s_ipsc->cCurrentModuleObject,
   10966              :                                                fndInput.name,
   10967            0 :                                                s_ipsc->cAlphaFieldNames(alpF),
   10968            0 :                                                s_ipsc->cAlphaArgs(alpF)));
   10969            0 :                         ShowContinueError(state, "Must be of type \"Material\"");
   10970            0 :                         continue;
   10971              :                     }
   10972            0 :                     fndInput.intVIns.material = Kiva::Material(m->Conductivity, m->Density, m->SpecHeat);
   10973            0 :                     fndInput.intVIns.width = -m->Thickness;
   10974            0 :                     fndInput.intVIns.x = 0.0;
   10975            0 :                     fndInput.intVIns.z = 0.0;
   10976              :                 }
   10977            1 :                 alpF++;
   10978              : 
   10979            1 :                 if (!s_ipsc->lAlphaFieldBlanks(alpF - 1)) {
   10980            0 :                     if (s_ipsc->lNumericFieldBlanks(numF)) {
   10981            0 :                         ErrorsFound = true;
   10982            0 :                         ShowSevereError(state,
   10983            0 :                                         format("{}=\"{}\", {} defined, but no {}provided",
   10984            0 :                                                s_ipsc->cCurrentModuleObject,
   10985              :                                                fndInput.name,
   10986            0 :                                                s_ipsc->cAlphaFieldNames(alpF - 1),
   10987            0 :                                                s_ipsc->cNumericFieldNames(numF)));
   10988            0 :                         continue;
   10989              :                     } else {
   10990            0 :                         fndInput.intVIns.depth = s_ipsc->rNumericArgs(numF);
   10991              :                     }
   10992            0 :                     numF++;
   10993              :                 } else {
   10994            1 :                     if (!s_ipsc->lNumericFieldBlanks(numF)) {
   10995            0 :                         ShowWarningError(
   10996              :                             state,
   10997            0 :                             format("{}=\"{}\", no {} defined", s_ipsc->cCurrentModuleObject, fndInput.name, s_ipsc->cAlphaFieldNames(alpF - 1)));
   10998            0 :                         ShowContinueError(state, format("{} will not be used.", s_ipsc->cNumericFieldNames(numF)));
   10999              :                     }
   11000            1 :                     numF++;
   11001              :                 }
   11002              : 
   11003              :                 // Exterior horizontal insulation
   11004            1 :                 if (!s_ipsc->lAlphaFieldBlanks(alpF)) {
   11005            0 :                     int index = Material::GetMaterialNum(state, s_ipsc->cAlphaArgs(alpF));
   11006            0 :                     if (index == 0) {
   11007            0 :                         ErrorsFound = true;
   11008            0 :                         ShowSevereError(state,
   11009            0 :                                         format("Did not find matching material for {}=\"{}\", {}, missing material = {}",
   11010            0 :                                                s_ipsc->cCurrentModuleObject,
   11011              :                                                fndInput.name,
   11012            0 :                                                s_ipsc->cAlphaFieldNames(alpF),
   11013            0 :                                                s_ipsc->cAlphaArgs(alpF)));
   11014            0 :                         continue;
   11015              :                     }
   11016            0 :                     auto *m = s_mat->materials(index);
   11017            0 :                     if (m->group != Material::Group::Regular || m->ROnly) {
   11018            0 :                         ErrorsFound = true;
   11019            0 :                         ShowSevereError(state,
   11020            0 :                                         format("{}=\"{}\", invalid {}=\"{}",
   11021            0 :                                                s_ipsc->cCurrentModuleObject,
   11022              :                                                fndInput.name,
   11023            0 :                                                s_ipsc->cAlphaFieldNames(alpF),
   11024            0 :                                                s_ipsc->cAlphaArgs(alpF)));
   11025            0 :                         ShowContinueError(state, "Must be of type \"Material\"");
   11026            0 :                         continue;
   11027              :                     }
   11028            0 :                     fndInput.extHIns.x = 0.0;
   11029            0 :                     fndInput.extHIns.material = Kiva::Material(m->Conductivity, m->Density, m->SpecHeat);
   11030            0 :                     fndInput.extHIns.depth = m->Thickness;
   11031              :                 }
   11032            1 :                 alpF++;
   11033              : 
   11034            1 :                 if (!s_ipsc->lAlphaFieldBlanks(alpF - 1)) {
   11035            0 :                     if (s_ipsc->lNumericFieldBlanks(numF)) {
   11036            0 :                         fndInput.extHIns.z = 0.0;
   11037              :                     } else {
   11038            0 :                         fndInput.extHIns.z = s_ipsc->rNumericArgs(numF);
   11039              :                     }
   11040            0 :                     numF++;
   11041            0 :                     if (s_ipsc->lNumericFieldBlanks(numF)) {
   11042            0 :                         ErrorsFound = true;
   11043            0 :                         ShowSevereError(state,
   11044            0 :                                         format("{}=\"{}\", {} defined, but no {}provided",
   11045            0 :                                                s_ipsc->cCurrentModuleObject,
   11046              :                                                fndInput.name,
   11047            0 :                                                s_ipsc->cAlphaFieldNames(alpF - 1),
   11048            0 :                                                s_ipsc->cNumericFieldNames(numF)));
   11049            0 :                         continue;
   11050              :                     } else {
   11051            0 :                         fndInput.extHIns.width = s_ipsc->rNumericArgs(numF);
   11052              :                     }
   11053            0 :                     numF++;
   11054              :                 } else {
   11055            1 :                     if (!s_ipsc->lNumericFieldBlanks(numF)) {
   11056            0 :                         ShowWarningError(
   11057              :                             state,
   11058            0 :                             format("{}=\"{}\", no {} defined", s_ipsc->cCurrentModuleObject, fndInput.name, s_ipsc->cAlphaFieldNames(alpF - 1)));
   11059            0 :                         ShowContinueError(state, format("{} will not be used.", s_ipsc->cNumericFieldNames(numF)));
   11060              :                     }
   11061            1 :                     numF++;
   11062            1 :                     if (!s_ipsc->lNumericFieldBlanks(numF)) {
   11063            0 :                         ShowWarningError(
   11064              :                             state,
   11065            0 :                             format("{}=\"{}\", no {} defined", s_ipsc->cCurrentModuleObject, fndInput.name, s_ipsc->cAlphaFieldNames(alpF - 1)));
   11066            0 :                         ShowContinueError(state, format("{} will not be used.", s_ipsc->cNumericFieldNames(numF)));
   11067              :                     }
   11068            1 :                     numF++;
   11069              :                 }
   11070              : 
   11071              :                 // Exterior vertical insulation
   11072            1 :                 if (!s_ipsc->lAlphaFieldBlanks(alpF)) {
   11073            0 :                     int index = Material::GetMaterialNum(state, s_ipsc->cAlphaArgs(alpF));
   11074            0 :                     if (index == 0) {
   11075            0 :                         ErrorsFound = true;
   11076            0 :                         ShowSevereError(state,
   11077            0 :                                         format("Did not find matching material for {}=\"{}\", {}, missing material = {}",
   11078            0 :                                                s_ipsc->cCurrentModuleObject,
   11079              :                                                fndInput.name,
   11080            0 :                                                s_ipsc->cAlphaFieldNames(alpF),
   11081            0 :                                                s_ipsc->cAlphaArgs(alpF)));
   11082            0 :                         continue;
   11083              :                     }
   11084            0 :                     auto *m = s_mat->materials(index);
   11085            0 :                     if (m->group != Material::Group::Regular || m->ROnly) {
   11086            0 :                         ErrorsFound = true;
   11087            0 :                         ShowSevereError(state,
   11088            0 :                                         format("{}=\"{}\", invalid {}=\"{}",
   11089            0 :                                                s_ipsc->cCurrentModuleObject,
   11090              :                                                fndInput.name,
   11091            0 :                                                s_ipsc->cAlphaFieldNames(alpF),
   11092            0 :                                                s_ipsc->cAlphaArgs(alpF)));
   11093            0 :                         ShowContinueError(state, "Must be of type \"Material\"");
   11094            0 :                         continue;
   11095              :                     }
   11096            0 :                     fndInput.extVIns.material = Kiva::Material(m->Conductivity, m->Density, m->SpecHeat);
   11097            0 :                     fndInput.extVIns.width = m->Thickness;
   11098            0 :                     fndInput.extVIns.x = 0.0;
   11099            0 :                     fndInput.extVIns.z = 0.0;
   11100              :                 }
   11101            1 :                 alpF++;
   11102              : 
   11103            1 :                 if (!s_ipsc->lAlphaFieldBlanks(alpF - 1)) {
   11104            0 :                     if (s_ipsc->lNumericFieldBlanks(numF)) {
   11105            0 :                         ErrorsFound = true;
   11106            0 :                         ShowSevereError(state,
   11107            0 :                                         format("{}=\"{}\", {} defined, but no {}provided",
   11108            0 :                                                s_ipsc->cCurrentModuleObject,
   11109              :                                                fndInput.name,
   11110            0 :                                                s_ipsc->cAlphaFieldNames(alpF - 1),
   11111            0 :                                                s_ipsc->cNumericFieldNames(numF)));
   11112            0 :                         continue;
   11113              :                     } else {
   11114            0 :                         fndInput.extVIns.depth = s_ipsc->rNumericArgs(numF);
   11115              :                     }
   11116            0 :                     numF++;
   11117              :                 } else {
   11118            1 :                     if (!s_ipsc->lNumericFieldBlanks(numF)) {
   11119            0 :                         ShowWarningError(
   11120              :                             state,
   11121            0 :                             format("{}=\"{}\", no {} defined", s_ipsc->cCurrentModuleObject, fndInput.name, s_ipsc->cAlphaFieldNames(alpF - 1)));
   11122            0 :                         ShowContinueError(state, format("{} will not be used.", s_ipsc->cNumericFieldNames(numF)));
   11123              :                     }
   11124            1 :                     numF++;
   11125              :                 }
   11126              : 
   11127              :                 // Foundation wall
   11128            1 :                 if (!s_ipsc->lNumericFieldBlanks(numF)) {
   11129            1 :                     fnd.wall.heightAboveGrade = s_ipsc->rNumericArgs(numF);
   11130              :                 }
   11131            1 :                 numF++;
   11132              : 
   11133            1 :                 if (!s_ipsc->lNumericFieldBlanks(numF)) {
   11134            1 :                     fnd.wall.depthBelowSlab = s_ipsc->rNumericArgs(numF);
   11135              :                 }
   11136            1 :                 numF++;
   11137              : 
   11138            1 :                 if (!s_ipsc->lAlphaFieldBlanks(alpF)) {
   11139            0 :                     fndInput.wallConstructionIndex = Util::FindItemInList(s_ipsc->cAlphaArgs(alpF), state.dataConstruction->Construct);
   11140            0 :                     if (fndInput.wallConstructionIndex == 0) {
   11141            0 :                         ErrorsFound = true;
   11142            0 :                         ShowSevereError(state,
   11143            0 :                                         format("Did not find matching construction for {}=\"{}\", {}, missing construction = {}",
   11144            0 :                                                s_ipsc->cCurrentModuleObject,
   11145              :                                                fndInput.name,
   11146            0 :                                                s_ipsc->cAlphaFieldNames(alpF),
   11147            0 :                                                s_ipsc->cAlphaArgs(alpF)));
   11148            0 :                         continue;
   11149              :                     }
   11150            0 :                     auto &c = state.dataConstruction->Construct(fndInput.wallConstructionIndex);
   11151            0 :                     c.IsUsed = true;
   11152            0 :                     if (c.TypeIsWindow) {
   11153            0 :                         ErrorsFound = true;
   11154            0 :                         ShowSevereError(state,
   11155            0 :                                         format("{}=\"{}\", invalid {}=\"{}",
   11156            0 :                                                s_ipsc->cCurrentModuleObject,
   11157              :                                                fndInput.name,
   11158            0 :                                                s_ipsc->cAlphaFieldNames(alpF),
   11159            0 :                                                s_ipsc->cAlphaArgs(alpF)));
   11160            0 :                         ShowContinueError(state, "Cannot be a window construction");
   11161            0 :                         continue;
   11162              :                     }
   11163              :                 } else {
   11164            1 :                     fndInput.wallConstructionIndex = 0; // Use default wall construction
   11165              :                 }
   11166            1 :                 alpF++;
   11167              : 
   11168              :                 // Footing
   11169            1 :                 if (!s_ipsc->lAlphaFieldBlanks(alpF)) {
   11170            0 :                     int index = Material::GetMaterialNum(state, s_ipsc->cAlphaArgs(alpF));
   11171            0 :                     if (index == 0) {
   11172            0 :                         ErrorsFound = true;
   11173            0 :                         ShowSevereError(state,
   11174            0 :                                         format("Did not find matching material for {}=\"{}\", {}, missing material = {}",
   11175            0 :                                                s_ipsc->cCurrentModuleObject,
   11176              :                                                fndInput.name,
   11177            0 :                                                s_ipsc->cAlphaFieldNames(alpF),
   11178            0 :                                                s_ipsc->cAlphaArgs(alpF)));
   11179            0 :                         continue;
   11180              :                     }
   11181            0 :                     auto *m = s_mat->materials(index);
   11182            0 :                     if (m->group != Material::Group::Regular || m->ROnly) {
   11183            0 :                         ErrorsFound = true;
   11184            0 :                         ShowSevereError(state,
   11185            0 :                                         format("{}=\"{}\", invalid {}=\"{}",
   11186            0 :                                                s_ipsc->cCurrentModuleObject,
   11187              :                                                fndInput.name,
   11188            0 :                                                s_ipsc->cAlphaFieldNames(alpF),
   11189            0 :                                                s_ipsc->cAlphaArgs(alpF)));
   11190            0 :                         ShowContinueError(state, "Must be of type \"Material\"");
   11191            0 :                         continue;
   11192              :                     }
   11193            0 :                     fndInput.footing.material = Kiva::Material(m->Conductivity, m->Density, m->SpecHeat);
   11194            0 :                     fndInput.footing.width = m->Thickness;
   11195            0 :                     fndInput.footing.x = 0.0;
   11196            0 :                     fndInput.footing.z = 0.0;
   11197              :                 }
   11198            1 :                 alpF++;
   11199              : 
   11200            1 :                 if (!s_ipsc->lAlphaFieldBlanks(alpF - 1)) {
   11201            0 :                     if (s_ipsc->lNumericFieldBlanks(numF)) {
   11202            0 :                         ErrorsFound = true;
   11203            0 :                         ShowSevereError(state,
   11204            0 :                                         format("{}=\"{}\", {} defined, but no {}provided",
   11205            0 :                                                s_ipsc->cCurrentModuleObject,
   11206              :                                                fndInput.name,
   11207            0 :                                                s_ipsc->cAlphaFieldNames(alpF - 1),
   11208            0 :                                                s_ipsc->cNumericFieldNames(numF)));
   11209            0 :                         continue;
   11210              :                     } else {
   11211            0 :                         fndInput.footing.depth = s_ipsc->rNumericArgs(numF);
   11212              :                     }
   11213            0 :                     numF++;
   11214              :                 } else {
   11215            1 :                     if (!s_ipsc->lNumericFieldBlanks(numF)) {
   11216            0 :                         ShowWarningError(
   11217              :                             state,
   11218            0 :                             format("{}=\"{}\", no {} defined", s_ipsc->cCurrentModuleObject, fndInput.name, s_ipsc->cAlphaFieldNames(alpF - 1)));
   11219            0 :                         ShowContinueError(state, format("{} will not be used.", s_ipsc->cNumericFieldNames(numF)));
   11220              :                     }
   11221            1 :                     numF++;
   11222              :                 }
   11223              : 
   11224              :                 // General Blocks
   11225            1 :                 int numRemainingFields = NumAlphas - (alpF - 1) + NumProps - (numF - 1);
   11226            1 :                 if (numRemainingFields > 0) {
   11227            1 :                     int numBlocks = numRemainingFields / 4;
   11228            1 :                     if (mod(numRemainingFields, 4) != 0) {
   11229            0 :                         ShowWarningError(state,
   11230            0 :                                          format("{}=\"{}\", number of Block fields not even multiple of 4. Will read in {}",
   11231            0 :                                                 s_ipsc->cCurrentModuleObject,
   11232              :                                                 fndInput.name,
   11233              :                                                 numBlocks));
   11234              :                     }
   11235            2 :                     for (int blockNum = 0; blockNum < numBlocks; blockNum++) {
   11236            1 :                         Kiva::InputBlock block;
   11237            1 :                         if (!s_ipsc->lAlphaFieldBlanks(alpF)) {
   11238            1 :                             int index = Material::GetMaterialNum(state, s_ipsc->cAlphaArgs(alpF));
   11239            1 :                             if (index == 0) {
   11240            0 :                                 ErrorsFound = true;
   11241            0 :                                 ShowSevereError(state,
   11242            0 :                                                 format("Did not find matching material for {}=\"{}\", {}, missing material = {}",
   11243            0 :                                                        s_ipsc->cCurrentModuleObject,
   11244              :                                                        fndInput.name,
   11245            0 :                                                        s_ipsc->cAlphaFieldNames(alpF),
   11246            0 :                                                        s_ipsc->cAlphaArgs(alpF)));
   11247            0 :                                 continue;
   11248              :                             }
   11249            1 :                             auto *m = s_mat->materials(index);
   11250            1 :                             if (m->group != Material::Group::Regular || m->ROnly) {
   11251            0 :                                 ErrorsFound = true;
   11252            0 :                                 ShowSevereError(state,
   11253            0 :                                                 format("{}=\"{}\", invalid {}=\"{}",
   11254            0 :                                                        s_ipsc->cCurrentModuleObject,
   11255              :                                                        fndInput.name,
   11256            0 :                                                        s_ipsc->cAlphaFieldNames(alpF),
   11257            0 :                                                        s_ipsc->cAlphaArgs(alpF)));
   11258            0 :                                 ShowContinueError(state, "Must be of type \"Material\"");
   11259            0 :                                 continue;
   11260              :                             }
   11261            1 :                             block.material = Kiva::Material(m->Conductivity, m->Density, m->SpecHeat);
   11262            1 :                             block.width = m->Thickness;
   11263              :                         } else {
   11264            0 :                             ErrorsFound = true;
   11265            0 :                             ShowSevereError(state,
   11266            0 :                                             format("{}=\"{}\", {} is required and not given.",
   11267            0 :                                                    s_ipsc->cCurrentModuleObject,
   11268              :                                                    fndInput.name,
   11269            0 :                                                    s_ipsc->cAlphaFieldNames(alpF)));
   11270            0 :                             continue;
   11271              :                         }
   11272            1 :                         alpF++;
   11273              : 
   11274            1 :                         if (s_ipsc->lNumericFieldBlanks(numF)) {
   11275            0 :                             block.depth = 0.0; // Temporary indicator to default to foundation depth
   11276              :                         } else {
   11277            1 :                             block.depth = s_ipsc->rNumericArgs(numF);
   11278              :                         }
   11279            1 :                         numF++;
   11280              : 
   11281            1 :                         if (s_ipsc->lNumericFieldBlanks(numF)) {
   11282            0 :                             ErrorsFound = true;
   11283            0 :                             ShowSevereError(state,
   11284            0 :                                             format("{}=\"{}\", {} defined, but no {}provided",
   11285            0 :                                                    s_ipsc->cCurrentModuleObject,
   11286              :                                                    fndInput.name,
   11287            0 :                                                    s_ipsc->cAlphaFieldNames(alpF - 1),
   11288            0 :                                                    s_ipsc->cNumericFieldNames(numF)));
   11289            0 :                             continue;
   11290              :                         } else {
   11291            1 :                             block.x = s_ipsc->rNumericArgs(numF);
   11292              :                         }
   11293            1 :                         numF++;
   11294              : 
   11295            1 :                         if (s_ipsc->lNumericFieldBlanks(numF)) {
   11296            0 :                             block.z = 0.0;
   11297              :                         } else {
   11298            1 :                             block.z = s_ipsc->rNumericArgs(numF);
   11299              :                         }
   11300            1 :                         numF++;
   11301              : 
   11302            1 :                         fnd.inputBlocks.push_back(block);
   11303              :                     }
   11304              :                 }
   11305              : 
   11306            1 :                 state.dataSurfaceGeometry->kivaManager.foundationInputs.push_back(fndInput);
   11307            1 :             }
   11308              :         }
   11309          234 :     }
   11310              : 
   11311          231 :     void GetOSCData(EnergyPlusData &state, bool &ErrorsFound)
   11312              :     {
   11313              : 
   11314              :         // SUBROUTINE INFORMATION:
   11315              :         //       AUTHOR         Linda Lawrie
   11316              :         //       DATE WRITTEN   May 2000
   11317              :         //       MODIFIED       Jul 2011, M.J. Witte and C.O. Pedersen, add new fields to OSC for last T, max and min
   11318              : 
   11319              :         // PURPOSE OF THIS SUBROUTINE:
   11320              :         // This subroutine gets the OtherSideCoefficient data.
   11321              : 
   11322              :         // REFERENCES:
   11323              :         // Other Side Coefficient Definition
   11324              :         // OtherSideCoefficients,
   11325              :         //       \memo This object sets the other side conditions for a surface in a variety of ways.
   11326              :         //   A1, \field OtherSideCoeff Name
   11327              :         //       \required-field
   11328              :         //       \reference OSCNames
   11329              :         //       \reference OutFaceEnvNames
   11330              :         //   N1, \field Combined convective/radiative film coefficient
   11331              :         //       \required-field
   11332              :         //       \type real
   11333              :         //       \note if>0, N1 becomes exterior convective/radiative film coefficient and other fields
   11334              :         //       \note are used to calc outside air temp then exterior surface temp based on outside air
   11335              :         //       \note and specified coefficient
   11336              :         //       \note if<=0, then remaining fields calculate the outside surface temperature(?)
   11337              :         //       \note following fields are used in the equation:
   11338              :         //       \note SurfTemp=N7*TempZone + N4*OutsideDryBulb + N2*N3 + GroundTemp*N5 + WindSpeed*N6*OutsideDryBulb
   11339              :         //   N2, \field User selected Constant Temperature
   11340              :         //       \units C
   11341              :         //       \type real
   11342              :         //       \note This parameter will be overwritten by the values from the schedule(A2 below) if one is present
   11343              :         //   N3, \field Coefficient modifying the user selected constant temperature
   11344              :         //       \note This coefficient is used even with a schedule.  It should normally be 1.0 in that case
   11345              :         //   N4, \field Coefficient modifying the external dry bulb temperature
   11346              :         //       \type real
   11347              :         //   N5, \field Coefficient modifying the ground temperature
   11348              :         //       \type real
   11349              :         //   N6, \field Coefficient modifying the wind speed term (s/m)
   11350              :         //       \type real
   11351              :         //   N7, \field Coefficient modifying the zone air temperature part of the equation
   11352              :         //       \type real
   11353              :         //   A2, \field ScheduleName for constant temperature
   11354              :         //       \note Name of Schedule for values of "const" temperature.
   11355              :         //       \note Schedule values replace N2 - User selected constant temperature.
   11356              :         //       \type object-list
   11357              :         //       \object-list ScheduleNames
   11358              :         //   A3, \field Sinusoidal Variation of Constant Temperature Coefficient
   11359              :         //       \note Optionally used to vary Constant Temperature Coefficient with unitary sine wave
   11360              :         //       \type choice
   11361              :         //       \key Yes
   11362              :         //       \key No
   11363              :         //       \default No
   11364              :         //   N8; \field Period of Sinusoidal Variation
   11365              :         //       \note Use with sinusoidal variation to define the time period
   11366              :         //       \type real
   11367              :         //       \units hr
   11368              :         //       \default 24
   11369              :         //  N9, \field Previous Other Side Temperature Coefficient
   11370              :         //      \note This coefficient multiplies the other side temperature result from the
   11371              :         //      \note previous zone timestep
   11372              :         //      \type real
   11373              :         //      \default 0
   11374              :         // N10, \field Minimum Other Side Temperature
   11375              :         //      \type real
   11376              :         //      \units C
   11377              :         //      \default -100
   11378              :         // N11; \field Maximum Other Side Temperature
   11379              :         //      \type real
   11380              :         //      \units C
   11381              :         //      \default 200
   11382              : 
   11383              :         static constexpr std::string_view routineName = "GetOSCData";
   11384              :         // Locals
   11385              :         // SUBROUTINE ARGUMENT DEFINITIONS:
   11386              : 
   11387              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
   11388              :         int NumAlphas;
   11389              :         int NumProps;
   11390              :         int Loop;
   11391              :         int IOStat;
   11392          231 :         std::string cOSCLimitsString;
   11393              : 
   11394          231 :         auto &s_ipsc = state.dataIPShortCut;
   11395              : 
   11396          231 :         s_ipsc->cCurrentModuleObject = "SurfaceProperty:OtherSideCoefficients";
   11397          231 :         state.dataSurface->TotOSC = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
   11398          231 :         state.dataSurface->OSC.allocate(state.dataSurface->TotOSC);
   11399              : 
   11400          231 :         int OSCNum = 0;
   11401          231 :         for (Loop = 1; Loop <= state.dataSurface->TotOSC; ++Loop) {
   11402            0 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
   11403            0 :                                                                      s_ipsc->cCurrentModuleObject,
   11404              :                                                                      Loop,
   11405            0 :                                                                      s_ipsc->cAlphaArgs,
   11406              :                                                                      NumAlphas,
   11407            0 :                                                                      s_ipsc->rNumericArgs,
   11408              :                                                                      NumProps,
   11409              :                                                                      IOStat,
   11410            0 :                                                                      s_ipsc->lNumericFieldBlanks,
   11411            0 :                                                                      s_ipsc->lAlphaFieldBlanks,
   11412            0 :                                                                      s_ipsc->cAlphaFieldNames,
   11413            0 :                                                                      s_ipsc->cNumericFieldNames);
   11414              : 
   11415            0 :             ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
   11416            0 :             bool ErrorInName = false;
   11417            0 :             bool IsBlank = false;
   11418            0 :             Util::VerifyName(
   11419            0 :                 state, s_ipsc->cAlphaArgs(1), state.dataSurface->OSC, OSCNum, ErrorInName, IsBlank, s_ipsc->cCurrentModuleObject + " Name");
   11420            0 :             if (ErrorInName) {
   11421            0 :                 ErrorsFound = true;
   11422            0 :                 continue;
   11423              :             }
   11424              : 
   11425            0 :             ++OSCNum;
   11426            0 :             state.dataSurface->OSC(OSCNum).Name = s_ipsc->cAlphaArgs(1);
   11427            0 :             state.dataSurface->OSC(OSCNum).SurfFilmCoef = s_ipsc->rNumericArgs(1);
   11428            0 :             state.dataSurface->OSC(OSCNum).ConstTemp = s_ipsc->rNumericArgs(2); //  This will be replaced if  schedule is used
   11429            0 :             state.dataSurface->OSC(OSCNum).ConstTempCoef =
   11430            0 :                 s_ipsc->rNumericArgs(3); //  This multiplier is used (even with schedule).  It should normally be 1.0
   11431            0 :             state.dataSurface->OSC(OSCNum).ExtDryBulbCoef = s_ipsc->rNumericArgs(4);
   11432            0 :             state.dataSurface->OSC(OSCNum).GroundTempCoef = s_ipsc->rNumericArgs(5);
   11433            0 :             state.dataSurface->OSC(OSCNum).WindSpeedCoef = s_ipsc->rNumericArgs(6);
   11434            0 :             state.dataSurface->OSC(OSCNum).ZoneAirTempCoef = s_ipsc->rNumericArgs(7);
   11435            0 :             state.dataSurface->OSC(OSCNum).SinusoidPeriod = s_ipsc->rNumericArgs(8);
   11436              : 
   11437            0 :             if ((NumAlphas == 1) || s_ipsc->lAlphaFieldBlanks(2)) { //  Const temp will come from schedule specified below.
   11438            0 :             } else if ((state.dataSurface->OSC(OSCNum).constTempSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(2))) == nullptr) {
   11439            0 :                 ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2));
   11440            0 :                 ErrorsFound = true;
   11441              :             }
   11442              : 
   11443            0 :             if (!s_ipsc->lAlphaFieldBlanks(3)) {
   11444            0 :                 if (BooleanSwitch bs = getYesNoValue(s_ipsc->cAlphaArgs(3)); bs != BooleanSwitch::Invalid) {
   11445            0 :                     state.dataSurface->OSC(OSCNum).SinusoidalConstTempCoef = static_cast<bool>(bs);
   11446              :                 } else {
   11447            0 :                     ShowSevereInvalidBool(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3));
   11448            0 :                     ErrorsFound = true;
   11449              :                 }
   11450              :             }
   11451              : 
   11452            0 :             if (s_ipsc->rNumericArgs(1) > 0.0 && !any_ne(s_ipsc->rNumericArgs({3, 7}), 0.0) &&
   11453            0 :                 (!state.dataSurface->OSC(OSCNum).SinusoidalConstTempCoef)) {
   11454            0 :                 ShowSevereError(state, format("{}=\"{}\" has zeros for all coefficients.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
   11455            0 :                 ShowContinueError(state, "...The outdoor air temperature for surfaces using this OtherSideCoefficients object will always be 0C.");
   11456              :             }
   11457              : 
   11458            0 :             if (s_ipsc->rNumericArgs(1) <= 0.0 && !any_ne(s_ipsc->rNumericArgs({3, 7}), 0.0) &&
   11459            0 :                 (!state.dataSurface->OSC(OSCNum).SinusoidalConstTempCoef)) {
   11460            0 :                 ShowSevereError(state, format("{}=\"{}\" has zeros for all coefficients.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
   11461            0 :                 ShowContinueError(state,
   11462              :                                   "...The outside surface temperature for surfaces using this OtherSideCoefficients object will always be 0C.");
   11463              :             }
   11464              : 
   11465            0 :             state.dataSurface->OSC(OSCNum).TPreviousCoef = s_ipsc->rNumericArgs(9);
   11466              : 
   11467            0 :             if (!s_ipsc->lNumericFieldBlanks(10)) {
   11468            0 :                 state.dataSurface->OSC(OSCNum).MinLimitPresent = true;
   11469            0 :                 state.dataSurface->OSC(OSCNum).MinTempLimit = s_ipsc->rNumericArgs(10);
   11470            0 :                 cOSCLimitsString = format("{:.3R}", s_ipsc->rNumericArgs(10));
   11471              :             } else {
   11472            0 :                 cOSCLimitsString = "N/A";
   11473              :             }
   11474            0 :             if (!s_ipsc->lNumericFieldBlanks(11)) {
   11475            0 :                 state.dataSurface->OSC(OSCNum).MaxLimitPresent = true;
   11476            0 :                 state.dataSurface->OSC(OSCNum).MaxTempLimit = s_ipsc->rNumericArgs(11);
   11477            0 :                 cOSCLimitsString += format(",{:.3R}", s_ipsc->rNumericArgs(10));
   11478              :             } else {
   11479            0 :                 cOSCLimitsString += ",N/A";
   11480              :             }
   11481              :         }
   11482              : 
   11483          231 :         for (Loop = 1; Loop <= state.dataSurface->TotOSC; ++Loop) {
   11484            0 :             if (Loop == 1) {
   11485              :                 static constexpr std::string_view OSCFormat1(
   11486              :                     "! <Other Side Coefficients>,Name,Combined convective/radiative film coefficient {W/m2-K},User selected "
   11487              :                     "Constant Temperature {C},Coefficient modifying the constant temperature term,Coefficient modifying the external "
   11488              :                     "dry bulb temperature term,Coefficient modifying the ground temperature term,Coefficient modifying the wind speed "
   11489              :                     "term {s/m},Coefficient modifying the zone air temperature term,Constant Temperature Schedule Name,Sinusoidal "
   11490              :                     "Variation,Period of Sinusoidal Variation,Previous Other Side Temperature Coefficient,Minimum Other Side "
   11491              :                     "Temperature {C},Maximum Other Side Temperature {C}");
   11492            0 :                 print(state.files.eio, "{}\n", OSCFormat1);
   11493              :             }
   11494            0 :             if (state.dataSurface->OSC(Loop).SurfFilmCoef > 0.0) {
   11495            0 :                 s_ipsc->cAlphaArgs(1) = format("{:.3R}", state.dataSurface->OSC(Loop).SurfFilmCoef);
   11496            0 :                 SetupOutputVariable(state,
   11497              :                                     "Surface Other Side Coefficients Exterior Air Drybulb Temperature",
   11498              :                                     Constant::Units::C,
   11499            0 :                                     state.dataSurface->OSC(Loop).OSCTempCalc,
   11500              :                                     OutputProcessor::TimeStepType::System,
   11501              :                                     OutputProcessor::StoreType::Average,
   11502            0 :                                     state.dataSurface->OSC(Loop).Name);
   11503              :             } else {
   11504            0 :                 s_ipsc->cAlphaArgs(1) = "N/A";
   11505              :             }
   11506              : 
   11507            0 :             print(state.files.eio,
   11508              :                   "Other Side Coefficients,{},{},{},{:.3R},{:.3R},{:.3R},{:.3R},{:.3R},{},{},{:.3R},{:.3R},{}\n",
   11509            0 :                   state.dataSurface->OSC(Loop).Name,
   11510            0 :                   s_ipsc->cAlphaArgs(1),
   11511            0 :                   (state.dataSurface->OSC(Loop).constTempSched != nullptr) ? "N/A" : format("{:.2R}", state.dataSurface->OSC(Loop).ConstTemp),
   11512            0 :                   state.dataSurface->OSC(Loop).ConstTempCoef,
   11513            0 :                   state.dataSurface->OSC(Loop).ExtDryBulbCoef,
   11514            0 :                   state.dataSurface->OSC(Loop).GroundTempCoef,
   11515            0 :                   state.dataSurface->OSC(Loop).WindSpeedCoef,
   11516            0 :                   state.dataSurface->OSC(Loop).ZoneAirTempCoef,
   11517            0 :                   (state.dataSurface->OSC(Loop).constTempSched == nullptr) ? "N/A" : state.dataSurface->OSC(Loop).constTempSched->Name,
   11518            0 :                   s_ipsc->cAlphaArgs(3),
   11519            0 :                   state.dataSurface->OSC(Loop).SinusoidPeriod,
   11520            0 :                   state.dataSurface->OSC(Loop).TPreviousCoef,
   11521              :                   cOSCLimitsString);
   11522              :         }
   11523          231 :     }
   11524              : 
   11525          257 :     void GetOSCMData(EnergyPlusData &state, bool &ErrorsFound)
   11526              :     {
   11527              : 
   11528              :         // SUBROUTINE INFORMATION:
   11529              :         //       AUTHOR         Brent Griffith
   11530              :         //       DATE WRITTEN   November 2004
   11531              : 
   11532              :         // PURPOSE OF THIS SUBROUTINE:
   11533              :         // This subroutine gets the OtherSideConditionsModel data.
   11534              : 
   11535              :         // REFERENCES:
   11536              :         // derived from GetOSCData subroutine by Linda Lawrie
   11537              : 
   11538              :         //  OtherSideConditionsModel,
   11539              :         //      \memo This object sets up modifying the other side conditions for a surface from other model results.
   11540              :         //  A1, \field OtherSideConditionsModel Name
   11541              :         //      \required-field
   11542              :         //      \reference OSCMNames
   11543              :         //      \reference OutFaceEnvNames
   11544              :         //  A2; \field Type of Model to determine Boundary Conditions
   11545              :         //      \type choice
   11546              :         //      \key Transpired Collector
   11547              :         //      \key Vented PV Cavity
   11548              :         //      \key Hybrid PV Transpired Collector
   11549              : 
   11550              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
   11551              :         int NumAlphas;
   11552              :         int NumProps;
   11553              :         int IOStat;
   11554              : 
   11555          257 :         auto &s_ipsc = state.dataIPShortCut;
   11556          257 :         s_ipsc->cCurrentModuleObject = "SurfaceProperty:OtherSideConditionsModel";
   11557          257 :         state.dataSurface->TotOSCM = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
   11558          257 :         state.dataSurface->OSCM.allocate(state.dataSurface->TotOSCM);
   11559              :         // OSCM is already initialized in derived type defn.
   11560              : 
   11561          257 :         int OSCMNum = 0;
   11562          286 :         for (int Loop = 1; Loop <= state.dataSurface->TotOSCM; ++Loop) {
   11563           58 :             state.dataInputProcessing->inputProcessor->getObjectItem(
   11564           29 :                 state, s_ipsc->cCurrentModuleObject, Loop, s_ipsc->cAlphaArgs, NumAlphas, s_ipsc->rNumericArgs, NumProps, IOStat);
   11565           29 :             bool ErrorInName = false;
   11566           29 :             bool IsBlank = false;
   11567           29 :             Util::VerifyName(
   11568           29 :                 state, s_ipsc->cAlphaArgs(1), state.dataSurface->OSCM, OSCMNum, ErrorInName, IsBlank, s_ipsc->cCurrentModuleObject + " Name");
   11569           29 :             if (ErrorInName) {
   11570            0 :                 ErrorsFound = true;
   11571            0 :                 continue;
   11572              :             }
   11573              : 
   11574           29 :             ++OSCMNum;
   11575           29 :             state.dataSurface->OSCM(OSCMNum).Name = s_ipsc->cAlphaArgs(1);
   11576              :             // Note no validation of the below at this time:
   11577           29 :             state.dataSurface->OSCM(OSCMNum).Class = s_ipsc->cAlphaArgs(2);
   11578              :             // setup output vars for modeled coefficients
   11579           58 :             SetupOutputVariable(state,
   11580              :                                 "Surface Other Side Conditions Modeled Convection Air Temperature",
   11581              :                                 Constant::Units::C,
   11582           29 :                                 state.dataSurface->OSCM(OSCMNum).TConv,
   11583              :                                 OutputProcessor::TimeStepType::System,
   11584              :                                 OutputProcessor::StoreType::Average,
   11585           29 :                                 state.dataSurface->OSCM(OSCMNum).Name);
   11586           58 :             SetupOutputVariable(state,
   11587              :                                 "Surface Other Side Conditions Modeled Convection Heat Transfer Coefficient",
   11588              :                                 Constant::Units::W_m2K,
   11589           29 :                                 state.dataSurface->OSCM(OSCMNum).HConv,
   11590              :                                 OutputProcessor::TimeStepType::System,
   11591              :                                 OutputProcessor::StoreType::Average,
   11592           29 :                                 state.dataSurface->OSCM(OSCMNum).Name);
   11593           58 :             SetupOutputVariable(state,
   11594              :                                 "Surface Other Side Conditions Modeled Radiation Temperature",
   11595              :                                 Constant::Units::C,
   11596           29 :                                 state.dataSurface->OSCM(OSCMNum).TRad,
   11597              :                                 OutputProcessor::TimeStepType::System,
   11598              :                                 OutputProcessor::StoreType::Average,
   11599           29 :                                 state.dataSurface->OSCM(OSCMNum).Name);
   11600           58 :             SetupOutputVariable(state,
   11601              :                                 "Surface Other Side Conditions Modeled Radiation Heat Transfer Coefficient",
   11602              :                                 Constant::Units::W_m2K,
   11603           29 :                                 state.dataSurface->OSCM(OSCMNum).HRad,
   11604              :                                 OutputProcessor::TimeStepType::System,
   11605              :                                 OutputProcessor::StoreType::Average,
   11606           29 :                                 state.dataSurface->OSCM(OSCMNum).Name);
   11607              : 
   11608           29 :             if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
   11609            0 :                 SetupEMSActuator(state,
   11610              :                                  "Other Side Boundary Conditions",
   11611            0 :                                  state.dataSurface->OSCM(OSCMNum).Name,
   11612              :                                  "Convection Bulk Air Temperature",
   11613              :                                  "[C]",
   11614            0 :                                  state.dataSurface->OSCM(OSCMNum).EMSOverrideOnTConv,
   11615            0 :                                  state.dataSurface->OSCM(OSCMNum).EMSOverrideTConvValue);
   11616            0 :                 SetupEMSActuator(state,
   11617              :                                  "Other Side Boundary Conditions",
   11618            0 :                                  state.dataSurface->OSCM(OSCMNum).Name,
   11619              :                                  "Convection Heat Transfer Coefficient",
   11620              :                                  "[W/m2-K]",
   11621            0 :                                  state.dataSurface->OSCM(OSCMNum).EMSOverrideOnHConv,
   11622            0 :                                  state.dataSurface->OSCM(OSCMNum).EMSOverrideHConvValue);
   11623            0 :                 SetupEMSActuator(state,
   11624              :                                  "Other Side Boundary Conditions",
   11625            0 :                                  state.dataSurface->OSCM(OSCMNum).Name,
   11626              :                                  "Radiation Effective Temperature",
   11627              :                                  "[C]",
   11628            0 :                                  state.dataSurface->OSCM(OSCMNum).EMSOverrideOnTRad,
   11629            0 :                                  state.dataSurface->OSCM(OSCMNum).EMSOverrideTRadValue);
   11630            0 :                 SetupEMSActuator(state,
   11631              :                                  "Other Side Boundary Conditions",
   11632            0 :                                  state.dataSurface->OSCM(OSCMNum).Name,
   11633              :                                  "Radiation Linear Heat Transfer Coefficient",
   11634              :                                  "[W/m2-K]",
   11635            0 :                                  state.dataSurface->OSCM(OSCMNum).EMSOverrideOnHrad,
   11636            0 :                                  state.dataSurface->OSCM(OSCMNum).EMSOverrideHradValue);
   11637              :             }
   11638              :         }
   11639              : 
   11640          286 :         for (int Loop = 1; Loop <= state.dataSurface->TotOSCM; ++Loop) {
   11641           29 :             if (Loop == 1) {
   11642              :                 static constexpr std::string_view OSCMFormat1("! <Other Side Conditions Model>,Name,Class\n");
   11643           29 :                 print(state.files.eio, OSCMFormat1);
   11644              :             }
   11645           29 :             print(state.files.eio, "Other Side Conditions Model,{},{}\n", state.dataSurface->OSCM(Loop).Name, state.dataSurface->OSCM(Loop).Class);
   11646              :         }
   11647          257 :     }
   11648              : 
   11649          225 :     void GetMovableInsulationData(EnergyPlusData &state, bool &ErrorsFound) // If errors found in input
   11650              :     {
   11651              : 
   11652              :         // SUBROUTINE INFORMATION:
   11653              :         //       AUTHOR         Linda Lawrie
   11654              :         //       DATE WRITTEN   May 2000
   11655              : 
   11656              :         // PURPOSE OF THIS SUBROUTINE:
   11657              :         // This subroutine gets the movable insulation data that can be associated with a surface.
   11658              : 
   11659              :         // REFERENCES:
   11660              :         // Movable Insulation Definition
   11661              :         // SurfaceControl:MovableInsulation,
   11662              :         //       \memo Exterior or Interior Insulation on opaque surfaces
   11663              :         //   A1, \field Insulation Type
   11664              :         //       \required-field
   11665              :         //       \type choice
   11666              :         //       \key Outside
   11667              :         //       \key Inside
   11668              :         //   A2, \field Surface Name
   11669              :         //       \required-field
   11670              :         //       \type object-list
   11671              :         //       \object-list SurfaceNames
   11672              :         //   A3, \field Material Name
   11673              :         //       \required-field
   11674              :         //       \object-list MaterialName
   11675              :         //   A4; \field Schedule Name
   11676              :         //        \required-field
   11677              :         //        \type object-list
   11678              :         //        \object-list ScheduleNames
   11679              : 
   11680              :         static constexpr std::string_view routineName = "GetMovableInsulationInput";
   11681              : 
   11682              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
   11683              :         int NAlphas;
   11684              :         int NNums;
   11685              :         int IOStat;
   11686              : 
   11687              :         enum class InsulationType
   11688              :         {
   11689              :             Invalid = -1,
   11690              :             Outside,
   11691              :             Inside,
   11692              :             Num
   11693              :         };
   11694          225 :         constexpr std::array<std::string_view, static_cast<int>(InsulationType::Num)> insulationTypeNamesUC = {"OUTSIDE", "INSIDE"};
   11695              : 
   11696          225 :         auto &s_ipsc = state.dataIPShortCut;
   11697          225 :         auto &s_mat = state.dataMaterial;
   11698              : 
   11699          225 :         s_ipsc->cCurrentModuleObject = "SurfaceControl:MovableInsulation";
   11700          225 :         int NMatInsul = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
   11701          226 :         for (int Loop = 1; Loop <= NMatInsul; ++Loop) {
   11702            2 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
   11703            1 :                                                                      s_ipsc->cCurrentModuleObject,
   11704              :                                                                      Loop,
   11705            1 :                                                                      s_ipsc->cAlphaArgs,
   11706              :                                                                      NAlphas,
   11707            1 :                                                                      s_ipsc->rNumericArgs,
   11708              :                                                                      NNums,
   11709              :                                                                      IOStat,
   11710            1 :                                                                      s_ipsc->lNumericFieldBlanks,
   11711            1 :                                                                      s_ipsc->lAlphaFieldBlanks,
   11712            1 :                                                                      s_ipsc->cAlphaFieldNames,
   11713            1 :                                                                      s_ipsc->cNumericFieldNames);
   11714            1 :             ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
   11715              : 
   11716            1 :             InsulationType insulationType = static_cast<InsulationType>(getEnumValue(insulationTypeNamesUC, s_ipsc->cAlphaArgs(1)));
   11717            1 :             if (insulationType == InsulationType::Invalid) {
   11718            0 :                 ShowSevereInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(1), s_ipsc->cAlphaArgs(1));
   11719            0 :                 ErrorsFound = true;
   11720            0 :                 continue;
   11721              :             }
   11722              : 
   11723              :             int SurfNum;
   11724            1 :             if ((SurfNum = Util::FindItemInList(s_ipsc->cAlphaArgs(2), state.dataSurface->Surface, state.dataSurface->TotSurfaces)) == 0) {
   11725            0 :                 ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2));
   11726            0 :                 ErrorsFound = true;
   11727            0 :                 continue;
   11728              :             }
   11729              : 
   11730              :             int MaterNum;
   11731            1 :             if ((MaterNum = Material::GetMaterialNum(state, s_ipsc->cAlphaArgs(3))) == 0) {
   11732            0 :                 ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3));
   11733            0 :                 ErrorsFound = true;
   11734            0 :                 continue;
   11735              :             }
   11736              : 
   11737            1 :             Sched::Schedule *sched = nullptr;
   11738            1 :             if (s_ipsc->lAlphaFieldBlanks(4)) {
   11739            0 :                 ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(4));
   11740            0 :                 ErrorsFound = true;
   11741            0 :                 continue;
   11742            1 :             } else if ((sched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(4))) == nullptr) {
   11743            0 :                 ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(4), s_ipsc->cAlphaArgs(4));
   11744            0 :                 ErrorsFound = true;
   11745            0 :                 continue;
   11746              :             }
   11747              : 
   11748            1 :             auto *thisMaterial = s_mat->materials(MaterNum);
   11749              : 
   11750              :             Array1D_string const cMaterialGroupType({-1, 18},
   11751              :                                                     {"invalid",
   11752              :                                                      "Material/Material:NoMass",
   11753              :                                                      "Material:AirGap",
   11754              :                                                      "WindowMaterial:Shade",
   11755              :                                                      "WindowMaterial:Glazing*",
   11756              :                                                      "WindowMaterial:Gas",
   11757              :                                                      "WindowMaterial:Blind",
   11758              :                                                      "WindowMaterial:GasMixture",
   11759              :                                                      "WindowMaterial:Screen",
   11760              :                                                      "Material:RoofVegetation",
   11761              :                                                      "Material:InfraredTransparent",
   11762              :                                                      "WindowMaterial:SimpleGlazingSystem",
   11763              :                                                      "WindowMaterial:ComplexShade",
   11764              :                                                      "WindowMaterial:Gap",
   11765              :                                                      "WindowMaterial:Glazing:EquivalentLayer",
   11766              :                                                      "WindowMaterial:Shade:EquivalentLayer",
   11767              :                                                      "WindowMaterial:Drape:EquivalentLayer",
   11768              :                                                      "WindowMaterial:Blind:EquivalentLayer",
   11769              :                                                      "WindowMaterial:Screen:EquivalentLayer",
   11770            1 :                                                      "WindowMaterial:Gap:EquivalentLayer"});
   11771              : 
   11772            1 :             Material::Group const MaterialLayerGroup = thisMaterial->group;
   11773            1 :             if ((MaterialLayerGroup == Material::Group::GlassSimple) || (MaterialLayerGroup == Material::Group::ShadeEQL) ||
   11774            0 :                 (MaterialLayerGroup == Material::Group::DrapeEQL) || (MaterialLayerGroup == Material::Group::BlindEQL) ||
   11775            0 :                 (MaterialLayerGroup == Material::Group::ScreenEQL) || (MaterialLayerGroup == Material::Group::WindowGapEQL)) {
   11776            1 :                 ShowSevereError(state, format("Invalid movable insulation material for {}:", s_ipsc->cCurrentModuleObject));
   11777            2 :                 ShowSevereError(
   11778            2 :                     state, format("...Movable insulation material type specified = {}", cMaterialGroupType(static_cast<int>(MaterialLayerGroup))));
   11779            1 :                 ShowSevereError(state, format("...Movable insulation material name specified = {}", s_ipsc->cAlphaArgs(3)));
   11780            1 :                 ErrorsFound = true;
   11781              :             }
   11782              : 
   11783            1 :             switch (insulationType) {
   11784            1 :             case InsulationType::Outside: {
   11785            1 :                 auto &movInsul = state.dataSurface->extMovInsuls(SurfNum);
   11786            1 :                 if (movInsul.matNum > 0) {
   11787            0 :                     ShowSevereDuplicateAssignment(
   11788            0 :                         state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2), s_mat->materials(movInsul.matNum)->Name);
   11789            0 :                     ErrorsFound = true;
   11790              :                 }
   11791              : 
   11792            1 :                 movInsul.matNum = MaterNum;
   11793            1 :                 movInsul.sched = sched;
   11794            1 :                 state.dataSurface->AnyMovableInsulation = true;
   11795            1 :                 state.dataSurface->extMovInsulSurfNums.push_back(SurfNum);
   11796              : 
   11797            1 :                 if (thisMaterial->Resistance <= 0.0) {
   11798            0 :                     if (thisMaterial->Conductivity <= 0.0 || thisMaterial->Thickness <= 0.0) {
   11799            0 :                         ShowSevereError(state,
   11800            0 :                                         format("{}, {}=\"{}\", invalid material.",
   11801            0 :                                                s_ipsc->cCurrentModuleObject,
   11802            0 :                                                s_ipsc->cAlphaFieldNames(2),
   11803            0 :                                                s_ipsc->cAlphaArgs(2)));
   11804            0 :                         ShowContinueError(state, "\"Outside\", invalid material for movable insulation.");
   11805            0 :                         ShowContinueError(state,
   11806            0 :                                           format("Material=\"{}\",Resistance=[{:.3R}], must be > 0 for use in Movable Insulation.",
   11807            0 :                                                  thisMaterial->Name,
   11808            0 :                                                  thisMaterial->Resistance));
   11809            0 :                         ErrorsFound = true;
   11810            0 :                     } else if (thisMaterial->Conductivity > 0.0) {
   11811            0 :                         thisMaterial->Resistance = thisMaterial->Thickness / thisMaterial->Conductivity;
   11812              :                     }
   11813              :                 }
   11814              : 
   11815            1 :                 if (thisMaterial->Conductivity <= 0.0) {
   11816            0 :                     if (thisMaterial->Resistance <= 0.0) {
   11817            0 :                         ShowSevereError(state,
   11818            0 :                                         format("{}, {}=\"{}\", invalid material.",
   11819            0 :                                                s_ipsc->cCurrentModuleObject,
   11820            0 :                                                s_ipsc->cAlphaFieldNames(2),
   11821            0 :                                                s_ipsc->cAlphaArgs(2)));
   11822            0 :                         ShowContinueError(state, "\"Outside\", invalid material for movable insulation.");
   11823            0 :                         ShowContinueError(state,
   11824            0 :                                           format("Material=\"{}\",Conductivity=[{:.3R}], must be > 0 for use in Movable Insulation.",
   11825            0 :                                                  thisMaterial->Name,
   11826            0 :                                                  thisMaterial->Conductivity));
   11827            0 :                         ErrorsFound = true;
   11828              :                     }
   11829              :                 }
   11830            1 :             } break;
   11831              : 
   11832            0 :             case InsulationType::Inside: {
   11833            0 :                 auto &movInsul = state.dataSurface->intMovInsuls(SurfNum);
   11834            0 :                 if (movInsul.matNum > 0) {
   11835            0 :                     ShowSevereDuplicateAssignment(
   11836            0 :                         state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2), s_mat->materials(movInsul.matNum)->Name);
   11837            0 :                     ErrorsFound = true;
   11838              :                 }
   11839              : 
   11840            0 :                 movInsul.matNum = MaterNum;
   11841            0 :                 movInsul.sched = sched;
   11842            0 :                 state.dataSurface->AnyMovableInsulation = true;
   11843            0 :                 state.dataSurface->intMovInsulSurfNums.push_back(SurfNum);
   11844            0 :                 if (thisMaterial->Resistance <= 0.0) {
   11845            0 :                     if (thisMaterial->Conductivity <= 0.0 || thisMaterial->Thickness <= 0.0) {
   11846            0 :                         ShowSevereError(state,
   11847            0 :                                         format("{}, {}=\"{}\", invalid material.",
   11848            0 :                                                s_ipsc->cCurrentModuleObject,
   11849            0 :                                                s_ipsc->cAlphaFieldNames(2),
   11850            0 :                                                s_ipsc->cAlphaArgs(2)));
   11851            0 :                         ShowContinueError(state, "\"Inside\", invalid material for movable insulation.");
   11852            0 :                         ShowContinueError(state,
   11853            0 :                                           format("Material=\"{}\",Resistance=[{:.3R}], must be > 0 for use in Movable Insulation.",
   11854            0 :                                                  thisMaterial->Name,
   11855            0 :                                                  thisMaterial->Resistance));
   11856            0 :                         ErrorsFound = true;
   11857            0 :                     } else if (thisMaterial->Conductivity > 0.0) {
   11858            0 :                         thisMaterial->Resistance = thisMaterial->Thickness / thisMaterial->Conductivity;
   11859              :                     }
   11860              :                 }
   11861            0 :             } break;
   11862            0 :             default: {
   11863            0 :                 assert(false);
   11864              :             } break;
   11865              :             } // switch (inulationType)
   11866              : 
   11867            1 :             if (state.dataSurface->Surface(SurfNum).Class == SurfaceClass::Window) {
   11868            0 :                 ShowSevereError(state, format("{}, {}=\"{}\"", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2)));
   11869            0 :                 ShowContinueError(state, "invalid use on a Window. Use WindowShadingControl instead.");
   11870            0 :                 ErrorsFound = true;
   11871              :             }
   11872            1 :         } // for (Loop)
   11873          225 :     } // GetMovableInsulationData()
   11874              : 
   11875              :     // Calculates the volume (m3) of a zone using the surfaces as possible.
   11876          197 :     void CalculateZoneVolume(EnergyPlusData &state)
   11877              :     {
   11878              :         // SUBROUTINE INFORMATION:
   11879              :         //       AUTHOR         Legacy Code
   11880              :         //       DATE WRITTEN   1992-1994
   11881              :         //       MODIFIED       Sep 2007, Mar 2017
   11882              : 
   11883              :         // METHODOLOGY EMPLOYED:
   11884              :         // Uses surface area information for calculations.  Modified to use the
   11885              :         // user-entered ceiling height (x floor area, if applicable) instead of using
   11886              :         // the calculated volume when the user enters the ceiling height.
   11887              : 
   11888              :         // REFERENCES:
   11889              :         // Legacy Code (IBLAST)
   11890              : 
   11891          197 :         Vectors::Polyhedron ZoneStruct;
   11892          197 :         bool initmsg = true;
   11893          394 :         bool ShowZoneSurfaces = (state.dataInputProcessing->inputProcessor->getNumSectionsFound("SHOWZONESURFACES_DEBUG") > 0);
   11894          197 :         EPVector<int> surfacenotused;
   11895              : 
   11896              :         enum class ZoneVolumeCalcMethod
   11897              :         {
   11898              :             Invalid = -1,
   11899              :             Enclosed,
   11900              :             FloorAreaTimesHeight1,
   11901              :             FloorAreaTimesHeight2,
   11902              :             CeilingAreaTimesHeight,
   11903              :             OpWallAreaTimesDistance,
   11904              :             UserProvided,
   11905              :             Num
   11906              :         };
   11907              : 
   11908          197 :         int countNotFullyEnclosedZones = 0;
   11909          477 :         for (auto &thisZone : state.dataHeatBal->Zone) {
   11910          280 :             if (!thisZone.HasFloor) {
   11911           32 :                 ShowWarningError(state,
   11912           32 :                                  format("No floor exists in Zone=\"{}\", zone floor area is zero. All values for this zone that are entered per "
   11913              :                                         "floor area will be zero.",
   11914           16 :                                         thisZone.Name));
   11915              :             }
   11916              : 
   11917          280 :             Real64 SumAreas = 0.0;
   11918          280 :             Real64 CalcVolume = 0.0;
   11919              :             // Use AllSurfaceFirst which includes air boundaries
   11920          280 :             int NFaces = thisZone.AllSurfaceLast - thisZone.AllSurfaceFirst + 1;
   11921          280 :             int notused = 0;
   11922          280 :             ZoneStruct.NumSurfaceFaces = NFaces;
   11923          280 :             ZoneStruct.SurfaceFace.allocate(NFaces);
   11924          280 :             int NActFaces = 0;
   11925          280 :             surfacenotused.dimension(NFaces, 0);
   11926              : 
   11927         1920 :             for (int SurfNum = thisZone.AllSurfaceFirst; SurfNum <= thisZone.AllSurfaceLast; ++SurfNum) {
   11928         1640 :                 assert(SurfNum > 0);
   11929         1640 :                 auto &thisSurface = state.dataSurface->Surface(SurfNum);
   11930              :                 // Only include Base Surfaces in Calc.
   11931              : 
   11932         1640 :                 if (thisSurface.Class != SurfaceClass::Wall && thisSurface.Class != SurfaceClass::Floor && thisSurface.Class != SurfaceClass::Roof) {
   11933          145 :                     ++notused;
   11934          145 :                     surfacenotused(notused) = SurfNum;
   11935          145 :                     continue;
   11936              :                 }
   11937              : 
   11938         1495 :                 ++NActFaces;
   11939         1495 :                 auto &thisFace = ZoneStruct.SurfaceFace(NActFaces);
   11940         1495 :                 thisFace.FacePoints.allocate(thisSurface.Sides);
   11941         1495 :                 thisFace.NSides = thisSurface.Sides;
   11942         1495 :                 thisFace.SurfNum = SurfNum;
   11943         1495 :                 thisFace.FacePoints({1, thisSurface.Sides}) = thisSurface.Vertex({1, thisSurface.Sides});
   11944         1495 :                 Vectors::CreateNewellAreaVector(thisFace.FacePoints, thisFace.NSides, thisFace.NewellAreaVector);
   11945         1495 :                 SumAreas += Vectors::VecLength(thisFace.NewellAreaVector);
   11946              :             }
   11947          280 :             ZoneStruct.NumSurfaceFaces = NActFaces;
   11948              : 
   11949          280 :             bool isFloorHorizontal = false;
   11950          280 :             bool isCeilingHorizontal = false;
   11951          280 :             bool areWallsVertical = false;
   11952          280 :             std::tie(isFloorHorizontal, isCeilingHorizontal, areWallsVertical) = areSurfaceHorizAndVert(state, ZoneStruct);
   11953          280 :             Real64 oppositeWallArea = 0.0;
   11954          280 :             Real64 distanceBetweenOppositeWalls = 0.0;
   11955              : 
   11956          280 :             bool areWallsSameHeight = areWallHeightSame(state, ZoneStruct);
   11957              : 
   11958          280 :             std::vector<EdgeOfSurf> listOfedgeNotUsedTwice;
   11959          280 :             bool isZoneEnclosed = isEnclosedVolume(ZoneStruct, listOfedgeNotUsedTwice);
   11960              :             ZoneVolumeCalcMethod volCalcMethod;
   11961              : 
   11962          280 :             Real64 floorAreaForVolume = (thisZone.FloorArea > 0.0) ? thisZone.FloorArea : thisZone.geometricFloorArea;
   11963          280 :             Real64 ceilingAreaForVolume = (thisZone.CeilingArea > 0.0) ? thisZone.CeilingArea : thisZone.geometricCeilingArea;
   11964              : 
   11965          280 :             if (isZoneEnclosed) {
   11966          186 :                 CalcVolume = Vectors::CalcPolyhedronVolume(state, ZoneStruct);
   11967          186 :                 volCalcMethod = ZoneVolumeCalcMethod::Enclosed;
   11968           94 :             } else if (floorAreaForVolume > 0.0 && thisZone.CeilingHeight > 0.0 && areFloorAndCeilingSame(state, ZoneStruct)) {
   11969           17 :                 CalcVolume = floorAreaForVolume * thisZone.CeilingHeight;
   11970           17 :                 volCalcMethod = ZoneVolumeCalcMethod::FloorAreaTimesHeight1;
   11971           77 :             } else if (isFloorHorizontal && areWallsVertical && areWallsSameHeight && floorAreaForVolume > 0.0 && thisZone.CeilingHeight > 0.0) {
   11972           54 :                 CalcVolume = floorAreaForVolume * thisZone.CeilingHeight;
   11973           54 :                 volCalcMethod = ZoneVolumeCalcMethod::FloorAreaTimesHeight2;
   11974           23 :             } else if (isCeilingHorizontal && areWallsVertical && areWallsSameHeight && ceilingAreaForVolume > 0.0 && thisZone.CeilingHeight > 0.0) {
   11975            4 :                 CalcVolume = ceilingAreaForVolume * thisZone.CeilingHeight;
   11976            4 :                 volCalcMethod = ZoneVolumeCalcMethod::CeilingAreaTimesHeight;
   11977           19 :             } else if (areOppositeWallsSame(state, ZoneStruct, oppositeWallArea, distanceBetweenOppositeWalls)) {
   11978            2 :                 CalcVolume = oppositeWallArea * distanceBetweenOppositeWalls;
   11979            2 :                 volCalcMethod = ZoneVolumeCalcMethod::OpWallAreaTimesDistance;
   11980           17 :             } else if (thisZone.Volume == Constant::AutoCalculate) { // no user entered zone volume
   11981           24 :                 ShowSevereError(state,
   11982           24 :                                 format("For zone: {} it is not possible to calculate the volume from the surrounding surfaces so either provide the "
   11983              :                                        "volume value or define all the surfaces to fully enclose the zone.",
   11984           12 :                                        thisZone.Name));
   11985           12 :                 CalcVolume = 0.;
   11986           12 :                 volCalcMethod = ZoneVolumeCalcMethod::Invalid;
   11987              :             } else {
   11988            5 :                 CalcVolume = 0.;
   11989            5 :                 volCalcMethod = ZoneVolumeCalcMethod::UserProvided;
   11990              :             }
   11991          280 :             if (!isZoneEnclosed) {
   11992           94 :                 ++countNotFullyEnclosedZones;
   11993           94 :                 if (state.dataGlobal->DisplayExtraWarnings) { // report missing
   11994            6 :                     ShowWarningError(state,
   11995            6 :                                      format("CalculateZoneVolume: The Zone=\"{}\" is not fully enclosed. To be fully enclosed, each edge of a "
   11996              :                                             "surface must also be an edge on one other surface.",
   11997            3 :                                             thisZone.Name));
   11998            3 :                     switch (volCalcMethod) {
   11999            0 :                     case ZoneVolumeCalcMethod::FloorAreaTimesHeight1:
   12000            0 :                         ShowContinueError(state,
   12001              :                                           "  The zone volume was calculated using the floor area times ceiling height method where the floor and "
   12002              :                                           "ceiling are the same except for the z-coordinates.");
   12003            0 :                         break;
   12004            0 :                     case ZoneVolumeCalcMethod::FloorAreaTimesHeight2:
   12005            0 :                         ShowContinueError(state,
   12006              :                                           "  The zone volume was calculated using the floor area times ceiling height method where the floor is "
   12007              :                                           "horizontal, the walls are vertical, and the wall heights are all the same.");
   12008            0 :                         break;
   12009            3 :                     case ZoneVolumeCalcMethod::CeilingAreaTimesHeight:
   12010            6 :                         ShowContinueError(state,
   12011              :                                           "  The zone volume was calculated using the ceiling area times ceiling height method where the ceiling is "
   12012              :                                           "horizontal, the walls are vertical, and the wall heights are all the same.");
   12013            3 :                         break;
   12014            0 :                     case ZoneVolumeCalcMethod::OpWallAreaTimesDistance:
   12015            0 :                         ShowContinueError(state,
   12016              :                                           "  The zone volume was calculated using the opposite wall area times the distance between them method ");
   12017            0 :                         break;
   12018            0 :                     case ZoneVolumeCalcMethod::UserProvided:
   12019            0 :                         ShowContinueError(state, "  The zone volume was provided as an input to the ZONE object ");
   12020            0 :                         break;
   12021            0 :                     case ZoneVolumeCalcMethod::Invalid:
   12022            0 :                         ShowContinueError(state, "  The zone volume was not calculated and an error exists. ");
   12023            0 :                         break;
   12024            0 :                     case ZoneVolumeCalcMethod::Enclosed: // should not be called but completes enumeration
   12025            0 :                         ShowContinueError(state, "  The zone volume was calculated using multiple pyramids and was fully enclosed. ");
   12026            0 :                         break;
   12027            0 :                     default:
   12028            0 :                         assert(false);
   12029              :                     }
   12030           15 :                     for (auto &edge : listOfedgeNotUsedTwice) {
   12031           12 :                         if (edge.count < 2) {
   12032           12 :                             ShowContinueError(
   12033              :                                 state,
   12034           12 :                                 fmt::format("  The surface \"{}\" has an edge that was used only once: it is not an edge on another surface",
   12035           12 :                                             state.dataSurface->Surface(edge.surfNum).Name));
   12036              : 
   12037              :                         } else {
   12038            0 :                             ShowContinueError(
   12039              :                                 state,
   12040            0 :                                 fmt::format("  The surface \"{}\" has an edge that was used {} times: it is an edge on three or more surfaces: ",
   12041            0 :                                             state.dataSurface->Surface(edge.surfNum).Name,
   12042            0 :                                             edge.count));
   12043            0 :                             std::string surfaceNames = "    It was found on the following Surfaces: ";
   12044            0 :                             for (int surfNum : edge.otherSurfNums) {
   12045            0 :                                 surfaceNames += fmt::format("'{}' ", state.dataSurface->Surface(surfNum).Name);
   12046            0 :                             }
   12047            0 :                             ShowContinueError(state, surfaceNames);
   12048            0 :                         }
   12049           12 :                         ShowContinueError(state, format("    Vertex start {{ {:.4R}, {:.4R}, {:.4R}}}", edge.start.x, edge.start.y, edge.start.z));
   12050           12 :                         ShowContinueError(state, format("    Vertex end   {{ {:.4R}, {:.4R}, {:.4R}}}", edge.end.x, edge.end.y, edge.end.z));
   12051            3 :                     }
   12052              :                 }
   12053              :             }
   12054          280 :             if (thisZone.Volume > 0.0) { // User entered zone volume, produce message if not near calculated
   12055           43 :                 if (CalcVolume > 0.0) {
   12056           36 :                     if (std::abs(CalcVolume - thisZone.Volume) / thisZone.Volume > 0.05) {
   12057            8 :                         ++state.dataSurfaceGeometry->ErrCount5;
   12058            8 :                         if (state.dataSurfaceGeometry->ErrCount5 == 1 && !state.dataGlobal->DisplayExtraWarnings) {
   12059            8 :                             if (initmsg) {
   12060           16 :                                 ShowMessage(state,
   12061              :                                             "Note that the following warning(s) may/will occur if you have not enclosed your zone completely.");
   12062            8 :                                 initmsg = false;
   12063              :                             }
   12064           16 :                             ShowWarningError(state, "Entered Zone Volumes differ from calculated zone volume(s).");
   12065           24 :                             ShowContinueError(state, "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on individual zones.");
   12066              :                         }
   12067            8 :                         if (state.dataGlobal->DisplayExtraWarnings) {
   12068            0 :                             if (initmsg) {
   12069            0 :                                 ShowMessage(state,
   12070              :                                             "Note that the following warning(s) may/will occur if you have not enclosed your zone completely.");
   12071            0 :                                 initmsg = false;
   12072              :                             }
   12073              :                             // Warn user of using specified Zone Volume
   12074            0 :                             ShowWarningError(
   12075              :                                 state,
   12076            0 :                                 format("Entered Volume entered for Zone=\"{}\" significantly different from calculated Volume", thisZone.Name));
   12077            0 :                             ShowContinueError(state,
   12078            0 :                                               format("Entered Zone Volume value={:.2R}, Calculated Zone Volume value={:.2R}, entered volume will be "
   12079              :                                                      "used in calculations.",
   12080            0 :                                                      thisZone.Volume,
   12081              :                                                      CalcVolume));
   12082              :                         }
   12083              :                     }
   12084              :                 }
   12085          237 :             } else if (thisZone.ceilingHeightEntered) { // User did not enter zone volume, but entered ceiling height
   12086           33 :                 if (floorAreaForVolume > 0.0) {
   12087           30 :                     thisZone.Volume = floorAreaForVolume * thisZone.CeilingHeight;
   12088              :                 } else { // ceiling height entered but floor area zero
   12089            3 :                     thisZone.Volume = CalcVolume;
   12090              :                 }
   12091              :             } else { // Neither ceiling height nor volume entered
   12092          204 :                 thisZone.Volume = CalcVolume;
   12093              :             }
   12094              : 
   12095          280 :             if (thisZone.Volume <= 0.0) {
   12096           16 :                 ShowWarningError(state, format("Indicated Zone Volume <= 0.0 for Zone={}", thisZone.Name));
   12097           16 :                 ShowContinueError(state, format("The calculated Zone Volume was={:.2R}", thisZone.Volume));
   12098           32 :                 ShowContinueError(state, "The simulation will continue with the Zone Volume set to 10.0 m3. ");
   12099           32 :                 ShowContinueError(state, "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on individual zones.");
   12100           16 :                 thisZone.Volume = 10.;
   12101              :             }
   12102              :             // For now - pro-rate space volumes by floor area, if not entered
   12103          580 :             for (int spaceNum : thisZone.spaceIndexes) {
   12104          300 :                 auto &thisSpace = state.dataHeatBal->space(spaceNum);
   12105              :                 // don't touch if already user-specified
   12106          300 :                 if (thisSpace.Volume > 0.0) {
   12107            1 :                     continue;
   12108              :                 }
   12109          299 :                 if (thisZone.numSpaces == 1) {
   12110          261 :                     thisSpace.Volume = thisZone.Volume;
   12111           38 :                 } else if (thisZone.geometricFloorArea > 0.0) {
   12112           34 :                     thisSpace.Volume = thisZone.Volume * thisSpace.FloorArea / thisZone.geometricFloorArea;
   12113              :                 }
   12114          280 :             }
   12115          280 :             Real64 totSpacesVolume = 0.0;
   12116          580 :             for (int spaceNum : thisZone.spaceIndexes) {
   12117          300 :                 totSpacesVolume += state.dataHeatBal->space(spaceNum).Volume;
   12118          280 :             }
   12119          280 :             if (totSpacesVolume > 0.0) {
   12120          571 :                 for (int spaceNum : thisZone.spaceIndexes) {
   12121          296 :                     state.dataHeatBal->space(spaceNum).fracZoneVolume = state.dataHeatBal->space(spaceNum).Volume / totSpacesVolume;
   12122          275 :                 }
   12123              :             } // else leave fractions at zero
   12124              : 
   12125          280 :             if (ShowZoneSurfaces) {
   12126            0 :                 if (state.dataSurfaceGeometry->ShowZoneSurfaceHeaders) {
   12127            0 :                     print(state.files.debug, "{}\n", "===================================");
   12128            0 :                     print(state.files.debug, "{}\n", "showing zone surfaces used and not used in volume calculation");
   12129            0 :                     print(state.files.debug, "{}\n", "for volume calculation, only floors, walls and roofs/ceilings are used");
   12130            0 :                     print(state.files.debug, "{}\n", "surface class, 1=wall, 2=floor, 3=roof/ceiling");
   12131            0 :                     print(state.files.debug, "{}\n", "unused surface class(es), 5=internal mass, 11=window, 12=glass door");
   12132            0 :                     print(state.files.debug, "{}\n", "                          13=door, 14=shading, 15=overhang, 16=fin");
   12133            0 :                     print(state.files.debug, "{}\n", "                          17=TDD Dome, 18=TDD Diffuser");
   12134            0 :                     state.dataSurfaceGeometry->ShowZoneSurfaceHeaders = false;
   12135              :                 }
   12136            0 :                 print(state.files.debug, "{}\n", "===================================");
   12137            0 :                 print(state.files.debug, "zone={} calc volume={}\n", thisZone.Name, CalcVolume);
   12138            0 :                 print(state.files.debug, " nsurfaces={} nactual={}\n", NFaces, NActFaces);
   12139              :             }
   12140         1775 :             for (int faceNum = 1; faceNum <= ZoneStruct.NumSurfaceFaces; ++faceNum) {
   12141         1495 :                 auto &thisFace = ZoneStruct.SurfaceFace(faceNum);
   12142         1495 :                 if (ShowZoneSurfaces) {
   12143            0 :                     if (faceNum <= NActFaces) {
   12144            0 :                         auto &thisSurface = state.dataSurface->Surface(thisFace.SurfNum);
   12145            0 :                         print(state.files.debug, "surface={} nsides={}\n", thisFace.SurfNum, thisFace.NSides);
   12146            0 :                         print(state.files.debug, "surface name={} class={}\n", thisSurface.Name, thisSurface.Class);
   12147            0 :                         print(state.files.debug, "area={}\n", thisSurface.GrossArea);
   12148            0 :                         for (int iside = 1; iside <= thisFace.NSides; ++iside) {
   12149            0 :                             auto const &FacePoint(thisFace.FacePoints(iside));
   12150            0 :                             print(state.files.debug, "{} {} {}\n", FacePoint.x, FacePoint.y, FacePoint.z);
   12151              :                         }
   12152              :                     }
   12153              :                 }
   12154         1495 :                 thisFace.FacePoints.deallocate();
   12155              :             }
   12156          280 :             if (ShowZoneSurfaces) {
   12157            0 :                 for (int SurfNum = 1; SurfNum <= notused; ++SurfNum) {
   12158            0 :                     print(state.files.debug,
   12159              :                           "notused:surface={} name={} class={}\n",
   12160              :                           surfacenotused(SurfNum),
   12161            0 :                           state.dataSurface->Surface(surfacenotused(SurfNum)).Name,
   12162            0 :                           state.dataSurface->Surface(surfacenotused(SurfNum)).Class);
   12163              :                 }
   12164              :             }
   12165              : 
   12166          280 :             ZoneStruct.SurfaceFace.deallocate();
   12167          280 :             surfacenotused.deallocate();
   12168              : 
   12169          477 :         } // zone loop
   12170          197 :         if (!state.dataGlobal->DisplayExtraWarnings) {
   12171          184 :             if (countNotFullyEnclosedZones == 1) {
   12172          138 :                 ShowWarningError(
   12173              :                     state, "CalculateZoneVolume: 1 zone is not fully enclosed. For more details use:  Output:Diagnostics,DisplayExtrawarnings; ");
   12174          138 :             } else if (countNotFullyEnclosedZones > 1) {
   12175           28 :                 ShowWarningError(state,
   12176           28 :                                  format("CalculateZoneVolume: {} zones are not fully enclosed. For more details use:  "
   12177              :                                         "Output:Diagnostics,DisplayExtrawarnings; ",
   12178              :                                         countNotFullyEnclosedZones));
   12179              :             }
   12180              :         }
   12181          197 :     }
   12182              : 
   12183              :     // test if the volume described by the polyhedron if full enclosed (would not leak)
   12184          285 :     bool isEnclosedVolume(DataVectorTypes::Polyhedron const &zonePoly, std::vector<EdgeOfSurf> &edgeNot2)
   12185              :     {
   12186              :         // J. Glazer - March 2017
   12187              : 
   12188          285 :         std::vector<Vector> uniqueVertices = makeListOfUniqueVertices(zonePoly);
   12189              : 
   12190          285 :         std::vector<EdgeOfSurf> edgeNot2orig = edgesNotTwoForEnclosedVolumeTest(zonePoly, uniqueVertices);
   12191              :         // if all edges had two counts then it is fully enclosed
   12192          285 :         if (edgeNot2orig.empty()) {
   12193          179 :             edgeNot2 = edgeNot2orig;
   12194          179 :             return true;
   12195              :         } else { // if the count is three or greater it is likely that a vertex that is colinear was counted on the faces on one edge and not
   12196              :                  // on the "other side" of the edge Go through all the points looking for the number that are colinear and see if that is
   12197              :                  // consistent with the number of edges found that didn't have a count of two
   12198              :             DataVectorTypes::Polyhedron updatedZonePoly = updateZonePolygonsForMissingColinearPoints(
   12199          106 :                 zonePoly, uniqueVertices); // this is done after initial test since it is computationally intensive.
   12200          106 :             std::vector<EdgeOfSurf> edgeNot2again = edgesNotTwoForEnclosedVolumeTest(updatedZonePoly, uniqueVertices);
   12201          106 :             if (edgeNot2again.empty()) {
   12202           10 :                 return true;
   12203              :             } else {
   12204          192 :                 edgeNot2 = edgesInBoth(edgeNot2orig,
   12205           96 :                                        edgeNot2again); // only return a list of those edges that appear in both the original edge and the
   12206              :                                                        // revised edges this eliminates added edges that will confuse users and edges that
   12207              :                                                        // were caught by the updateZonePoly routine
   12208           96 :                 return false;
   12209              :             }
   12210          106 :         }
   12211          285 :     }
   12212              : 
   12213              :     // returns a vector of edges that are in both vectors
   12214           96 :     std::vector<EdgeOfSurf> edgesInBoth(std::vector<EdgeOfSurf> const &edges1, std::vector<EdgeOfSurf> const &edges2)
   12215              :     {
   12216              :         // J. Glazer - June 2017
   12217              :         // this is not optimized but the number of edges for a typical polyhedron is 12 and is probably rarely bigger than 20.
   12218              : 
   12219           96 :         std::vector<EdgeOfSurf> inBoth;
   12220          680 :         for (const auto &e1 : edges1) {
   12221         2482 :             for (const auto &e2 : edges2) {
   12222         2412 :                 if (edgesEqualOnSameSurface(e1, e2)) {
   12223          514 :                     inBoth.push_back(e1);
   12224          514 :                     break;
   12225              :                 }
   12226          584 :             }
   12227           96 :         }
   12228           96 :         return inBoth;
   12229            0 :     }
   12230              : 
   12231              :     // returns true if the edges match - including the surface number
   12232         2412 :     bool edgesEqualOnSameSurface(EdgeOfSurf a, EdgeOfSurf b)
   12233              :     {
   12234         2412 :         if (a.surfNum != b.surfNum) {
   12235         1204 :             return false;
   12236              :         }
   12237              : 
   12238              :         // vertex comparison (we compare indices, so absolute equal)
   12239         1208 :         return ((a.start == b.start && a.end == b.end) || (a.start == b.end && a.end == b.start));
   12240              :     }
   12241              : 
   12242              :     // returns the number of times the edges of the polyhedron of the zone are not used twice by the sides
   12243          395 :     std::vector<EdgeOfSurf> edgesNotTwoForEnclosedVolumeTest(DataVectorTypes::Polyhedron const &zonePoly, std::vector<Vector> const &uniqueVertices)
   12244              :     {
   12245              :         // J. Glazer - March 2017
   12246              : 
   12247              :         struct EdgeByPts
   12248              :         {
   12249              :             int start;
   12250              :             int end;
   12251              :             int count;
   12252              :             int firstSurfNum;
   12253              :             std::vector<int> otherSurfNums;
   12254         4196 :             EdgeByPts() : start(0), end(0), count(0), firstSurfNum(0)
   12255              :             {
   12256         4196 :             }
   12257              :         };
   12258          395 :         std::vector<EdgeByPts> uniqueEdges;
   12259          395 :         uniqueEdges.reserve(zonePoly.NumSurfaceFaces * 6);
   12260              : 
   12261              :         // construct list of unique edges
   12262          395 :         Vector curVertex;
   12263              :         int curVertexIndex;
   12264         2408 :         for (int iFace = 1; iFace <= zonePoly.NumSurfaceFaces; ++iFace) {
   12265         2013 :             Vector prevVertex;
   12266              :             int prevVertexIndex;
   12267        10194 :             for (int jVertex = 1; jVertex <= zonePoly.SurfaceFace(iFace).NSides; ++jVertex) {
   12268         8181 :                 if (jVertex == 1) {
   12269         2013 :                     prevVertex = zonePoly.SurfaceFace(iFace).FacePoints(zonePoly.SurfaceFace(iFace).NSides); // the last point
   12270         2013 :                     prevVertexIndex = findIndexOfVertex(prevVertex, uniqueVertices);
   12271              :                 } else {
   12272         6168 :                     prevVertex = curVertex;
   12273         6168 :                     prevVertexIndex = curVertexIndex;
   12274              :                 }
   12275         8181 :                 curVertex = zonePoly.SurfaceFace(iFace).FacePoints(jVertex);
   12276         8181 :                 curVertexIndex = findIndexOfVertex(curVertex, uniqueVertices); // uses isAlmostEqual3dPt
   12277        16362 :                 auto it = std::find_if(uniqueEdges.begin(), uniqueEdges.end(), [&curVertexIndex, &prevVertexIndex](const auto &edge) {
   12278        98590 :                     return ((edge.start == curVertexIndex && edge.end == prevVertexIndex) ||
   12279        98590 :                             (edge.start == prevVertexIndex && edge.end == curVertexIndex));
   12280        16362 :                 });
   12281         8181 :                 if (it == uniqueEdges.end()) {
   12282         4196 :                     EdgeByPts curEdge;
   12283         4196 :                     curEdge.start = prevVertexIndex;
   12284         4196 :                     curEdge.end = curVertexIndex;
   12285         4196 :                     curEdge.count = 1;
   12286         4196 :                     curEdge.firstSurfNum = zonePoly.SurfaceFace(iFace).SurfNum;
   12287         4196 :                     uniqueEdges.emplace_back(curEdge);
   12288         4196 :                 } else {
   12289         3985 :                     ++(it->count);
   12290         3985 :                     it->otherSurfNums.push_back(zonePoly.SurfaceFace(iFace).SurfNum);
   12291              :                 }
   12292         8181 :             }
   12293         2013 :         }
   12294              :         // All edges for an enclosed polyhedron should be shared by two (and only two) sides.
   12295              :         // So if the count is not two for all edges, the polyhedron is not enclosed
   12296          395 :         std::vector<EdgeOfSurf> edgesNotTwoCount;
   12297         4591 :         for (const auto &anEdge : uniqueEdges) {
   12298         4196 :             if (anEdge.count != 2) {
   12299         1227 :                 EdgeOfSurf curEdgeOne;
   12300         1227 :                 curEdgeOne.surfNum = anEdge.firstSurfNum;
   12301         1227 :                 curEdgeOne.start = uniqueVertices[anEdge.start];
   12302         1227 :                 curEdgeOne.end = uniqueVertices[anEdge.end];
   12303         1227 :                 curEdgeOne.count = anEdge.count;
   12304         1227 :                 curEdgeOne.otherSurfNums = anEdge.otherSurfNums;
   12305         1227 :                 edgesNotTwoCount.push_back(curEdgeOne);
   12306         1227 :             }
   12307          395 :         }
   12308          790 :         return edgesNotTwoCount;
   12309          395 :     }
   12310              : 
   12311              :     // create a list of unique vertices given the polyhedron describing the zone
   12312          289 :     std::vector<Vector> makeListOfUniqueVertices(DataVectorTypes::Polyhedron const &zonePoly)
   12313              :     {
   12314              :         // J. Glazer - March 2017
   12315              : 
   12316          289 :         std::vector<Vector> uniqVertices;
   12317          289 :         uniqVertices.reserve(zonePoly.NumSurfaceFaces * 6);
   12318              : 
   12319         1842 :         for (int iFace = 1; iFace <= zonePoly.NumSurfaceFaces; ++iFace) {
   12320         7771 :             for (int jVertex = 1; jVertex <= zonePoly.SurfaceFace(iFace).NSides; ++jVertex) {
   12321         6218 :                 Vector curVertex = zonePoly.SurfaceFace(iFace).FacePoints(jVertex);
   12322         6218 :                 if (uniqVertices.size() == 0) {
   12323          286 :                     uniqVertices.emplace_back(curVertex);
   12324              :                 } else {
   12325         5932 :                     bool found = false;
   12326        28394 :                     for (const auto &unqV : uniqVertices) {
   12327        26468 :                         if (isAlmostEqual3dPt(curVertex, unqV)) {
   12328         4006 :                             found = true;
   12329         4006 :                             break;
   12330              :                         }
   12331         5932 :                     }
   12332         5932 :                     if (!found) {
   12333         1926 :                         uniqVertices.emplace_back(curVertex);
   12334              :                     }
   12335              :                 }
   12336         6218 :             }
   12337              :         }
   12338          289 :         return uniqVertices;
   12339            0 :     }
   12340              : 
   12341              :     // updates the polyhedron used to describe a zone to include points on an edge that are between and collinear to points already describing
   12342              :     // the edge
   12343          107 :     DataVectorTypes::Polyhedron updateZonePolygonsForMissingColinearPoints(DataVectorTypes::Polyhedron const &zonePoly,
   12344              :                                                                            std::vector<Vector> const &uniqVertices)
   12345              :     {
   12346              :         // J. Glazer - March 2017
   12347              : 
   12348          107 :         DataVectorTypes::Polyhedron updZonePoly = zonePoly; // set the return value to the original polyhedron describing the zone
   12349              : 
   12350          630 :         for (auto &updFace : updZonePoly.SurfaceFace) {
   12351          523 :             bool insertedVertext = true;
   12352         1704 :             while (insertedVertext) {
   12353          658 :                 insertedVertext = false;
   12354          658 :                 auto &vertices = updFace.FacePoints;
   12355         2894 :                 for (auto it = vertices.begin(); it != vertices.end(); ++it) {
   12356              : 
   12357         2371 :                     auto itnext = std::next(it);
   12358         2371 :                     if (itnext == std::end(vertices)) {
   12359          506 :                         itnext = std::begin(vertices);
   12360              :                     }
   12361              : 
   12362         2371 :                     auto curVertex = *it;      // (AUTO_OK_OBJ) can't tell if a copy is the intended behavior here
   12363         2371 :                     auto nextVertex = *itnext; // (AUTO_OK_OBJ)
   12364              : 
   12365              :                     // now go through all the vertices and see if they are colinear with start and end vertices
   12366        23283 :                     for (const auto &testVertex : uniqVertices) {
   12367        21047 :                         if (!isAlmostEqual3dPt(curVertex, testVertex) && !isAlmostEqual3dPt(nextVertex, testVertex)) {
   12368        16421 :                             if (isPointOnLineBetweenPoints(curVertex, nextVertex, testVertex)) {
   12369          135 :                                 vertices.insert(itnext, testVertex);
   12370          135 :                                 ++updFace.NSides;
   12371          135 :                                 insertedVertext = true;
   12372          135 :                                 break;
   12373              :                             }
   12374              :                         }
   12375         2371 :                     }
   12376              :                     // Break out of the loop on vertices of the surface too, and start again at the while
   12377         2371 :                     if (insertedVertext) {
   12378          135 :                         break;
   12379              :                     }
   12380         2506 :                 }
   12381              :             }
   12382              :         }
   12383          107 :         return updZonePoly;
   12384            0 :     }
   12385              : 
   12386              :     // test if the ceiling and floor are the same except for their height difference by looking at the corners
   12387           76 :     bool areFloorAndCeilingSame(EnergyPlusData &state, DataVectorTypes::Polyhedron const &zonePoly)
   12388              :     {
   12389              :         // J. Glazer - March 2017
   12390              : 
   12391              :         // check if the floor and ceiling are the same
   12392              :         // this is almost equivalent to saying, if you ignore the z-coordinate, are the vertices the same
   12393              :         // so if you could all the unique vertices of the floor and ceiling, ignoring the z-coordinate, they
   12394              :         // should always be even (they would be two but you might define multiple surfaces that meet in a corner)
   12395              : 
   12396           76 :         std::vector<DataVectorTypes::Vector2dCount> floorCeilingXY;
   12397           76 :         floorCeilingXY.reserve(zonePoly.NumSurfaceFaces * 6);
   12398              : 
   12399              :         // make list of x and y coordinates for all faces that are on the floor or ceiling
   12400          419 :         for (int iFace = 1; iFace <= zonePoly.NumSurfaceFaces; ++iFace) {
   12401          343 :             int curSurfNum = zonePoly.SurfaceFace(iFace).SurfNum;
   12402          565 :             if (state.dataSurface->Surface(curSurfNum).Class == SurfaceClass::Floor ||
   12403          222 :                 state.dataSurface->Surface(curSurfNum).Class == SurfaceClass::Roof) {
   12404          908 :                 for (int jVertex = 1; jVertex <= zonePoly.SurfaceFace(iFace).NSides; ++jVertex) {
   12405          726 :                     Vector curVertex = zonePoly.SurfaceFace(iFace).FacePoints(jVertex);
   12406          726 :                     DataVectorTypes::Vector2dCount curXYc;
   12407          726 :                     curXYc.x = curVertex.x;
   12408          726 :                     curXYc.y = curVertex.y;
   12409          726 :                     curXYc.count = 1;
   12410          726 :                     bool found = false;
   12411         2304 :                     for (DataVectorTypes::Vector2dCount &curFloorCeiling : floorCeilingXY) { // can't use just "auto" because updating floorCeilingXY
   12412         1955 :                         if (isAlmostEqual2dPt(curXYc, curFloorCeiling)) {                    // count ignored in comparison
   12413          377 :                             ++curFloorCeiling.count;
   12414          377 :                             found = true;
   12415          377 :                             break;
   12416              :                         }
   12417          726 :                     }
   12418          726 :                     if (!found) {
   12419          349 :                         floorCeilingXY.emplace_back(curXYc);
   12420              :                     }
   12421          726 :                 }
   12422              :             }
   12423              :         }
   12424              :         // now make sure every point has been counted and even number of times (usually twice)
   12425              :         // if they are then the ceiling and floor are (almost certainly) the same x and y coordinates.
   12426           76 :         bool areFlrAndClgSame = true;
   12427           76 :         if (floorCeilingXY.size() > 0) {
   12428          179 :             for (auto const &curFloorCeiling : floorCeilingXY) {
   12429          161 :                 if (curFloorCeiling.count % 2 != 0) {
   12430           57 :                     areFlrAndClgSame = false;
   12431           57 :                     break;
   12432              :                 }
   12433           75 :             }
   12434              :         } else {
   12435            1 :             areFlrAndClgSame = false;
   12436              :         }
   12437           76 :         return areFlrAndClgSame;
   12438           76 :     }
   12439              : 
   12440              :     // test if the walls of a zone are all the same height using the polyhedron describing the zone geometry
   12441          288 :     bool areWallHeightSame(EnergyPlusData &state, DataVectorTypes::Polyhedron const &zonePoly)
   12442              :     {
   12443              :         // J. Glazer - March 2017
   12444              : 
   12445              :         // test if all the wall heights are the same (all walls have the same maximum z-coordinate
   12446              : 
   12447          288 :         bool areWlHgtSame = true;
   12448          288 :         Real64 wallHeightZ = -Constant::BigNumber;
   12449          288 :         bool foundWallHeight = false;
   12450         1715 :         for (int iFace = 1; iFace <= zonePoly.NumSurfaceFaces; ++iFace) {
   12451         1443 :             int curSurfNum = zonePoly.SurfaceFace(iFace).SurfNum;
   12452         1443 :             if (state.dataSurface->Surface(curSurfNum).Class == SurfaceClass::Wall) {
   12453          908 :                 Real64 maxZ = -Constant::BigNumber;
   12454         4543 :                 for (int jVertex = 1; jVertex <= zonePoly.SurfaceFace(iFace).NSides; ++jVertex) {
   12455         3635 :                     Vector curVertex = zonePoly.SurfaceFace(iFace).FacePoints(jVertex);
   12456         3635 :                     if (maxZ < curVertex.z) {
   12457          992 :                         maxZ = curVertex.z;
   12458              :                     }
   12459         3635 :                 }
   12460          908 :                 if (foundWallHeight) {
   12461          637 :                     if (std::abs(maxZ - wallHeightZ) > Constant::TwoCentimeters) {
   12462           16 :                         areWlHgtSame = false;
   12463           16 :                         break;
   12464              :                     }
   12465              :                 } else {
   12466          271 :                     wallHeightZ = maxZ;
   12467          271 :                     foundWallHeight = true;
   12468              :                 }
   12469              :             }
   12470              :         }
   12471          288 :         return areWlHgtSame;
   12472              :     }
   12473              : 
   12474              :     // tests if the floor is horizontal, ceiling is horizontal, and walls are vertical and returns all three as a tuple of booleans
   12475          292 :     std::tuple<bool, bool, bool> areSurfaceHorizAndVert(EnergyPlusData &state, DataVectorTypes::Polyhedron const &zonePoly)
   12476              :     {
   12477              :         // J. Glazer - March 2017
   12478              : 
   12479              :         // check if floors and ceilings are horizontal and walls are vertical
   12480          292 :         bool isFlrHoriz = true;
   12481          292 :         bool isClgHoriz = true;
   12482          292 :         bool areWlVert = true;
   12483         1895 :         for (int iFace = 1; iFace <= zonePoly.NumSurfaceFaces; ++iFace) {
   12484         1603 :             int curSurfNum = zonePoly.SurfaceFace(iFace).SurfNum;
   12485         1603 :             if (state.dataSurface->Surface(curSurfNum).Class == SurfaceClass::Floor) {
   12486          354 :                 if (std::abs(state.dataSurface->Surface(curSurfNum).Tilt - 180.) > 1.) { // with 1 degree angle
   12487           25 :                     isFlrHoriz = false;
   12488              :                 }
   12489         1249 :             } else if (state.dataSurface->Surface(curSurfNum).Class == SurfaceClass::Roof) { // includes ceilings
   12490          295 :                 if (std::abs(state.dataSurface->Surface(curSurfNum).Tilt) > 1.) {            // with 1 degree angle of
   12491           58 :                     isClgHoriz = false;
   12492              :                 }
   12493          954 :             } else if (state.dataSurface->Surface(curSurfNum).Class == SurfaceClass::Wall) {
   12494          954 :                 if (std::abs(state.dataSurface->Surface(curSurfNum).Tilt - 90) > 1.) { // with 1 degree angle
   12495           32 :                     areWlVert = false;
   12496              :                 }
   12497              :             }
   12498              :         }
   12499          584 :         return std::make_tuple(isFlrHoriz, isClgHoriz, areWlVert);
   12500              :     }
   12501              : 
   12502              :     // tests whether a pair of walls in the zone are the same except offset from one another and facing the opposite direction and also
   12503              :     // returns the wall area and distance between
   12504           25 :     bool areOppositeWallsSame(EnergyPlusData &state,
   12505              :                               DataVectorTypes::Polyhedron const &zonePoly,
   12506              :                               Real64 &oppositeWallArea,            // return the area of the wall that has an opposite wall
   12507              :                               Real64 &distanceBetweenOppositeWalls // returns distance
   12508              :     )
   12509              :     {
   12510              :         // J. Glazer - March 2017
   12511              : 
   12512              :         // approach: if opposite surfaces have opposite azimuth and same area, then check the distance between the
   12513              :         // vertices( one counting backwards ) and if it is the same distance than assume that it is the same.
   12514           25 :         bool foundOppEqual = false;
   12515           76 :         for (int iFace = 1; iFace <= zonePoly.NumSurfaceFaces; ++iFace) {
   12516           57 :             int curSurfNum = zonePoly.SurfaceFace(iFace).SurfNum;
   12517           57 :             if (state.dataSurface->Surface(curSurfNum).Class == SurfaceClass::Wall) {
   12518           31 :                 std::vector<int> facesAtAz = listOfFacesFacingAzimuth(state, zonePoly, state.dataSurface->Surface(curSurfNum).Azimuth);
   12519           31 :                 bool allFacesEquidistant = true;
   12520           31 :                 oppositeWallArea = 0.;
   12521           42 :                 for (int curFace : facesAtAz) {
   12522           36 :                     int possOppFace = findPossibleOppositeFace(state, zonePoly, curFace);
   12523           36 :                     if (possOppFace > 0) { // an opposite fact was found
   12524           20 :                         oppositeWallArea += state.dataSurface->Surface(zonePoly.SurfaceFace(curFace).SurfNum).Area;
   12525           20 :                         if (!areCornersEquidistant(zonePoly, curFace, possOppFace, distanceBetweenOppositeWalls)) {
   12526            9 :                             allFacesEquidistant = false;
   12527            9 :                             break;
   12528              :                         }
   12529              :                     } else {
   12530           16 :                         allFacesEquidistant = false;
   12531           16 :                         break;
   12532              :                     }
   12533           31 :                 }
   12534           31 :                 if (allFacesEquidistant) {
   12535            6 :                     foundOppEqual = true;
   12536            6 :                     break; // only need to find the first case where opposite walls are the same
   12537              :                 }
   12538           31 :             }
   12539              :         }
   12540           25 :         return foundOppEqual;
   12541              :     }
   12542              : 
   12543              :     // provides a list of indices of polyhedron faces that are facing a specific azimuth
   12544           39 :     std::vector<int> listOfFacesFacingAzimuth(EnergyPlusData &state, DataVectorTypes::Polyhedron const &zonePoly, Real64 const azimuth)
   12545              :     {
   12546              :         // J. Glazer - March 2017
   12547              : 
   12548           39 :         std::vector<int> facingAzimuth;
   12549           39 :         facingAzimuth.reserve(zonePoly.NumSurfaceFaces);
   12550              : 
   12551          287 :         for (int iFace = 1; iFace <= zonePoly.NumSurfaceFaces; ++iFace) {
   12552          248 :             int curSurfNum = zonePoly.SurfaceFace(iFace).SurfNum;
   12553          248 :             if (General::rotAzmDiffDeg(state.dataSurface->Surface(curSurfNum).Azimuth, azimuth) < 1.) {
   12554           65 :                 facingAzimuth.emplace_back(iFace);
   12555              :             }
   12556              :         }
   12557           39 :         return facingAzimuth;
   12558            0 :     }
   12559              : 
   12560              :     // returns the index of the face of a polyhedron that is probably opposite of the face index provided
   12561           52 :     int findPossibleOppositeFace(EnergyPlusData &state, DataVectorTypes::Polyhedron const &zonePoly, int const faceIndex)
   12562              :     {
   12563              :         // J. Glazer - March 2017
   12564              : 
   12565           52 :         int selectedSurNum = zonePoly.SurfaceFace(faceIndex).SurfNum;
   12566           52 :         Real64 selectedAzimuth = state.dataSurface->Surface(selectedSurNum).Azimuth;
   12567           52 :         Real64 oppositeAzimuth = fmod(selectedAzimuth + 180., 360.);
   12568           52 :         Real64 selectedArea = state.dataSurface->Surface(selectedSurNum).Area;
   12569           52 :         int selectedNumCorners = zonePoly.SurfaceFace(faceIndex).NSides;
   12570           52 :         int found = -1;
   12571              : 
   12572          215 :         for (int iFace = 1; iFace <= zonePoly.NumSurfaceFaces; ++iFace) {
   12573          193 :             int curSurfNum = zonePoly.SurfaceFace(iFace).SurfNum;
   12574          368 :             if ((zonePoly.SurfaceFace(iFace).NSides == selectedNumCorners) &&
   12575          368 :                 (std::abs(state.dataSurface->Surface(curSurfNum).Area - selectedArea) < 0.01) &&
   12576           98 :                 (std::abs(state.dataSurface->Surface(curSurfNum).Azimuth - oppositeAzimuth) < 1.)) {
   12577           30 :                 found = iFace;
   12578           30 :                 break;
   12579              :             }
   12580              :         }
   12581           52 :         return found;
   12582              :     }
   12583              : 
   12584              :     // tests if the corners of one face of the polyhedron are the same distance from corners of another face
   12585           22 :     bool areCornersEquidistant(DataVectorTypes::Polyhedron const &zonePoly, int const faceIndex, int const opFaceIndex, Real64 &distanceBetween)
   12586              :     {
   12587              :         // J. Glazer - March 2017
   12588              : 
   12589           22 :         bool allAreEquidistant = true;
   12590           22 :         Real64 firstDistance = -99.;
   12591           22 :         if (zonePoly.SurfaceFace(faceIndex).NSides == zonePoly.SurfaceFace(opFaceIndex).NSides) { // double check that the number of sides match
   12592           82 :             for (int iVertex = 1; iVertex <= zonePoly.SurfaceFace(faceIndex).NSides; ++iVertex) {
   12593           70 :                 int iVertexOpp = 1 + zonePoly.SurfaceFace(faceIndex).NSides - iVertex; // count backwards for opposite face
   12594              :                 Real64 curDistBetwCorners =
   12595           70 :                     distance(zonePoly.SurfaceFace(faceIndex).FacePoints(iVertex), zonePoly.SurfaceFace(opFaceIndex).FacePoints(iVertexOpp));
   12596           70 :                 if (iVertex == 1) {
   12597           22 :                     firstDistance = curDistBetwCorners;
   12598              :                 } else {
   12599           48 :                     if (std::abs(curDistBetwCorners - firstDistance) > Constant::OneCentimeter) {
   12600           10 :                         allAreEquidistant = false;
   12601           10 :                         break;
   12602              :                     }
   12603              :                 }
   12604              :             }
   12605              :         } else {
   12606            0 :             allAreEquidistant = false;
   12607              :         }
   12608           22 :         if (allAreEquidistant) {
   12609           12 :             distanceBetween = firstDistance;
   12610              :         }
   12611           22 :         return allAreEquidistant;
   12612              :     }
   12613              : 
   12614              :     // test if two points in space are in the same position based on a small tolerance
   12615       125869 :     bool isAlmostEqual3dPt(DataVectorTypes::Vector v1, DataVectorTypes::Vector v2)
   12616              :     {
   12617              :         // J. Glazer - March 2017
   12618              : 
   12619       157260 :         return ((std::abs(v1.x - v2.x) < Constant::OneCentimeter) && (std::abs(v1.y - v2.y) < Constant::OneCentimeter) &&
   12620       157260 :                 (std::abs(v1.z - v2.z) < Constant::OneCentimeter));
   12621              :     }
   12622              : 
   12623              :     // test if two points on a plane are in the same position based on a small tolerance
   12624         1961 :     bool isAlmostEqual2dPt(DataVectorTypes::Vector_2d v1, DataVectorTypes::Vector_2d v2)
   12625              :     {
   12626              :         // J. Glazer - March 2017
   12627              : 
   12628         1961 :         return ((std::abs(v1.x - v2.x) < Constant::OneCentimeter) && (std::abs(v1.y - v2.y) < Constant::OneCentimeter));
   12629              :     }
   12630              : 
   12631              :     // test if two points on a plane are in the same position based on a small tolerance (based on Vector2dCount comparison)
   12632            0 :     bool isAlmostEqual2dPt(DataVectorTypes::Vector2dCount v1, DataVectorTypes::Vector2dCount v2)
   12633              :     {
   12634              :         // J. Glazer - March 2017
   12635              : 
   12636            0 :         return ((std::abs(v1.x - v2.x) < Constant::OneCentimeter) && (std::abs(v1.y - v2.y) < Constant::OneCentimeter));
   12637              :     }
   12638              : 
   12639              :     // returns the index of vertex in a list that is in the same position in space as the given vertex
   12640        10200 :     int findIndexOfVertex(DataVectorTypes::Vector vertexToFind, std::vector<DataVectorTypes::Vector> const &listOfVertices)
   12641              :     {
   12642              :         // J. Glazer - March 2017
   12643              : 
   12644        48683 :         for (std::size_t i = 0; i < listOfVertices.size(); i++) {
   12645        48681 :             if (isAlmostEqual3dPt(listOfVertices[i], vertexToFind)) {
   12646        10198 :                 return i;
   12647              :             }
   12648              :         }
   12649            2 :         return -1;
   12650              :     }
   12651              : 
   12652              :     // returns the distance between two points in space
   12653        12452 :     Real64 distance(DataVectorTypes::Vector v1, DataVectorTypes::Vector v2)
   12654              :     {
   12655              :         // J. Glazer - March 2017
   12656              : 
   12657        12452 :         return sqrt(pow(v1.x - v2.x, 2) + pow(v1.y - v2.y, 2) + pow(v1.z - v2.z, 2));
   12658              :     }
   12659              : 
   12660        17621 :     Real64 distanceFromPointToLine(DataVectorTypes::Vector start, DataVectorTypes::Vector end, DataVectorTypes::Vector test)
   12661              :     {
   12662              :         // np.linalg.norm(np.cross(e-s,p-s)/np.linalg.norm(e-s))
   12663        17621 :         DataVectorTypes::Vector t = end - start;
   12664        17621 :         t.normalize(); // Unit vector of start to end
   12665              : 
   12666        17621 :         DataVectorTypes::Vector other = test - start;
   12667              : 
   12668        17621 :         DataVectorTypes::Vector projection = DataVectorTypes::cross(t, other); // normal unit vector, that's the distance component
   12669        35242 :         return projection.length();
   12670        17621 :     }
   12671              : 
   12672              :     // tests if a point in space lies on the line segment defined by two other points
   12673        17620 :     bool isPointOnLineBetweenPoints(DataVectorTypes::Vector start, DataVectorTypes::Vector end, DataVectorTypes::Vector test)
   12674              :     {
   12675              :         // J. Glazer - March 2017
   12676              :         // The tolerance has to be low enough. Take for eg a plenum that has an edge that's 30meters long, you risk adding point from the
   12677              :         // floor to the roof, cf #7383 compute the shortest distance from the point to the line first to avoid false positive
   12678        17620 :         if (distanceFromPointToLine(start, end, test) <
   12679              :             Constant::OneCentimeter) { // distanceFromPointToLine always positive, it's calculated as norml_L2
   12680         1039 :             return (std::abs((distance(start, end) - (distance(start, test) + distance(test, end)))) < Constant::OneCentimeter);
   12681              :         }
   12682        16581 :         return false;
   12683              :     }
   12684              : 
   12685         2924 :     bool EdgeOfSurf::operator==(const EdgeOfSurf &other) const
   12686              :     {
   12687         8854 :         return ((isAlmostEqual3dPt(this->start, other.start) && isAlmostEqual3dPt(this->end, other.end)) ||
   12688         5930 :                 (isAlmostEqual3dPt(this->start, other.end) && isAlmostEqual3dPt(this->end, other.start)));
   12689              :     }
   12690              : 
   12691            0 :     bool EdgeOfSurf::operator!=(const EdgeOfSurf &other) const
   12692              :     {
   12693            0 :         return !(*this == other);
   12694              :     }
   12695              : 
   12696         1972 :     bool EdgeOfSurf::containsPoints(const Vector &vertex) const
   12697              :     {
   12698         5137 :         return (!isAlmostEqual3dPt(this->start, vertex) && !isAlmostEqual3dPt(this->end, vertex) &&
   12699         5137 :                 isPointOnLineBetweenPoints(this->start, this->end, vertex));
   12700              :     }
   12701              : 
   12702          372 :     double EdgeOfSurf::length() const
   12703              :     {
   12704          372 :         return distance(this->start, this->end);
   12705              :     }
   12706              : 
   12707         1702 :     void ProcessSurfaceVertices(EnergyPlusData &state, int const ThisSurf, bool &ErrorsFound)
   12708              :     {
   12709              :         // SUBROUTINE INFORMATION:
   12710              :         //       AUTHOR         Legacy Code (Walton)
   12711              :         //       DATE WRITTEN   1976
   12712              :         //       MODIFIED        FW, Mar 2002: Add triangular windows
   12713              :         //                       FW, May 2002: modify test for 4-sided but non-rectangular subsurfaces
   12714              :         //                       FW, Sep 2002: add shape for base surfaces (walls and detached shading surfaces)
   12715              : 
   12716              :         // PURPOSE OF THIS SUBROUTINE:
   12717              :         // This subroutine processes each surface into the vertex representation used
   12718              :         // by the shading procedures.
   12719              : 
   12720              :         // METHODOLOGY EMPLOYED:
   12721              :         // Detached Shading, Base Surfaces, Attached Shading surfaces are represented in the
   12722              :         // same manner as original.  Subsurfaces (windows, doors) are a "relative coordinate".
   12723              : 
   12724              :         static constexpr std::string_view RoutineName("ProcessSurfaceVertices: ");
   12725              : 
   12726              :         Real64 X1;           // Intermediate Result
   12727              :         Real64 Y1;           // Intermediate Result
   12728              :         Real64 Z1;           // Intermediate Result
   12729              :         Real64 XLLC;         // X-coordinate of lower left corner
   12730              :         Real64 YLLC;         // Y-coordinate of lower left corner
   12731              :         Real64 ZLLC;         // Z-coordinate of lower left corner
   12732              :         int n;               // Vertex Number in Loop
   12733              :         int ThisBaseSurface; // Current base surface
   12734              :         Real64 Xp;
   12735              :         Real64 Yp;
   12736              :         Real64 Zp;
   12737              :         Real64 SurfWorldAz; // Surface Azimuth (facing)
   12738              :         Real64 SurfTilt;    // Surface Tilt
   12739         1702 :         DataSurfaces::SurfaceShape ThisShape(DataSurfaces::SurfaceShape::None);
   12740              :         bool BaseSurface; // True if a base surface or a detached shading surface
   12741              :         Real64 ThisSurfAz;
   12742              :         Real64 ThisSurfTilt;
   12743              :         Real64 ThisReveal;
   12744              :         Real64 ThisWidth;
   12745              :         Real64 ThisHeight;
   12746              :         Real64 FrWidth;      // Frame width for exterior windows (m)
   12747              :         Real64 FrArea;       // Frame area for exterior windows(m2)
   12748              :         Real64 DivWidth;     // Divider width for exterior windows (m)
   12749              :         Real64 DivArea;      // Divider area for exterior windows (m2)
   12750              :         Real64 DivFrac;      // Fraction of divider area without overlaps
   12751              :         bool ErrorInSurface; // false/true, depending on pass through routine
   12752              :         bool HeatTransSurf;
   12753              :         Real64 OutOfLine;
   12754              : 
   12755              :         // Object Data
   12756         1702 :         Vectors::PlaneEq BasePlane;
   12757         1702 :         Vector TVect;
   12758         1702 :         Vector CoordinateTransVector;
   12759              : 
   12760         1702 :         if (state.dataSurface->Surface(ThisSurf).VerticesProcessed) {
   12761           10 :             return;
   12762              :         }
   12763              : 
   12764         1692 :         ErrorInSurface = false;
   12765              : 
   12766         1692 :         if (state.dataSurfaceGeometry->ProcessSurfaceVerticesOneTimeFlag) {
   12767          180 :             state.dataSurfaceGeometry->Xpsv.allocate(state.dataSurface->MaxVerticesPerSurface);
   12768          180 :             state.dataSurfaceGeometry->Ypsv.allocate(state.dataSurface->MaxVerticesPerSurface);
   12769          180 :             state.dataSurfaceGeometry->Zpsv.allocate(state.dataSurface->MaxVerticesPerSurface);
   12770          180 :             state.dataSurfaceGeometry->Xpsv = 0.0;
   12771          180 :             state.dataSurfaceGeometry->Ypsv = 0.0;
   12772          180 :             state.dataSurfaceGeometry->Zpsv = 0.0;
   12773          180 :             state.dataSurfaceGeometry->ProcessSurfaceVerticesOneTimeFlag = false;
   12774              :         }
   12775              : 
   12776              :         // Categorize this surface
   12777         1692 :         auto &surf = state.dataSurface->Surface(ThisSurf);
   12778         1692 :         BaseSurface = (surf.BaseSurf == 0 || surf.BaseSurf == ThisSurf);
   12779              : 
   12780         1692 :         ThisBaseSurface = surf.BaseSurf; // Dont know if this is still needed or not
   12781         1692 :         HeatTransSurf = surf.HeatTransSurf;
   12782              : 
   12783              :         // Kludge for daylighting shelves
   12784         1692 :         if (surf.IsShadowing) {
   12785           74 :             ThisBaseSurface = ThisSurf;
   12786           74 :             HeatTransSurf = true;
   12787              :         }
   12788              : 
   12789              :         // IF (Surface(ThisSurf)%Name(1:3) /= 'Mir') THEN
   12790         1692 :         if (!surf.MirroredSurf) {
   12791              :             bool IsCoPlanar;
   12792              :             int LastVertexInError;
   12793         1655 :             Vectors::CalcCoPlanarNess(surf.Vertex, surf.Sides, IsCoPlanar, OutOfLine, LastVertexInError);
   12794         1655 :             if (!IsCoPlanar) {
   12795            0 :                 if (OutOfLine > 0.01) {
   12796            0 :                     ShowSevereError(state,
   12797            0 :                                     format("{}Suspected non-planar surface:\"{}\", Max \"out of line\"={:.5T} at Vertex # {}",
   12798              :                                            RoutineName,
   12799            0 :                                            surf.Name,
   12800              :                                            OutOfLine,
   12801              :                                            LastVertexInError));
   12802              :                 } else {
   12803            0 :                     ShowWarningError(state,
   12804            0 :                                      format("{}Possible non-planar surface:\"{}\", Max \"out of line\"={:.5T} at Vertex # {}",
   12805              :                                             RoutineName,
   12806            0 :                                             surf.Name,
   12807              :                                             OutOfLine,
   12808              :                                             LastVertexInError));
   12809              :                 }
   12810              :                 //       ErrorInSurface=.TRUE.
   12811              :             }
   12812              :         }
   12813              : 
   12814         1692 :         if (BaseSurface) {
   12815         1557 :             SurfWorldAz = surf.Azimuth;
   12816         1557 :             SurfTilt = surf.Tilt;
   12817         7791 :             for (n = 1; n <= surf.Sides; ++n) {
   12818         6234 :                 state.dataSurfaceGeometry->Xpsv(n) = surf.Vertex(n).x;
   12819         6234 :                 state.dataSurfaceGeometry->Ypsv(n) = surf.Vertex(n).y;
   12820         6234 :                 state.dataSurfaceGeometry->Zpsv(n) = surf.Vertex(n).z;
   12821              :             }
   12822         1557 :             TVect = surf.Vertex(3) - surf.Vertex(2);
   12823         1557 :             ThisWidth = Vectors::VecLength(TVect);
   12824         1557 :             TVect = surf.Vertex(2) - surf.Vertex(1);
   12825         1557 :             ThisHeight = Vectors::VecLength(TVect);
   12826         1557 :             surf.Width = ThisWidth;
   12827         1557 :             surf.Height = ThisHeight; // For a horizontal surface this is actually length!
   12828         1557 :             if (surf.Sides == 3) {
   12829           16 :                 surf.Shape = DataSurfaces::SurfaceShape::Triangle;
   12830         1541 :             } else if (surf.Sides == 4) {
   12831              :                 // Test for rectangularity
   12832         1527 :                 if (isRectangle(state, ThisSurf)) {
   12833         1404 :                     surf.Shape = DataSurfaces::SurfaceShape::Rectangle;
   12834              :                 } else {
   12835          123 :                     surf.Shape = DataSurfaces::SurfaceShape::Quadrilateral;
   12836              :                 }
   12837              :             } else { // Surface( ThisSurf ).Sides > 4
   12838           14 :                 surf.Shape = DataSurfaces::SurfaceShape::Polygonal;
   12839           14 :                 if (std::abs(ThisHeight * ThisWidth - surf.GrossArea) > 0.001) {
   12840           14 :                     surf.Width = std::sqrt(surf.GrossArea);
   12841           14 :                     surf.Height = surf.Width;
   12842           14 :                     ThisWidth = surf.Width;
   12843           14 :                     ThisHeight = surf.Height;
   12844              :                 }
   12845              :             }
   12846              : 
   12847              :         } else { // It's a subsurface to previous basesurface in this set of calls
   12848              : 
   12849          135 :             ThisSurfAz = surf.Azimuth;
   12850          135 :             ThisSurfTilt = surf.Tilt;
   12851              : 
   12852              :             // Retrieve base surface info
   12853          135 :             Real64 const baseSurfWorldAz = state.dataSurface->Surface(ThisBaseSurface).Azimuth;
   12854          135 :             Real64 const baseSurfTilt = state.dataSurface->Surface(ThisBaseSurface).Tilt;
   12855          135 :             Real64 const BaseCosAzimuth = std::cos(baseSurfWorldAz * Constant::DegToRad);
   12856          135 :             Real64 const BaseSinAzimuth = std::sin(baseSurfWorldAz * Constant::DegToRad);
   12857          135 :             Real64 const BaseCosTilt = std::cos(baseSurfTilt * Constant::DegToRad);
   12858          135 :             Real64 const BaseSinTilt = std::sin(baseSurfTilt * Constant::DegToRad);
   12859          135 :             Real64 const BaseXLLC = state.dataSurface->Surface(ThisBaseSurface).Vertex(2).x;
   12860          135 :             Real64 const BaseYLLC = state.dataSurface->Surface(ThisBaseSurface).Vertex(2).y;
   12861          135 :             Real64 const BaseZLLC = state.dataSurface->Surface(ThisBaseSurface).Vertex(2).z;
   12862              : 
   12863          135 :             if (HeatTransSurf) {
   12864              : 
   12865          131 :                 if (surf.Sides == 4) {
   12866          129 :                     ThisShape = DataSurfaces::SurfaceShape::RectangularDoorWindow;
   12867            2 :                 } else if (surf.Sides == 3 && surf.Class == SurfaceClass::Window) {
   12868            1 :                     ThisShape = DataSurfaces::SurfaceShape::TriangularWindow;
   12869            1 :                 } else if (surf.Sides == 3 && surf.Class == SurfaceClass::Door) {
   12870            1 :                     ThisShape = DataSurfaces::SurfaceShape::TriangularDoor;
   12871              :                 } else {
   12872            0 :                     assert(false);
   12873              :                 }
   12874              : 
   12875              :             } else { //  this is a shadowing subsurface
   12876              : 
   12877            4 :                 if (std::abs(state.dataSurface->Surface(surf.BaseSurf).Tilt - ThisSurfTilt) <= 0.01) {
   12878              :                     // left or right fin
   12879            4 :                     if (ThisSurfAz < 0.0) {
   12880            0 :                         ThisSurfAz += 360.0;
   12881              :                     }
   12882            4 :                     if (ThisSurfAz > state.dataSurface->Surface(surf.BaseSurf).Azimuth) {
   12883            0 :                         ThisShape = DataSurfaces::SurfaceShape::RectangularLeftFin;
   12884              :                     } else {
   12885            4 :                         ThisShape = DataSurfaces::SurfaceShape::RectangularRightFin;
   12886              :                     }
   12887              :                 } else {
   12888            0 :                     ThisShape = DataSurfaces::SurfaceShape::RectangularOverhang;
   12889              :                 }
   12890              :             }
   12891              : 
   12892              :             // Setting relative coordinates for shadowing calculations for subsurfaces
   12893              :             bool SError; // Bool used for return value of calls to PlaneEquation
   12894          135 :             switch (ThisShape) {
   12895          129 :             case DataSurfaces::SurfaceShape::RectangularDoorWindow: { // Rectangular heat transfer subsurface
   12896          258 :                 Vectors::PlaneEquation(
   12897          129 :                     state.dataSurface->Surface(surf.BaseSurf).Vertex, state.dataSurface->Surface(surf.BaseSurf).Sides, BasePlane, SError);
   12898          129 :                 if (SError) {
   12899            0 :                     ShowSevereError(state, format("{}Degenerate surface (likely two vertices equal):\"{}\".", RoutineName, surf.Name));
   12900            0 :                     ErrorInSurface = true;
   12901              :                 }
   12902          129 :                 ThisReveal = -Vectors::Pt2Plane(surf.Vertex(2), BasePlane);
   12903          129 :                 if (std::abs(ThisReveal) < 0.0002) {
   12904          124 :                     ThisReveal = 0.0;
   12905              :                 }
   12906          129 :                 surf.Reveal = ThisReveal;
   12907          129 :                 Xp = surf.Vertex(2).x - BaseXLLC;
   12908          129 :                 Yp = surf.Vertex(2).y - BaseYLLC;
   12909          129 :                 Zp = surf.Vertex(2).z - BaseZLLC;
   12910          129 :                 XLLC = -Xp * BaseCosAzimuth + Yp * BaseSinAzimuth;
   12911          129 :                 YLLC = -Xp * BaseSinAzimuth * BaseCosTilt - Yp * BaseCosAzimuth * BaseCosTilt + Zp * BaseSinTilt;
   12912          129 :                 ZLLC = Xp * BaseSinAzimuth * BaseSinTilt + Yp * BaseCosAzimuth * BaseSinTilt + Zp * BaseCosTilt;
   12913          129 :                 TVect = surf.Vertex(3) - surf.Vertex(2);
   12914          129 :                 ThisWidth = Vectors::VecLength(TVect);
   12915          129 :                 TVect = surf.Vertex(2) - surf.Vertex(1);
   12916          129 :                 ThisHeight = Vectors::VecLength(TVect);
   12917          129 :                 surf.Width = ThisWidth;
   12918          129 :                 surf.Height = ThisHeight;
   12919              : 
   12920              :                 // Processing of 4-sided but non-rectangular Window, Door or GlassDoor, for use in calc of convective air flow.
   12921          129 :                 if (!isRectangle(state, ThisSurf)) {
   12922              : 
   12923              :                     // Transform the surface into an equivalent rectangular surface with the same area and aspect ratio.
   12924            3 :                     MakeEquivalentRectangle(state, ThisSurf, ErrorsFound);
   12925              : 
   12926            3 :                     if (state.dataGlobal->DisplayExtraWarnings) {
   12927            0 :                         ShowWarningError(state, format("{}Suspected 4-sided but non-rectangular Window, Door or GlassDoor:", RoutineName));
   12928            0 :                         ShowContinueError(
   12929              :                             state,
   12930            0 :                             format("Surface={} is transformed into an equivalent rectangular surface with the same area and aspect ratio. ",
   12931            0 :                                    surf.Name));
   12932              :                     }
   12933              :                 }
   12934              : 
   12935          129 :                 state.dataSurfaceGeometry->Xpsv(1) = XLLC;
   12936          129 :                 state.dataSurfaceGeometry->Xpsv(2) = XLLC;
   12937          129 :                 state.dataSurfaceGeometry->Xpsv(3) = XLLC + surf.Width;
   12938          129 :                 state.dataSurfaceGeometry->Xpsv(4) = XLLC + surf.Width;
   12939          129 :                 state.dataSurfaceGeometry->Ypsv(1) = YLLC + surf.Height;
   12940          129 :                 state.dataSurfaceGeometry->Ypsv(4) = YLLC + surf.Height;
   12941          129 :                 state.dataSurfaceGeometry->Ypsv(2) = YLLC;
   12942          129 :                 state.dataSurfaceGeometry->Ypsv(3) = YLLC;
   12943          129 :                 state.dataSurfaceGeometry->Zpsv(1) = ZLLC;
   12944          129 :                 state.dataSurfaceGeometry->Zpsv(2) = ZLLC;
   12945          129 :                 state.dataSurfaceGeometry->Zpsv(3) = ZLLC;
   12946          129 :                 state.dataSurfaceGeometry->Zpsv(4) = ZLLC;
   12947              : 
   12948          129 :                 if (surf.Class == SurfaceClass::Window && surf.ExtBoundCond == DataSurfaces::ExternalEnvironment && surf.FrameDivider > 0) {
   12949           19 :                     int FrDivNum = surf.FrameDivider;
   12950              :                     // Set flag for calculating beam solar reflection from outside and/or inside window reveal
   12951            0 :                     if ((surf.Reveal > 0.0 && state.dataSurface->FrameDivider(FrDivNum).OutsideRevealSolAbs > 0.0) ||
   12952           19 :                         (state.dataSurface->FrameDivider(FrDivNum).InsideSillDepth > 0.0 &&
   12953           38 :                          state.dataSurface->FrameDivider(FrDivNum).InsideSillSolAbs > 0.0) ||
   12954           19 :                         (state.dataSurface->FrameDivider(FrDivNum).InsideReveal > 0.0 &&
   12955            0 :                          state.dataSurface->FrameDivider(FrDivNum).InsideRevealSolAbs > 0.0)) {
   12956            0 :                         state.dataHeatBal->CalcWindowRevealReflection = true;
   12957              :                     }
   12958              : 
   12959              :                     // For exterior window with frame, subtract frame area from base surface
   12960              :                     // (only rectangular windows are allowed to have a frame and/or divider;
   12961              :                     // Surface(ThisSurf)%FrameDivider will be 0 for triangular windows)
   12962           19 :                     FrWidth = state.dataSurface->FrameDivider(FrDivNum).FrameWidth;
   12963           19 :                     if (FrWidth > 0.0) {
   12964           19 :                         FrArea = (surf.Height + 2.0 * FrWidth) * (surf.Width + 2.0 * FrWidth) - surf.Area / surf.Multiplier;
   12965           19 :                         state.dataSurface->SurfWinFrameArea(ThisSurf) = FrArea * surf.Multiplier;
   12966           19 :                         if ((state.dataSurface->Surface(surf.BaseSurf).Area - state.dataSurface->SurfWinFrameArea(ThisSurf)) <= 0.0) {
   12967            0 :                             ShowSevereError(state, format("{}Base Surface=\"{}\", ", RoutineName, state.dataSurface->Surface(surf.BaseSurf).Name));
   12968            0 :                             ShowContinueError(state,
   12969            0 :                                               format("Window Surface=\"{}\" area (with frame) is too large to fit on the surface.", surf.Name));
   12970            0 :                             ShowContinueError(state,
   12971            0 :                                               format("Base surface area (-windows and doors)=[{:.2T}] m2, frame area=[{:.2T}] m2.",
   12972            0 :                                                      state.dataSurface->Surface(surf.BaseSurf).Area,
   12973            0 :                                                      state.dataSurface->SurfWinFrameArea(ThisSurf)));
   12974            0 :                             ErrorInSurface = true;
   12975              :                         }
   12976           19 :                         state.dataSurface->Surface(surf.BaseSurf).Area -= state.dataSurface->SurfWinFrameArea(ThisSurf);
   12977              :                     }
   12978              :                     // If exterior window has divider, subtract divider area to get glazed area
   12979           19 :                     DivWidth = state.dataSurface->FrameDivider(surf.FrameDivider).DividerWidth;
   12980           19 :                     if (DivWidth > 0.0 && !ErrorInSurface) {
   12981           19 :                         DivArea = DivWidth * (state.dataSurface->FrameDivider(FrDivNum).HorDividers * surf.Width +
   12982           19 :                                               state.dataSurface->FrameDivider(FrDivNum).VertDividers * surf.Height -
   12983           19 :                                               state.dataSurface->FrameDivider(FrDivNum).HorDividers *
   12984           19 :                                                   state.dataSurface->FrameDivider(FrDivNum).VertDividers * DivWidth);
   12985           19 :                         state.dataSurface->SurfWinDividerArea(ThisSurf) = DivArea * surf.Multiplier;
   12986           19 :                         if ((surf.Area - state.dataSurface->SurfWinDividerArea(ThisSurf)) <= 0.0) {
   12987            0 :                             ShowSevereError(state, format("{}Divider area exceeds glazed opening for window {}", RoutineName, surf.Name));
   12988            0 :                             ShowContinueError(state,
   12989            0 :                                               format("Window surface area=[{:.2T}] m2, divider area=[{:.2T}] m2.",
   12990            0 :                                                      surf.Area,
   12991            0 :                                                      state.dataSurface->SurfWinDividerArea(ThisSurf)));
   12992            0 :                             ErrorInSurface = true;
   12993              :                         }
   12994           19 :                         surf.Area -= state.dataSurface->SurfWinDividerArea(ThisSurf); // Glazed area
   12995           19 :                         if (DivArea <= 0.0) {
   12996            0 :                             ShowWarningError(state, format("{}Calculated Divider Area <= 0.0 for Window={}", RoutineName, surf.Name));
   12997            0 :                             if (state.dataSurface->FrameDivider(FrDivNum).HorDividers == 0) {
   12998            0 :                                 ShowContinueError(state, "..Number of Horizontal Dividers = 0.");
   12999              :                             }
   13000            0 :                             if (state.dataSurface->FrameDivider(FrDivNum).VertDividers == 0) {
   13001            0 :                                 ShowContinueError(state, "..Number of Vertical Dividers = 0.");
   13002              :                             }
   13003              :                         } else {
   13004           19 :                             auto &surfWin = state.dataSurface->SurfaceWindow(ThisSurf);
   13005           19 :                             surfWin.glazedFrac = surf.Area / (surf.Area + state.dataSurface->SurfWinDividerArea(ThisSurf));
   13006              :                             // Correction factor for portion of divider subject to divider projection correction
   13007           19 :                             DivFrac = (1.0 - state.dataSurface->FrameDivider(FrDivNum).HorDividers *
   13008           19 :                                                  state.dataSurface->FrameDivider(FrDivNum).VertDividers * pow_2(DivWidth) / DivArea);
   13009           19 :                             state.dataSurface->SurfWinProjCorrDivOut(ThisSurf) =
   13010           19 :                                 DivFrac * state.dataSurface->FrameDivider(FrDivNum).DividerProjectionOut / DivWidth;
   13011           19 :                             state.dataSurface->SurfWinProjCorrDivIn(ThisSurf) =
   13012           19 :                                 DivFrac * state.dataSurface->FrameDivider(FrDivNum).DividerProjectionIn / DivWidth;
   13013              :                             // Correction factor for portion of frame subject to frame projection correction
   13014           19 :                             if (FrWidth > 0.0) {
   13015           19 :                                 state.dataSurface->SurfWinProjCorrFrOut(ThisSurf) =
   13016           19 :                                     (state.dataSurface->FrameDivider(FrDivNum).FrameProjectionOut / FrWidth) *
   13017           38 :                                     (ThisHeight + ThisWidth -
   13018           19 :                                      (state.dataSurface->FrameDivider(FrDivNum).HorDividers +
   13019           19 :                                       state.dataSurface->FrameDivider(FrDivNum).VertDividers) *
   13020           19 :                                          DivWidth) /
   13021           19 :                                     (ThisHeight + ThisWidth + 2 * FrWidth);
   13022           19 :                                 state.dataSurface->SurfWinProjCorrFrIn(ThisSurf) =
   13023           19 :                                     (state.dataSurface->FrameDivider(FrDivNum).FrameProjectionIn / FrWidth) *
   13024           38 :                                     (ThisHeight + ThisWidth -
   13025           19 :                                      (state.dataSurface->FrameDivider(FrDivNum).HorDividers +
   13026           19 :                                       state.dataSurface->FrameDivider(FrDivNum).VertDividers) *
   13027           19 :                                          DivWidth) /
   13028           19 :                                     (ThisHeight + ThisWidth + 2 * FrWidth);
   13029              :                             }
   13030              :                         }
   13031              :                     }
   13032              :                 }
   13033          129 :             } break;
   13034            2 :             case DataSurfaces::SurfaceShape::TriangularWindow:
   13035              :             case DataSurfaces::SurfaceShape::TriangularDoor: {
   13036            4 :                 Vectors::PlaneEquation(
   13037            2 :                     state.dataSurface->Surface(surf.BaseSurf).Vertex, state.dataSurface->Surface(surf.BaseSurf).Sides, BasePlane, SError);
   13038            2 :                 if (SError) {
   13039            0 :                     ShowSevereError(state, format("{}Degenerate surface (likely two vertices equal):\"{}\".", RoutineName, surf.Name));
   13040            0 :                     ErrorInSurface = true;
   13041              :                 }
   13042            2 :                 ThisReveal = -Vectors::Pt2Plane(surf.Vertex(2), BasePlane);
   13043            2 :                 if (std::abs(ThisReveal) < 0.0002) {
   13044            2 :                     ThisReveal = 0.0;
   13045              :                 }
   13046            2 :                 surf.Reveal = ThisReveal;
   13047            2 :                 Xp = surf.Vertex(2).x - BaseXLLC;
   13048            2 :                 Yp = surf.Vertex(2).y - BaseYLLC;
   13049            2 :                 Zp = surf.Vertex(2).z - BaseZLLC;
   13050            2 :                 state.dataSurfaceGeometry->Xpsv(2) = -Xp * BaseCosAzimuth + Yp * BaseSinAzimuth;
   13051            2 :                 state.dataSurfaceGeometry->Ypsv(2) = -Xp * BaseSinAzimuth * BaseCosTilt - Yp * BaseCosAzimuth * BaseCosTilt + Zp * BaseSinTilt;
   13052            2 :                 state.dataSurfaceGeometry->Zpsv(2) = Xp * BaseSinAzimuth * BaseSinTilt + Yp * BaseCosAzimuth * BaseSinTilt + Zp * BaseCosTilt;
   13053            2 :                 TVect = surf.Vertex(3) - surf.Vertex(2);
   13054            2 :                 ThisWidth = Vectors::VecLength(TVect);
   13055            2 :                 TVect = surf.Vertex(2) - surf.Vertex(1);
   13056            2 :                 ThisHeight = Vectors::VecLength(TVect);
   13057            2 :                 surf.Width = ThisWidth;
   13058              :                 // Effective height and width of a triangular window for use in calc of convective air flow
   13059              :                 // in gap between glass and shading device when shading device is present
   13060            2 :                 surf.Height = 4.0 * surf.Area / (3.0 * surf.Width);
   13061            2 :                 surf.Width *= 0.75;
   13062              : 
   13063            2 :                 Xp = surf.Vertex(1).x - BaseXLLC;
   13064            2 :                 Yp = surf.Vertex(1).y - BaseYLLC;
   13065            2 :                 Zp = surf.Vertex(1).z - BaseZLLC;
   13066            2 :                 state.dataSurfaceGeometry->Xpsv(1) = -Xp * BaseCosAzimuth + Yp * BaseSinAzimuth;
   13067            2 :                 state.dataSurfaceGeometry->Ypsv(1) = -Xp * BaseSinAzimuth * BaseCosTilt - Yp * BaseCosAzimuth * BaseCosTilt + Zp * BaseSinTilt;
   13068            2 :                 state.dataSurfaceGeometry->Zpsv(1) = Xp * BaseSinAzimuth * BaseSinTilt + Yp * BaseCosAzimuth * BaseSinTilt + Zp * BaseCosTilt;
   13069              : 
   13070            2 :                 Xp = surf.Vertex(3).x - BaseXLLC;
   13071            2 :                 Yp = surf.Vertex(3).y - BaseYLLC;
   13072            2 :                 Zp = surf.Vertex(3).z - BaseZLLC;
   13073            2 :                 state.dataSurfaceGeometry->Xpsv(3) = -Xp * BaseCosAzimuth + Yp * BaseSinAzimuth;
   13074            2 :                 state.dataSurfaceGeometry->Ypsv(3) = -Xp * BaseSinAzimuth * BaseCosTilt - Yp * BaseCosAzimuth * BaseCosTilt + Zp * BaseSinTilt;
   13075            2 :                 state.dataSurfaceGeometry->Zpsv(3) = Xp * BaseSinAzimuth * BaseSinTilt + Yp * BaseCosAzimuth * BaseSinTilt + Zp * BaseCosTilt;
   13076            2 :             } break;
   13077            0 :             case DataSurfaces::SurfaceShape::RectangularOverhang: {
   13078            0 :                 Xp = surf.Vertex(2).x - BaseXLLC;
   13079            0 :                 Yp = surf.Vertex(2).y - BaseYLLC;
   13080            0 :                 Zp = surf.Vertex(2).z - BaseZLLC;
   13081            0 :                 XLLC = -Xp * BaseCosAzimuth + Yp * BaseSinAzimuth;
   13082            0 :                 YLLC = -Xp * BaseSinAzimuth * BaseCosTilt - Yp * BaseCosAzimuth * BaseCosTilt + Zp * BaseSinTilt;
   13083            0 :                 ZLLC = Xp * BaseSinAzimuth * BaseSinTilt + Yp * BaseCosAzimuth * BaseSinTilt + Zp * BaseCosTilt;
   13084            0 :                 TVect = surf.Vertex(3) - surf.Vertex(2);
   13085            0 :                 ThisWidth = Vectors::VecLength(TVect);
   13086            0 :                 TVect = surf.Vertex(2) - surf.Vertex(1);
   13087            0 :                 ThisHeight = Vectors::VecLength(TVect);
   13088            0 :                 surf.Width = ThisWidth;
   13089            0 :                 surf.Height = ThisHeight;
   13090            0 :                 state.dataSurfaceGeometry->Xpsv(1) = XLLC;
   13091            0 :                 state.dataSurfaceGeometry->Xpsv(2) = XLLC;
   13092            0 :                 state.dataSurfaceGeometry->Xpsv(3) = XLLC + surf.Width;
   13093            0 :                 state.dataSurfaceGeometry->Xpsv(4) = XLLC + surf.Width;
   13094            0 :                 state.dataSurfaceGeometry->Ypsv(1) = YLLC;
   13095            0 :                 state.dataSurfaceGeometry->Ypsv(2) = YLLC;
   13096            0 :                 state.dataSurfaceGeometry->Ypsv(3) = YLLC;
   13097            0 :                 state.dataSurfaceGeometry->Ypsv(4) = YLLC;
   13098            0 :                 state.dataSurfaceGeometry->Zpsv(1) = surf.Height;
   13099            0 :                 state.dataSurfaceGeometry->Zpsv(4) = surf.Height;
   13100            0 :                 state.dataSurfaceGeometry->Zpsv(2) = 0.0;
   13101            0 :                 state.dataSurfaceGeometry->Zpsv(3) = 0.0;
   13102            0 :             } break;
   13103            0 :             case DataSurfaces::SurfaceShape::RectangularLeftFin: {
   13104            0 :                 Xp = surf.Vertex(2).x - BaseXLLC;
   13105            0 :                 Yp = surf.Vertex(2).y - BaseYLLC;
   13106            0 :                 Zp = surf.Vertex(2).z - BaseZLLC;
   13107            0 :                 XLLC = -Xp * BaseCosAzimuth + Yp * BaseSinAzimuth;
   13108            0 :                 YLLC = -Xp * BaseSinAzimuth * BaseCosTilt - Yp * BaseCosAzimuth * BaseCosTilt + Zp * BaseSinTilt;
   13109            0 :                 ZLLC = Xp * BaseSinAzimuth * BaseSinTilt + Yp * BaseCosAzimuth * BaseSinTilt + Zp * BaseCosTilt;
   13110            0 :                 TVect = surf.Vertex(3) - surf.Vertex(2);
   13111            0 :                 ThisWidth = Vectors::VecLength(TVect);
   13112            0 :                 TVect = surf.Vertex(2) - surf.Vertex(1);
   13113            0 :                 ThisHeight = Vectors::VecLength(TVect);
   13114            0 :                 surf.Width = ThisWidth;
   13115            0 :                 surf.Height = ThisHeight;
   13116            0 :                 state.dataSurfaceGeometry->Xpsv(1) = XLLC;
   13117            0 :                 state.dataSurfaceGeometry->Xpsv(2) = XLLC;
   13118            0 :                 state.dataSurfaceGeometry->Xpsv(3) = XLLC;
   13119            0 :                 state.dataSurfaceGeometry->Xpsv(4) = XLLC;
   13120            0 :                 state.dataSurfaceGeometry->Ypsv(1) = YLLC;
   13121            0 :                 state.dataSurfaceGeometry->Ypsv(2) = YLLC;
   13122            0 :                 state.dataSurfaceGeometry->Ypsv(3) = YLLC + surf.Width;
   13123            0 :                 state.dataSurfaceGeometry->Ypsv(4) = YLLC + surf.Width;
   13124            0 :                 state.dataSurfaceGeometry->Zpsv(1) = surf.Height;
   13125            0 :                 state.dataSurfaceGeometry->Zpsv(4) = surf.Height;
   13126            0 :                 state.dataSurfaceGeometry->Zpsv(2) = 0.0;
   13127            0 :                 state.dataSurfaceGeometry->Zpsv(3) = 0.0;
   13128            0 :             } break;
   13129            4 :             case DataSurfaces::SurfaceShape::RectangularRightFin: {
   13130            4 :                 Xp = surf.Vertex(2).x - BaseXLLC;
   13131            4 :                 Yp = surf.Vertex(2).y - BaseYLLC;
   13132            4 :                 Zp = surf.Vertex(2).z - BaseZLLC;
   13133            4 :                 XLLC = -Xp * BaseCosAzimuth + Yp * BaseSinAzimuth;
   13134            4 :                 YLLC = -Xp * BaseSinAzimuth * BaseCosTilt - Yp * BaseCosAzimuth * BaseCosTilt + Zp * BaseSinTilt;
   13135            4 :                 ZLLC = Xp * BaseSinAzimuth * BaseSinTilt + Yp * BaseCosAzimuth * BaseSinTilt + Zp * BaseCosTilt;
   13136            4 :                 TVect = surf.Vertex(3) - surf.Vertex(2);
   13137            4 :                 ThisWidth = Vectors::VecLength(TVect);
   13138            4 :                 TVect = surf.Vertex(2) - surf.Vertex(1);
   13139            4 :                 ThisHeight = Vectors::VecLength(TVect);
   13140            4 :                 surf.Width = ThisWidth;
   13141            4 :                 surf.Height = ThisHeight;
   13142            4 :                 state.dataSurfaceGeometry->Xpsv(1) = XLLC;
   13143            4 :                 state.dataSurfaceGeometry->Xpsv(2) = XLLC;
   13144            4 :                 state.dataSurfaceGeometry->Xpsv(3) = XLLC;
   13145            4 :                 state.dataSurfaceGeometry->Xpsv(4) = XLLC;
   13146            4 :                 state.dataSurfaceGeometry->Ypsv(1) = YLLC + surf.Width;
   13147            4 :                 state.dataSurfaceGeometry->Ypsv(2) = YLLC + surf.Width;
   13148            4 :                 state.dataSurfaceGeometry->Ypsv(3) = YLLC;
   13149            4 :                 state.dataSurfaceGeometry->Ypsv(4) = YLLC;
   13150            4 :                 state.dataSurfaceGeometry->Zpsv(1) = surf.Height;
   13151            4 :                 state.dataSurfaceGeometry->Zpsv(4) = surf.Height;
   13152            4 :                 state.dataSurfaceGeometry->Zpsv(2) = 0.0;
   13153            4 :                 state.dataSurfaceGeometry->Zpsv(3) = 0.0;
   13154            4 :             } break;
   13155            0 :             default: {
   13156              :                 // Error Condition
   13157            0 :                 ShowSevereError(state, format("{}Incorrect surface shape number.", RoutineName), OptionalOutputFileRef{state.files.eso});
   13158            0 :                 ShowContinueError(state, "Please notify EnergyPlus support of this error and send input file.");
   13159            0 :                 ErrorInSurface = true;
   13160            0 :             } break;
   13161              :             }
   13162              : 
   13163          673 :             for (n = 1; n <= surf.Sides; ++n) {
   13164              :                 // if less than 1/10 inch
   13165          538 :                 state.dataSurfaceGeometry->Xpsv(n) = nint64(10000.0 * state.dataSurfaceGeometry->Xpsv(n)) / 10000.0;
   13166          538 :                 if (std::abs(state.dataSurfaceGeometry->Xpsv(n)) < 0.0025) {
   13167            6 :                     state.dataSurfaceGeometry->Xpsv(n) = 0.0;
   13168              :                 }
   13169          538 :                 state.dataSurfaceGeometry->Ypsv(n) = nint64(10000.0 * state.dataSurfaceGeometry->Ypsv(n)) / 10000.0;
   13170          538 :                 if (std::abs(state.dataSurfaceGeometry->Ypsv(n)) < 0.0025) {
   13171           36 :                     state.dataSurfaceGeometry->Ypsv(n) = 0.0;
   13172              :                 }
   13173          538 :                 state.dataSurfaceGeometry->Zpsv(n) = nint64(10000.0 * state.dataSurfaceGeometry->Zpsv(n)) / 10000.0;
   13174          538 :                 if (std::abs(state.dataSurfaceGeometry->Zpsv(n)) < 0.0025) {
   13175          510 :                     state.dataSurfaceGeometry->Zpsv(n) = 0.0;
   13176              :                 }
   13177              :             }
   13178              : 
   13179          135 :             surf.Shape = ThisShape;
   13180              : 
   13181              :         } // End of check if ThisSurf is a base surface
   13182              : 
   13183         1692 :         if (ErrorInSurface) {
   13184            0 :             ErrorsFound = true;
   13185            0 :             return;
   13186              :         }
   13187              : 
   13188              :         // Transfer to XV,YV,ZV arrays
   13189              : 
   13190         1692 :         state.dataSurface->ShadeV(ThisSurf).NVert = surf.Sides;
   13191         1692 :         state.dataSurface->ShadeV(ThisSurf).XV.allocate(surf.Sides);
   13192         1692 :         state.dataSurface->ShadeV(ThisSurf).YV.allocate(surf.Sides);
   13193         1692 :         state.dataSurface->ShadeV(ThisSurf).ZV.allocate(surf.Sides);
   13194              : 
   13195         8464 :         for (n = 1; n <= surf.Sides; ++n) {
   13196              :             // if less than 1/10 inch
   13197         6772 :             state.dataSurface->ShadeV(ThisSurf).XV(n) = state.dataSurfaceGeometry->Xpsv(n);
   13198         6772 :             state.dataSurface->ShadeV(ThisSurf).YV(n) = state.dataSurfaceGeometry->Ypsv(n);
   13199         6772 :             state.dataSurface->ShadeV(ThisSurf).ZV(n) = state.dataSurfaceGeometry->Zpsv(n);
   13200              :         }
   13201              : 
   13202              :         // Process Surfaces According to Type of Coordinate Origin.
   13203         1692 :         if (BaseSurface) {
   13204              : 
   13205              :             // General Surfaces:
   13206         1557 :             CalcCoordinateTransformation(state, ThisSurf, CoordinateTransVector); // X00,Y00,Z00,X,Y,Z,A)    ! Compute Coordinate Transformation
   13207              : 
   13208              :             // RECORD DIRECTION COSINES.
   13209         1557 :             if (HeatTransSurf) { // This is a general surface but not detached shading surface
   13210              : 
   13211              :                 // RECORD COORDINATE TRANSFORMATION FOR BASE SURFACES.
   13212         1511 :                 state.dataSurface->X0(ThisBaseSurface) = CoordinateTransVector.x;
   13213         1511 :                 state.dataSurface->Y0(ThisBaseSurface) = CoordinateTransVector.y;
   13214         1511 :                 state.dataSurface->Z0(ThisBaseSurface) = CoordinateTransVector.z;
   13215              : 
   13216              :                 // COMPUTE INVERSE TRANSFORMATION.
   13217         1511 :                 X1 = state.dataSurfaceGeometry->Xpsv(2) - CoordinateTransVector.x;
   13218         1511 :                 Y1 = state.dataSurfaceGeometry->Ypsv(2) - CoordinateTransVector.y;
   13219         1511 :                 Z1 = state.dataSurfaceGeometry->Zpsv(2) - CoordinateTransVector.z;
   13220              :                 // Store the relative coordinate shift values for later use by any subsurfaces
   13221         3022 :                 state.dataSurface->Surface(ThisBaseSurface).XShift = state.dataSurface->Surface(ThisBaseSurface).lcsx.x * X1 +
   13222         1511 :                                                                      state.dataSurface->Surface(ThisBaseSurface).lcsx.y * Y1 +
   13223         1511 :                                                                      state.dataSurface->Surface(ThisBaseSurface).lcsx.z * Z1;
   13224         3022 :                 state.dataSurface->Surface(ThisBaseSurface).YShift = state.dataSurface->Surface(ThisBaseSurface).lcsy.x * X1 +
   13225         1511 :                                                                      state.dataSurface->Surface(ThisBaseSurface).lcsy.y * Y1 +
   13226         1511 :                                                                      state.dataSurface->Surface(ThisBaseSurface).lcsy.z * Z1;
   13227         1511 :                 state.dataSurface->Surface(ThisBaseSurface).VerticesProcessed = true;
   13228              :             }
   13229              : 
   13230              :             // SUBSURFACES: (Surface(ThisSurf)%BaseSurf /= ThisSurf)
   13231              :         } else {
   13232              :             // WINDOWS OR DOORS:
   13233              : 
   13234              :             // SHIFT RELATIVE COORDINATES FROM LOWER LEFT CORNER TO ORIGIN DEFINED
   13235              :             // BY CTRAN AND SET DIRECTION COSINES SAME AS BASE SURFACE.
   13236          135 :             if (!state.dataSurface->Surface(ThisBaseSurface).VerticesProcessed) {
   13237              : 
   13238            4 :                 if (surf.IsAirBoundarySurf) {
   13239            4 :                     ProcessSurfaceVertices(state, ThisBaseSurface, ErrorsFound);
   13240              :                 } else {
   13241              : 
   13242            0 :                     ShowSevereError(state, format("{}Developer error for Subsurface={}", RoutineName, surf.Name));
   13243            0 :                     ShowContinueError(state,
   13244            0 :                                       format("Base surface={} vertices must be processed before any subsurfaces.",
   13245            0 :                                              state.dataSurface->Surface(ThisBaseSurface).Name));
   13246            0 :                     ShowFatalError(state, std::string{RoutineName});
   13247              :                 }
   13248              :             }
   13249              : 
   13250          673 :             for (n = 1; n <= surf.Sides; ++n) {
   13251          538 :                 state.dataSurface->ShadeV(ThisSurf).XV(n) += state.dataSurface->Surface(ThisBaseSurface).XShift;
   13252          538 :                 state.dataSurface->ShadeV(ThisSurf).YV(n) += state.dataSurface->Surface(ThisBaseSurface).YShift;
   13253              :             }
   13254              :         }
   13255         1712 :     }
   13256              : 
   13257         1557 :     void CalcCoordinateTransformation(EnergyPlusData &state,
   13258              :                                       int const SurfNum,            // Surface Number
   13259              :                                       Vector &CompCoordTranslVector // Coordinate Translation Vector
   13260              :     )
   13261              :     {
   13262              :         // SUBROUTINE INFORMATION:
   13263              :         //       AUTHOR         George Walton, BLAST
   13264              :         //       DATE WRITTEN   August 1976
   13265              :         //       MODIFIED       LKL, May 2004 -- >4 sided polygons
   13266              :         //       RE-ENGINEERED  Yes
   13267              : 
   13268              :         // PURPOSE OF THIS SUBROUTINE:
   13269              :         // This subroutine develops a coordinate transformation such that the X-axis goes
   13270              :         // through points 2 and 3 and the Y-axis goes through point 1
   13271              :         // of a plane figure in 3-d space.
   13272              : 
   13273              :         // REFERENCES:
   13274              :         // 'NECAP' - NASA'S Energy-Cost Analysis Program
   13275              : 
   13276              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
   13277              :         Real64 Gamma; // Intermediate Result
   13278              :         Real64 DotSelfX23;
   13279              : 
   13280              :         // Object Data
   13281         1557 :         Vector x21;
   13282         1557 :         Vector x23;
   13283              : 
   13284              :         // Determine Components of the Coordinate Translation Vector.
   13285         1557 :         auto const &surf = state.dataSurface->Surface(SurfNum);
   13286              : 
   13287         1557 :         x21 = surf.Vertex(2) - surf.Vertex(1);
   13288         1557 :         x23 = surf.Vertex(2) - surf.Vertex(3);
   13289              : 
   13290         1557 :         DotSelfX23 = magnitude_squared(x23);
   13291              : 
   13292         1557 :         if (DotSelfX23 <= Constant::OneMillionth) {
   13293            0 :             ShowSevereError(state, format("CalcCoordinateTransformation: Invalid dot product, surface=\"{}\":", surf.Name));
   13294            0 :             for (int I = 1; I <= surf.Sides; ++I) {
   13295            0 :                 auto const &point = surf.Vertex(I);
   13296            0 :                 ShowContinueError(state, format(" ({:8.3F},{:8.3F},{:8.3F})", point.x, point.y, point.z));
   13297              :             }
   13298            0 :             ShowFatalError(
   13299            0 :                 state, "CalcCoordinateTransformation: Program terminates due to preceding condition.", OptionalOutputFileRef{state.files.eso});
   13300            0 :             return;
   13301              :         }
   13302              : 
   13303         1557 :         Gamma = dot(x21, x23) / magnitude_squared(x23);
   13304              : 
   13305         1557 :         CompCoordTranslVector = surf.Vertex(2) + Gamma * (surf.Vertex(3) - surf.Vertex(2));
   13306         1557 :     }
   13307              : 
   13308            0 :     void CreateShadedWindowConstruction(EnergyPlusData &state,
   13309              :                                         int const SurfNum,          // Surface number
   13310              :                                         int const WSCPtr,           // Pointer to WindowShadingControl for SurfNum
   13311              :                                         int const ShDevNum,         // Shading device material number for WSCptr
   13312              :                                         int const shadeControlIndex // index to the Surface().windowShadingControlList,
   13313              :                                                                     // Surface().shadedConstructionList, and Surface().shadedStormWinConstructionList
   13314              :     )
   13315              :     {
   13316              :         // SUBROUTINE INFORMATION:
   13317              :         //       AUTHOR         Fred Winkelmann
   13318              :         //       DATE WRITTEN   Nov 2001
   13319              : 
   13320              :         // PURPOSE OF THIS SUBROUTINE:
   13321              :         // Creates a shaded window construction for windows whose WindowShadingControl
   13322              :         // has a shading device specified instead of a shaded construction
   13323              : 
   13324              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
   13325              :         int ConstrNewSh;          // Number of shaded construction that is created
   13326            0 :         std::string ConstrNameSh; // Shaded construction name
   13327              : 
   13328            0 :         auto &s_mat = state.dataMaterial;
   13329            0 :         auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
   13330              : 
   13331            0 :         std::string const &ShDevName = s_mat->materials(ShDevNum)->Name;
   13332            0 :         int ConstrNum = surfTemp.Construction;
   13333            0 :         std::string const &ConstrName = state.dataConstruction->Construct(ConstrNum).Name;
   13334              : 
   13335            0 :         if (ANY_INTERIOR_SHADE_BLIND(state.dataSurface->WindowShadingControl(WSCPtr).ShadingType)) {
   13336            0 :             ConstrNameSh = ConstrName + ':' + ShDevName + ":INT";
   13337              :         } else {
   13338            0 :             ConstrNameSh = ConstrName + ':' + ShDevName + ":EXT";
   13339              :         }
   13340              : 
   13341              :         // If this construction name already exists, set the surface's shaded construction number to it
   13342              : 
   13343            0 :         ConstrNewSh = Util::FindItemInList(ConstrNameSh, state.dataConstruction->Construct);
   13344              : 
   13345            0 :         if (ConstrNewSh > 0) {
   13346            0 :             surfTemp.shadedConstructionList[shadeControlIndex] = ConstrNewSh;
   13347            0 :             surfTemp.activeShadedConstruction = ConstrNewSh; // set the active to the current for now
   13348              :         } else {
   13349              : 
   13350              :             // Create new construction
   13351              : 
   13352            0 :             ConstrNewSh = state.dataHeatBal->TotConstructs + 1;
   13353            0 :             surfTemp.shadedConstructionList[shadeControlIndex] = ConstrNewSh;
   13354            0 :             surfTemp.activeShadedConstruction = ConstrNewSh; // set the active to the current for now
   13355            0 :             state.dataHeatBal->TotConstructs = ConstrNewSh;
   13356            0 :             state.dataConstruction->Construct.redimension(state.dataHeatBal->TotConstructs);
   13357            0 :             state.dataHeatBal->NominalRforNominalUCalculation.redimension(state.dataHeatBal->TotConstructs);
   13358            0 :             state.dataHeatBal->NominalRforNominalUCalculation(state.dataHeatBal->TotConstructs) = 0.0;
   13359            0 :             state.dataHeatBal->NominalU.redimension(state.dataHeatBal->TotConstructs);
   13360            0 :             state.dataHeatBal->NominalU(state.dataHeatBal->TotConstructs) = 0.0;
   13361            0 :             state.dataHeatBal->NominalUBeforeAdjusted.redimension(state.dataHeatBal->TotConstructs);
   13362            0 :             state.dataHeatBal->CoeffAdjRatio.redimension(state.dataHeatBal->TotConstructs) = 1.0;
   13363              : 
   13364            0 :             state.dataConstruction->Construct(state.dataHeatBal->TotConstructs).setArraysBasedOnMaxSolidWinLayers(state);
   13365              : 
   13366            0 :             int TotLayersOld = state.dataConstruction->Construct(ConstrNum).TotLayers;
   13367            0 :             int TotLayersNew = TotLayersOld + 1;
   13368              : 
   13369            0 :             state.dataConstruction->Construct(ConstrNewSh).LayerPoint = 0;
   13370              : 
   13371            0 :             auto const *thisMaterialSh = s_mat->materials(ShDevNum);
   13372            0 :             auto &thisConstructNewSh = state.dataConstruction->Construct(ConstrNewSh);
   13373            0 :             if (state.dataSurface->WindowShadingControl(WSCPtr).ShadingType == DataSurfaces::WinShadingType::IntShade ||
   13374            0 :                 state.dataSurface->WindowShadingControl(WSCPtr).ShadingType == DataSurfaces::WinShadingType::IntBlind) {
   13375              :                 // Interior shading device
   13376            0 :                 thisConstructNewSh.LayerPoint({1, TotLayersOld}) = state.dataConstruction->Construct(ConstrNum).LayerPoint({1, TotLayersOld});
   13377            0 :                 thisConstructNewSh.LayerPoint(TotLayersNew) = ShDevNum;
   13378            0 :                 thisConstructNewSh.InsideAbsorpSolar = thisMaterialSh->AbsorpSolar;
   13379            0 :                 auto const *thisMaterialShLayer1 = s_mat->materials(state.dataConstruction->Construct(ConstrNewSh).LayerPoint(1));
   13380            0 :                 thisConstructNewSh.OutsideAbsorpSolar = thisMaterialShLayer1->AbsorpSolar;
   13381            0 :                 thisConstructNewSh.OutsideAbsorpThermal = thisMaterialShLayer1->AbsorpThermalFront;
   13382              :             } else {
   13383              :                 // Exterior shading device
   13384            0 :                 thisConstructNewSh.LayerPoint(1) = ShDevNum;
   13385            0 :                 thisConstructNewSh.LayerPoint({2, TotLayersNew}) = state.dataConstruction->Construct(ConstrNum).LayerPoint({1, TotLayersOld});
   13386            0 :                 auto const *thisMaterialShInside = s_mat->materials(state.dataConstruction->Construct(ConstrNewSh).LayerPoint(TotLayersNew));
   13387            0 :                 thisConstructNewSh.InsideAbsorpSolar = thisMaterialShInside->AbsorpSolar;
   13388            0 :                 thisConstructNewSh.OutsideAbsorpSolar = thisMaterialSh->AbsorpSolar;
   13389            0 :                 thisConstructNewSh.OutsideAbsorpThermal = thisMaterialSh->AbsorpThermalFront;
   13390              :             }
   13391              :             // The following InsideAbsorpThermal applies only to inside glass; it is corrected
   13392              :             //  later in InitGlassOpticalCalculations if construction has inside shade or blind.
   13393            0 :             thisConstructNewSh.InsideAbsorpThermal =
   13394            0 :                 s_mat->materials(state.dataConstruction->Construct(ConstrNum).LayerPoint(TotLayersOld))->AbsorpThermalBack;
   13395            0 :             thisConstructNewSh.OutsideRoughness = Material::SurfaceRoughness::VerySmooth;
   13396            0 :             thisConstructNewSh.DayltPropPtr = 0;
   13397            0 :             thisConstructNewSh.CTFCross.fill(0.0);
   13398            0 :             thisConstructNewSh.CTFFlux.fill(0.0);
   13399            0 :             thisConstructNewSh.CTFInside.fill(0.0);
   13400            0 :             thisConstructNewSh.CTFOutside.fill(0.0);
   13401            0 :             thisConstructNewSh.CTFSourceIn.fill(0.0);
   13402            0 :             thisConstructNewSh.CTFSourceOut.fill(0.0);
   13403            0 :             thisConstructNewSh.CTFTimeStep = 0.0;
   13404            0 :             thisConstructNewSh.CTFTSourceOut.fill(0.0);
   13405            0 :             thisConstructNewSh.CTFTSourceIn.fill(0.0);
   13406            0 :             thisConstructNewSh.CTFTSourceQ.fill(0.0);
   13407            0 :             thisConstructNewSh.CTFTUserOut.fill(0.0);
   13408            0 :             thisConstructNewSh.CTFTUserIn.fill(0.0);
   13409            0 :             thisConstructNewSh.CTFTUserSource.fill(0.0);
   13410            0 :             thisConstructNewSh.NumHistories = 0;
   13411            0 :             thisConstructNewSh.NumCTFTerms = 0;
   13412            0 :             thisConstructNewSh.UValue = 0.0;
   13413            0 :             thisConstructNewSh.SourceSinkPresent = false;
   13414            0 :             thisConstructNewSh.SolutionDimensions = 0;
   13415            0 :             thisConstructNewSh.SourceAfterLayer = 0;
   13416            0 :             thisConstructNewSh.TempAfterLayer = 0;
   13417            0 :             thisConstructNewSh.ThicknessPerpend = 0.0;
   13418            0 :             thisConstructNewSh.AbsDiff = 0.0;
   13419            0 :             thisConstructNewSh.AbsDiffBack = 0.0;
   13420            0 :             thisConstructNewSh.AbsDiffShade = 0.0;
   13421            0 :             thisConstructNewSh.AbsDiffBackShade = 0.0;
   13422            0 :             thisConstructNewSh.ShadeAbsorpThermal = 0.0;
   13423            0 :             std::fill(thisConstructNewSh.AbsBeamShadeCoef.begin(), thisConstructNewSh.AbsBeamShadeCoef.end(), 0.0);
   13424            0 :             thisConstructNewSh.TransDiff = 0.0;
   13425            0 :             thisConstructNewSh.TransDiffVis = 0.0;
   13426            0 :             thisConstructNewSh.ReflectSolDiffBack = 0.0;
   13427            0 :             thisConstructNewSh.ReflectSolDiffFront = 0.0;
   13428            0 :             thisConstructNewSh.ReflectVisDiffBack = 0.0;
   13429            0 :             thisConstructNewSh.ReflectVisDiffFront = 0.0;
   13430            0 :             std::fill(thisConstructNewSh.TransSolBeamCoef.begin(), thisConstructNewSh.TransSolBeamCoef.end(), 0.0);
   13431            0 :             std::fill(thisConstructNewSh.TransVisBeamCoef.begin(), thisConstructNewSh.TransVisBeamCoef.end(), 0.0);
   13432            0 :             std::fill(thisConstructNewSh.ReflSolBeamFrontCoef.begin(), thisConstructNewSh.ReflSolBeamFrontCoef.end(), 0.0);
   13433            0 :             std::fill(thisConstructNewSh.ReflSolBeamBackCoef.begin(), thisConstructNewSh.ReflSolBeamBackCoef.end(), 0.0);
   13434            0 :             thisConstructNewSh.W5FrameDivider = 0;
   13435            0 :             thisConstructNewSh.FromWindow5DataFile = false;
   13436              : 
   13437            0 :             thisConstructNewSh.Name = ConstrNameSh;
   13438            0 :             thisConstructNewSh.TotLayers = TotLayersNew;
   13439            0 :             thisConstructNewSh.TotSolidLayers = state.dataConstruction->Construct(ConstrNum).TotSolidLayers + 1;
   13440            0 :             thisConstructNewSh.TotGlassLayers = state.dataConstruction->Construct(ConstrNum).TotGlassLayers;
   13441            0 :             thisConstructNewSh.TypeIsWindow = true;
   13442            0 :             thisConstructNewSh.IsUsed = true;
   13443              : 
   13444            0 :             for (int Layer = 1; Layer <= state.dataHeatBal->MaxSolidWinLayers; ++Layer) {
   13445            0 :                 std::fill(thisConstructNewSh.AbsBeamCoef(Layer).begin(), thisConstructNewSh.AbsBeamCoef(Layer).end(), 0.0);
   13446            0 :                 std::fill(thisConstructNewSh.AbsBeamBackCoef(Layer).begin(), thisConstructNewSh.AbsBeamBackCoef(Layer).end(), 0.0);
   13447              :             }
   13448              :         }
   13449            0 :     }
   13450              : 
   13451            0 :     void CreateStormWindowConstructions(EnergyPlusData &state)
   13452              :     {
   13453              :         // For windows with an associated StormWindow object, creates a construction
   13454              :         // consisting of the base construction plus a storm window and air gap on the outside.
   13455              :         // If the window has an interior or between-glass shade/blind, also creates a
   13456              :         // construction consisting of the storm window added to the shaded construction.
   13457            0 :         DisplayString(state, "Creating Storm Window Constructions");
   13458              : 
   13459            0 :         auto &s_mat = state.dataMaterial;
   13460              : 
   13461            0 :         for (int StormWinNum = 1; StormWinNum <= state.dataSurface->TotStormWin; ++StormWinNum) {
   13462            0 :             int SurfNum = state.dataSurface->StormWindow(StormWinNum).BaseWindowNum; // Surface number
   13463            0 :             auto &surf = state.dataSurface->Surface(SurfNum);
   13464            0 :             int ConstrNum = surf.Construction; // Number of unshaded construction
   13465              :             // Fatal error if base construction has more than three glass layers
   13466            0 :             if (state.dataConstruction->Construct(ConstrNum).TotGlassLayers > 3) {
   13467            0 :                 ShowFatalError(state, format("Window={} has more than 3 glass layers; a storm window cannot be applied.", surf.Name));
   13468              :             }
   13469              : 
   13470              :             // create unshaded construction with storm window
   13471            0 :             const std::string ChrNum = fmt::to_string(StormWinNum);
   13472            0 :             std::string ConstrNameSt = "BARECONSTRUCTIONWITHSTORMWIN:" + ChrNum; // Name of unshaded construction with storm window
   13473              :             // If this construction name already exists, set the surface's storm window construction number to it
   13474            0 :             int ConstrNewSt = Util::FindItemInList(ConstrNameSt,
   13475            0 :                                                    state.dataConstruction->Construct,
   13476            0 :                                                    state.dataHeatBal->TotConstructs); // Number of unshaded storm window construction that is created
   13477              :             // If necessary, create new material corresponding to the air layer between the storm window and the rest of the window
   13478            0 :             int MatNewStAir = createAirMaterialFromDistance(state, state.dataSurface->StormWindow(StormWinNum).StormWinDistance, "AIR:STORMWIN:");
   13479            0 :             if (ConstrNewSt == 0) {
   13480            0 :                 ConstrNewSt = createConstructionWithStorm(
   13481            0 :                     state, ConstrNum, ConstrNameSt, state.dataSurface->StormWindow(StormWinNum).StormWinMaterialNum, MatNewStAir);
   13482              :             }
   13483            0 :             state.dataSurface->SurfWinStormWinConstr(SurfNum) = ConstrNewSt;
   13484              : 
   13485              :             // create shaded constructions with storm window
   13486            0 :             surf.shadedStormWinConstructionList.resize(surf.shadedConstructionList.size(),
   13487            0 :                                                        0); // make the shaded storm window size the same size as the number of shaded constructions
   13488            0 :             for (std::size_t iConstruction = 0; iConstruction < surf.shadedConstructionList.size(); ++iConstruction) {
   13489            0 :                 int curConstruction = surf.shadedConstructionList[iConstruction];
   13490              :                 // Set ShAndSt, which is true if the window has a shaded construction to which a storm window
   13491              :                 // can be added. (A storm window can be added if there is an interior shade or blind and up to three
   13492              :                 // glass layers, or there is a between-glass shade or blind and two glass layers.)
   13493            0 :                 bool ShAndSt = false; // True if unshaded and shaded window can have a storm window
   13494            0 :                 int TotLayers = state.dataConstruction->Construct(curConstruction).TotLayers;            // Total layers in a construction
   13495            0 :                 int MatIntSh = state.dataConstruction->Construct(curConstruction).LayerPoint(TotLayers); // Material number of interior shade or blind
   13496            0 :                 int MatBetweenGlassSh = 0; // Material number of between-glass shade or blind
   13497            0 :                 if (TotLayers == 5) {
   13498            0 :                     MatBetweenGlassSh = state.dataConstruction->Construct(curConstruction).LayerPoint(3);
   13499              :                 }
   13500            0 :                 if (state.dataConstruction->Construct(curConstruction).TotGlassLayers <= 3 &&
   13501            0 :                     (s_mat->materials(MatIntSh)->group == Material::Group::Shade || s_mat->materials(MatIntSh)->group == Material::Group::Blind)) {
   13502            0 :                     ShAndSt = true;
   13503              :                 }
   13504            0 :                 if (MatBetweenGlassSh > 0) {
   13505            0 :                     if (s_mat->materials(MatBetweenGlassSh)->group == Material::Group::Shade ||
   13506            0 :                         s_mat->materials(MatBetweenGlassSh)->group == Material::Group::Blind) {
   13507            0 :                         ShAndSt = true;
   13508              :                     } else {
   13509            0 :                         ShowContinueError(state, format("Window={} has a shaded construction to which a storm window cannot be applied.", surf.Name));
   13510            0 :                         ShowContinueError(state, "Storm windows can only be applied to shaded constructions that:");
   13511            0 :                         ShowContinueError(state, "have an interior shade or blind and up to three glass layers, or");
   13512            0 :                         ShowContinueError(state, "have a between-glass shade or blind and two glass layers.");
   13513            0 :                         ShowFatalError(state, "EnergyPlus is exiting due to reason stated above.");
   13514              :                     }
   13515              :                 }
   13516            0 :                 if (ShAndSt) {
   13517            0 :                     std::string ConstrNameStSh = "SHADEDCONSTRUCTIONWITHSTORMWIN:" + state.dataConstruction->Construct(iConstruction).Name + ":" +
   13518            0 :                                                  ChrNum; // Name of shaded construction with storm window
   13519            0 :                     int ConstrNewStSh = createConstructionWithStorm(
   13520            0 :                         state, ConstrNum, ConstrNameStSh, state.dataSurface->StormWindow(StormWinNum).StormWinMaterialNum, MatNewStAir);
   13521            0 :                     surf.shadedStormWinConstructionList[iConstruction] = ConstrNewStSh; // put in same index as the shaded construction
   13522            0 :                 }
   13523              :             } // end of loop for shaded constructions
   13524            0 :         } // end of loop over storm window objects
   13525            0 :     }
   13526              : 
   13527            3 :     int createAirMaterialFromDistance(EnergyPlusData &state, Real64 distance, std::string_view namePrefix)
   13528              :     {
   13529            3 :         auto const &s_mat = state.dataMaterial;
   13530              : 
   13531            3 :         int mmDistance = int(1000 * distance); // Thickness of air gap in mm (usually between storm window and rest of window)
   13532            3 :         std::string MatNameStAir = format("{}{}MM", namePrefix, mmDistance); // Name of created air layer material
   13533            3 :         int matNum = Material::GetMaterialNum(state, MatNameStAir);
   13534            3 :         if (matNum != 0) {
   13535            1 :             return matNum;
   13536              :         }
   13537              : 
   13538              :         // Create new material
   13539            2 :         auto *mat = new Material::MaterialGasMix;
   13540            2 :         mat->Name = MatNameStAir;
   13541            2 :         mat->group = Material::Group::Gas;
   13542              : 
   13543            2 :         s_mat->materials.push_back(mat);
   13544            2 :         mat->Num = s_mat->materials.isize();
   13545            2 :         s_mat->materialMap.insert_or_assign(Util::makeUPPER(mat->Name), mat->Num);
   13546              : 
   13547            2 :         mat->Roughness = Material::SurfaceRoughness::MediumRough;
   13548            2 :         mat->Conductivity = 0.0;
   13549            2 :         mat->Density = 0.0;
   13550            2 :         mat->Resistance = 0.0;
   13551            2 :         mat->SpecHeat = 0.0;
   13552            2 :         mat->Thickness = distance;
   13553            2 :         mat->numGases = 1;
   13554            2 :         mat->gases[0] = Material::gases[(int)Material::GasType::Air];
   13555            2 :         mat->gasFracts[0] = 1.0;
   13556            2 :         mat->AbsorpSolar = 0.0;
   13557            2 :         mat->AbsorpThermal = 0.0;
   13558            2 :         mat->AbsorpVisible = 0.0;
   13559            2 :         return mat->Num;
   13560            3 :     }
   13561              : 
   13562              :     // create a new construction with storm based on an old construction and storm and gap materials
   13563            1 :     int createConstructionWithStorm(EnergyPlusData &state, int oldConstruction, std::string name, int stormMaterial, int gapMaterial)
   13564              :     {
   13565            1 :         int newConstruct = Util::FindItemInList(name,
   13566            1 :                                                 state.dataConstruction->Construct,
   13567            1 :                                                 state.dataHeatBal->TotConstructs); // Number of shaded storm window construction that is created
   13568            1 :         if (newConstruct == 0) {
   13569            1 :             auto &s_mat = state.dataMaterial;
   13570            1 :             state.dataHeatBal->TotConstructs = state.dataHeatBal->TotConstructs + 1;
   13571            1 :             newConstruct = state.dataHeatBal->TotConstructs;
   13572            1 :             state.dataConstruction->Construct.redimension(state.dataHeatBal->TotConstructs);
   13573            1 :             state.dataHeatBal->NominalRforNominalUCalculation.redimension(state.dataHeatBal->TotConstructs);
   13574            1 :             state.dataHeatBal->NominalU.redimension(state.dataHeatBal->TotConstructs);
   13575            1 :             state.dataHeatBal->NominalUBeforeAdjusted.redimension(state.dataHeatBal->TotConstructs);
   13576            1 :             state.dataHeatBal->CoeffAdjRatio.redimension(state.dataHeatBal->TotConstructs) = 1.0;
   13577              : 
   13578            1 :             auto &thisConstruct = state.dataConstruction->Construct(state.dataHeatBal->TotConstructs);
   13579              :             // these Construct arrays dimensioned based on MaxSolidWinLayers
   13580            1 :             thisConstruct.setArraysBasedOnMaxSolidWinLayers(state);
   13581              : 
   13582            1 :             int TotLayersOld = state.dataConstruction->Construct(oldConstruction).TotLayers;
   13583            1 :             thisConstruct.LayerPoint({1, Construction::MaxLayersInConstruct}) = 0;
   13584            1 :             thisConstruct.LayerPoint(1) = stormMaterial;
   13585            1 :             thisConstruct.LayerPoint(2) = gapMaterial;
   13586            1 :             thisConstruct.LayerPoint({3, TotLayersOld + 2}) = state.dataConstruction->Construct(oldConstruction).LayerPoint({1, TotLayersOld});
   13587            1 :             thisConstruct.Name = name;
   13588            1 :             thisConstruct.TotLayers = TotLayersOld + 2;
   13589            1 :             thisConstruct.TotSolidLayers = state.dataConstruction->Construct(oldConstruction).TotSolidLayers + 1;
   13590            1 :             thisConstruct.TotGlassLayers = state.dataConstruction->Construct(oldConstruction).TotGlassLayers + 1;
   13591            1 :             thisConstruct.TypeIsWindow = true;
   13592            1 :             thisConstruct.InsideAbsorpVis = 0.0;
   13593            1 :             thisConstruct.OutsideAbsorpVis = 0.0;
   13594            1 :             thisConstruct.InsideAbsorpSolar = 0.0;
   13595            1 :             thisConstruct.OutsideAbsorpSolar = 0.0;
   13596            1 :             thisConstruct.InsideAbsorpThermal = state.dataConstruction->Construct(oldConstruction).InsideAbsorpThermal;
   13597            1 :             thisConstruct.OutsideAbsorpThermal = s_mat->materials(stormMaterial)->AbsorpThermalFront;
   13598            1 :             thisConstruct.OutsideRoughness = Material::SurfaceRoughness::VerySmooth;
   13599            1 :             thisConstruct.DayltPropPtr = 0;
   13600            1 :             thisConstruct.CTFCross.fill(0.0);
   13601            1 :             thisConstruct.CTFFlux.fill(0.0);
   13602            1 :             thisConstruct.CTFInside.fill(0.0);
   13603            1 :             thisConstruct.CTFOutside.fill(0.0);
   13604            1 :             thisConstruct.CTFSourceIn.fill(0.0);
   13605            1 :             thisConstruct.CTFSourceOut.fill(0.0);
   13606            1 :             thisConstruct.CTFTimeStep = 0.0;
   13607            1 :             thisConstruct.CTFTSourceOut.fill(0.0);
   13608            1 :             thisConstruct.CTFTSourceIn.fill(0.0);
   13609            1 :             thisConstruct.CTFTSourceQ.fill(0.0);
   13610            1 :             thisConstruct.CTFTUserOut.fill(0.0);
   13611            1 :             thisConstruct.CTFTUserIn.fill(0.0);
   13612            1 :             thisConstruct.CTFTUserSource.fill(0.0);
   13613            1 :             thisConstruct.NumHistories = 0;
   13614            1 :             thisConstruct.NumCTFTerms = 0;
   13615            1 :             thisConstruct.UValue = 0.0;
   13616            1 :             thisConstruct.SourceSinkPresent = false;
   13617            1 :             thisConstruct.SolutionDimensions = 0;
   13618            1 :             thisConstruct.SourceAfterLayer = 0;
   13619            1 :             thisConstruct.TempAfterLayer = 0;
   13620            1 :             thisConstruct.ThicknessPerpend = 0.0;
   13621            1 :             thisConstruct.AbsDiffIn = 0.0;
   13622            1 :             thisConstruct.AbsDiffOut = 0.0;
   13623            1 :             thisConstruct.AbsDiff = 0.0;
   13624            1 :             thisConstruct.AbsDiffBack = 0.0;
   13625            1 :             thisConstruct.AbsDiffShade = 0.0;
   13626            1 :             thisConstruct.AbsDiffBackShade = 0.0;
   13627            1 :             thisConstruct.ShadeAbsorpThermal = 0.0;
   13628            1 :             std::fill(thisConstruct.AbsBeamShadeCoef.begin(), thisConstruct.AbsBeamShadeCoef.end(), 0.0);
   13629            1 :             thisConstruct.TransDiff = 0.0;
   13630            1 :             thisConstruct.TransDiffVis = 0.0;
   13631            1 :             thisConstruct.ReflectSolDiffBack = 0.0;
   13632            1 :             thisConstruct.ReflectSolDiffFront = 0.0;
   13633            1 :             thisConstruct.ReflectVisDiffBack = 0.0;
   13634            1 :             thisConstruct.ReflectVisDiffFront = 0.0;
   13635            1 :             std::fill(thisConstruct.TransSolBeamCoef.begin(), thisConstruct.TransSolBeamCoef.end(), 0.0);
   13636            1 :             std::fill(thisConstruct.TransVisBeamCoef.begin(), thisConstruct.TransVisBeamCoef.end(), 0.0);
   13637            1 :             std::fill(thisConstruct.ReflSolBeamFrontCoef.begin(), thisConstruct.ReflSolBeamFrontCoef.end(), 0.0);
   13638            1 :             std::fill(thisConstruct.ReflSolBeamBackCoef.begin(), thisConstruct.ReflSolBeamBackCoef.end(), 0.0);
   13639            1 :             thisConstruct.W5FrameDivider = 0;
   13640            1 :             thisConstruct.FromWindow5DataFile = false;
   13641            1 :             thisConstruct.W5FileMullionWidth = 0.0;
   13642            1 :             thisConstruct.W5FileMullionOrientation = DataWindowEquivalentLayer::Orientation::Invalid;
   13643            1 :             thisConstruct.W5FileGlazingSysWidth = 0.0;
   13644            1 :             thisConstruct.W5FileGlazingSysHeight = 0.0;
   13645            1 :             for (int Layer = 1; Layer <= state.dataHeatBal->MaxSolidWinLayers; ++Layer) {
   13646            0 :                 std::fill(thisConstruct.AbsBeamCoef(Layer).begin(), thisConstruct.AbsBeamCoef(Layer).end(), 0.0);
   13647            0 :                 std::fill(thisConstruct.AbsBeamBackCoef(Layer).begin(), thisConstruct.AbsBeamBackCoef(Layer).end(), 0.0);
   13648              :             }
   13649              :         }
   13650            1 :         return (newConstruct);
   13651              :     }
   13652              : 
   13653            0 :     void ModifyWindow(EnergyPlusData &state,
   13654              :                       int const SurfNum,    // SurfNum has construction of glazing system from Window5 Data File;
   13655              :                       bool &ErrorsFound,    // Set to true if errors found
   13656              :                       int &AddedSubSurfaces // Subsurfaces added when window references a
   13657              :     )
   13658              :     {
   13659              :         // SUBROUTINE INFORMATION:
   13660              :         //       AUTHOR         Fred Winkelmann
   13661              :         //       DATE WRITTEN   Feb 2002
   13662              :         //       MODIFIED       June 2004, FCW: SinAzim, CosAzim, SinTilt, CosTilt, OutNormVec, GrossArea
   13663              :         //                       and Perimeter weren't being set for created window for case when
   13664              :         //                       window from Window5DataFile had two different glazing systems. Also,
   13665              :         //                       GrossArea and Perimeter of original window were not being recalculated.
   13666              :         //                      October 2007, LKL: Net area for shading calculations was not being
   13667              :         //                       recalculated.
   13668              : 
   13669              :         // PURPOSE OF THIS SUBROUTINE:
   13670              :         // If a window from the Window5DataFile has one glazing system, modify the
   13671              :         // vertex coordinates of the original window to correspond to the dimensions
   13672              :         // of the glazing system on the Data File.
   13673              :         // If a window from the Window5DataFile has two different glazing systems, split
   13674              :         // the window into two separate windows with different properties and adjust the
   13675              :         // vertices of these windows taking into account the dimensions of the glazing systems
   13676              :         // on the Data File and the width and orientation of the mullion that separates
   13677              :         // the glazing systems.
   13678              : 
   13679              :         // SUBROUTINE ARGUMENT DEFINITIONS:
   13680              :         // If there is a second glazing system on the Data File, SurfNum+1
   13681              :         // has the construction of the second glazing system.
   13682              : 
   13683              :         // 2-glazing system Window5 data file entry
   13684              : 
   13685              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
   13686              :         Real64 H; // Height and width of original window (m)
   13687              :         Real64 W;
   13688              :         // unused1208  REAL(r64)    :: MulWidth                        ! Mullion width (m)
   13689              :         Real64 h1; // height and width of first glazing system (m)
   13690              :         Real64 w1;
   13691              :         // unused1208  REAL(r64)    :: h2,w2                           ! height and width of second glazing system (m)
   13692              :         // unused1208  type (rectangularwindow) :: NewCoord
   13693              :         int IConst;             // Construction number of first glazing system
   13694              :         int IConst2;            // Construction number of second glazing system
   13695            0 :         std::string Const2Name; // Name of construction of second glazing system
   13696              :         // unused1208  REAL(r64)    :: AreaNew                         ! Sum of areas of the two glazing systems (m2)
   13697              : 
   13698            0 :         auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
   13699              : 
   13700              :         struct rectangularwindow
   13701              :         {
   13702              :             // Members
   13703              :             Array1D<Vector> Vertex;
   13704              : 
   13705              :             // Default Constructor
   13706            0 :             rectangularwindow() : Vertex(4)
   13707              :             {
   13708            0 :             }
   13709              :         };
   13710              : 
   13711              :         // Object Data
   13712            0 :         Vector TVect;
   13713            0 :         rectangularwindow OriginalCoord;
   13714              : 
   13715            0 :         IConst = surfTemp.Construction;
   13716              : 
   13717              :         // Height and width of original window
   13718            0 :         TVect = surfTemp.Vertex(3) - surfTemp.Vertex(2);
   13719            0 :         W = Vectors::VecLength(TVect); // SQRT((X(3)-X(2))**2 + (Y(3)-Y(2))**2 + (Z(3)-Z(2))**2)
   13720            0 :         TVect = surfTemp.Vertex(2) - surfTemp.Vertex(1);
   13721            0 :         H = Vectors::VecLength(TVect); // SQRT((X(1)-X(2))**2 + (Y(1)-Y(2))**2 + (Z(1)-Z(2))**2)
   13722              : 
   13723              :         // Save coordinates of original window in case Window 5 data overwrites.
   13724            0 :         OriginalCoord.Vertex({1, surfTemp.Sides}) = surfTemp.Vertex({1, surfTemp.Sides});
   13725              : 
   13726              :         // Height and width of first glazing system
   13727            0 :         h1 = state.dataConstruction->Construct(IConst).W5FileGlazingSysHeight;
   13728            0 :         w1 = state.dataConstruction->Construct(IConst).W5FileGlazingSysWidth;
   13729              : 
   13730            0 :         Const2Name = state.dataConstruction->Construct(IConst).Name + ":2";
   13731            0 :         IConst2 = Util::FindItemInList(Const2Name, state.dataConstruction->Construct);
   13732              : 
   13733            0 :         if (IConst2 == 0) { // Only one glazing system on Window5 Data File for this window.
   13734              : 
   13735              :             // So... original dimensions and area of window are used (entered in IDF)
   13736              :             // Warning if dimensions of original window differ from those on Data File by more than 10%
   13737              : 
   13738            0 :             if (std::abs((H - h1) / H) > 0.10 || std::abs((W - w1) / W) > 0.10) {
   13739              : 
   13740            0 :                 if (state.dataGlobal->DisplayExtraWarnings) {
   13741            0 :                     ShowWarningError(state,
   13742            0 :                                      format("SurfaceGeometry: ModifyWindow: Window {} uses the Window5 Data File Construction {}",
   13743            0 :                                             surfTemp.Name,
   13744            0 :                                             state.dataConstruction->Construct(IConst).Name));
   13745            0 :                     ShowContinueError(state, format("The height {:.3R}(m) or width  (m) of this window differs by more than 10%{:.3R}", H, W));
   13746            0 :                     ShowContinueError(state,
   13747            0 :                                       format("from the corresponding height {:.3R} (m) or width  (m) on the Window5 Data file.{:.3R}", h1, w1));
   13748            0 :                     ShowContinueError(state, "This will affect the frame heat transfer calculation if the frame in the Data File entry");
   13749            0 :                     ShowContinueError(state, "is not uniform, i.e., has sections with different geometry and/or thermal properties.");
   13750              :                 } else {
   13751            0 :                     ++state.dataSurfaceGeometry->Warning1Count;
   13752              :                 }
   13753              :             }
   13754              : 
   13755              :             // Calculate net area for base surface
   13756            0 :             state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).Area -= surfTemp.Area;
   13757            0 :             if (state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).Area <= 0.0) {
   13758            0 :                 ShowSevereError(
   13759              :                     state,
   13760            0 :                     format("Subsurfaces have too much area for base surface={}", state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).Name));
   13761            0 :                 ShowContinueError(state, format("Subsurface creating error={}", surfTemp.Name));
   13762            0 :                 ErrorsFound = true;
   13763              :             }
   13764              : 
   13765              :             // Net area of base surface with unity window multipliers (used in shadowing checks)
   13766            0 :             state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).NetAreaShadowCalc -= surfTemp.Area / surfTemp.Multiplier;
   13767              : 
   13768              :         } else { // Two glazing systems on Window5 data file for this window
   13769              : 
   13770              :             // if exterior window, okay.
   13771              : 
   13772            0 :             if (surfTemp.ExtBoundCond == DataSurfaces::ExternalEnvironment) {
   13773              :                 // There are two glazing systems (separated by a vertical or horizontal mullion) on the Window5 Data File.
   13774              :                 // Fill in geometry data for the second window (corresponding to the second glazing system on the data file.
   13775              :                 // The first glazing system is assumed to be at left for vertical mullion, at bottom for horizontal mullion.
   13776              :                 // The second glazing system is assumed to be at right for vertical mullion, at top for horizontal mullion.
   13777              :                 // The lower left-hand corner of the original window (its vertex #2) is assumed to coincide with
   13778              :                 // vertex #2 of the first glazing system.
   13779              : 
   13780            0 :                 if (state.dataGlobal->DisplayExtraWarnings) {
   13781            0 :                     ShowMessage(state,
   13782            0 :                                 format("SurfaceGeometry: ModifyWindow: Window {} has been replaced with the Window 5/6 two glazing system=\"{}\".",
   13783            0 :                                        surfTemp.Name,
   13784            0 :                                        state.dataConstruction->Construct(IConst).Name));
   13785            0 :                     ShowContinueError(state, "Note that originally entered dimensions are overridden.");
   13786              :                 } else {
   13787            0 :                     ++state.dataSurfaceGeometry->Warning2Count;
   13788              :                 }
   13789              : 
   13790              :                 // Allocate another window
   13791            0 :                 AddWindow(state, SurfNum, ErrorsFound, AddedSubSurfaces);
   13792              : 
   13793            0 :             } else if (surfTemp.ExtBoundCond > 0) { // Interior window, specified  ! not external environment
   13794              : 
   13795            0 :                 if (state.dataGlobal->DisplayExtraWarnings) {
   13796            0 :                     ShowWarningError(
   13797              :                         state,
   13798            0 :                         format("SurfaceGeometry: ModifyWindow: Interior Window {} has been replaced with the Window 5/6 two glazing system=\"{}\".",
   13799            0 :                                surfTemp.Name,
   13800            0 :                                state.dataConstruction->Construct(IConst).Name));
   13801            0 :                     ShowContinueError(
   13802              :                         state, "Please check to make sure interior window is correct. Note that originally entered dimensions are overridden.");
   13803              :                 } else {
   13804            0 :                     ++state.dataSurfaceGeometry->Warning3Count;
   13805              :                 }
   13806              : 
   13807            0 :                 AddWindow(state, SurfNum, ErrorsFound, AddedSubSurfaces);
   13808              : 
   13809              :             } else { // Interior window, specified not entered
   13810              : 
   13811            0 :                 ShowSevereError(state, format("SurfaceGeometry: ModifyWindow: Interior Window {} is a window in an adjacent zone.", surfTemp.Name));
   13812            0 :                 ShowContinueError(
   13813              :                     state,
   13814            0 :                     format("Attempted to add/reverse Window 5/6 multiple glazing system=\"{}\".", state.dataConstruction->Construct(IConst).Name));
   13815            0 :                 ShowContinueError(state, "Cannot use these Window 5/6 constructs for these Interior Windows. Program will terminate.");
   13816            0 :                 ErrorsFound = true;
   13817              :             }
   13818              : 
   13819              :         } // End of check if one or two glazing systems are on the Window5 Data File
   13820            0 :     }
   13821              : 
   13822            0 :     void AddWindow(EnergyPlusData &state,
   13823              :                    int const SurfNum,    // SurfNum has construction of glazing system from Window5 Data File;
   13824              :                    bool &ErrorsFound,    // Set to true if errors found
   13825              :                    int &AddedSubSurfaces // Subsurfaces added when window references a
   13826              :     )
   13827              :     {
   13828              :         // SUBROUTINE INFORMATION:
   13829              :         //       AUTHOR         Linda Lawrie
   13830              :         //       DATE WRITTEN   Nov 2008
   13831              : 
   13832              :         // PURPOSE OF THIS SUBROUTINE:
   13833              :         // This routine is called from ModifyWindow to add a window.  Allows it to be
   13834              :         // called in more than one place in the calling routine so as to be able to have
   13835              :         // specific warnings or errors issued.
   13836              : 
   13837              :         // SUBROUTINE ARGUMENT DEFINITIONS:
   13838              :         // If there is a second glazing system on the Data File, SurfNum+1
   13839              :         // has the construction of the second glazing system.
   13840              : 
   13841              :         // 2-glazing system Window5 data file entry
   13842              : 
   13843              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
   13844              :         int loop; // DO loop index
   13845              :         Real64 H; // Height and width of original window (m)
   13846              :         Real64 W;
   13847              :         Real64 MulWidth; // Mullion width (m)
   13848              :         Real64 h1;       // height and width of first glazing system (m)
   13849              :         Real64 w1;
   13850              :         Real64 h2; // height and width of second glazing system (m)
   13851              :         Real64 w2;
   13852              :         Real64 xa; // Vertex intermediate variables (m)
   13853              :         Real64 ya;
   13854              :         Real64 za;
   13855              :         Real64 xb;
   13856              :         Real64 yb;
   13857              :         Real64 zb;
   13858              :         Real64 dx; // Vertex displacements from original window (m)
   13859              :         Real64 dy;
   13860              :         int IConst;             // Construction number of first glazing system
   13861              :         int IConst2;            // Construction number of second glazing system
   13862            0 :         std::string Const2Name; // Name of construction of second glazing system
   13863              :         Real64 AreaNew;         // Sum of areas of the two glazing systems (m2)
   13864              : 
   13865              :         struct rectangularwindow
   13866              :         {
   13867              :             // Members
   13868              :             Array1D<Vector> Vertex;
   13869              : 
   13870              :             // Default Constructor
   13871            0 :             rectangularwindow() : Vertex(4)
   13872              :             {
   13873            0 :             }
   13874              :         };
   13875              : 
   13876              :         // Object Data
   13877            0 :         Vector TVect;
   13878            0 :         rectangularwindow NewCoord;
   13879            0 :         rectangularwindow OriginalCoord;
   13880              : 
   13881            0 :         auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
   13882              : 
   13883            0 :         IConst = surfTemp.Construction;
   13884              : 
   13885              :         // Height and width of original window
   13886            0 :         TVect = surfTemp.Vertex(3) - surfTemp.Vertex(2);
   13887            0 :         W = Vectors::VecLength(TVect); // SQRT((X(3)-X(2))**2 + (Y(3)-Y(2))**2 + (Z(3)-Z(2))**2)
   13888            0 :         TVect = surfTemp.Vertex(2) - surfTemp.Vertex(1);
   13889            0 :         H = Vectors::VecLength(TVect); // SQRT((X(1)-X(2))**2 + (Y(1)-Y(2))**2 + (Z(1)-Z(2))**2)
   13890              : 
   13891              :         // Save coordinates of original window in case Window 5 data overwrites.
   13892            0 :         OriginalCoord.Vertex({1, surfTemp.Sides}) = surfTemp.Vertex({1, surfTemp.Sides});
   13893              : 
   13894              :         // Height and width of first glazing system
   13895            0 :         h1 = state.dataConstruction->Construct(IConst).W5FileGlazingSysHeight;
   13896            0 :         w1 = state.dataConstruction->Construct(IConst).W5FileGlazingSysWidth;
   13897              : 
   13898            0 :         Const2Name = state.dataConstruction->Construct(IConst).Name + ":2";
   13899            0 :         IConst2 = Util::FindItemInList(Const2Name, state.dataConstruction->Construct);
   13900              : 
   13901            0 :         ++AddedSubSurfaces;
   13902            0 :         state.dataSurfaceGeometry->SurfaceTmp.redimension(++state.dataSurface->TotSurfaces);
   13903              : 
   13904            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Vertex.allocate(4);
   13905              : 
   13906            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Name = surfTemp.Name + ":2";
   13907            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Construction = IConst2;
   13908            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).ConstructionStoredInputValue = IConst2;
   13909            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Class = surfTemp.Class;
   13910            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Azimuth = surfTemp.Azimuth;
   13911              :         // Sine and cosine of azimuth and tilt
   13912            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).SinAzim = surfTemp.SinAzim;
   13913            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).CosAzim = surfTemp.CosAzim;
   13914            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).SinTilt = surfTemp.SinTilt;
   13915            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).CosTilt = surfTemp.CosTilt;
   13916              :         // Outward normal unit vector (pointing away from room)
   13917            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Centroid = surfTemp.Centroid;
   13918            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).lcsx = surfTemp.lcsx;
   13919            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).lcsy = surfTemp.lcsy;
   13920            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).lcsz = surfTemp.lcsz;
   13921            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).NewellAreaVector = surfTemp.NewellAreaVector;
   13922            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).OutNormVec = surfTemp.OutNormVec;
   13923            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Reveal = surfTemp.Reveal;
   13924            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Shape = surfTemp.Shape;
   13925            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Sides = surfTemp.Sides;
   13926            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Tilt = surfTemp.Tilt;
   13927            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).convOrientation = Convect::GetSurfConvOrientation(surfTemp.Tilt);
   13928            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).HeatTransSurf = surfTemp.HeatTransSurf;
   13929            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).BaseSurfName = surfTemp.BaseSurfName;
   13930            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).BaseSurf = surfTemp.BaseSurf;
   13931            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).ZoneName = surfTemp.ZoneName;
   13932            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Zone = surfTemp.Zone;
   13933            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).ExtBoundCondName = surfTemp.ExtBoundCondName;
   13934            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).ExtBoundCond = surfTemp.ExtBoundCond;
   13935            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).ExtSolar = surfTemp.ExtSolar;
   13936            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).ExtWind = surfTemp.ExtWind;
   13937            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).ViewFactorGround = surfTemp.ViewFactorGround;
   13938            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).ViewFactorSky = surfTemp.ViewFactorSky;
   13939            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).ViewFactorGroundIR = surfTemp.ViewFactorGroundIR;
   13940            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).ViewFactorSkyIR = surfTemp.ViewFactorSkyIR;
   13941            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).OSCPtr = surfTemp.OSCPtr;
   13942            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).shadowSurfSched = surfTemp.shadowSurfSched;
   13943            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).activeWindowShadingControl = surfTemp.activeWindowShadingControl;
   13944            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).windowShadingControlList = surfTemp.windowShadingControlList;
   13945            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).HasShadeControl = surfTemp.HasShadeControl;
   13946            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).activeShadedConstruction = surfTemp.activeShadedConstruction;
   13947            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).windowShadingControlList = surfTemp.windowShadingControlList;
   13948            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).shadedStormWinConstructionList =
   13949            0 :             surfTemp.shadedStormWinConstructionList;
   13950            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).FrameDivider = surfTemp.FrameDivider;
   13951            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Multiplier = surfTemp.Multiplier;
   13952            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).NetAreaShadowCalc = surfTemp.NetAreaShadowCalc;
   13953              : 
   13954            0 :         MulWidth = state.dataConstruction->Construct(IConst).W5FileMullionWidth;
   13955            0 :         w2 = state.dataConstruction->Construct(IConst2).W5FileGlazingSysWidth;
   13956            0 :         h2 = state.dataConstruction->Construct(IConst2).W5FileGlazingSysHeight;
   13957              : 
   13958              :         // Correction to net area of base surface. Add back in the original glazing area and subtract the
   13959              :         // area of the two glazing systems. Note that for Surface(SurfNum)%Class = 'Window' the effect
   13960              :         // of a window multiplier is included in the glazing area. Note that frame areas are subtracted later.
   13961              : 
   13962            0 :         AreaNew = surfTemp.Multiplier * (h1 * w1 + h2 * w2); // both glazing systems
   13963              :         // Adjust net area for base surface
   13964            0 :         state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).Area -= AreaNew;
   13965              : 
   13966              :         // Net area of base surface with unity window multipliers (used in shadowing checks)
   13967            0 :         state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).NetAreaShadowCalc -= AreaNew / surfTemp.Multiplier;
   13968              : 
   13969              :         // Reset area, etc. of original window
   13970            0 :         surfTemp.Area = surfTemp.Multiplier * (h1 * w1);
   13971            0 :         surfTemp.GrossArea = surfTemp.Area;
   13972            0 :         surfTemp.NetAreaShadowCalc = h1 * w1;
   13973            0 :         surfTemp.Perimeter = 2 * (h1 + w1);
   13974            0 :         surfTemp.Height = h1;
   13975            0 :         surfTemp.Width = w1;
   13976              :         // Set area, etc. of new window
   13977            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Area =
   13978            0 :             state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Multiplier * (h2 * w2);
   13979            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).GrossArea =
   13980            0 :             state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Area;
   13981            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).NetAreaShadowCalc = h2 * w2;
   13982            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Perimeter = 2 * (h2 + w2);
   13983            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Height = h2;
   13984            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Width = w2;
   13985              : 
   13986            0 :         if (state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).Area <= 0.0) {
   13987            0 :             ShowSevereError(state,
   13988            0 :                             format("SurfaceGeometry: ModifyWindow: Subsurfaces have too much area for base surface={}",
   13989            0 :                                    state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).Name));
   13990            0 :             ShowContinueError(state, format("Subsurface (window) creating error={}", surfTemp.Name));
   13991            0 :             ShowContinueError(state,
   13992            0 :                               format("This window has been replaced by two windows from the Window5 Data File of total area {:.2R} m2", AreaNew));
   13993            0 :             ErrorsFound = true;
   13994              :         }
   13995              : 
   13996              :         // Assign vertices to the new window; modify vertices of original window.
   13997              :         // In the following, vertices are numbered counter-clockwise with vertex #1 at the upper left.
   13998              : 
   13999            0 :         if (state.dataConstruction->Construct(IConst).W5FileMullionOrientation == DataWindowEquivalentLayer::Orientation::Vertical) {
   14000              : 
   14001              :             // VERTICAL MULLION: original window is modified to become left-hand glazing (system #1);
   14002              :             // new window is created to become right-hand glazing (system #2)
   14003              : 
   14004              :             // Left-hand glazing
   14005              : 
   14006              :             // Vertex 1
   14007            0 :             dx = 0.0;
   14008            0 :             dy = H - h1;
   14009            0 :             xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
   14010            0 :             ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
   14011            0 :             za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
   14012            0 :             xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
   14013            0 :             yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
   14014            0 :             zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
   14015            0 :             NewCoord.Vertex(1).x = xa + (dx / W) * (xb - xa);
   14016            0 :             NewCoord.Vertex(1).y = ya + (dx / W) * (yb - ya);
   14017            0 :             NewCoord.Vertex(1).z = za + (dx / W) * (zb - za);
   14018              : 
   14019              :             // Vertex 2
   14020            0 :             dx = 0.0;
   14021            0 :             dy = H;
   14022            0 :             xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
   14023            0 :             ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
   14024            0 :             za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
   14025            0 :             xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
   14026            0 :             yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
   14027            0 :             zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
   14028            0 :             NewCoord.Vertex(2).x = xa + (dx / W) * (xb - xa);
   14029            0 :             NewCoord.Vertex(2).y = ya + (dx / W) * (yb - ya);
   14030            0 :             NewCoord.Vertex(2).z = za + (dx / W) * (zb - za);
   14031              : 
   14032              :             // Vertex 3
   14033            0 :             dx = w1;
   14034            0 :             dy = H;
   14035            0 :             xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
   14036            0 :             ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
   14037            0 :             za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
   14038            0 :             xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
   14039            0 :             yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
   14040            0 :             zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
   14041            0 :             NewCoord.Vertex(3).x = xa + (dx / W) * (xb - xa);
   14042            0 :             NewCoord.Vertex(3).y = ya + (dx / W) * (yb - ya);
   14043            0 :             NewCoord.Vertex(3).z = za + (dx / W) * (zb - za);
   14044              : 
   14045              :             // Vertex 4
   14046            0 :             dx = w1;
   14047            0 :             dy = H - h1;
   14048            0 :             xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
   14049            0 :             ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
   14050            0 :             za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
   14051            0 :             xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
   14052            0 :             yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
   14053            0 :             zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
   14054            0 :             NewCoord.Vertex(4).x = xa + (dx / W) * (xb - xa);
   14055            0 :             NewCoord.Vertex(4).y = ya + (dx / W) * (yb - ya);
   14056            0 :             NewCoord.Vertex(4).z = za + (dx / W) * (zb - za);
   14057              : 
   14058            0 :             for (loop = 1; loop <= surfTemp.Sides; ++loop) {
   14059            0 :                 surfTemp.Vertex(loop) = NewCoord.Vertex(loop);
   14060              :             }
   14061              : 
   14062              :             // Right-hand glazing
   14063              : 
   14064              :             // Vertex 1
   14065            0 :             dx = w1 + MulWidth;
   14066            0 :             dy = H - (h1 + h2) / 2.0;
   14067            0 :             xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
   14068            0 :             ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
   14069            0 :             za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
   14070            0 :             xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
   14071            0 :             yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
   14072            0 :             zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
   14073            0 :             NewCoord.Vertex(1).x = xa + (dx / W) * (xb - xa);
   14074            0 :             NewCoord.Vertex(1).y = ya + (dx / W) * (yb - ya);
   14075            0 :             NewCoord.Vertex(1).z = za + (dx / W) * (zb - za);
   14076              : 
   14077              :             // Vertex 2
   14078            0 :             dx = w1 + MulWidth;
   14079            0 :             dy = H + (h2 - h1) / 2.0;
   14080            0 :             xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
   14081            0 :             ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
   14082            0 :             za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
   14083            0 :             xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
   14084            0 :             yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
   14085            0 :             zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
   14086            0 :             NewCoord.Vertex(2).x = xa + (dx / W) * (xb - xa);
   14087            0 :             NewCoord.Vertex(2).y = ya + (dx / W) * (yb - ya);
   14088            0 :             NewCoord.Vertex(2).z = za + (dx / W) * (zb - za);
   14089              : 
   14090              :             // Vertex 3
   14091            0 :             dx = w1 + MulWidth + w2;
   14092            0 :             dy = H + (h2 - h1) / 2.0;
   14093            0 :             xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
   14094            0 :             ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
   14095            0 :             za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
   14096            0 :             xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
   14097            0 :             yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
   14098            0 :             zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
   14099            0 :             NewCoord.Vertex(3).x = xa + (dx / W) * (xb - xa);
   14100            0 :             NewCoord.Vertex(3).y = ya + (dx / W) * (yb - ya);
   14101            0 :             NewCoord.Vertex(3).z = za + (dx / W) * (zb - za);
   14102              : 
   14103              :             // Vertex 4
   14104            0 :             dx = w1 + MulWidth + w2;
   14105            0 :             dy = H - (h1 + h2) / 2.0;
   14106            0 :             xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
   14107            0 :             ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
   14108            0 :             za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
   14109            0 :             xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
   14110            0 :             yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
   14111            0 :             zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
   14112            0 :             NewCoord.Vertex(4).x = xa + (dx / W) * (xb - xa);
   14113            0 :             NewCoord.Vertex(4).y = ya + (dx / W) * (yb - ya);
   14114            0 :             NewCoord.Vertex(4).z = za + (dx / W) * (zb - za);
   14115              : 
   14116            0 :             for (loop = 1; loop <= state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Sides; ++loop) {
   14117            0 :                 state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Vertex(loop) = NewCoord.Vertex(loop);
   14118              :             }
   14119              : 
   14120              :         } else { // Horizontal mullion
   14121              : 
   14122              :             // HORIZONTAL MULLION: original window is modified to become bottom glazing (system #1);
   14123              :             // new window is created to become top glazing (system #2)
   14124              : 
   14125              :             // Bottom glazing
   14126              : 
   14127              :             // Vertex 1
   14128            0 :             dx = 0.0;
   14129            0 :             dy = H - h1;
   14130            0 :             xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
   14131            0 :             ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
   14132            0 :             za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
   14133            0 :             xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
   14134            0 :             yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
   14135            0 :             zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
   14136            0 :             NewCoord.Vertex(1).x = xa + (dx / W) * (xb - xa);
   14137            0 :             NewCoord.Vertex(1).y = ya + (dx / W) * (yb - ya);
   14138            0 :             NewCoord.Vertex(1).z = za + (dx / W) * (zb - za);
   14139              : 
   14140              :             // Vertex 2
   14141            0 :             dx = 0.0;
   14142            0 :             dy = H;
   14143            0 :             xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
   14144            0 :             ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
   14145            0 :             za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
   14146            0 :             xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
   14147            0 :             yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
   14148            0 :             zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
   14149            0 :             NewCoord.Vertex(2).x = xa + (dx / W) * (xb - xa);
   14150            0 :             NewCoord.Vertex(2).y = ya + (dx / W) * (yb - ya);
   14151            0 :             NewCoord.Vertex(2).z = za + (dx / W) * (zb - za);
   14152              : 
   14153              :             // Vertex 3
   14154            0 :             dx = w1;
   14155            0 :             dy = H;
   14156            0 :             xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
   14157            0 :             ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
   14158            0 :             za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
   14159            0 :             xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
   14160            0 :             yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
   14161            0 :             zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
   14162            0 :             NewCoord.Vertex(3).x = xa + (dx / W) * (xb - xa);
   14163            0 :             NewCoord.Vertex(3).y = ya + (dx / W) * (yb - ya);
   14164            0 :             NewCoord.Vertex(3).z = za + (dx / W) * (zb - za);
   14165              : 
   14166              :             // Vertex 4
   14167            0 :             dx = w1;
   14168            0 :             dy = H - h1;
   14169            0 :             xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
   14170            0 :             ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
   14171            0 :             za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
   14172            0 :             xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
   14173            0 :             yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
   14174            0 :             zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
   14175            0 :             NewCoord.Vertex(4).x = xa + (dx / W) * (xb - xa);
   14176            0 :             NewCoord.Vertex(4).y = ya + (dx / W) * (yb - ya);
   14177            0 :             NewCoord.Vertex(4).z = za + (dx / W) * (zb - za);
   14178              : 
   14179            0 :             for (loop = 1; loop <= surfTemp.Sides; ++loop) {
   14180            0 :                 surfTemp.Vertex(loop) = NewCoord.Vertex(loop);
   14181              :             }
   14182              : 
   14183              :             // Top glazing
   14184              : 
   14185              :             // Vertex 1
   14186            0 :             dx = (w1 - w2) / 2.0;
   14187            0 :             dy = H - (h1 + h2 + MulWidth);
   14188            0 :             xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
   14189            0 :             ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
   14190            0 :             za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
   14191            0 :             xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
   14192            0 :             yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
   14193            0 :             zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
   14194            0 :             NewCoord.Vertex(1).x = xa + (dx / W) * (xb - xa);
   14195            0 :             NewCoord.Vertex(1).y = ya + (dx / W) * (yb - ya);
   14196            0 :             NewCoord.Vertex(1).z = za + (dx / W) * (zb - za);
   14197              : 
   14198              :             // Vertex 2
   14199            0 :             dx = (w1 - w2) / 2.0;
   14200            0 :             dy = H - (h1 + MulWidth);
   14201            0 :             xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
   14202            0 :             ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
   14203            0 :             za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
   14204            0 :             xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
   14205            0 :             yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
   14206            0 :             zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
   14207            0 :             NewCoord.Vertex(2).x = xa + (dx / W) * (xb - xa);
   14208            0 :             NewCoord.Vertex(2).y = ya + (dx / W) * (yb - ya);
   14209            0 :             NewCoord.Vertex(2).z = za + (dx / W) * (zb - za);
   14210              : 
   14211              :             // Vertex 3
   14212            0 :             dx = (w1 + w2) / 2.0;
   14213            0 :             dy = H - (h1 + MulWidth);
   14214            0 :             xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
   14215            0 :             ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
   14216            0 :             za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
   14217            0 :             xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
   14218            0 :             yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
   14219            0 :             zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
   14220            0 :             NewCoord.Vertex(3).x = xa + (dx / W) * (xb - xa);
   14221            0 :             NewCoord.Vertex(3).y = ya + (dx / W) * (yb - ya);
   14222            0 :             NewCoord.Vertex(3).z = za + (dx / W) * (zb - za);
   14223              : 
   14224              :             // Vertex 4
   14225            0 :             dx = (w1 + w2) / 2.0;
   14226            0 :             dy = H - (h1 + h2 + MulWidth);
   14227            0 :             xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
   14228            0 :             ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
   14229            0 :             za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
   14230            0 :             xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
   14231            0 :             yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
   14232            0 :             zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
   14233            0 :             NewCoord.Vertex(4).x = xa + (dx / W) * (xb - xa);
   14234            0 :             NewCoord.Vertex(4).y = ya + (dx / W) * (yb - ya);
   14235            0 :             NewCoord.Vertex(4).z = za + (dx / W) * (zb - za);
   14236              : 
   14237            0 :             for (loop = 1; loop <= state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Sides; ++loop) {
   14238            0 :                 state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Vertex(loop) = NewCoord.Vertex(loop);
   14239              :             }
   14240              : 
   14241              :         } // End of check if vertical or horizontal mullion
   14242            0 :     }
   14243              : 
   14244         2213 :     void TransformVertsByAspect(EnergyPlusData &state,
   14245              :                                 int const SurfNum, // Current surface number
   14246              :                                 int const NSides   // Number of sides to figure
   14247              :     )
   14248              :     {
   14249              :         // SUBROUTINE INFORMATION:
   14250              :         //       AUTHOR         Brent T Griffith
   14251              :         //       DATE WRITTEN   April 2003
   14252              : 
   14253              :         // PURPOSE OF THIS SUBROUTINE:
   14254              :         // Alter input for surface geometry
   14255              :         // Optimizing building design for energy can involve
   14256              :         //  altering building geometry.  Rather than assemble routines to transform
   14257              :         //  geometry through pre-processing on input, it may be simpler to change
   14258              :         //  vertices within EnergyPlus since it already reads the data from the input
   14259              :         //  file and there would no longer be a need to rewrite the text data.
   14260              :         //  This is essentially a crude hack to allow adjusting geometry with
   14261              :         //  a single parameter...
   14262              : 
   14263              :         // METHODOLOGY EMPLOYED:
   14264              :         // once vertices have been converted to WCS, change them to reflect a different aspect
   14265              :         // ratio for the entire building based on user input.
   14266              :         // This routine is called once for each surface by subroutine GetVertices
   14267              : 
   14268         2635 :         static std::string const CurrentModuleObject("GeometryTransform");
   14269              : 
   14270         2213 :         Array1D_string cAlphas(1);
   14271         2213 :         Array1D<Real64> rNumerics(2);
   14272         2213 :         auto &OldAspectRatio = state.dataSurfaceGeometry->OldAspectRatio;
   14273         2213 :         auto &NewAspectRatio = state.dataSurfaceGeometry->NewAspectRatio;
   14274              :         int n;
   14275              :         Real64 Xo;
   14276              :         Real64 XnoRot;
   14277              :         Real64 Xtrans;
   14278              :         Real64 Yo;
   14279              :         Real64 YnoRot;
   14280              :         Real64 Ytrans;
   14281              :         // begin execution
   14282              :         // get user input...
   14283              : 
   14284         2213 :         auto &s_ipsc = state.dataIPShortCut;
   14285         2213 :         auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
   14286              : 
   14287         2213 :         if (state.dataSurfaceGeometry->firstTime) {
   14288          220 :             if (state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject) == 1) {
   14289              :                 int NAlphas;
   14290              :                 int NNum;
   14291              :                 int IOStat;
   14292            0 :                 auto &s_ipsc = state.dataIPShortCut;
   14293            0 :                 auto &transformPlane = state.dataSurfaceGeometry->transformPlane;
   14294            0 :                 state.dataInputProcessing->inputProcessor->getObjectItem(state,
   14295              :                                                                          CurrentModuleObject,
   14296              :                                                                          1,
   14297              :                                                                          cAlphas,
   14298              :                                                                          NAlphas,
   14299              :                                                                          rNumerics,
   14300              :                                                                          NNum,
   14301              :                                                                          IOStat,
   14302            0 :                                                                          s_ipsc->lNumericFieldBlanks,
   14303            0 :                                                                          s_ipsc->lAlphaFieldBlanks,
   14304            0 :                                                                          s_ipsc->cAlphaFieldNames,
   14305            0 :                                                                          s_ipsc->cNumericFieldNames);
   14306            0 :                 OldAspectRatio = rNumerics(1);
   14307            0 :                 NewAspectRatio = rNumerics(2);
   14308            0 :                 transformPlane = cAlphas(1);
   14309            0 :                 if (transformPlane != "XY") {
   14310            0 :                     ShowWarningError(state, format("{}: invalid {}=\"{}...ignored.", CurrentModuleObject, s_ipsc->cAlphaFieldNames(1), cAlphas(1)));
   14311              :                 }
   14312            0 :                 state.dataSurfaceGeometry->firstTime = false;
   14313            0 :                 state.dataSurfaceGeometry->noTransform = false;
   14314            0 :                 state.dataSurface->AspectTransform = true;
   14315            0 :                 if (state.dataSurface->WorldCoordSystem) {
   14316            0 :                     ShowWarningError(state, format("{}: must use Relative Coordinate System.  Transform request ignored.", CurrentModuleObject));
   14317            0 :                     state.dataSurfaceGeometry->noTransform = true;
   14318            0 :                     state.dataSurface->AspectTransform = false;
   14319              :                 }
   14320              :             } else {
   14321          220 :                 state.dataSurfaceGeometry->firstTime = false;
   14322              :             }
   14323              :         }
   14324         2213 :         if (state.dataSurfaceGeometry->noTransform) {
   14325         2213 :             return;
   14326              :         }
   14327              : 
   14328              :         // check surface type.
   14329            0 :         if (!surfTemp.HeatTransSurf) {
   14330              :             // Site Shading do not get transformed.
   14331            0 :             if (surfTemp.Class == SurfaceClass::Detached_F) {
   14332            0 :                 return;
   14333              :             }
   14334              :         }
   14335              : 
   14336              :         // testing method of transforming  x and y coordinates as follows
   14337              : 
   14338              :         // this works if not rotated wrt north axis ... but if it is, then trouble
   14339              :         // try to first derotate it , transform by aspect and then rotate back.
   14340              : 
   14341            0 :         for (n = 1; n <= NSides; ++n) {
   14342            0 :             Xo = surfTemp.Vertex(n).x; // world coordinates.... shifted by relative north angle...
   14343            0 :             Yo = surfTemp.Vertex(n).y;
   14344              :             // next derotate the building
   14345            0 :             XnoRot = Xo * state.dataSurfaceGeometry->CosBldgRelNorth + Yo * state.dataSurfaceGeometry->SinBldgRelNorth;
   14346            0 :             YnoRot = Yo * state.dataSurfaceGeometry->CosBldgRelNorth - Xo * state.dataSurfaceGeometry->SinBldgRelNorth;
   14347              :             // translate
   14348            0 :             Xtrans = XnoRot * std::sqrt(NewAspectRatio / OldAspectRatio);
   14349            0 :             Ytrans = YnoRot * std::sqrt(OldAspectRatio / NewAspectRatio);
   14350              :             // rerotate
   14351            0 :             surfTemp.Vertex(n).x = Xtrans * state.dataSurfaceGeometry->CosBldgRelNorth - Ytrans * state.dataSurfaceGeometry->SinBldgRelNorth;
   14352              : 
   14353            0 :             surfTemp.Vertex(n).y = Xtrans * state.dataSurfaceGeometry->SinBldgRelNorth + Ytrans * state.dataSurfaceGeometry->CosBldgRelNorth;
   14354              :         }
   14355         4426 :     }
   14356              : 
   14357          225 :     void CalcSurfaceCentroid(EnergyPlusData &state)
   14358              :     {
   14359              :         // SUBROUTINE INFORMATION:
   14360              :         //       AUTHOR         B. Griffith
   14361              :         //       DATE WRITTEN   Feb. 2004
   14362              : 
   14363              :         // PURPOSE OF THIS SUBROUTINE:
   14364              :         // compute centroid of all the surfaces in the main
   14365              :         // surface structure. Store the vertex coordinates of
   14366              :         // the centroid in the 'SURFACE' derived type.
   14367              : 
   14368              :         // METHODOLOGY EMPLOYED:
   14369              :         // The centroid of triangle is easily computed by averaging the vertices
   14370              :         // The centroid of a quadrilateral is computed by area weighting the centroids
   14371              :         // of two triangles.
   14372              :         // (Algorithm would need to be changed for higher order
   14373              :         // polygons with more than four sides).
   14374              : 
   14375          225 :         auto &Triangle1 = state.dataSurfaceGeometry->Triangle1;
   14376          225 :         auto &Triangle2 = state.dataSurfaceGeometry->Triangle2;
   14377          225 :         static Vector const zero_vector(0.0);
   14378          225 :         Vector centroid;
   14379              : 
   14380          225 :         int negZcount(0); // for warning error in surface centroids
   14381              : 
   14382              :         // loop through all the surfaces
   14383         2495 :         for (int ThisSurf = 1; ThisSurf <= state.dataSurface->TotSurfaces; ++ThisSurf) {
   14384         2270 :             auto &surface = state.dataSurface->Surface(ThisSurf);
   14385              : 
   14386         2270 :             if (surface.Class == SurfaceClass::IntMass) {
   14387           16 :                 continue;
   14388              :             }
   14389              : 
   14390         2254 :             auto const &vertex = surface.Vertex;
   14391              : 
   14392         2254 :             if (surface.Sides == 3) { // 3-sided polygon
   14393              : 
   14394           30 :                 centroid = cen(vertex(1), vertex(2), vertex(3));
   14395              : 
   14396         2224 :             } else if (surface.Sides == 4) { // 4-sided polygon
   14397              : 
   14398              :                 // split into 2 3-sided polygons (Triangle 1 and Triangle 2)
   14399         2202 :                 Triangle1(1) = vertex(1);
   14400         2202 :                 Triangle1(2) = vertex(2);
   14401         2202 :                 Triangle1(3) = vertex(3);
   14402         2202 :                 Triangle2(1) = vertex(1);
   14403         2202 :                 Triangle2(2) = vertex(3);
   14404         2202 :                 Triangle2(3) = vertex(4);
   14405              : 
   14406              :                 // get total Area of quad.
   14407         2202 :                 Real64 TotalArea(surface.GrossArea);
   14408         2202 :                 if (TotalArea <= 0.0) {
   14409              :                     // catch a problem....
   14410            0 :                     ShowWarningError(state, format("CalcSurfaceCentroid: zero area surface, for surface={}", surface.Name));
   14411            0 :                     continue;
   14412              :                 }
   14413              : 
   14414              :                 // get area fraction of triangles.
   14415         2202 :                 Real64 Tri1Area(Vectors::AreaPolygon(3, Triangle1) / TotalArea);
   14416         2202 :                 Real64 Tri2Area(Vectors::AreaPolygon(3, Triangle2) / TotalArea);
   14417              : 
   14418              :                 // check if sum of fractions are slightly greater than 1.0 which is a symptom of the triangles for a non-convex
   14419              :                 // quadrilateral using the wrong two triangles
   14420         2202 :                 if ((Tri1Area + Tri2Area) > 1.05) {
   14421              : 
   14422              :                     // if so repeat the process with the other two possible triangles (notice the vertices are in a different order this
   14423              :                     // time) split into 2 3-sided polygons (Triangle 1 and Triangle 2)
   14424            3 :                     Triangle1(1) = vertex(1);
   14425            3 :                     Triangle1(2) = vertex(2);
   14426            3 :                     Triangle1(3) = vertex(4);
   14427            3 :                     Triangle2(1) = vertex(2);
   14428            3 :                     Triangle2(2) = vertex(3);
   14429            3 :                     Triangle2(3) = vertex(4);
   14430              : 
   14431              :                     // get area fraction of triangles.
   14432            3 :                     Real64 AreaTriangle1 = Vectors::AreaPolygon(3, Triangle1);
   14433            3 :                     Real64 AreaTriangle2 = Vectors::AreaPolygon(3, Triangle2);
   14434            3 :                     TotalArea = AreaTriangle1 + AreaTriangle2;
   14435            3 :                     Tri1Area = AreaTriangle1 / TotalArea;
   14436            3 :                     Tri2Area = AreaTriangle2 / TotalArea;
   14437              :                 }
   14438              : 
   14439              :                 // get centroid of Triangle 1
   14440         2202 :                 Vector cen1(cen(Triangle1(1), Triangle1(2), Triangle1(3)));
   14441              : 
   14442              :                 // get centroid of Triangle 2
   14443         2202 :                 Vector cen2(cen(Triangle2(1), Triangle2(2), Triangle2(3)));
   14444              : 
   14445              :                 // find area weighted combination of the two centroids (coded to avoid temporary Vectors)
   14446         2202 :                 cen1 *= Tri1Area;
   14447         2202 :                 cen2 *= Tri2Area;
   14448         2202 :                 centroid = cen1;
   14449         2202 :                 centroid += cen2;
   14450              : 
   14451         2224 :             } else if (surface.Sides >= 5) { // multi-sided polygon
   14452              :                 // (Maybe triangulate?  For now, use old "z" average method")
   14453              :                 // and X and Y -- straight average
   14454              : 
   14455              :                 //        X1=MINVAL(Surface(ThisSurf)%Vertex(1:Surface(ThisSurf)%Sides)%x)
   14456              :                 //        X2=MAXVAL(Surface(ThisSurf)%Vertex(1:Surface(ThisSurf)%Sides)%x)
   14457              :                 //        Y1=MINVAL(Surface(ThisSurf)%Vertex(1:Surface(ThisSurf)%Sides)%y)
   14458              :                 //        Y2=MAXVAL(Surface(ThisSurf)%Vertex(1:Surface(ThisSurf)%Sides)%y)
   14459              :                 //        Z1=MINVAL(Surface(ThisSurf)%Vertex(1:Surface(ThisSurf)%Sides)%z)
   14460              :                 //        Z2=MAXVAL(Surface(ThisSurf)%Vertex(1:Surface(ThisSurf)%Sides)%z)
   14461              :                 //        Xcm=(X1+X2)/2.0d0
   14462              :                 //        Ycm=(Y1+Y2)/2.0d0
   14463              :                 //        Zcm=(Z1+Z2)/2.0d0
   14464              : 
   14465              :                 // Calc centroid as average of surfaces
   14466           13 :                 centroid = 0.0;
   14467           86 :                 for (int vert = 1; vert <= surface.Sides; ++vert) {
   14468           73 :                     centroid += vertex(vert);
   14469              :                 }
   14470           13 :                 centroid /= double(surface.Sides);
   14471              : 
   14472              :             } else {
   14473              : 
   14474            9 :                 if (!surface.Name.empty()) {
   14475            0 :                     ShowWarningError(state, format("CalcSurfaceCentroid: caught problem with # of sides, for surface={}", surface.Name));
   14476            0 :                     ShowContinueError(state, format("... number of sides must be >= 3, this surface # sides={}", surface.Sides));
   14477              :                 } else {
   14478            9 :                     ShowWarningError(state, format("CalcSurfaceCentroid: caught problem with # of sides, for surface=#{}", ThisSurf));
   14479           18 :                     ShowContinueError(state,
   14480              :                                       "...surface name is blank. Examine surfaces -- this may be a problem with ill-formed interzone surfaces.");
   14481            9 :                     ShowContinueError(state, format("... number of sides must be >= 3, this surface # sides={}", surface.Sides));
   14482              :                 }
   14483            9 :                 centroid = 0.0;
   14484              :             }
   14485              : 
   14486              :             // store result in the surface structure in DataSurfaces
   14487         2254 :             surface.Centroid = centroid;
   14488              : 
   14489         2254 :             if (centroid.z < 0.0) {
   14490            5 :                 if (surface.ExtWind || surface.ExtBoundCond == DataSurfaces::ExternalEnvironment) {
   14491            1 :                     ++negZcount;
   14492              :                 }
   14493              :             }
   14494              : 
   14495              :         } // loop through surfaces
   14496              : 
   14497          225 :         if (negZcount > 0) {
   14498            1 :             ShowWarningError(state, format("CalcSurfaceCentroid: {} Surfaces have the Z coordinate < 0.", negZcount));
   14499            2 :             ShowContinueError(state, "...in any calculations, Wind Speed will be 0.0 for these surfaces.");
   14500            2 :             ShowContinueError(state,
   14501            2 :                               format("...in any calculations, Outside temperatures will be the outside temperature + {:.3R} for these surfaces.",
   14502            1 :                                      state.dataEnvrn->WeatherFileTempModCoeff));
   14503            3 :             ShowContinueError(state, "...that is, these surfaces will have conditions as though at ground level.");
   14504              :         }
   14505          225 :     }
   14506              : 
   14507          224 :     void SetupShadeSurfacesForSolarCalcs(EnergyPlusData &state)
   14508              :     {
   14509              :         // SUBROUTINE INFORMATION:
   14510              :         //       AUTHOR         B. Griffith
   14511              :         //       DATE WRITTEN   Dec. 2008
   14512              : 
   14513              :         // PURPOSE OF THIS SUBROUTINE:
   14514              :         // determine if Shading surfaces need full solar calcs because they
   14515              :         // are also used to define geometry of an active solar component.
   14516              :         // Normally, a shading surface is not included in calculations of incident solar, only shading
   14517              : 
   14518              :         // METHODOLOGY EMPLOYED:
   14519              :         // Mine solar renewables input and collect surface names.
   14520              :         // find shading surfaces with names that match those in solar objects.
   14521              :         // setup flags for shading surfaces so that the solar renewables can reuse incident solar calcs
   14522              :         // new solar component models that use shading surfaces will have to extend the code here.
   14523              : 
   14524              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
   14525          224 :         Array1D_string TmpCandidateSurfaceNames;
   14526          224 :         Array1D_string TmpCandidateICSSurfaceNames;
   14527          224 :         Array1D_string TmpCandidateICSBCTypeNames;
   14528              :         int NumAlphas;  // Number of alpha names being passed
   14529              :         int NumNumbers; // Number of numeric parameters being passed
   14530              :         int IOStatus;
   14531              : 
   14532          224 :         auto &s_ipsc = state.dataIPShortCut;
   14533              :         // First collect names of surfaces referenced by active solar components
   14534          224 :         s_ipsc->cCurrentModuleObject = "SolarCollector:FlatPlate:Water";
   14535          224 :         int NumOfFlatPlateUnits = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
   14536          224 :         s_ipsc->cCurrentModuleObject = "SolarCollector:FlatPlate:PhotovoltaicThermal";
   14537          224 :         int NumPVTs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
   14538          224 :         s_ipsc->cCurrentModuleObject = "Generator:Photovoltaic";
   14539          224 :         int NumPVs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
   14540          224 :         s_ipsc->cCurrentModuleObject = "SolarCollector:IntegralCollectorStorage";
   14541          224 :         int NumOfICSUnits = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
   14542              : 
   14543          224 :         int NumCandidateNames = NumOfFlatPlateUnits + NumPVTs + NumPVs + NumOfICSUnits;
   14544          224 :         int NumOfCollectors = NumOfFlatPlateUnits + NumOfICSUnits;
   14545              : 
   14546          224 :         TmpCandidateSurfaceNames.allocate(NumCandidateNames);
   14547          224 :         TmpCandidateICSSurfaceNames.allocate(NumOfCollectors);
   14548          224 :         TmpCandidateICSBCTypeNames.allocate(NumOfCollectors);
   14549              : 
   14550          224 :         if (NumOfCollectors > 0) {
   14551            0 :             s_ipsc->cCurrentModuleObject = "SolarCollector:FlatPlate:Water";
   14552            0 :             for (int CollectorNum = 1; CollectorNum <= NumOfFlatPlateUnits; ++CollectorNum) {
   14553              : 
   14554            0 :                 state.dataInputProcessing->inputProcessor->getObjectItem(
   14555            0 :                     state, s_ipsc->cCurrentModuleObject, CollectorNum, s_ipsc->cAlphaArgs, NumAlphas, s_ipsc->rNumericArgs, NumNumbers, IOStatus);
   14556              : 
   14557            0 :                 TmpCandidateSurfaceNames(CollectorNum) = s_ipsc->cAlphaArgs(3);
   14558            0 :                 TmpCandidateICSBCTypeNames(CollectorNum) = "";
   14559              :             }
   14560              :         }
   14561              : 
   14562          224 :         if (NumPVTs > 0) {
   14563            2 :             s_ipsc->cCurrentModuleObject = "SolarCollector:FlatPlate:PhotovoltaicThermal";
   14564            4 :             for (int PVTnum = 1; PVTnum <= NumPVTs; ++PVTnum) {
   14565              : 
   14566            4 :                 state.dataInputProcessing->inputProcessor->getObjectItem(
   14567            2 :                     state, s_ipsc->cCurrentModuleObject, PVTnum, s_ipsc->cAlphaArgs, NumAlphas, s_ipsc->rNumericArgs, NumNumbers, IOStatus);
   14568              : 
   14569            2 :                 TmpCandidateSurfaceNames(NumOfFlatPlateUnits + PVTnum) = s_ipsc->cAlphaArgs(2);
   14570              :             }
   14571              :         }
   14572              : 
   14573          224 :         if (NumPVs > 0) {
   14574            2 :             s_ipsc->cCurrentModuleObject = "Generator:Photovoltaic";
   14575            4 :             for (int PVnum = 1; PVnum <= NumPVs; ++PVnum) {
   14576            4 :                 state.dataInputProcessing->inputProcessor->getObjectItem(
   14577            2 :                     state, s_ipsc->cCurrentModuleObject, PVnum, s_ipsc->cAlphaArgs, NumAlphas, s_ipsc->rNumericArgs, NumNumbers, IOStatus);
   14578            2 :                 TmpCandidateSurfaceNames(NumOfFlatPlateUnits + NumPVTs + PVnum) = s_ipsc->cAlphaArgs(2);
   14579              :             }
   14580              :         }
   14581              : 
   14582          224 :         if (NumOfICSUnits > 0) {
   14583            0 :             s_ipsc->cCurrentModuleObject = "SolarCollector:IntegralCollectorStorage";
   14584            0 :             for (int CollectorNum = 1; CollectorNum <= NumOfICSUnits; ++CollectorNum) {
   14585            0 :                 state.dataInputProcessing->inputProcessor->getObjectItem(
   14586            0 :                     state, s_ipsc->cCurrentModuleObject, CollectorNum, s_ipsc->cAlphaArgs, NumAlphas, s_ipsc->rNumericArgs, NumNumbers, IOStatus);
   14587            0 :                 TmpCandidateSurfaceNames(NumOfFlatPlateUnits + NumPVTs + NumPVs + CollectorNum) = s_ipsc->cAlphaArgs(3);
   14588            0 :                 TmpCandidateICSSurfaceNames(NumOfFlatPlateUnits + CollectorNum) = s_ipsc->cAlphaArgs(3);
   14589            0 :                 TmpCandidateICSBCTypeNames(NumOfFlatPlateUnits + CollectorNum) = s_ipsc->cAlphaArgs(4);
   14590              :             }
   14591              :         }
   14592              : 
   14593              :         // loop through all the surfaces
   14594         2484 :         for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
   14595         2260 :             auto &surf = state.dataSurface->Surface(SurfNum);
   14596         2260 :             int Found = Util::FindItemInList(surf.Name, TmpCandidateSurfaceNames, NumCandidateNames);
   14597         2260 :             if (Found > 0) {
   14598            2 :                 if (!surf.HeatTransSurf) { // not BIPV, must be a shading surf with solar device
   14599              :                     // Setup missing values to allow shading surfaces to model incident solar and wind
   14600            1 :                     surf.ExtSolar = true;
   14601            1 :                     surf.ExtWind = true;
   14602            1 :                     surf.ViewFactorGround = 0.5 * (1.0 - surf.CosTilt);
   14603              :                 }
   14604              :                 // check if this surface is used for ICS collector mounting and has OthersideCondictionsModel as its
   14605              :                 // boundary condition
   14606            2 :                 if (NumOfICSUnits > 0) {
   14607            0 :                     for (int CollectorNum = 1; CollectorNum <= NumOfCollectors; ++CollectorNum) {
   14608            0 :                         if (Util::SameString(surf.Name, TmpCandidateICSSurfaceNames(CollectorNum)) &&
   14609            0 :                             Util::SameString(TmpCandidateICSBCTypeNames(CollectorNum), "OTHERSIDECONDITIONSMODEL")) {
   14610            0 :                             state.dataSurface->SurfIsICS(SurfNum) = true;
   14611            0 :                             state.dataSurface->SurfICSPtr(SurfNum) = CollectorNum;
   14612              :                         }
   14613              :                     }
   14614              :                 }
   14615              : 
   14616              :             } // end of IF (Found > 0) Then
   14617              :         }
   14618          224 :     }
   14619              : 
   14620              :     void
   14621          416 :     SetupEnclosuresAndAirBoundaries(EnergyPlusData &state,
   14622              :                                     EPVector<DataViewFactorInformation::EnclosureViewFactorInformation> &Enclosures, // Radiant or Solar Enclosures
   14623              :                                     SurfaceGeometry::enclosureType const EnclosureType,                              // Radiant or Solar
   14624              :                                     bool &ErrorsFound)                                                               // Set to true if errors found
   14625              :     {
   14626              :         static constexpr std::string_view RoutineName = "SetupEnclosuresAndAirBoundaries";
   14627          416 :         bool anyGroupedSpaces = false;
   14628          416 :         bool radiantSetup = false;
   14629          416 :         bool solarSetup = false;
   14630          416 :         std::string RadiantOrSolar = "";
   14631          416 :         int enclosureNum = 0;
   14632          416 :         if (EnclosureType == RadiantEnclosures) {
   14633          224 :             radiantSetup = true;
   14634          224 :             RadiantOrSolar = "Radiant";
   14635          224 :             state.dataViewFactor->EnclRadInfo.allocate(state.dataGlobal->numSpaces);
   14636          192 :         } else if (EnclosureType == SolarEnclosures) {
   14637          192 :             solarSetup = true;
   14638          192 :             RadiantOrSolar = "Solar";
   14639          192 :             state.dataViewFactor->EnclSolInfo.allocate(state.dataGlobal->numSpaces);
   14640              :         } else {
   14641            0 :             ShowFatalError(
   14642            0 :                 state, format("{}: Illegal call to this function. Second argument must be 'RadiantEnclosures' or 'SolarEnclosures'", RoutineName));
   14643              :         }
   14644          416 :         if (std::any_of(state.dataConstruction->Construct.begin(),
   14645          416 :                         state.dataConstruction->Construct.end(),
   14646         1390 :                         [](Construction::ConstructionProps const &e) { return e.TypeIsAirBoundary; })) {
   14647           18 :             int errorCount = 0;
   14648          222 :             for (int surfNum = 1; surfNum <= state.dataSurface->TotSurfaces; ++surfNum) {
   14649          204 :                 auto &surf = state.dataSurface->Surface(surfNum);
   14650          204 :                 if (surf.Construction == 0) {
   14651            0 :                     continue;
   14652              :                 }
   14653          204 :                 auto &constr = state.dataConstruction->Construct(surf.Construction);
   14654          204 :                 if (!constr.TypeIsAirBoundary) {
   14655          120 :                     continue;
   14656              :                 }
   14657           84 :                 surf.IsAirBoundarySurf = true;
   14658              : 
   14659              :                 // Check for invalid air boundary surfaces - valid only on non-adiabatic interzone surfaces
   14660              :                 // Only check this once during radiant setup, skip for solar setup
   14661           84 :                 if (radiantSetup && (surf.ExtBoundCond <= 0 || surf.ExtBoundCond == surfNum)) {
   14662            0 :                     ErrorsFound = true;
   14663            0 :                     if (!state.dataGlobal->DisplayExtraWarnings) {
   14664            0 :                         ++errorCount;
   14665              :                     } else {
   14666            0 :                         ShowSevereError(
   14667            0 :                             state, format("{}: Surface=\"{}\" uses Construction:AirBoundary in a non-interzone surface.", RoutineName, surf.Name));
   14668              :                     }
   14669              :                 } else {
   14670              :                     // Process air boundary - set surface properties and set up enclosures Radiant exchange, Boundary is grouped - assign enclosure
   14671           84 :                     state.dataHeatBal->AnyAirBoundary = true;
   14672           84 :                     int thisSideEnclosureNum = 0;
   14673           84 :                     int otherSideEnclosureNum = 0;
   14674           84 :                     if (radiantSetup) {
   14675              :                         // Radiant enclosure setup
   14676           42 :                         constr.IsUsedCTF = false;
   14677           42 :                         surf.HeatTransSurf = false;
   14678           42 :                         surf.HeatTransferAlgorithm = DataSurfaces::HeatTransferModel::AirBoundaryNoHT;
   14679           42 :                         thisSideEnclosureNum = state.dataHeatBal->space(surf.spaceNum).radiantEnclosureNum;
   14680           42 :                         otherSideEnclosureNum = state.dataHeatBal->space(state.dataSurface->Surface(surf.ExtBoundCond).spaceNum).radiantEnclosureNum;
   14681              :                     } else {
   14682              :                         // Solar enclosure setup
   14683           42 :                         thisSideEnclosureNum = state.dataHeatBal->space(surf.spaceNum).solarEnclosureNum;
   14684           42 :                         otherSideEnclosureNum = state.dataHeatBal->space(state.dataSurface->Surface(surf.ExtBoundCond).spaceNum).solarEnclosureNum;
   14685              :                     }
   14686           84 :                     anyGroupedSpaces = true;
   14687           84 :                     if ((thisSideEnclosureNum == 0) && (otherSideEnclosureNum == 0)) {
   14688              :                         // Neither zone is assigned to an enclosure, so increment the counter and assign to both
   14689           22 :                         ++enclosureNum;
   14690           22 :                         auto &thisEnclosure = Enclosures(enclosureNum);
   14691           22 :                         thisSideEnclosureNum = enclosureNum;
   14692           22 :                         thisEnclosure.Name = format("{} Enclosure {}", RadiantOrSolar, enclosureNum);
   14693           22 :                         thisEnclosure.spaceNames.push_back(state.dataHeatBal->space(surf.spaceNum).Name);
   14694           22 :                         thisEnclosure.spaceNums.push_back(surf.spaceNum);
   14695           22 :                         thisEnclosure.FloorArea += state.dataHeatBal->space(surf.spaceNum).FloorArea;
   14696           22 :                         otherSideEnclosureNum = enclosureNum;
   14697           22 :                         int otherSideSpaceNum = state.dataSurface->Surface(surf.ExtBoundCond).spaceNum;
   14698           22 :                         if (otherSideSpaceNum != surf.spaceNum) {
   14699           20 :                             thisEnclosure.spaceNames.push_back(state.dataHeatBal->space(otherSideSpaceNum).Name);
   14700           20 :                             thisEnclosure.spaceNums.push_back(otherSideSpaceNum);
   14701           20 :                             thisEnclosure.FloorArea += state.dataHeatBal->space(otherSideSpaceNum).FloorArea;
   14702              :                         }
   14703           22 :                         if (radiantSetup) {
   14704           11 :                             state.dataHeatBal->space(surf.spaceNum).radiantEnclosureNum = thisSideEnclosureNum;
   14705           11 :                             state.dataHeatBal->space(state.dataSurface->Surface(surf.ExtBoundCond).spaceNum).radiantEnclosureNum =
   14706              :                                 otherSideEnclosureNum;
   14707              :                         } else {
   14708           11 :                             thisEnclosure.ExtWindowArea += state.dataHeatBal->space(surf.spaceNum).extWindowArea;
   14709           11 :                             thisEnclosure.TotalSurfArea += state.dataHeatBal->space(surf.spaceNum).totalSurfArea;
   14710           11 :                             if (otherSideSpaceNum != surf.spaceNum) {
   14711           10 :                                 thisEnclosure.ExtWindowArea += state.dataHeatBal->space(otherSideSpaceNum).extWindowArea;
   14712           10 :                                 thisEnclosure.TotalSurfArea += state.dataHeatBal->space(otherSideSpaceNum).totalSurfArea;
   14713              :                             }
   14714           11 :                             state.dataHeatBal->space(surf.spaceNum).solarEnclosureNum = thisSideEnclosureNum;
   14715           11 :                             state.dataHeatBal->space(state.dataSurface->Surface(surf.ExtBoundCond).spaceNum).solarEnclosureNum =
   14716              :                                 otherSideEnclosureNum;
   14717              :                         }
   14718           84 :                     } else if (thisSideEnclosureNum == 0) {
   14719              :                         // Other side is assigned, so use that one for both
   14720            0 :                         thisSideEnclosureNum = otherSideEnclosureNum;
   14721            0 :                         auto &thisEnclosure = Enclosures(thisSideEnclosureNum);
   14722            0 :                         thisEnclosure.spaceNames.push_back(state.dataHeatBal->space(surf.spaceNum).Name);
   14723            0 :                         thisEnclosure.spaceNums.push_back(surf.spaceNum);
   14724            0 :                         thisEnclosure.FloorArea += state.dataHeatBal->space(surf.spaceNum).FloorArea;
   14725            0 :                         if (radiantSetup) {
   14726            0 :                             state.dataHeatBal->space(surf.spaceNum).radiantEnclosureNum = thisSideEnclosureNum;
   14727              :                         } else {
   14728            0 :                             thisEnclosure.ExtWindowArea += state.dataHeatBal->space(surf.spaceNum).extWindowArea;
   14729            0 :                             thisEnclosure.TotalSurfArea += state.dataHeatBal->space(surf.spaceNum).totalSurfArea;
   14730            0 :                             state.dataHeatBal->space(surf.spaceNum).solarEnclosureNum = thisSideEnclosureNum;
   14731              :                         }
   14732           62 :                     } else if (otherSideEnclosureNum == 0) {
   14733              :                         // This side is assigned, so use that one for both
   14734           14 :                         otherSideEnclosureNum = thisSideEnclosureNum;
   14735           14 :                         auto &thisEnclosure = Enclosures(thisSideEnclosureNum);
   14736           14 :                         thisEnclosure.spaceNames.push_back(state.dataHeatBal->space(state.dataSurface->Surface(surf.ExtBoundCond).spaceNum).Name);
   14737           14 :                         thisEnclosure.spaceNums.push_back(state.dataSurface->Surface(surf.ExtBoundCond).spaceNum);
   14738           14 :                         thisEnclosure.FloorArea += state.dataHeatBal->space(state.dataSurface->Surface(surf.ExtBoundCond).spaceNum).FloorArea;
   14739           14 :                         if (radiantSetup) {
   14740            7 :                             state.dataHeatBal->space(state.dataSurface->Surface(surf.ExtBoundCond).spaceNum).radiantEnclosureNum =
   14741              :                                 otherSideEnclosureNum;
   14742              :                         } else {
   14743            7 :                             thisEnclosure.ExtWindowArea +=
   14744            7 :                                 state.dataHeatBal->space(state.dataSurface->Surface(surf.ExtBoundCond).spaceNum).extWindowArea;
   14745            7 :                             thisEnclosure.TotalSurfArea +=
   14746            7 :                                 state.dataHeatBal->space(state.dataSurface->Surface(surf.ExtBoundCond).spaceNum).totalSurfArea;
   14747            7 :                             state.dataHeatBal->space(state.dataSurface->Surface(surf.ExtBoundCond).spaceNum).solarEnclosureNum =
   14748              :                                 otherSideEnclosureNum;
   14749              :                         }
   14750           48 :                     } else if (thisSideEnclosureNum != otherSideEnclosureNum) {
   14751              :                         // If both sides are already assigned to an enclosure, then merge the two enclosures
   14752            4 :                         auto const &thisEnclosure = Enclosures(thisSideEnclosureNum);
   14753            4 :                         auto &otherEnclosure = Enclosures(otherSideEnclosureNum);
   14754           16 :                         for (const auto &zName : thisEnclosure.spaceNames) {
   14755           12 :                             otherEnclosure.spaceNames.push_back(zName);
   14756            4 :                         }
   14757           16 :                         for (int zNum : thisEnclosure.spaceNums) {
   14758           12 :                             otherEnclosure.spaceNums.push_back(zNum);
   14759           12 :                             if (radiantSetup) {
   14760            6 :                                 state.dataHeatBal->space(zNum).radiantEnclosureNum = otherSideEnclosureNum;
   14761              :                             } else {
   14762            6 :                                 state.dataHeatBal->space(zNum).solarEnclosureNum = otherSideEnclosureNum;
   14763              :                             }
   14764            4 :                         }
   14765            4 :                         otherEnclosure.FloorArea += thisEnclosure.FloorArea;
   14766            4 :                         otherEnclosure.ExtWindowArea += thisEnclosure.ExtWindowArea;
   14767            4 :                         otherEnclosure.TotalSurfArea += thisEnclosure.TotalSurfArea;
   14768              :                         // Move any enclosures beyond thisEnclosure down one slot - at this point all enclosures are named "Radiant
   14769              :                         // Enclosure N"
   14770            8 :                         for (int enclNum = thisSideEnclosureNum; enclNum < enclosureNum; ++enclNum) {
   14771            4 :                             std::string saveName = Enclosures(enclNum).Name;
   14772            4 :                             Enclosures(enclNum) = Enclosures(enclNum + 1);
   14773            4 :                             Enclosures(enclNum).Name = saveName;
   14774           22 :                             for (int sNum : Enclosures(enclNum).spaceNums) {
   14775           18 :                                 if (radiantSetup) {
   14776            9 :                                     state.dataHeatBal->space(sNum).radiantEnclosureNum = enclNum;
   14777              :                                 } else {
   14778            9 :                                     state.dataHeatBal->space(sNum).solarEnclosureNum = enclNum;
   14779              :                                 }
   14780            4 :                             }
   14781            4 :                         }
   14782              :                         // Clear the last rad enclosure and reduce the total number of enclosures by 1
   14783            4 :                         Enclosures(enclosureNum).Name.clear();
   14784            4 :                         Enclosures(enclosureNum).spaceNames.clear();
   14785            4 :                         Enclosures(enclosureNum).spaceNums.clear();
   14786            4 :                         Enclosures(enclosureNum).FloorArea = 0;
   14787            4 :                         Enclosures(enclosureNum).ExtWindowArea = 0;
   14788            4 :                         Enclosures(enclosureNum).TotalSurfArea = 0;
   14789            4 :                         enclosureNum -= 1;
   14790              :                     }
   14791           84 :                     if (solarSetup && constr.TypeIsAirBoundaryMixing) {
   14792              :                         // Set up mixing air boundaries only once, during solar setup
   14793            4 :                         int spaceNum1 = min(surf.spaceNum, state.dataSurface->Surface(surf.ExtBoundCond).spaceNum);
   14794            4 :                         int spaceNum2 = max(surf.spaceNum, state.dataSurface->Surface(surf.ExtBoundCond).spaceNum);
   14795              :                         // This pair already saved?
   14796            4 :                         bool found = false;
   14797            4 :                         for (auto const &thisAirBoundaryMixing : state.dataHeatBal->airBoundaryMixing) {
   14798            2 :                             if ((spaceNum1 == thisAirBoundaryMixing.space1) && (spaceNum2 == thisAirBoundaryMixing.space2)) {
   14799            2 :                                 found = true;
   14800            2 :                                 break;
   14801              :                             }
   14802            4 :                         }
   14803            4 :                         if (!found) {
   14804              :                             // Store the space pairs, schedule, and flow rate to use later to create cross mixing objects
   14805            2 :                             DataHeatBalance::AirBoundaryMixingSpecs newAirBoundaryMixing;
   14806            2 :                             newAirBoundaryMixing.space1 = spaceNum1;
   14807            2 :                             newAirBoundaryMixing.space2 = spaceNum2;
   14808            2 :                             newAirBoundaryMixing.sched = state.dataConstruction->Construct(surf.Construction).airBoundaryMixingSched;
   14809            2 :                             Real64 mixingVolume = state.dataConstruction->Construct(surf.Construction).AirBoundaryACH *
   14810            2 :                                                   min(state.dataHeatBal->space(spaceNum1).Volume, state.dataHeatBal->space(spaceNum2).Volume) /
   14811            2 :                                                   Constant::rSecsInHour;
   14812            2 :                             newAirBoundaryMixing.mixingVolumeFlowRate = mixingVolume;
   14813            2 :                             state.dataHeatBal->airBoundaryMixing.push_back(newAirBoundaryMixing);
   14814              :                         }
   14815              :                     }
   14816              :                 }
   14817              :             }
   14818           18 :             if (errorCount > 0) {
   14819            0 :                 ShowSevereError(state, format("{}: {} surfaces use Construction:AirBoundary in non-interzone surfaces.", RoutineName, errorCount));
   14820            0 :                 ShowContinueError(state, "For explicit details on each use, use Output:Diagnostics,DisplayExtraWarnings;");
   14821              :             }
   14822              :         }
   14823              :         // Check for any spaces defined only by floor surface(s) and group them
   14824         1045 :         for (auto const &zone : state.dataHeatBal->Zone) {
   14825          629 :             int newEnclosureNum = 0;
   14826         1300 :             for (int const spaceNum : zone.spaceIndexes) {
   14827          671 :                 int spaceEnclosureNum = 0;
   14828          671 :                 bool spaceHasOnlyFloors = false;
   14829          671 :                 if (radiantSetup) {
   14830          375 :                     spaceEnclosureNum = state.dataHeatBal->space(spaceNum).radiantEnclosureNum;
   14831              :                 } else {
   14832          296 :                     spaceEnclosureNum = state.dataHeatBal->space(spaceNum).solarEnclosureNum;
   14833              :                 }
   14834          671 :                 if (spaceEnclosureNum == 0) {
   14835          614 :                     spaceHasOnlyFloors = true;
   14836          697 :                     for (int const surfNum : state.dataHeatBal->space(spaceNum).surfaces) {
   14837          628 :                         if (state.dataSurface->Surface(surfNum).Class == SurfaceClass::IntMass) {
   14838            0 :                             continue;
   14839              :                         }
   14840          628 :                         if (state.dataSurface->Surface(surfNum).Class != SurfaceClass::Floor) {
   14841          545 :                             spaceHasOnlyFloors = false;
   14842          545 :                             break;
   14843              :                         }
   14844          614 :                     }
   14845              :                 }
   14846          671 :                 if (spaceEnclosureNum == 0 && spaceHasOnlyFloors) {
   14847           69 :                     anyGroupedSpaces = true;
   14848           69 :                     if (newEnclosureNum == 0) {
   14849              :                         // Assign one new enclosure for all loose floors in this zone
   14850           47 :                         ++enclosureNum;
   14851           47 :                         newEnclosureNum = enclosureNum;
   14852              :                     }
   14853           69 :                     if (radiantSetup) {
   14854           36 :                         state.dataHeatBal->space(spaceNum).radiantEnclosureNum = enclosureNum;
   14855              :                     } else {
   14856           33 :                         state.dataHeatBal->space(spaceNum).solarEnclosureNum = enclosureNum;
   14857              :                     }
   14858           69 :                     auto &thisEnclosure = Enclosures(enclosureNum);
   14859              :                     // Give this enclosure the zone name and assign this to the zone-remainder space if it exists
   14860           69 :                     thisEnclosure.Name = zone.Name;
   14861           69 :                     thisEnclosure.spaceNames.push_back(state.dataHeatBal->space(spaceNum).Name);
   14862           69 :                     thisEnclosure.spaceNums.push_back(spaceNum);
   14863           69 :                     thisEnclosure.FloorArea = state.dataHeatBal->space(spaceNum).FloorArea;
   14864           69 :                     thisEnclosure.ExtWindowArea = state.dataHeatBal->space(spaceNum).extWindowArea;
   14865           69 :                     thisEnclosure.TotalSurfArea = state.dataHeatBal->space(spaceNum).totalSurfArea;
   14866              :                 }
   14867          629 :             }
   14868          416 :         }
   14869              : 
   14870          416 :         if (anyGroupedSpaces) {
   14871              :             // All grouped spaces have been assigned to an enclosure, now assign remaining spaces
   14872          207 :             for (int spaceNum = 1; spaceNum <= state.dataGlobal->numSpaces; ++spaceNum) {
   14873          156 :                 auto &curSpace = state.dataHeatBal->space(spaceNum);
   14874          156 :                 int spaceEnclosureNum = 0;
   14875          156 :                 if (radiantSetup) {
   14876           80 :                     spaceEnclosureNum = curSpace.radiantEnclosureNum;
   14877              :                 } else {
   14878           76 :                     spaceEnclosureNum = curSpace.solarEnclosureNum;
   14879              :                 }
   14880          156 :                 if (spaceEnclosureNum == 0) {
   14881           31 :                     if (Util::SameString(curSpace.Name, state.dataHeatBal->Zone(curSpace.zoneNum).Name + "-REMAINDER")) {
   14882              :                         // Search for existing enclosure with same name as the zone
   14883            0 :                         spaceEnclosureNum = Util::FindItemInList(state.dataHeatBal->Zone(curSpace.zoneNum).Name, Enclosures);
   14884              :                     }
   14885           31 :                     if (spaceEnclosureNum == 0) {
   14886              :                         // Otherwise add a new one named for the space
   14887           31 :                         ++enclosureNum;
   14888           31 :                         spaceEnclosureNum = enclosureNum;
   14889           31 :                         Enclosures(spaceEnclosureNum).Name = curSpace.Name;
   14890              :                     }
   14891           31 :                     if (radiantSetup) {
   14892           16 :                         curSpace.radiantEnclosureNum = spaceEnclosureNum;
   14893              :                     } else {
   14894           15 :                         curSpace.solarEnclosureNum = spaceEnclosureNum;
   14895              :                     }
   14896           31 :                     auto &thisEnclosure = Enclosures(spaceEnclosureNum);
   14897           31 :                     thisEnclosure.spaceNames.push_back(curSpace.Name);
   14898           31 :                     thisEnclosure.spaceNums.push_back(spaceNum);
   14899           31 :                     thisEnclosure.FloorArea += curSpace.FloorArea;
   14900           31 :                     thisEnclosure.ExtWindowArea += curSpace.extWindowArea;
   14901           31 :                     thisEnclosure.TotalSurfArea += curSpace.totalSurfArea;
   14902              :                 }
   14903              :             }
   14904           51 :             if (radiantSetup) {
   14905           27 :                 state.dataViewFactor->NumOfRadiantEnclosures = enclosureNum;
   14906              :             } else {
   14907           24 :                 state.dataViewFactor->NumOfSolarEnclosures = enclosureNum;
   14908              :             }
   14909              :         } else {
   14910              :             // There are no grouped radiant air boundaries, assign each space to it's own radiant enclosure
   14911          880 :             for (int spaceNum = 1; spaceNum <= state.dataGlobal->numSpaces; ++spaceNum) {
   14912          515 :                 auto &thisEnclosure = Enclosures(spaceNum);
   14913          515 :                 thisEnclosure.Name = state.dataHeatBal->space(spaceNum).Name;
   14914          515 :                 thisEnclosure.spaceNames.push_back(state.dataHeatBal->space(spaceNum).Name);
   14915          515 :                 thisEnclosure.spaceNums.push_back(spaceNum);
   14916          515 :                 thisEnclosure.FloorArea = state.dataHeatBal->space(spaceNum).FloorArea;
   14917          515 :                 if (radiantSetup) {
   14918          295 :                     state.dataHeatBal->space(spaceNum).radiantEnclosureNum = spaceNum;
   14919              :                 } else {
   14920          220 :                     state.dataHeatBal->space(spaceNum).solarEnclosureNum = spaceNum;
   14921          220 :                     thisEnclosure.ExtWindowArea = state.dataHeatBal->space(spaceNum).extWindowArea;
   14922          220 :                     thisEnclosure.TotalSurfArea = state.dataHeatBal->space(spaceNum).totalSurfArea;
   14923              :                 }
   14924              :             }
   14925          365 :             if (radiantSetup) {
   14926          197 :                 state.dataViewFactor->NumOfRadiantEnclosures = state.dataGlobal->numSpaces;
   14927              :             } else {
   14928          168 :                 state.dataViewFactor->NumOfSolarEnclosures = state.dataGlobal->numSpaces;
   14929              :             }
   14930              :         }
   14931          416 :         if (radiantSetup) {
   14932          224 :             assert(state.dataViewFactor->NumOfRadiantEnclosures <= int(Enclosures.size()));
   14933          224 :             Enclosures.resize(state.dataViewFactor->NumOfRadiantEnclosures);
   14934              :         } else {
   14935          192 :             assert(state.dataViewFactor->NumOfSolarEnclosures <= int(Enclosures.size()));
   14936          192 :             Enclosures.resize(state.dataViewFactor->NumOfSolarEnclosures);
   14937              :         }
   14938              : 
   14939         1027 :         for (auto &thisEnclosure : state.dataViewFactor->EnclRadInfo) {
   14940         1222 :             SetupOutputVariable(state,
   14941              :                                 "Enclosure Mean Radiant Temperature",
   14942              :                                 Constant::Units::C,
   14943          611 :                                 thisEnclosure.MRT,
   14944              :                                 OutputProcessor::TimeStepType::Zone,
   14945              :                                 OutputProcessor::StoreType::Average,
   14946          611 :                                 thisEnclosure.Name);
   14947          416 :         }
   14948              : 
   14949              :         // TODO MJW: For now, set the max and min enclosure numbers for each zone to be used in CalcInteriorRadExchange with ZoneToResimulate
   14950         1045 :         for (int zoneNum = 1; zoneNum <= state.dataGlobal->NumOfZones; ++zoneNum) {
   14951         1300 :             for (int spaceNum : state.dataHeatBal->Zone(zoneNum).spaceIndexes) {
   14952          671 :                 if (state.dataHeatBal->Zone(zoneNum).zoneRadEnclosureFirst == -1) { // initial value
   14953          354 :                     state.dataHeatBal->Zone(zoneNum).zoneRadEnclosureFirst = state.dataHeatBal->space(spaceNum).radiantEnclosureNum;
   14954              :                 } else {
   14955          317 :                     state.dataHeatBal->Zone(zoneNum).zoneRadEnclosureFirst =
   14956          317 :                         min(state.dataHeatBal->Zone(zoneNum).zoneRadEnclosureFirst, state.dataHeatBal->space(spaceNum).radiantEnclosureNum);
   14957              :                 }
   14958          671 :                 state.dataHeatBal->Zone(zoneNum).zoneRadEnclosureLast =
   14959          671 :                     max(state.dataHeatBal->Zone(zoneNum).zoneRadEnclosureLast, state.dataHeatBal->space(spaceNum).radiantEnclosureNum);
   14960          629 :             }
   14961          629 :             assert(state.dataHeatBal->Zone(zoneNum).zoneRadEnclosureFirst != -1);
   14962          629 :             assert(state.dataHeatBal->Zone(zoneNum).zoneRadEnclosureLast != -1);
   14963          629 :             assert(state.dataHeatBal->Zone(zoneNum).zoneRadEnclosureFirst <= state.dataHeatBal->Zone(zoneNum).zoneRadEnclosureLast);
   14964              :         }
   14965          416 :     }
   14966              : 
   14967         2201 :     void CheckConvexity(EnergyPlusData &state,
   14968              :                         int const SurfNum, // Current surface number
   14969              :                         int const NSides   // Number of sides to figure
   14970              :     )
   14971              :     {
   14972              :         // SUBROUTINE INFORMATION:
   14973              :         //       AUTHOR         Tyler Hoyt
   14974              :         //       DATE WRITTEN   December 2010
   14975              :         //       MODIFIED       CR8752 - incorrect note of non-convex polygons
   14976              : 
   14977              :         // PURPOSE OF THIS SUBROUTINE: This subroutine verifies the convexity of a
   14978              :         // surface that is exposed to the sun in the case that full shading calculations
   14979              :         // are required. The calculation conveniently detects collinear points as well,
   14980              :         // and returns a list of indices that are collinear within the plane of the surface.
   14981              : 
   14982              :         // METHODOLOGY EMPLOYED: First the surface is determined to have dimension 2 in
   14983              :         // either the xy, yz, or xz plane. That plane is selected to do the testing.
   14984              :         // Vectors representing the edges of the polygon and the perpendicular dot product
   14985              :         // between adjacent edges are computed. This allows the turning angle to be determined.
   14986              :         // If the turning angle is greater than pi/2, it turns to the right, and if it is
   14987              :         // less than pi/2, it turns left. The direction of the turn is stored, and if it
   14988              :         // changes as the edges are iterated the surface is not convex. Meanwhile it stores
   14989              :         // the indices of vertices that are collinear and are later removed.
   14990              : 
   14991              :         // REFERENCES:
   14992              :         // http://mathworld.wolfram.com/ConvexPolygon.html
   14993              : 
   14994         2201 :         constexpr Real64 TurnThreshold = 0.000001; // Sensitivity of convexity test, in radians
   14995              : 
   14996         2201 :         Real64 LastTheta = 0.0;                 // Angle between edge vectors
   14997              :         bool SignFlag;                          // Direction of edge turn : true is right, false is left
   14998         2201 :         bool PrevSignFlag(false);               // Container for the sign of the previous iteration's edge turn
   14999         2201 :         bool PrevSignFlagInitialized(false);    // Whether we picked a PrevSignFlag already or not
   15000         2201 :         auto &X = state.dataSurfaceGeometry->X; // containers for x,y,z vertices of the surface
   15001         2201 :         auto &Y = state.dataSurfaceGeometry->Y;
   15002         2201 :         auto &Z = state.dataSurfaceGeometry->Z;
   15003         2201 :         auto &A = state.dataSurfaceGeometry->A; // containers for convexity test
   15004         2201 :         auto &B = state.dataSurfaceGeometry->B;
   15005         2201 :         auto &VertSize = state.dataSurfaceGeometry->VertSize; // size of X,Y,Z,A,B arrays
   15006              : 
   15007         2201 :         std::vector<int> surfCollinearVerts; // index of vertices to remove, 1-indexed
   15008         2201 :         surfCollinearVerts.reserve(NSides + 2);
   15009              : 
   15010         2201 :         if (state.dataSurfaceGeometry->CheckConvexityFirstTime) {
   15011          225 :             X.allocate(state.dataSurface->MaxVerticesPerSurface + 2);
   15012          225 :             Y.allocate(state.dataSurface->MaxVerticesPerSurface + 2);
   15013          225 :             Z.allocate(state.dataSurface->MaxVerticesPerSurface + 2);
   15014          225 :             A.allocate(state.dataSurface->MaxVerticesPerSurface + 2);
   15015          225 :             B.allocate(state.dataSurface->MaxVerticesPerSurface + 2);
   15016          225 :             VertSize = state.dataSurface->MaxVerticesPerSurface;
   15017          225 :             state.dataSurfaceGeometry->CheckConvexityFirstTime = false;
   15018              :         }
   15019              : 
   15020         2201 :         if (NSides > VertSize) {
   15021            7 :             X.deallocate();
   15022            7 :             Y.deallocate();
   15023            7 :             Z.deallocate();
   15024            7 :             A.deallocate();
   15025            7 :             B.deallocate();
   15026            7 :             X.allocate(state.dataSurface->MaxVerticesPerSurface + 2);
   15027            7 :             Y.allocate(state.dataSurface->MaxVerticesPerSurface + 2);
   15028            7 :             Z.allocate(state.dataSurface->MaxVerticesPerSurface + 2);
   15029            7 :             A.allocate(state.dataSurface->MaxVerticesPerSurface + 2);
   15030            7 :             B.allocate(state.dataSurface->MaxVerticesPerSurface + 2);
   15031            7 :             VertSize = state.dataSurface->MaxVerticesPerSurface;
   15032              :         }
   15033              : 
   15034         2201 :         auto &surfaceTmp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
   15035         2201 :         auto &vertices = surfaceTmp.Vertex;
   15036              : 
   15037        11069 :         for (int n = 1; n <= NSides; ++n) {
   15038         8868 :             X(n) = vertices(n).x;
   15039         8868 :             Y(n) = vertices(n).y;
   15040         8868 :             Z(n) = vertices(n).z;
   15041              :         }
   15042         2201 :         X(NSides + 1) = vertices(1).x;
   15043         2201 :         Y(NSides + 1) = vertices(1).y;
   15044         2201 :         Z(NSides + 1) = vertices(1).z;
   15045         2201 :         X(NSides + 2) = vertices(2).x;
   15046         2201 :         Y(NSides + 2) = vertices(2).y;
   15047         2201 :         Z(NSides + 2) = vertices(2).z;
   15048              : 
   15049              :         // Determine a suitable plane in which to do the tests
   15050         2201 :         Real64 Det = 0.0;
   15051        11069 :         for (int n = 1; n <= NSides; ++n) {
   15052         8868 :             Det += X(n) * Y(n + 1) - X(n + 1) * Y(n);
   15053              :         }
   15054         2201 :         if (std::abs(Det) > Constant::SmallDistance) {
   15055          850 :             A = X;
   15056          850 :             B = Y;
   15057              :         } else {
   15058         1351 :             Det = 0.0;
   15059         6755 :             for (int n = 1; n <= NSides; ++n) {
   15060         5404 :                 Det += X(n) * Z(n + 1) - X(n + 1) * Z(n);
   15061              :             }
   15062         1351 :             if (std::abs(Det) > Constant::SmallDistance) {
   15063          848 :                 A = X;
   15064          848 :                 B = Z;
   15065              :             } else {
   15066          503 :                 Det = 0.0;
   15067         2514 :                 for (int n = 1; n <= NSides; ++n) {
   15068         2011 :                     Det += Y(n) * Z(n + 1) - Y(n + 1) * Z(n);
   15069              :                 }
   15070          503 :                 if (std::abs(Det) > Constant::SmallDistance) {
   15071          502 :                     A = Y;
   15072          502 :                     B = Z;
   15073              :                 } else {
   15074              :                     // This condition should not be reached if the surfaces are guaranteed to be planar already
   15075            1 :                     ShowSevereError(state, format("CheckConvexity: Surface=\"{}\" is non-planar.", surfaceTmp.Name));
   15076            2 :                     ShowContinueError(state, "Coincident Vertices will be removed as possible.");
   15077            4 :                     for (int n = 1; n <= surfaceTmp.Sides; ++n) {
   15078            3 :                         auto const &point = vertices(n);
   15079              :                         static constexpr std::string_view ErrFmt = " ({:8.3F},{:8.3F},{:8.3F})";
   15080            3 :                         ShowContinueError(state, format(ErrFmt, point.x, point.y, point.z));
   15081              :                     }
   15082              :                 }
   15083              :             }
   15084              :         }
   15085              : 
   15086        11069 :         for (int n = 1; n <= NSides; ++n) { // perform convexity test in the plane determined above.
   15087              : 
   15088         8868 :             DataVectorTypes::Vector_2d pt0(A(n), B(n));
   15089         8868 :             DataVectorTypes::Vector_2d pt1(A(n + 1), B(n + 1));
   15090         8868 :             DataVectorTypes::Vector_2d pt2(A(n + 2), B(n + 2));
   15091              : 
   15092         8868 :             DataVectorTypes::Vector_2d V1 = pt1 - pt0;
   15093         8868 :             DataVectorTypes::Vector_2d V2 = pt2 - pt1;
   15094              : 
   15095         8868 :             Real64 V1len = V1.length(); // = norm_L2()
   15096         8868 :             Real64 V2len = V2.length();
   15097         8868 :             if (V1len <= 1.e-8 || V2len <= 1.e-8) {
   15098              :                 // At least two points are coincident. Should this happen? GetVertices is supposed to pop these vertices
   15099            0 :                 continue;
   15100              :             }
   15101         8868 :             Real64 CrossProd = V1.cross(V2);
   15102         8868 :             Real64 sinarg = CrossProd / (V1len * V2len);
   15103         8868 :             if (sinarg < -1.0) {
   15104           16 :                 sinarg = -1.0;
   15105         8852 :             } else if (sinarg > 1.0) {
   15106           12 :                 sinarg = 1.0;
   15107              :             }
   15108         8868 :             Real64 Theta = std::asin(sinarg);
   15109         8868 :             if (Theta > TurnThreshold) {
   15110         4526 :                 SignFlag = true;
   15111         4342 :             } else if (Theta < -TurnThreshold) {
   15112         4318 :                 SignFlag = false;
   15113              :             } else { // std::abs(Theta) < TurnThreshold
   15114              :                 // Store the index of the collinear vertex for removal
   15115           24 :                 int colinearIndex = n + 1;
   15116           24 :                 if (colinearIndex > NSides) {
   15117            2 :                     colinearIndex -= NSides;
   15118              :                 }
   15119           24 :                 if (state.dataGlobal->DisplayExtraWarnings) {
   15120            0 :                     ShowWarningError(
   15121              :                         state,
   15122            0 :                         format("CheckConvexity: Surface=\"{}\", vertex {} is colinear with previous and next.", surfaceTmp.Name, colinearIndex));
   15123              :                 }
   15124           24 :                 ++state.dataErrTracking->TotalCoincidentVertices;
   15125           24 :                 surfCollinearVerts.push_back(colinearIndex);
   15126           24 :                 continue;
   15127           24 :             }
   15128              : 
   15129         8844 :             if (!PrevSignFlagInitialized) {
   15130         2201 :                 PrevSignFlag = SignFlag;
   15131         2201 :                 LastTheta = Theta;
   15132         2201 :                 PrevSignFlagInitialized = true;
   15133         2201 :                 continue;
   15134              :             }
   15135              : 
   15136         6643 :             if (SignFlag != PrevSignFlag) {
   15137           37 :                 if (state.dataGlobal->DisplayExtraWarnings && surfaceTmp.ExtSolar &&
   15138            0 :                     (state.dataHeatBal->SolarDistribution != DataHeatBalance::Shadowing::Minimal) && surfaceTmp.IsConvex &&
   15139           37 :                     !state.dataSysVars->SutherlandHodgman &&
   15140            0 :                     (state.dataSysVars->shadingMethod == DataSystemVariables::ShadingMethod::PolygonClipping)) {
   15141            0 :                     ShowWarningError(state,
   15142            0 :                                      format("CheckConvexity: Zone=\"{}\", Surface=\"{}\" is non-convex.",
   15143            0 :                                             state.dataHeatBal->Zone(surfaceTmp.Zone).Name,
   15144            0 :                                             surfaceTmp.Name));
   15145            0 :                     int Np1 = n + 1;
   15146            0 :                     if (Np1 > NSides) {
   15147            0 :                         Np1 -= NSides;
   15148              :                     }
   15149            0 :                     int Np2 = n + 2;
   15150            0 :                     if (Np2 > NSides) {
   15151            0 :                         Np2 -= NSides;
   15152              :                     }
   15153            0 :                     ShowContinueError(state, format("...vertex {} to vertex {} to vertex {}", n, Np1, Np2));
   15154            0 :                     ShowContinueError(state, format("...vertex {}=[{:.2R},{:.2R},{:.2R}]", n, X(n), Y(n), Z(n)));
   15155            0 :                     ShowContinueError(state, format("...vertex {}=[{:.2R},{:.2R},{:.2R}]", Np1, X(n + 1), Y(n + 1), Z(n + 1)));
   15156            0 :                     ShowContinueError(state, format("...vertex {}=[{:.2R},{:.2R},{:.2R}]", Np2, X(n + 2), Y(n + 2), Z(n + 2)));
   15157              :                     // ShowContinueError(state, format("...theta angle=[{:.6R}]", Theta));
   15158              :                     // ShowContinueError(state, format("...last theta angle=[{:.6R}]", LastTheta));
   15159              :                 }
   15160           34 :                 surfaceTmp.IsConvex = false;
   15161              :                 // #10103 - We do not want to break early, because we do want to consistently remove colinear vertices
   15162              :                 // to avoid potential vertex size mismatch fatal errors
   15163              :                 // break;
   15164              :             }
   15165         6643 :             PrevSignFlag = SignFlag;
   15166         6643 :             LastTheta = Theta;
   15167        17768 :         }
   15168              : 
   15169              :         // must check to make sure don't remove NSides below 3
   15170         2201 :         int M = surfCollinearVerts.size();
   15171         2201 :         if (M > 0) { // Remove the collinear points determined above
   15172            6 :             if (NSides - M >= 3) {
   15173            6 :                 surfaceTmp.Sides = NSides - M;
   15174            6 :                 if (state.dataGlobal->DisplayExtraWarnings) {
   15175            0 :                     ShowWarningError(state,
   15176            0 :                                      format("CheckConvexity: Surface=\"{}\" has [{}] collinear points that have been removed.", surfaceTmp.Name, M));
   15177              :                 }
   15178              :             } else { // too many
   15179            0 :                 if (state.dataGlobal->DisplayExtraWarnings) {
   15180            0 :                     ShowWarningError(state, format("CheckConvexity: Surface=\"{}\" has [{}] collinear points.", surfaceTmp.Name, M));
   15181            0 :                     ShowContinueError(state, "...too many to remove all.  Will leave the surface with 3 sides. But this is now a degenerate surface");
   15182              :                 }
   15183            0 :                 ++state.dataErrTracking->TotalDegenerateSurfaces;
   15184            0 :                 surfaceTmp.Sides = 3; // max(NSides - M, 3) = 3 since NSide - M is < 3;
   15185            0 :                 surfCollinearVerts.resize(NSides - 3);
   15186              :             }
   15187              : 
   15188              :             // remove duplicated points: For that we construct a new array of vertices, only copying indices that aren't in SurfCollinearVerts
   15189              :             // Then we move that array into the original one
   15190            6 :             Array1D<Vector> newVertices;
   15191            6 :             newVertices.allocate(surfaceTmp.Sides);
   15192              : 
   15193            6 :             int n = 0;
   15194           58 :             for (int i = 1; i <= NSides; ++i) {
   15195           52 :                 if (std::find(surfCollinearVerts.cbegin(), surfCollinearVerts.cend(), i) == surfCollinearVerts.cend()) {
   15196           28 :                     newVertices(++n) = vertices(i);
   15197              :                 }
   15198              :             }
   15199            6 :             vertices = std::move(newVertices);
   15200              : 
   15201            6 :             if (state.dataGlobal->DisplayExtraWarnings) {
   15202            0 :                 ShowWarningError(state,
   15203            0 :                                  format("CheckConvexity: Surface=\"{}\": The vertex points has been reprocessed as Sides = {}",
   15204            0 :                                         surfaceTmp.Name,
   15205            0 :                                         surfaceTmp.Sides));
   15206              :             }
   15207            6 :         }
   15208         2201 :     }
   15209              : 
   15210         1662 :     bool isRectangle(EnergyPlusData &state, int const ThisSurf // Surface number
   15211              :     )
   15212              :     {
   15213              :         // SUBROUTINE INFORMATION:
   15214              :         //       AUTHOR         M.J. Witte
   15215              :         //       DATE WRITTEN   October 2015
   15216              : 
   15217              :         // PURPOSE: Check if a 4-sided surface is a rectangle
   15218              : 
   15219              :         Real64 Diagonal1;                                            // Length of diagonal of 4-sided figure from vertex 1 to vertex 3 (m)
   15220              :         Real64 Diagonal2;                                            // Length of diagonal of 4-sided figure from vertex 2 to vertex 4 (m)
   15221              :         Real64 DotProd;                                              // Dot product of two adjacent sides - to test for right angle
   15222         1662 :         Real64 const cos89deg = std::cos(89.0 * Constant::DegToRad); // tolerance for right angle
   15223         1662 :         Vector Vect32;                                               // normalized vector from vertex 3 to vertex 2
   15224         1662 :         Vector Vect21;                                               // normalized vector from vertex 2 to vertex 1
   15225              : 
   15226         1662 :         auto &surf = state.dataSurface->Surface(ThisSurf);
   15227         1662 :         Diagonal1 = Vectors::VecLength(surf.Vertex(1) - surf.Vertex(3));
   15228         1662 :         Diagonal2 = Vectors::VecLength(surf.Vertex(2) - surf.Vertex(4));
   15229              :         // Test for rectangularity
   15230         1662 :         if (std::abs(Diagonal1 - Diagonal2) < 0.020) { // This tolerance based on coincident vertex tolerance of 0.01
   15231         1613 :             Vect32 = Vectors::VecNormalize(surf.Vertex(3) - surf.Vertex(2));
   15232         1613 :             Vect21 = Vectors::VecNormalize(surf.Vertex(2) - surf.Vertex(1));
   15233         1613 :             DotProd = dot(Vect32, Vect21);
   15234         1613 :             if (std::abs(DotProd) <= cos89deg) {
   15235         1531 :                 return true;
   15236              :             } else {
   15237           82 :                 return false;
   15238              :             }
   15239              :         } else {
   15240           49 :             return false;
   15241              :         }
   15242         1662 :     }
   15243              : 
   15244            6 :     void MakeEquivalentRectangle(EnergyPlusData &state,
   15245              :                                  int const SurfNum, // Surface number
   15246              :                                  bool &ErrorsFound  // Error flag indicator (true if errors found)
   15247              :     )
   15248              :     {
   15249              :         // SUBROUTINE INFORMATION:
   15250              :         //       AUTHOR         R. Zhang, LBNL
   15251              :         //       DATE WRITTEN   September 2016
   15252              : 
   15253              :         // PURPOSE OF THIS SUBROUTINE:
   15254              :         // Processing of 4-sided but non-rectangular Window, Door or GlassDoor.
   15255              :         // Calculate the effective height and width of the surface.
   15256              :         //
   15257              :         // METHODOLOGY EMPLOYED:
   15258              :         // Transform the surface into an equivalent rectangular surface with the same area and aspect ratio.
   15259              : 
   15260              :         Real64 AspectRatio; // Aspect ratio
   15261              :         Real64 WidthEff;    // Effective width of the surface
   15262              :         Real64 WidthMax;    // X difference between the vertex on the most left and the one on the most right
   15263              :         Real64 HeightEff;   // Effective height of the surface
   15264              :         Real64 HeightMax;   // Y difference between the lowest and highest vertices
   15265              :         Real64 Xp;
   15266              :         Real64 Yp;
   15267              :         Real64 Zp;
   15268              :         Real64 XLLC;
   15269              :         Real64 YLLC;
   15270              :         Real64 ZLLC;
   15271              : 
   15272            6 :         if (SurfNum == 0) {
   15273              :             // invalid surface
   15274            0 :             ErrorsFound = true;
   15275            0 :             return;
   15276              :         }
   15277              : 
   15278            6 :         auto &surf = state.dataSurface->Surface(SurfNum);
   15279            6 :         if (surf.Sides != 4) {
   15280              :             // the method is designed for 4-sided surface
   15281            0 :             return;
   15282            6 :         } else if (isRectangle(state, SurfNum)) {
   15283              :             // no need to transform
   15284            1 :             return;
   15285              :         }
   15286              : 
   15287            5 :         Real64 SurfWorldAz = surf.Azimuth;
   15288            5 :         Real64 SurfTilt = surf.Tilt;
   15289            5 :         Real64 BaseCosAzimuth = std::cos(SurfWorldAz * Constant::DegToRad);
   15290            5 :         Real64 BaseSinAzimuth = std::sin(SurfWorldAz * Constant::DegToRad);
   15291            5 :         Real64 BaseCosTilt = std::cos(SurfTilt * Constant::DegToRad);
   15292            5 :         Real64 BaseSinTilt = std::sin(SurfTilt * Constant::DegToRad);
   15293            5 :         int NumSurfSides = surf.Sides;
   15294              : 
   15295              :         // Calculate WidthMax and HeightMax
   15296            5 :         WidthMax = 0.0;
   15297            5 :         HeightMax = 0.0;
   15298           20 :         for (int i = 1; i < NumSurfSides; ++i) {
   15299           45 :             for (int j = i + 1; j <= NumSurfSides; ++j) {
   15300              : 
   15301           30 :                 Xp = surf.Vertex(j).x - surf.Vertex(i).x;
   15302           30 :                 Yp = surf.Vertex(j).y - surf.Vertex(i).y;
   15303           30 :                 Zp = surf.Vertex(j).z - surf.Vertex(i).z;
   15304              : 
   15305           30 :                 XLLC = -Xp * BaseCosAzimuth + Yp * BaseSinAzimuth;
   15306           30 :                 YLLC = -Xp * BaseSinAzimuth * BaseCosTilt - Yp * BaseCosAzimuth * BaseCosTilt + Zp * BaseSinTilt;
   15307           30 :                 ZLLC = Xp * BaseSinAzimuth * BaseSinTilt + Yp * BaseCosAzimuth * BaseSinTilt + Zp * BaseCosTilt;
   15308              : 
   15309           30 :                 if (std::abs(XLLC) > WidthMax) {
   15310           10 :                     WidthMax = std::abs(XLLC);
   15311              :                 }
   15312           30 :                 if (std::abs(YLLC) > WidthMax) {
   15313            2 :                     HeightMax = std::abs(YLLC);
   15314              :                 }
   15315              :             }
   15316              :         }
   15317              : 
   15318              :         // Perform transformation by calculating WidthEff and HeightEff
   15319            5 :         if ((WidthMax > 0) && (HeightMax > 0)) {
   15320            2 :             AspectRatio = WidthMax / HeightMax;
   15321              :         } else {
   15322            3 :             AspectRatio = 1;
   15323              :         }
   15324            5 :         WidthEff = std::sqrt(surf.Area * AspectRatio);
   15325            5 :         HeightEff = std::sqrt(surf.Area / AspectRatio);
   15326              : 
   15327              :         // Assign the effective width and length to the surface
   15328            5 :         surf.Width = WidthEff;
   15329            5 :         surf.Height = HeightEff;
   15330              :     }
   15331              : 
   15332          201 :     void CheckForReversedLayers(EnergyPlusData &state,
   15333              :                                 bool &RevLayerDiffs,    // true when differences are discovered in interzone constructions
   15334              :                                 int const ConstrNum,    // construction index
   15335              :                                 int const ConstrNumRev, // construction index for reversed construction
   15336              :                                 int const TotalLayers   // total layers for construction definition
   15337              :     )
   15338              :     {
   15339          201 :         auto &s_mat = state.dataMaterial;
   15340          201 :         RevLayerDiffs = false;
   15341              : 
   15342          625 :         for (int LayerNo = 1; LayerNo <= TotalLayers; ++LayerNo) {
   15343              : 
   15344          427 :             int thisConstLayer = state.dataConstruction->Construct(ConstrNum).LayerPoint(LayerNo);
   15345          427 :             int revConstLayer = state.dataConstruction->Construct(ConstrNumRev).LayerPoint(TotalLayers - LayerNo + 1);
   15346          427 :             if (thisConstLayer == revConstLayer) {
   15347          421 :                 continue;
   15348              :             }
   15349              : 
   15350            6 :             auto const *mat = s_mat->materials(thisConstLayer);
   15351            6 :             auto const *matRev = s_mat->materials(revConstLayer);
   15352              : 
   15353              :             // If not point to the same layer, check to see if this is window glass which might need to have
   15354              :             // front and back material properties reversed.
   15355            6 :             Real64 constexpr SmallDiff = 0.0001;
   15356            6 :             if ((mat->group == Material::Group::Glass) && (matRev->group == Material::Group::Glass)) {
   15357            3 :                 auto const *matGlass = dynamic_cast<Material::MaterialGlass const *>(mat);
   15358            3 :                 auto const *matGlassRev = dynamic_cast<Material::MaterialGlass const *>(matRev);
   15359            3 :                 assert(matGlass != nullptr);
   15360            3 :                 assert(matGlassRev != nullptr);
   15361              : 
   15362              :                 // Both layers are window glass, so need to check to see if the properties are reversed
   15363            6 :                 if ((abs(matGlass->Thickness - matGlassRev->Thickness) > SmallDiff) ||
   15364            6 :                     (abs(matGlass->ReflectSolBeamBack - matGlassRev->ReflectSolBeamFront) > SmallDiff) ||
   15365            6 :                     (abs(matGlass->ReflectSolBeamFront - matGlassRev->ReflectSolBeamBack) > SmallDiff) ||
   15366            6 :                     (abs(matGlass->TransVis - matGlassRev->TransVis) > SmallDiff) ||
   15367            5 :                     (abs(matGlass->ReflectVisBeamBack - matGlassRev->ReflectVisBeamFront) > SmallDiff) ||
   15368            4 :                     (abs(matGlass->ReflectVisBeamFront - matGlassRev->ReflectVisBeamBack) > SmallDiff) ||
   15369            4 :                     (abs(matGlass->TransThermal - matGlassRev->TransThermal) > SmallDiff) ||
   15370            4 :                     (abs(matGlass->AbsorpThermalBack - matGlassRev->AbsorpThermalFront) > SmallDiff) ||
   15371            4 :                     (abs(matGlass->AbsorpThermalFront - matGlassRev->AbsorpThermalBack) > SmallDiff) ||
   15372            4 :                     (abs(matGlass->Conductivity - matGlassRev->Conductivity) > SmallDiff) ||
   15373            2 :                     (abs(matGlass->GlassTransDirtFactor - matGlassRev->GlassTransDirtFactor) > SmallDiff) ||
   15374            4 :                     (matGlass->SolarDiffusing != matGlassRev->SolarDiffusing) ||
   15375            8 :                     (abs(matGlass->YoungModulus - matGlassRev->YoungModulus) > SmallDiff) ||
   15376            2 :                     (abs(matGlass->PoissonsRatio - matGlassRev->PoissonsRatio) > SmallDiff)) {
   15377            1 :                     RevLayerDiffs = true;
   15378            1 :                     break; // exit when diff
   15379              :                 } // If none of the above conditions is met, then these should be the same layers in reverse (RevLayersDiffs = false)
   15380            5 :             } else if ((mat->group == Material::Group::GlassEQL) && (matRev->group == Material::Group::GlassEQL)) {
   15381            2 :                 auto const *matGlass = dynamic_cast<Material::MaterialGlassEQL const *>(mat);
   15382            2 :                 auto const *matGlassRev = dynamic_cast<Material::MaterialGlassEQL const *>(matRev);
   15383              : 
   15384            4 :                 if ((abs(matGlass->TAR.Sol.Bk.Bm[0].BmTra - matGlassRev->TAR.Sol.Ft.Bm[0].BmTra) > SmallDiff) ||
   15385            4 :                     (abs(matGlass->TAR.Sol.Ft.Bm[0].BmTra - matGlassRev->TAR.Sol.Bk.Bm[0].BmTra) > SmallDiff) ||
   15386            4 :                     (abs(matGlass->TAR.Sol.Bk.Bm[0].BmRef - matGlassRev->TAR.Sol.Ft.Bm[0].BmRef) > SmallDiff) ||
   15387            4 :                     (abs(matGlass->TAR.Sol.Ft.Bm[0].BmRef - matGlassRev->TAR.Sol.Bk.Bm[0].BmRef) > SmallDiff) ||
   15388            4 :                     (abs(matGlass->TAR.Vis.Bk.Bm[0].BmTra - matGlassRev->TAR.Vis.Ft.Bm[0].BmTra) > SmallDiff) ||
   15389            4 :                     (abs(matGlass->TAR.Vis.Ft.Bm[0].BmTra - matGlassRev->TAR.Vis.Bk.Bm[0].BmTra) > SmallDiff) ||
   15390            4 :                     (abs(matGlass->TAR.Vis.Bk.Bm[0].BmRef - matGlassRev->TAR.Vis.Ft.Bm[0].BmRef) > SmallDiff) ||
   15391            4 :                     (abs(matGlass->TAR.Vis.Ft.Bm[0].BmRef - matGlassRev->TAR.Vis.Bk.Bm[0].BmRef) > SmallDiff) ||
   15392            4 :                     (abs(matGlass->TAR.Sol.Bk.Bm[0].DfTra - matGlassRev->TAR.Sol.Ft.Bm[0].DfTra) > SmallDiff) ||
   15393            4 :                     (abs(matGlass->TAR.Sol.Ft.Bm[0].DfTra - matGlassRev->TAR.Sol.Bk.Bm[0].DfTra) > SmallDiff) ||
   15394            4 :                     (abs(matGlass->TAR.Sol.Bk.Bm[0].DfRef - matGlassRev->TAR.Sol.Ft.Bm[0].DfRef) > SmallDiff) ||
   15395            4 :                     (abs(matGlass->TAR.Sol.Ft.Bm[0].DfRef - matGlassRev->TAR.Sol.Bk.Bm[0].DfRef) > SmallDiff) ||
   15396            4 :                     (abs(matGlass->TAR.Vis.Bk.Bm[0].DfTra - matGlassRev->TAR.Vis.Ft.Bm[0].DfTra) > SmallDiff) ||
   15397            4 :                     (abs(matGlass->TAR.Vis.Ft.Bm[0].DfTra - matGlassRev->TAR.Vis.Bk.Bm[0].DfTra) > SmallDiff) ||
   15398            4 :                     (abs(matGlass->TAR.Vis.Bk.Bm[0].DfRef - matGlassRev->TAR.Vis.Ft.Bm[0].DfRef) > SmallDiff) ||
   15399            4 :                     (abs(matGlass->TAR.Vis.Ft.Bm[0].DfRef - matGlassRev->TAR.Vis.Bk.Bm[0].DfRef) > SmallDiff) ||
   15400            4 :                     (abs(matGlass->TAR.Sol.Ft.Df.Tra - matGlassRev->TAR.Sol.Ft.Df.Tra) > SmallDiff) ||
   15401            4 :                     (abs(matGlass->TAR.Sol.Bk.Df.Ref - matGlassRev->TAR.Sol.Ft.Df.Ref) > SmallDiff) ||
   15402            4 :                     (abs(matGlass->TAR.Sol.Ft.Df.Ref - matGlassRev->TAR.Sol.Bk.Df.Ref) > SmallDiff) ||
   15403            4 :                     (abs(matGlass->TAR.Vis.Ft.Df.Tra - matGlassRev->TAR.Vis.Ft.Df.Tra) > SmallDiff) ||
   15404            4 :                     (abs(matGlass->TAR.Vis.Bk.Df.Ref - matGlassRev->TAR.Vis.Ft.Df.Ref) > SmallDiff) ||
   15405            4 :                     (abs(matGlass->TAR.Vis.Ft.Df.Ref - matGlassRev->TAR.Vis.Bk.Df.Ref) > SmallDiff) ||
   15406            4 :                     (abs(matGlass->TAR.IR.Ft.Tra - matGlassRev->TAR.IR.Ft.Tra) > SmallDiff) ||
   15407            3 :                     (abs(matGlass->TAR.IR.Bk.Emi - matGlassRev->TAR.IR.Ft.Emi) > SmallDiff) ||
   15408            5 :                     (abs(matGlass->TAR.IR.Ft.Emi - matGlassRev->TAR.IR.Bk.Emi) > SmallDiff) ||
   15409            1 :                     (abs(matGlass->Resistance - matGlassRev->Resistance) > SmallDiff)) {
   15410            1 :                     RevLayerDiffs = true;
   15411            1 :                     break; // exit when diff
   15412              :                 } // If none of the above conditions is met, then these should be the same layers in reverse (RevLayersDiffs = false)
   15413              : 
   15414            1 :             } else {
   15415              :                 // Other material types do not have reversed constructions so if they are not the same layer there is a problem
   15416              :                 // (RevLayersDiffs = true)
   15417            1 :                 RevLayerDiffs = true;
   15418            1 :                 break; // exit when diff
   15419              :             } // End check of whether or not these are WindowGlass
   15420              :         }
   15421          201 :     }
   15422              : 
   15423          134 :     void GetGeoSummaryRoof(EnergyPlusData const &state, GeoSummary &geoSummaryRoof)
   15424              :     {
   15425          134 :         std::vector<Vector> uniqueRoofVertices;
   15426          134 :         std::vector<SurfaceGeometry::EdgeOfSurf> uniqEdgeOfSurfs; // I'm only partially using this
   15427          988 :         for (const auto &surface : state.dataSurface->Surface) {
   15428              : 
   15429          854 :             if (surface.ExtBoundCond != DataSurfaces::ExternalEnvironment) {
   15430          263 :                 continue;
   15431              :             }
   15432          591 :             if (!surface.HeatTransSurf) {
   15433           20 :                 continue;
   15434              :             }
   15435              : 
   15436          571 :             if (surface.Tilt > 45.0) { // TODO Double check tilt wrt outside vs inside?
   15437          448 :                 continue;
   15438              :             }
   15439              : 
   15440          123 :             Real64 const z_min(minval(surface.Vertex, &Vector::z));
   15441          123 :             Real64 const z_max(maxval(surface.Vertex, &Vector::z));
   15442          123 :             Real64 const verticalHeight = z_max - z_min;
   15443          123 :             geoSummaryRoof.Height += verticalHeight * surface.Area;
   15444          123 :             geoSummaryRoof.Tilt += surface.Tilt * surface.Area;
   15445          123 :             geoSummaryRoof.Azimuth += surface.Azimuth * surface.Area;
   15446          123 :             geoSummaryRoof.Area += surface.Area;
   15447              : 
   15448          615 :             for (auto it = surface.Vertex.begin(); it != surface.Vertex.end(); ++it) {
   15449              : 
   15450          492 :                 auto itnext = std::next(it);
   15451          984 :                 if (itnext == std::end(surface.Vertex)) {
   15452          246 :                     itnext = std::begin(surface.Vertex);
   15453              :                 }
   15454              : 
   15455          492 :                 auto &curVertex = *it;
   15456          492 :                 auto &nextVertex = *itnext;
   15457          984 :                 auto it2 = std::find_if(uniqueRoofVertices.begin(), uniqueRoofVertices.end(), [&curVertex](const auto &unqV) {
   15458          986 :                     return SurfaceGeometry::isAlmostEqual3dPt(curVertex, unqV);
   15459          984 :                 });
   15460          492 :                 if (it2 == std::end(uniqueRoofVertices)) {
   15461          417 :                     uniqueRoofVertices.emplace_back(curVertex);
   15462              :                 }
   15463              : 
   15464          492 :                 SurfaceGeometry::EdgeOfSurf thisEdge;
   15465          492 :                 thisEdge.start = std::move(curVertex);
   15466          492 :                 thisEdge.end = std::move(nextVertex);
   15467          492 :                 thisEdge.count = 1;
   15468              : 
   15469              :                 // Uses the custom operator== that uses isAlmostEqual3dPt internally and doesn't care about order of the start/end
   15470          492 :                 auto itEdge = std::find(uniqEdgeOfSurfs.begin(), uniqEdgeOfSurfs.end(), thisEdge);
   15471          492 :                 if (itEdge == uniqEdgeOfSurfs.end()) {
   15472          425 :                     uniqEdgeOfSurfs.emplace_back(std::move(thisEdge));
   15473              :                 } else {
   15474           67 :                     ++(itEdge->count);
   15475              :                 }
   15476          492 :             }
   15477          134 :         }
   15478              : 
   15479          134 :         if (geoSummaryRoof.Area > 0) {
   15480           95 :             geoSummaryRoof.Height /= geoSummaryRoof.Area;
   15481           95 :             geoSummaryRoof.Tilt /= geoSummaryRoof.Area;
   15482           95 :             geoSummaryRoof.Azimuth /= geoSummaryRoof.Area;
   15483              :         } else {
   15484           39 :             geoSummaryRoof.Height = 0.0;
   15485           39 :             geoSummaryRoof.Tilt = 0.0;
   15486           39 :             geoSummaryRoof.Azimuth = 0.0;
   15487              :         }
   15488              : 
   15489              :         // Remove the ones that are already used twice
   15490          268 :         uniqEdgeOfSurfs.erase(
   15491          693 :             std::remove_if(uniqEdgeOfSurfs.begin(), uniqEdgeOfSurfs.end(), [](const auto &edge) -> bool { return edge.count == 2; }),
   15492          268 :             uniqEdgeOfSurfs.end());
   15493              : 
   15494              :         // Intersect with unique vertices as much as needed
   15495          134 :         bool insertedVertext = true;
   15496          270 :         while (insertedVertext) {
   15497          136 :             insertedVertext = false;
   15498              : 
   15499          524 :             for (auto &edge : uniqEdgeOfSurfs) {
   15500              : 
   15501              :                 // now go through all the vertices and see if they are colinear with start and end vertices
   15502         2360 :                 for (const auto &testVertex : uniqueRoofVertices) {
   15503         1972 :                     if (edge.containsPoints(testVertex)) {
   15504            2 :                         SurfaceGeometry::EdgeOfSurf newEdgeOfSurface;
   15505            2 :                         newEdgeOfSurface.start = testVertex;
   15506            2 :                         newEdgeOfSurface.end = edge.end;
   15507            2 :                         edge.end = testVertex;
   15508            2 :                         uniqEdgeOfSurfs.emplace_back(std::move(newEdgeOfSurface));
   15509            2 :                         insertedVertext = true;
   15510            2 :                         break;
   15511            2 :                     }
   15512          390 :                 }
   15513              :                 // Break out of the loop on edges, and start again at the while
   15514          390 :                 if (insertedVertext) {
   15515            2 :                     break;
   15516              :                 }
   15517          136 :             }
   15518              :         }
   15519              : 
   15520              :         // recount
   15521          510 :         for (auto &edge : uniqEdgeOfSurfs) {
   15522          376 :             edge.count = std::count(uniqEdgeOfSurfs.begin(), uniqEdgeOfSurfs.end(), edge);
   15523          134 :         }
   15524              : 
   15525          268 :         uniqEdgeOfSurfs.erase(
   15526          644 :             std::remove_if(uniqEdgeOfSurfs.begin(), uniqEdgeOfSurfs.end(), [](const auto &edge) -> bool { return edge.count == 2; }),
   15527          268 :             uniqEdgeOfSurfs.end());
   15528              : 
   15529          134 :         geoSummaryRoof.Perimeter =
   15530          134 :             std::accumulate(uniqEdgeOfSurfs.cbegin(), uniqEdgeOfSurfs.cend(), 0.0, [](const double &sum, const SurfaceGeometry::EdgeOfSurf &edge) {
   15531          372 :                 return sum + edge.length();
   15532              :             });
   15533          134 :     }
   15534              : 
   15535              : } // namespace SurfaceGeometry
   15536              : 
   15537              : } // namespace EnergyPlus
        

Generated by: LCOV version 2.0-1