LCOV - code coverage report
Current view: top level - EnergyPlus - SurfaceGeometry.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 55.7 % 9113 5080
Test Date: 2025-05-22 16:09:37 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) CreateStormWindowConstructions(state);
     305              : 
     306          192 :         DataHeatBalance::SetFlagForWindowConstructionWithShadeOrBlindLayer(state);
     307              : 
     308          192 :         state.dataSurfaceGeometry->CosZoneRelNorth.deallocate();
     309          192 :         state.dataSurfaceGeometry->SinZoneRelNorth.deallocate();
     310              : 
     311          192 :         state.dataHeatBal->CalcWindowRevealReflection = false; // Set to True in ProcessSurfaceVertices if beam solar reflection from window reveals
     312              :         // is requested for one or more exterior windows.
     313          192 :         state.dataSurface->BuildingShadingCount = 0;
     314          192 :         state.dataSurface->FixedShadingCount = 0;
     315          192 :         state.dataSurface->AttachedShadingCount = 0;
     316          192 :         state.dataSurface->ShadingSurfaceFirst = 0;
     317          192 :         state.dataSurface->ShadingSurfaceLast = -1;
     318              : 
     319              :         // Reserve space to avoid excess allocations
     320          192 :         state.dataSurface->AllExtSolAndShadingSurfaceList.reserve(state.dataSurface->TotSurfaces);
     321              : 
     322         1883 :         for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) { // Loop through all surfaces...
     323         1691 :             auto &thisSurface = state.dataSurface->Surface(SurfNum);
     324              : 
     325         1691 :             state.dataSurface->SurfAirSkyRadSplit(SurfNum) = std::sqrt(0.5 * (1.0 + thisSurface.CosTilt));
     326              : 
     327              :             // Set flag that determines whether a surface is a shadowing surface
     328         1691 :             thisSurface.IsShadowing = false;
     329         1691 :             if (thisSurface.Class == SurfaceClass::Shading || thisSurface.Class == SurfaceClass::Detached_F ||
     330         1637 :                 thisSurface.Class == SurfaceClass::Detached_B) {
     331           74 :                 thisSurface.IsShadowing = true;
     332           74 :                 if (state.dataSurface->ShadingSurfaceFirst == 0) state.dataSurface->ShadingSurfaceFirst = SurfNum;
     333           74 :                 state.dataSurface->ShadingSurfaceLast = SurfNum;
     334              :             }
     335         1691 :             if ((thisSurface.HeatTransSurf && thisSurface.ExtSolar) || thisSurface.IsShadowing) {
     336              :                 // Some attached shading surfaces may be true for both
     337         1091 :                 state.dataSurface->AllExtSolAndShadingSurfaceList.push_back(SurfNum);
     338              :             }
     339         1691 :             if (thisSurface.Class == SurfaceClass::Shading) ++state.dataSurface->AttachedShadingCount;
     340         1691 :             if (thisSurface.Class == SurfaceClass::Detached_F) ++state.dataSurface->FixedShadingCount;
     341         1691 :             if (thisSurface.Class == SurfaceClass::Detached_B) ++state.dataSurface->BuildingShadingCount;
     342              : 
     343         1691 :             if (thisSurface.Class != SurfaceClass::IntMass) ProcessSurfaceVertices(state, SurfNum, ErrorsFound);
     344              :         }
     345              : 
     346          467 :         for (auto &e : state.dataHeatBal->Zone) {
     347          275 :             e.ExtWindowArea = 0.0;
     348          275 :             e.HasWindow = false;
     349          275 :             e.ExtGrossWallArea = 0.0;
     350          275 :             e.ExtNetWallArea = 0.0;
     351          275 :             e.TotalSurfArea = 0.0;
     352              :         }
     353              : 
     354          489 :         for (auto &s : state.dataHeatBal->space) {
     355          297 :             s.extWindowArea = 0.0;
     356          297 :             s.totalSurfArea = 0.0;
     357              :         }
     358          384 :         bool DetailedWWR = (state.dataInputProcessing->inputProcessor->getNumSectionsFound("DETAILEDWWR_DEBUG") > 0);
     359          192 :         if (DetailedWWR) {
     360            0 :             print(state.files.debug, "{}", "=======User Entered Classification =================");
     361            0 :             print(state.files.debug, "{}", "Surface,Class,Area,Tilt");
     362              :         }
     363              : 
     364         1883 :         for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) { // Loop through all surfaces to find windows...
     365         1691 :             auto &thisSurface = state.dataSurface->Surface(SurfNum);
     366              : 
     367         1691 :             if (!thisSurface.HeatTransSurf && !thisSurface.IsAirBoundarySurf) continue; // Skip shadowing (sub)surfaces
     368         1617 :             auto &thisZone = state.dataHeatBal->Zone(thisSurface.Zone);
     369         1617 :             auto &thisSpace = state.dataHeatBal->space(thisSurface.spaceNum);
     370              : 
     371         1617 :             thisZone.TotalSurfArea += thisSurface.Area;
     372         1617 :             thisSpace.totalSurfArea += thisSurface.Area;
     373         1617 :             if (thisSurface.Class == SurfaceClass::Roof) {
     374          257 :                 thisZone.geometricCeilingArea += thisSurface.GrossArea;
     375         1360 :             } else if (thisSurface.Class == SurfaceClass::Floor) {
     376          328 :                 thisZone.geometricFloorArea += thisSurface.GrossArea;
     377              :             }
     378         1617 :             if (state.dataConstruction->Construct(thisSurface.Construction).TypeIsWindow) {
     379          125 :                 thisZone.TotalSurfArea += state.dataSurface->SurfWinFrameArea(SurfNum);
     380          125 :                 thisZone.HasWindow = true;
     381          125 :                 thisSpace.totalSurfArea += state.dataSurface->SurfWinFrameArea(SurfNum);
     382          125 :                 if (((thisSurface.ExtBoundCond == DataSurfaces::ExternalEnvironment) ||
     383            6 :                      (thisSurface.ExtBoundCond == DataSurfaces::OtherSideCondModeledExt)) &&
     384          119 :                     (thisSurface.Class != SurfaceClass::TDD_Dome)) {
     385          112 :                     thisZone.ExtWindowArea += thisSurface.GrossArea;
     386          112 :                     thisSpace.extWindowArea += thisSurface.GrossArea;
     387          112 :                     thisZone.ExtWindowArea_Multiplied =
     388          112 :                         thisZone.ExtWindowArea + thisSurface.GrossArea * thisSurface.Multiplier * thisZone.Multiplier * thisZone.ListMultiplier;
     389          112 :                     if (DetailedWWR) {
     390            0 :                         print(state.files.debug,
     391              :                               "{},Window,{:.2R},{:.1R}\n",
     392            0 :                               thisSurface.Name,
     393            0 :                               thisSurface.GrossArea * thisSurface.Multiplier * thisZone.Multiplier * thisZone.ListMultiplier,
     394            0 :                               thisSurface.Tilt);
     395              :                     }
     396              :                 }
     397              :             } else {
     398         1492 :                 if (thisSurface.ExtBoundCond == DataSurfaces::ExternalEnvironment ||
     399          526 :                     thisSurface.ExtBoundCond == DataSurfaces::OtherSideCondModeledExt) {
     400          967 :                     thisZone.ExteriorTotalSurfArea += thisSurface.GrossArea;
     401          967 :                     thisSpace.ExteriorTotalSurfArea += thisSurface.GrossArea;
     402          967 :                     if (thisSurface.Class == SurfaceClass::Wall) {
     403          643 :                         thisZone.ExtNetWallArea += thisSurface.Area;
     404          643 :                         thisZone.ExtGrossWallArea += thisSurface.GrossArea;
     405          643 :                         thisSpace.ExtGrossWallArea += thisSurface.GrossArea;
     406          643 :                         thisZone.ExtGrossWallArea_Multiplied += thisSurface.GrossArea * thisZone.Multiplier * thisZone.ListMultiplier;
     407          643 :                         thisZone.extPerimeter += thisSurface.Width;
     408          643 :                         thisSpace.extPerimeter += thisSurface.Width;
     409          643 :                         if (DetailedWWR) {
     410            0 :                             print(state.files.debug,
     411              :                                   "{},Wall,{:.2R},{:.1R}\n",
     412            0 :                                   thisSurface.Name,
     413            0 :                                   thisSurface.GrossArea * thisZone.Multiplier * thisZone.ListMultiplier,
     414            0 :                                   thisSurface.Tilt);
     415              :                         }
     416              :                     }
     417          525 :                 } else if (thisSurface.ExtBoundCond == DataSurfaces::Ground || thisSurface.ExtBoundCond == DataSurfaces::GroundFCfactorMethod ||
     418          419 :                            thisSurface.ExtBoundCond == DataSurfaces::KivaFoundation) {
     419          106 :                     thisZone.ExteriorTotalGroundSurfArea += thisSurface.GrossArea;
     420          106 :                     if (thisSurface.Class == SurfaceClass::Wall) {
     421            3 :                         thisZone.ExtGrossGroundWallArea += thisSurface.GrossArea;
     422            3 :                         thisZone.ExtGrossGroundWallArea_Multiplied += thisSurface.GrossArea * thisZone.Multiplier * thisZone.ListMultiplier;
     423            3 :                         if (DetailedWWR) {
     424            0 :                             print(state.files.debug,
     425              :                                   "{},Wall-GroundContact,{:.2R},{:.1R}\n",
     426            0 :                                   thisSurface.Name,
     427            0 :                                   thisSurface.GrossArea * thisZone.Multiplier * thisZone.ListMultiplier,
     428            0 :                                   thisSurface.Tilt);
     429              :                         }
     430              :                     }
     431              :                 }
     432              :             }
     433              : 
     434              :         } // ...end of surfaces windows DO loop
     435              : 
     436          192 :         if (DetailedWWR) {
     437            0 :             print(state.files.debug, "{}\n", "========================");
     438            0 :             print(state.files.debug, "{}\n", "Zone,ExtWallArea,ExtWindowArea");
     439              :         }
     440              : 
     441          467 :         for (auto &thisZone : state.dataHeatBal->Zone) {
     442          275 :             int CeilCount = 0;
     443          275 :             int FloorCount = 0;
     444          275 :             int WallCount = 0;
     445          275 :             Real64 AverageHeight = 0.0; // Used to keep track of average height of a surface/zone
     446          275 :             Real64 ZMax = -99999.0;     // Maximum Z of a surface (detailed outside coefficient calculation)
     447          275 :             Real64 ZMin = 99999.0;      // Minimum Z of a surface (detailed outside coefficient calculation)
     448          275 :             Real64 ZCeilAvg = 0.0;
     449          275 :             Real64 ZFlrAvg = 0.0;
     450          275 :             if (DetailedWWR) {
     451            0 :                 print(state.files.debug, "{},{:.2R},{:.2R}\n", thisZone.Name, thisZone.ExtGrossWallArea, thisZone.ExtWindowArea);
     452              :             }
     453          572 :             for (int spaceNum : thisZone.spaceIndexes) {
     454          297 :                 auto const &thisSpace = state.dataHeatBal->space(spaceNum);
     455              :                 // Use AllSurfaceFirst which includes air boundaries
     456         1914 :                 for (int SurfNum = thisSpace.AllSurfaceFirst; SurfNum <= thisSpace.AllSurfaceLast; ++SurfNum) {
     457         1617 :                     auto &thisSurface = state.dataSurface->Surface(SurfNum);
     458              : 
     459         1617 :                     if (thisSurface.Class == SurfaceClass::Roof) {
     460              :                         // Use Average Z for surface, more important for roofs than floors...
     461          257 :                         ++CeilCount;
     462          257 :                         Real64 Z1 = minval(thisSurface.Vertex, &Vector::z);
     463          257 :                         Real64 Z2 = maxval(thisSurface.Vertex, &Vector::z);
     464              :                         //        ZCeilAvg=ZCeilAvg+(Z1+Z2)/2.d0
     465          257 :                         ZCeilAvg += ((Z1 + Z2) / 2.0) * (thisSurface.GrossArea / thisZone.geometricCeilingArea);
     466              :                     }
     467         1617 :                     if (thisSurface.Class == SurfaceClass::Floor) {
     468              :                         // Use Average Z for surface, more important for roofs than floors...
     469          328 :                         ++FloorCount;
     470          328 :                         Real64 Z1 = minval(thisSurface.Vertex, &Vector::z);
     471          328 :                         Real64 Z2 = maxval(thisSurface.Vertex, &Vector::z);
     472              :                         //        ZFlrAvg=ZFlrAvg+(Z1+Z2)/2.d0
     473          328 :                         ZFlrAvg += ((Z1 + Z2) / 2.0) * (thisSurface.GrossArea / thisZone.geometricFloorArea);
     474              :                     }
     475         1617 :                     if (thisSurface.Class == SurfaceClass::Wall) {
     476              :                         // Use Wall calculation in case no roof & floor in zone
     477          887 :                         ++WallCount;
     478          887 :                         if (WallCount == 1) {
     479          258 :                             ZMax = thisSurface.Vertex(1).z;
     480          258 :                             ZMin = ZMax;
     481              :                         }
     482          887 :                         ZMax = max(ZMax, maxval(thisSurface.Vertex, &Vector::z));
     483          887 :                         ZMin = min(ZMin, minval(thisSurface.Vertex, &Vector::z));
     484              :                     }
     485              :                 }
     486              :             }
     487          275 :             if (CeilCount > 0 && FloorCount > 0) {
     488          197 :                 AverageHeight = ZCeilAvg - ZFlrAvg;
     489              :             } else {
     490           78 :                 AverageHeight = (ZMax - ZMin);
     491              :             }
     492          275 :             if (AverageHeight <= 0.0) {
     493           24 :                 AverageHeight = (ZMax - ZMin);
     494              :             }
     495              : 
     496          275 :             if (thisZone.CeilingHeight > 0.0) {
     497           70 :                 thisZone.ceilingHeightEntered = true;
     498           70 :                 if (AverageHeight > 0.0) {
     499           67 :                     if (std::abs(AverageHeight - thisZone.CeilingHeight) / thisZone.CeilingHeight > 0.05) {
     500            4 :                         if (state.dataSurfaceGeometry->ErrCount == 1 && !state.dataGlobal->DisplayExtraWarnings) {
     501            0 :                             ShowWarningError(
     502              :                                 state,
     503            0 :                                 format("{}Entered Ceiling Height for some zone(s) significantly different from calculated Ceiling Height",
     504              :                                        RoutineName));
     505            0 :                             ShowContinueError(state,
     506              :                                               "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on each max iteration exceeded.");
     507              :                         }
     508            4 :                         if (state.dataGlobal->DisplayExtraWarnings) {
     509            0 :                             ShowWarningError(state,
     510            0 :                                              format("{}Entered Ceiling Height for Zone=\"{}\" significantly different from calculated Ceiling Height",
     511              :                                                     RoutineName,
     512            0 :                                                     thisZone.Name));
     513              :                             static constexpr std::string_view ValFmt("{:.2F}");
     514            0 :                             std::string String1 = format(ValFmt, thisZone.CeilingHeight);
     515            0 :                             std::string String2 = format(ValFmt, AverageHeight);
     516            0 :                             ShowContinueError(
     517              :                                 state,
     518            0 :                                 format("{}Entered Ceiling Height={}, Calculated Ceiling Height={}, entered height will be used in calculations.",
     519              :                                        RoutineName,
     520              :                                        String1,
     521              :                                        String2));
     522            0 :                         }
     523              :                     }
     524              :                 }
     525              :             }
     526          275 :             if ((thisZone.CeilingHeight <= 0.0) && (AverageHeight > 0.0)) thisZone.CeilingHeight = AverageHeight;
     527              :             // Need to add check here - don't touch if already user-specified
     528              :         }
     529              : 
     530          192 :         CalculateZoneVolume(state); // Calculate Zone Volumes
     531              : 
     532              :         // Calculate zone centroid (and min/max x,y,z for zone)
     533              :         // Use AllSurfaceFirst which includes air boundaries
     534          467 :         for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
     535          275 :             auto &thisZone = state.dataHeatBal->Zone(ZoneNum);
     536          275 :             bool nonInternalMassSurfacesPresent = false;
     537          275 :             bool internalMassSurfacesPresent = false;
     538          275 :             Real64 TotSurfArea = 0.0;
     539          275 :             thisZone.Centroid = Vector(0.0, 0.0, 0.0);
     540          275 :             if ((thisZone.AllSurfaceFirst > 0) && (state.dataSurface->Surface(thisZone.AllSurfaceFirst).Sides > 0)) {
     541          272 :                 thisZone.MinimumX = state.dataSurface->Surface(thisZone.AllSurfaceFirst).Vertex(1).x;
     542          272 :                 thisZone.MaximumX = state.dataSurface->Surface(thisZone.AllSurfaceFirst).Vertex(1).x;
     543          272 :                 thisZone.MinimumY = state.dataSurface->Surface(thisZone.AllSurfaceFirst).Vertex(1).y;
     544          272 :                 thisZone.MaximumY = state.dataSurface->Surface(thisZone.AllSurfaceFirst).Vertex(1).y;
     545          272 :                 thisZone.MinimumZ = state.dataSurface->Surface(thisZone.AllSurfaceFirst).Vertex(1).z;
     546          272 :                 thisZone.MaximumZ = state.dataSurface->Surface(thisZone.AllSurfaceFirst).Vertex(1).z;
     547              :             }
     548          572 :             for (int spaceNum : thisZone.spaceIndexes) {
     549          297 :                 auto const &thisSpace = state.dataHeatBal->space(spaceNum);
     550              : 
     551         1914 :                 for (int SurfNum = thisSpace.AllSurfaceFirst; SurfNum <= thisSpace.AllSurfaceLast; ++SurfNum) {
     552         1617 :                     auto &thisSurface = state.dataSurface->Surface(SurfNum);
     553         1617 :                     if (thisSurface.Class == SurfaceClass::IntMass) {
     554            6 :                         internalMassSurfacesPresent = true;
     555            6 :                         continue;
     556              :                     }
     557         1611 :                     if (!thisSurface.IsAirBoundarySurf) nonInternalMassSurfacesPresent = true;
     558         1611 :                     if (thisSurface.Class == SurfaceClass::Wall || (thisSurface.Class == SurfaceClass::Roof) ||
     559          467 :                         (thisSurface.Class == SurfaceClass::Floor)) {
     560              : 
     561         1472 :                         thisZone.Centroid.x += thisSurface.Centroid.x * thisSurface.GrossArea;
     562         1472 :                         thisZone.Centroid.y += thisSurface.Centroid.y * thisSurface.GrossArea;
     563         1472 :                         thisZone.Centroid.z += thisSurface.Centroid.z * thisSurface.GrossArea;
     564         1472 :                         TotSurfArea += thisSurface.GrossArea;
     565              :                     }
     566         1611 :                     thisZone.MinimumX = min(thisZone.MinimumX, minval(thisSurface.Vertex, &Vector::x));
     567         1611 :                     thisZone.MaximumX = max(thisZone.MaximumX, maxval(thisSurface.Vertex, &Vector::x));
     568         1611 :                     thisZone.MinimumY = min(thisZone.MinimumY, minval(thisSurface.Vertex, &Vector::y));
     569         1611 :                     thisZone.MaximumY = max(thisZone.MaximumY, maxval(thisSurface.Vertex, &Vector::y));
     570         1611 :                     thisZone.MinimumZ = min(thisZone.MinimumZ, minval(thisSurface.Vertex, &Vector::z));
     571         1611 :                     thisZone.MaximumZ = max(thisZone.MaximumZ, maxval(thisSurface.Vertex, &Vector::z));
     572              :                 }
     573              :             }
     574          275 :             if (TotSurfArea > 0.0) {
     575          272 :                 thisZone.Centroid.x /= TotSurfArea;
     576          272 :                 thisZone.Centroid.y /= TotSurfArea;
     577          272 :                 thisZone.Centroid.z /= TotSurfArea;
     578              :             }
     579          275 :             if (internalMassSurfacesPresent && !nonInternalMassSurfacesPresent) {
     580            0 :                 ShowSevereError(
     581            0 :                     state, format("{}Zone=\"{}\" has only internal mass surfaces.  Need at least one other surface.", RoutineName, thisZone.Name));
     582            0 :                 ErrorsFound = true;
     583              :             }
     584              :         }
     585              : 
     586          192 :         state.dataSurface->SurfAdjacentZone.dimension(state.dataSurface->TotSurfaces, 0);
     587              :         // note -- adiabatic surfaces will show same zone as surface
     588         1883 :         for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
     589         1691 :             if (state.dataSurface->Surface(SurfNum).ExtBoundCond <= 0) continue;
     590          425 :             state.dataSurface->SurfAdjacentZone(SurfNum) = state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).ExtBoundCond).Zone;
     591              :         }
     592              : 
     593          467 :         for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
     594         4185 :             for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
     595         3910 :                 auto const &thisSurface = state.dataSurface->Surface(SurfNum);
     596         3910 :                 if (!thisSurface.HeatTransSurf && thisSurface.ZoneName == state.dataHeatBal->Zone(ZoneNum).Name)
     597           90 :                     ++state.dataHeatBal->Zone(ZoneNum).NumShadingSurfaces;
     598              : 
     599         3910 :                 if (thisSurface.Zone != ZoneNum) continue;
     600              : 
     601         1617 :                 if (thisSurface.HeatTransSurf &&
     602         1575 :                     (thisSurface.Class == SurfaceClass::Wall || thisSurface.Class == SurfaceClass::Roof || thisSurface.Class == SurfaceClass::Floor))
     603         1434 :                     ++state.dataHeatBal->Zone(ZoneNum).NumSurfaces;
     604              : 
     605         1617 :                 if (thisSurface.HeatTransSurf && (thisSurface.Class == SurfaceClass::Window || thisSurface.Class == SurfaceClass::GlassDoor ||
     606         1457 :                                                   thisSurface.Class == SurfaceClass::Door || thisSurface.Class == SurfaceClass::TDD_Dome ||
     607         1440 :                                                   thisSurface.Class == SurfaceClass::TDD_Diffuser))
     608          135 :                     ++state.dataHeatBal->Zone(ZoneNum).NumSubSurfaces;
     609              : 
     610              :             } // surfaces
     611              :         }     // zones
     612              : 
     613         1883 :         for (int const SurfNum : state.dataSurface->AllSurfaceListReportOrder) {
     614         1691 :             auto const &thisSurface = state.dataSurface->Surface(SurfNum);
     615         1691 :             Real64 NominalUwithConvCoeffs = 0.0;
     616         1691 :             if (thisSurface.Construction > 0 && thisSurface.Construction <= state.dataHeatBal->TotConstructs) {
     617         1617 :                 bool isWithConvCoefValid = false;
     618         1617 :                 NominalUwithConvCoeffs = DataHeatBalance::ComputeNominalUwithConvCoeffs(state, SurfNum, isWithConvCoefValid);
     619              :             }
     620              : 
     621              :             // populate the predefined report related to u-values with films
     622              :             // only exterior surfaces including underground
     623         1691 :             DataSurfaces::SurfaceClass const SurfaceClass(thisSurface.Class);
     624         1691 :             if ((thisSurface.ExtBoundCond == DataSurfaces::ExternalEnvironment) || (thisSurface.ExtBoundCond == DataSurfaces::Ground) ||
     625          426 :                 (thisSurface.ExtBoundCond == DataSurfaces::KivaFoundation) || (thisSurface.ExtBoundCond == DataSurfaces::GroundFCfactorMethod)) {
     626         1265 :                 if ((SurfaceClass == SurfaceClass::Wall) || (SurfaceClass == SurfaceClass::Floor) || (SurfaceClass == SurfaceClass::Roof)) {
     627         2136 :                     OutputReportPredefined::PreDefTableEntry(
     628         3204 :                         state, state.dataOutRptPredefined->pdchOpUfactFilm, thisSurface.Name, NominalUwithConvCoeffs, 3);
     629          197 :                 } else if (SurfaceClass == SurfaceClass::Door) {
     630            8 :                     OutputReportPredefined::PreDefTableEntry(
     631           12 :                         state, state.dataOutRptPredefined->pdchDrUfactFilm, thisSurface.Name, NominalUwithConvCoeffs, 3);
     632              :                 }
     633              :             } else {
     634          426 :                 if ((SurfaceClass == SurfaceClass::Wall) || (SurfaceClass == SurfaceClass::Floor) || (SurfaceClass == SurfaceClass::Roof)) {
     635          808 :                     OutputReportPredefined::PreDefTableEntry(
     636         1212 :                         state, state.dataOutRptPredefined->pdchIntOpUfactFilm, thisSurface.Name, NominalUwithConvCoeffs, 3);
     637           22 :                 } else if (SurfaceClass == SurfaceClass::Door) {
     638           16 :                     OutputReportPredefined::PreDefTableEntry(
     639           24 :                         state, state.dataOutRptPredefined->pdchIntDrUfactFilm, thisSurface.Name, NominalUwithConvCoeffs, 3);
     640              :                 }
     641              :             }
     642              :         } // surfaces
     643              : 
     644              :         // Write number of shadings to initialization output file
     645          192 :         print(state.files.eio,
     646              :               "! <Shading Summary>, Number of Fixed Detached Shades, Number of Building Detached Shades, Number of Attached Shades\n");
     647              : 
     648          192 :         print(state.files.eio,
     649              :               " Shading Summary,{},{},{}\n",
     650          192 :               state.dataSurface->FixedShadingCount,
     651          192 :               state.dataSurface->BuildingShadingCount,
     652          192 :               state.dataSurface->AttachedShadingCount);
     653              : 
     654              :         // Write number of zones header to initialization output file
     655          192 :         print(state.files.eio, "! <Zone Summary>, Number of Zones, Number of Zone Surfaces, Number of SubSurfaces\n");
     656              : 
     657          192 :         print(state.files.eio,
     658              :               " Zone Summary,{},{},{}\n",
     659          192 :               state.dataGlobal->NumOfZones,
     660          192 :               state.dataSurface->TotSurfaces - state.dataSurface->FixedShadingCount - state.dataSurface->BuildingShadingCount -
     661          192 :                   state.dataSurface->AttachedShadingCount,
     662          192 :               sum(state.dataHeatBal->Zone, &DataHeatBalance::ZoneData::NumSubSurfaces));
     663              : 
     664              :         // Write Zone Information header to the initialization output file
     665              :         static constexpr std::string_view Format_721(
     666              :             "! <Zone Information>,Zone Name,North Axis {deg},Origin X-Coordinate {m},Origin Y-Coordinate {m},Origin Z-Coordinate "
     667              :             "{m},Centroid X-Coordinate {m},Centroid Y-Coordinate {m},Centroid Z-Coordinate {m},Type,Zone Multiplier,Zone List "
     668              :             "Multiplier,Minimum X {m},Maximum X {m},Minimum Y {m},Maximum Y {m},Minimum Z {m},Maximum Z {m},Ceiling Height {m},Volume "
     669              :             "{m3},Zone Inside Convection Algorithm {Simple-Detailed-CeilingDiffuser-TrombeWall},Zone Outside Convection Algorithm "
     670              :             "{Simple-Detailed-Tarp-MoWitt-DOE-2-BLAST}, Floor Area {m2},Exterior Gross Wall Area {m2},Exterior Net Wall Area {m2},Exterior "
     671              :             "Window "
     672              :             "Area {m2}, Number of Surfaces, Number of SubSurfaces, Number of Shading SubSurfaces,  Part of Total Building Area");
     673          192 :         print(state.files.eio, "{}\n", Format_721);
     674              : 
     675          467 :         for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
     676              :             // Write Zone Information to the initialization output file
     677          275 :             std::string String1;
     678          275 :             std::string String2;
     679          275 :             std::string String3;
     680              : 
     681          275 :             switch (state.dataHeatBal->Zone(ZoneNum).IntConvAlgo) {
     682           78 :             case Convect::HcInt::ASHRAESimple: {
     683           78 :                 String1 = "Simple";
     684           78 :             } break;
     685          190 :             case Convect::HcInt::ASHRAETARP: {
     686          190 :                 String1 = "TARP";
     687          190 :             } break;
     688            0 :             case Convect::HcInt::CeilingDiffuser: {
     689            0 :                 String1 = "CeilingDiffuser";
     690            0 :             } break;
     691            0 :             case Convect::HcInt::TrombeWall: {
     692            0 :                 String1 = "TrombeWall";
     693            0 :             } break;
     694            7 :             case Convect::HcInt::AdaptiveConvectionAlgorithm: {
     695            7 :                 String1 = "AdaptiveConvectionAlgorithm";
     696            7 :             } break;
     697            0 :             case Convect::HcInt::ASTMC1340: {
     698            0 :                 String1 = "ASTMC1340";
     699            0 :             } break;
     700            0 :             default:
     701            0 :                 break;
     702              :             }
     703              : 
     704          275 :             switch (state.dataHeatBal->Zone(ZoneNum).ExtConvAlgo) {
     705           78 :             case Convect::HcExt::ASHRAESimple: {
     706           78 :                 String2 = "Simple";
     707           78 :             } break;
     708           10 :             case Convect::HcExt::ASHRAETARP: {
     709           10 :                 String2 = "TARP";
     710           10 :             } break;
     711            0 :             case Convect::HcExt::TarpHcOutside: {
     712            0 :                 String2 = "TARP";
     713            0 :             } break;
     714            0 :             case Convect::HcExt::MoWiTTHcOutside: {
     715            0 :                 String2 = "MoWitt";
     716            0 :             } break;
     717          187 :             case Convect::HcExt::DOE2HcOutside: {
     718          187 :                 String2 = "DOE-2";
     719          187 :             } break;
     720            0 :             case Convect::HcExt::AdaptiveConvectionAlgorithm: {
     721            0 :                 String2 = "AdaptiveConvectionAlgorithm";
     722            0 :             } break;
     723            0 :             default:
     724            0 :                 break;
     725              :             }
     726              : 
     727          275 :             String3 = (state.dataHeatBal->Zone(ZoneNum).isPartOfTotalArea) ? "Yes" : "No";
     728              : 
     729              :             static constexpr std::string_view Format_720(
     730              :                 " Zone Information, "
     731              :                 "{},{:.1R},{:.2R},{:.2R},{:.2R},{:.2R},{:.2R},{:.2R},{},{},{},{:.2R},{:.2R},{:.2R},{:.2R},{:.2R},{:.2R},"
     732              :                 "{:.2R},{:.2R},{},{},{:.2R},{:.2R},{:.2R},{:.2R},{},{},{},{}\n");
     733              : 
     734          275 :             print(state.files.eio,
     735              :                   Format_720,
     736          275 :                   state.dataHeatBal->Zone(ZoneNum).Name,
     737          275 :                   state.dataHeatBal->Zone(ZoneNum).RelNorth,
     738          275 :                   state.dataHeatBal->Zone(ZoneNum).OriginX,
     739          275 :                   state.dataHeatBal->Zone(ZoneNum).OriginY,
     740          275 :                   state.dataHeatBal->Zone(ZoneNum).OriginZ,
     741          275 :                   state.dataHeatBal->Zone(ZoneNum).Centroid.x,
     742          275 :                   state.dataHeatBal->Zone(ZoneNum).Centroid.y,
     743          275 :                   state.dataHeatBal->Zone(ZoneNum).Centroid.z,
     744          275 :                   state.dataHeatBal->Zone(ZoneNum).OfType,
     745          275 :                   state.dataHeatBal->Zone(ZoneNum).Multiplier,
     746          275 :                   state.dataHeatBal->Zone(ZoneNum).ListMultiplier,
     747          275 :                   state.dataHeatBal->Zone(ZoneNum).MinimumX,
     748          275 :                   state.dataHeatBal->Zone(ZoneNum).MaximumX,
     749          275 :                   state.dataHeatBal->Zone(ZoneNum).MinimumY,
     750          275 :                   state.dataHeatBal->Zone(ZoneNum).MaximumY,
     751          275 :                   state.dataHeatBal->Zone(ZoneNum).MinimumZ,
     752          275 :                   state.dataHeatBal->Zone(ZoneNum).MaximumZ,
     753          275 :                   state.dataHeatBal->Zone(ZoneNum).CeilingHeight,
     754          275 :                   state.dataHeatBal->Zone(ZoneNum).Volume,
     755              :                   String1,
     756              :                   String2,
     757          275 :                   state.dataHeatBal->Zone(ZoneNum).FloorArea,
     758          275 :                   state.dataHeatBal->Zone(ZoneNum).ExtGrossWallArea,
     759          275 :                   state.dataHeatBal->Zone(ZoneNum).ExtNetWallArea,
     760          275 :                   state.dataHeatBal->Zone(ZoneNum).ExtWindowArea,
     761          275 :                   state.dataHeatBal->Zone(ZoneNum).NumSurfaces,
     762          275 :                   state.dataHeatBal->Zone(ZoneNum).NumSubSurfaces,
     763          275 :                   state.dataHeatBal->Zone(ZoneNum).NumShadingSurfaces,
     764              :                   String3);
     765              : 
     766          275 :         } // ZoneNum
     767              : 
     768              :         // Set up solar distribution enclosures allowing for any air boundaries
     769          192 :         SetupEnclosuresAndAirBoundaries(state, state.dataViewFactor->EnclSolInfo, SurfaceGeometry::enclosureType::SolarEnclosures, ErrorsFound);
     770              : 
     771              :         // Do the Stratosphere check
     772          192 :         DataHeatBalance::SetZoneOutBulbTempAt(state);
     773          192 :         DataHeatBalance::CheckZoneOutBulbTempAt(state);
     774              :     }
     775              : 
     776          228 :     void AllocateSurfaceArrays(EnergyPlusData &state)
     777              :     {
     778              : 
     779              :         // SUBROUTINE INFORMATION:
     780              :         //       AUTHOR         Rick Strand
     781              :         //       DATE WRITTEN   February 1998
     782              : 
     783              :         // PURPOSE OF THIS SUBROUTINE:
     784              :         // This subroutine allocates all of the arrays at the module level which require allocation.
     785              : 
     786              :         // METHODOLOGY EMPLOYED:
     787              :         // Allocation is dependent on the user input file.
     788              : 
     789          228 :         state.dataSurface->ShadeV.allocate(state.dataSurface->TotSurfaces);
     790         2506 :         for (auto &e : state.dataSurface->ShadeV)
     791         2278 :             e.NVert = 0;
     792              :         // Individual components (XV,YV,ZV) allocated in routine ProcessSurfaceVertices
     793          228 :         state.dataSurface->X0.dimension(state.dataSurface->TotSurfaces, 0.0);
     794          228 :         state.dataSurface->Y0.dimension(state.dataSurface->TotSurfaces, 0.0);
     795          228 :         state.dataSurface->Z0.dimension(state.dataSurface->TotSurfaces, 0.0);
     796              : 
     797              :         // Surface EMS arrays
     798          228 :         state.dataSurface->SurfEMSConstructionOverrideON.allocate(state.dataSurface->TotSurfaces);
     799          228 :         state.dataSurface->SurfEMSConstructionOverrideValue.allocate(state.dataSurface->TotSurfaces);
     800          228 :         state.dataSurface->SurfEMSOverrideIntConvCoef.allocate(state.dataSurface->TotSurfaces);
     801          228 :         state.dataSurface->SurfEMSValueForIntConvCoef.allocate(state.dataSurface->TotSurfaces);
     802          228 :         state.dataSurface->SurfEMSOverrideExtConvCoef.allocate(state.dataSurface->TotSurfaces);
     803          228 :         state.dataSurface->SurfEMSValueForExtConvCoef.allocate(state.dataSurface->TotSurfaces);
     804          228 :         state.dataSurface->SurfOutDryBulbTempEMSOverrideOn.allocate(state.dataSurface->TotSurfaces);
     805          228 :         state.dataSurface->SurfOutDryBulbTempEMSOverrideValue.allocate(state.dataSurface->TotSurfaces);
     806          228 :         state.dataSurface->SurfOutWetBulbTempEMSOverrideOn.allocate(state.dataSurface->TotSurfaces);
     807          228 :         state.dataSurface->SurfOutWetBulbTempEMSOverrideValue.allocate(state.dataSurface->TotSurfaces);
     808          228 :         state.dataSurface->SurfWindSpeedEMSOverrideOn.allocate(state.dataSurface->TotSurfaces);
     809          228 :         state.dataSurface->SurfWindSpeedEMSOverrideValue.allocate(state.dataSurface->TotSurfaces);
     810          228 :         state.dataSurface->SurfViewFactorGroundEMSOverrideOn.allocate(state.dataSurface->TotSurfaces);
     811          228 :         state.dataSurface->SurfViewFactorGroundEMSOverrideValue.allocate(state.dataSurface->TotSurfaces);
     812          228 :         state.dataSurface->SurfWindDirEMSOverrideOn.allocate(state.dataSurface->TotSurfaces);
     813          228 :         state.dataSurface->SurfWindDirEMSOverrideValue.allocate(state.dataSurface->TotSurfaces);
     814         2506 :         for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
     815         2278 :             state.dataSurface->SurfEMSConstructionOverrideON(SurfNum) = false;
     816         2278 :             state.dataSurface->SurfEMSConstructionOverrideValue(SurfNum) = 0.0;
     817         2278 :             state.dataSurface->SurfEMSOverrideIntConvCoef(SurfNum) = false;
     818         2278 :             state.dataSurface->SurfEMSValueForIntConvCoef(SurfNum) = 0.0;
     819         2278 :             state.dataSurface->SurfEMSOverrideExtConvCoef(SurfNum) = false;
     820         2278 :             state.dataSurface->SurfEMSValueForExtConvCoef(SurfNum) = 0.0;
     821         2278 :             state.dataSurface->SurfOutDryBulbTempEMSOverrideOn(SurfNum) = false;
     822         2278 :             state.dataSurface->SurfOutDryBulbTempEMSOverrideValue(SurfNum) = 0.0;
     823         2278 :             state.dataSurface->SurfOutWetBulbTempEMSOverrideOn(SurfNum) = false;
     824         2278 :             state.dataSurface->SurfOutWetBulbTempEMSOverrideValue(SurfNum) = 0.0;
     825         2278 :             state.dataSurface->SurfWindSpeedEMSOverrideOn(SurfNum) = false;
     826         2278 :             state.dataSurface->SurfWindSpeedEMSOverrideValue(SurfNum) = 0.0;
     827         2278 :             state.dataSurface->SurfViewFactorGroundEMSOverrideOn(SurfNum) = false;
     828         2278 :             state.dataSurface->SurfViewFactorGroundEMSOverrideValue(SurfNum) = 0.0;
     829         2278 :             state.dataSurface->SurfWindDirEMSOverrideOn(SurfNum) = false;
     830         2278 :             state.dataSurface->SurfWindDirEMSOverrideValue(SurfNum) = 0.0;
     831              :         }
     832              :         // Following are surface hb arrays
     833          228 :         state.dataSurface->SurfOutDryBulbTemp.allocate(state.dataSurface->TotSurfaces);
     834          228 :         state.dataSurface->SurfOutWetBulbTemp.allocate(state.dataSurface->TotSurfaces);
     835          228 :         state.dataSurface->SurfOutWindSpeed.allocate(state.dataSurface->TotSurfaces);
     836          228 :         state.dataSurface->SurfOutWindDir.allocate(state.dataSurface->TotSurfaces);
     837          228 :         state.dataSurface->SurfGenericContam.allocate(state.dataSurface->TotSurfaces);
     838          228 :         state.dataSurface->SurfPenumbraID.allocate(state.dataSurface->TotSurfaces);
     839          228 :         state.dataSurface->SurfAirSkyRadSplit.allocate(state.dataSurface->TotSurfaces);
     840         2506 :         for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
     841         2278 :             state.dataSurface->SurfOutDryBulbTemp(SurfNum) = 0.0;
     842         2278 :             state.dataSurface->SurfOutWetBulbTemp(SurfNum) = 0.0;
     843         2278 :             state.dataSurface->SurfOutWindSpeed(SurfNum) = 0.0;
     844         2278 :             state.dataSurface->SurfOutWindDir(SurfNum) = 0.0;
     845         2278 :             state.dataSurface->SurfGenericContam(SurfNum) = 0.0;
     846         2278 :             state.dataSurface->SurfPenumbraID(SurfNum) = -1;
     847         2278 :             state.dataSurface->SurfAirSkyRadSplit(SurfNum) = 0.0;
     848              :         }
     849              :         // Following are surface property arrays used in SurfaceGeometry
     850          228 :         state.dataSurface->SurfShadowRecSurfNum.allocate(state.dataSurface->TotSurfaces);
     851          228 :         state.dataSurface->SurfShadowDisabledZoneList.allocate(state.dataSurface->TotSurfaces);
     852          228 :         state.dataSurface->SurfShadowDiffuseSolRefl.allocate(state.dataSurface->TotSurfaces);
     853          228 :         state.dataSurface->SurfShadowDiffuseVisRefl.allocate(state.dataSurface->TotSurfaces);
     854          228 :         state.dataSurface->SurfShadowGlazingFrac.allocate(state.dataSurface->TotSurfaces);
     855          228 :         state.dataSurface->SurfShadowGlazingConstruct.allocate(state.dataSurface->TotSurfaces);
     856         2506 :         for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
     857         2278 :             state.dataSurface->SurfShadowRecSurfNum(SurfNum) = 0;
     858         2278 :             state.dataSurface->SurfShadowDiffuseSolRefl(SurfNum) = 0.0;
     859         2278 :             state.dataSurface->SurfShadowDiffuseVisRefl(SurfNum) = 0.0;
     860         2278 :             state.dataSurface->SurfShadowGlazingFrac(SurfNum) = 0.0;
     861         2278 :             state.dataSurface->SurfShadowGlazingConstruct(SurfNum) = 0;
     862              :         }
     863          228 :         state.dataSurface->SurfExtEcoRoof.allocate(state.dataSurface->TotSurfaces);
     864          228 :         state.dataSurface->SurfExtCavityPresent.allocate(state.dataSurface->TotSurfaces);
     865          228 :         state.dataSurface->SurfExtCavNum.allocate(state.dataSurface->TotSurfaces);
     866          228 :         state.dataSurface->SurfIsPV.allocate(state.dataSurface->TotSurfaces);
     867          228 :         state.dataSurface->SurfIsICS.allocate(state.dataSurface->TotSurfaces);
     868          228 :         state.dataSurface->SurfIsPool.allocate(state.dataSurface->TotSurfaces);
     869          228 :         state.dataSurface->SurfICSPtr.allocate(state.dataSurface->TotSurfaces);
     870          228 :         state.dataSurface->SurfIsRadSurfOrVentSlabOrPool.allocate(state.dataSurface->TotSurfaces);
     871          228 :         state.dataSurface->SurfDaylightingShelfInd.allocate(state.dataSurface->TotSurfaces);
     872         2506 :         for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
     873         2278 :             state.dataSurface->SurfExtEcoRoof(SurfNum) = false;
     874         2278 :             state.dataSurface->SurfExtCavityPresent(SurfNum) = false;
     875         2278 :             state.dataSurface->SurfExtCavNum(SurfNum) = 0;
     876         2278 :             state.dataSurface->SurfIsPV(SurfNum) = false;
     877         2278 :             state.dataSurface->SurfIsICS(SurfNum) = false;
     878         2278 :             state.dataSurface->SurfIsPool(SurfNum) = false;
     879         2278 :             state.dataSurface->SurfICSPtr(SurfNum) = 0;
     880         2278 :             state.dataSurface->SurfIsRadSurfOrVentSlabOrPool(SurfNum) = false;
     881         2278 :             state.dataSurface->SurfDaylightingShelfInd(SurfNum) = 0;
     882              :         }
     883          228 :         state.dataSurface->SurfLowTempErrCount.allocate(state.dataSurface->TotSurfaces);
     884          228 :         state.dataSurface->SurfHighTempErrCount.allocate(state.dataSurface->TotSurfaces);
     885          228 :         state.dataSurface->surfIntConv.allocate(state.dataSurface->TotSurfaces);
     886          228 :         state.dataSurface->SurfTAirRef.allocate(state.dataSurface->TotSurfaces);
     887          228 :         state.dataSurface->SurfTAirRefRpt.allocate(state.dataSurface->TotSurfaces);
     888          228 :         state.dataSurface->surfExtConv.allocate(state.dataSurface->TotSurfaces);
     889         2506 :         for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
     890         2278 :             state.dataSurface->SurfLowTempErrCount(SurfNum) = 0;
     891         2278 :             state.dataSurface->SurfHighTempErrCount(SurfNum) = 0;
     892         2278 :             state.dataSurface->surfIntConv(SurfNum) = DataSurfaces::SurfIntConv();
     893         2278 :             state.dataSurface->surfExtConv(SurfNum) = DataSurfaces::SurfExtConv();
     894         2278 :             state.dataSurface->SurfTAirRef(SurfNum) = DataSurfaces::RefAirTemp::Invalid;
     895         2278 :             state.dataSurface->SurfTAirRefRpt(SurfNum) = static_cast<int>(DataSurfaces::RefAirTemp::Invalid);
     896              :         }
     897              : 
     898          228 :         state.dataSurface->intMovInsuls.allocate(state.dataSurface->TotSurfaces);
     899          228 :         state.dataSurface->extMovInsuls.allocate(state.dataSurface->TotSurfaces);
     900          228 :     }
     901              : 
     902          244 :     void GetSurfaceData(EnergyPlusData &state, bool &ErrorsFound) // If errors found in input
     903              :     {
     904              : 
     905              :         // SUBROUTINE INFORMATION:
     906              :         //       AUTHOR         Richard Liesen
     907              :         //       DATE WRITTEN   November 1997
     908              :         //       MODIFIED       April 1999, Linda Lawrie
     909              :         //                      Dec. 2000, FW (add "one-wall zone" checks)
     910              :         //       RE-ENGINEERED  May 2000, Linda Lawrie (breakout surface type gets)
     911              : 
     912              :         // PURPOSE OF THIS SUBROUTINE:
     913              :         // The purpose of this subroutine is to read in the surface information
     914              :         // from the input data file and interpret and put in the derived type
     915              : 
     916              :         // METHODOLOGY EMPLOYED:
     917              :         // The order of surfaces does not matter and the surfaces are resorted into
     918              :         // the hierarchical order:
     919              :         //  All Shading Surfaces
     920              :         //  Airwalls for space x1
     921              :         //  Base Surfaces for space x1
     922              :         //  Opaque Subsurfaces for space x1
     923              :         //  Window Subsurfaces for space x1
     924              :         //  TDD Dome Surfaces for space x1
     925              :         //  Airwalls for space x2
     926              :         //  Base Surfaces for space x2
     927              :         //  etc
     928              :         //  Pointers are set in the spaces (AllSurfaceFirst/Last, HTSurfaceFirst/Last, OpaqOrIntMassSurfaceFirst/Last, WindowSurfaceFirst/Last,
     929              :         //  OpaqOrWinSurfaceFirst/Last, TDDDomeFirst/Last)
     930              : 
     931              :         // REFERENCES:
     932              :         //   This routine manages getting the input for the following Objects:
     933              :         // SurfaceGeometry
     934              :         // Surface:Shading:Detached
     935              :         // Surface:HeatTransfer
     936              :         // Surface:HeatTransfer:Sub
     937              :         // Surface:Shading:Attached
     938              :         // Surface:InternalMass
     939              : 
     940              :         // Vertex input:
     941              :         //  N3 , \field Number of Surface Vertices -- Number of (X,Y,Z) groups in this surface
     942              :         //       \note currently limited 3 or 4, later?
     943              :         //       \min 3
     944              :         //       \max 4
     945              :         //       \memo vertices are given in SurfaceGeometry coordinates -- if relative, all surface coordinates
     946              :         //       \memo are "relative" to the Zone Origin.  if WCS, then building and zone origins are used
     947              :         //       \memo for some internal calculations, but all coordinates are given in an "absolute" system.
     948              :         //  N4,  \field Vertex 1 X-coordinate
     949              :         //       \units m
     950              :         //       \type real
     951              :         //  N5 , \field Vertex 1 Y-coordinate
     952              :         //       \units m
     953              :         //       \type real
     954              :         //  N6 , \field Vertex 1 Z-coordinate
     955              :         //       \units m
     956              :         //       \type real
     957              :         //  N7,  \field Vertex 2 X-coordinate
     958              :         //       \units m
     959              :         //       \type real
     960              :         //  N8,  \field Vertex 2 Y-coordinate
     961              :         //       \units m
     962              :         //       \type real
     963              :         //  N9,  \field Vertex 2 Z-coordinate
     964              :         //       \units m
     965              :         //       \type real
     966              :         //  N10, \field Vertex 3 X-coordinate
     967              :         //       \units m
     968              :         //       \type real
     969              :         //  N11, \field Vertex 3 Y-coordinate
     970              :         //       \units m
     971              :         //       \type real
     972              :         //  N12, \field Vertex 3 Z-coordinate
     973              :         //       \units m
     974              :         //       \type real
     975              :         //  N13, \field Vertex 4 X-coordinate
     976              :         //       \units m
     977              :         //       \type real
     978              :         //  N14, \field Vertex 4 Y-coordinate
     979              :         //       \type real
     980              :         //       \units m
     981              :         //  N15; \field Vertex 4 Z-coordinate
     982              :         //       \units m
     983              :         //       \type real
     984              : 
     985              :         // The vertices are stored in the surface derived type.
     986              :         //      +(1)-------------------------(4)+
     987              :         //      |                               |
     988              :         //      |                               |
     989              :         //      |                               |
     990              :         //      +(2)-------------------------(3)+
     991              :         //  The above diagram shows the actual coordinate points of a typical wall
     992              :         //  (you're on the outside looking toward the wall) as stored into
     993              :         //  Surface%Vertex(1:<number-of-sides>)
     994              : 
     995              :         static constexpr std::string_view RoutineName = "GetSurfaceData: ";
     996              :         using namespace Vectors;
     997              :         using namespace DataErrorTracking;
     998              : 
     999              :         int ConstrNumFound;    // Construction number of matching interzone surface
    1000          244 :         bool NonMatch(false);  // Error for non-matching interzone surfaces
    1001              :         int MovedSurfs;        // Number of Moved Surfaces (when sorting into hierarchical structure)
    1002          244 :         bool SurfError(false); // General Surface Error, causes fatal error at end of routine
    1003              :         int TotLay;            // Total layers in a construction
    1004              :         int TotLayFound;       // Total layers in the construction of a matching interzone surface
    1005              :         // Simple Surfaces (Rectangular)
    1006              :         int LayNumOutside; // Outside material numbers for a shaded construction
    1007              :         // entries with two glazing systems
    1008              :         int NeedToAddSurfaces;    // Surfaces that will be added due to "unentered" other zone surface
    1009              :         int NeedToAddSubSurfaces; // SubSurfaces that will be added due to "unentered" other zone surface
    1010          244 :         int CurNewSurf = 0;
    1011              :         Real64 SurfWorldAz;
    1012              :         Real64 SurfTilt;
    1013              : 
    1014              :         int MultFound;
    1015              :         int MultSurfNum;
    1016              :         bool SubSurfaceSevereDisplayed;
    1017          244 :         bool subSurfaceError(false);
    1018              :         bool errFlag;
    1019              : 
    1020              :         bool izConstDiff;    // differences in construction for IZ surfaces
    1021              :         bool izConstDiffMsg; // display message about hb diffs only once.
    1022              : 
    1023              :         // Get the total number of surfaces to allocate derived type and for surface loops
    1024              : 
    1025          244 :         if (state.dataSurfaceGeometry->GetSurfaceDataOneTimeFlag) {
    1026           18 :             return;
    1027              :         } else {
    1028          226 :             state.dataSurfaceGeometry->GetSurfaceDataOneTimeFlag = true;
    1029              :         }
    1030              : 
    1031          226 :         GetGeometryParameters(state, ErrorsFound);
    1032              : 
    1033          226 :         if (state.dataSurface->WorldCoordSystem) {
    1034           82 :             bool RelWarning = false;
    1035           82 :             if (state.dataHeatBal->BuildingAzimuth != 0.0) RelWarning = true;
    1036          209 :             for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
    1037          127 :                 if (state.dataHeatBal->Zone(ZoneNum).RelNorth != 0.0) RelWarning = true;
    1038              :             }
    1039           82 :             if (RelWarning && !state.dataSurfaceGeometry->WarningDisplayed) {
    1040            0 :                 ShowWarningError(
    1041              :                     state,
    1042            0 :                     format("{}World Coordinate System selected.  Any non-zero Building/Zone North Axes or non-zero Zone Origins are ignored.",
    1043              :                            RoutineName));
    1044            0 :                 ShowContinueError(state,
    1045              :                                   "These may be used in daylighting reference point coordinate calculations but not in normal geometry inputs.");
    1046            0 :                 state.dataSurfaceGeometry->WarningDisplayed = true;
    1047              :             }
    1048           82 :             RelWarning = false;
    1049          209 :             for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
    1050          127 :                 if (state.dataHeatBal->Zone(ZoneNum).OriginX != 0.0) RelWarning = true;
    1051          127 :                 if (state.dataHeatBal->Zone(ZoneNum).OriginY != 0.0) RelWarning = true;
    1052          127 :                 if (state.dataHeatBal->Zone(ZoneNum).OriginZ != 0.0) RelWarning = true;
    1053              :             }
    1054           82 :             if (RelWarning && !state.dataSurfaceGeometry->WarningDisplayed) {
    1055            2 :                 ShowWarningError(
    1056              :                     state,
    1057            2 :                     format("{}World Coordinate System selected.  Any non-zero Building/Zone North Axes or non-zero Zone Origins are ignored.",
    1058              :                            RoutineName));
    1059            2 :                 ShowContinueError(state,
    1060              :                                   "These may be used in daylighting reference point coordinate calculations but not in normal geometry inputs.");
    1061            1 :                 state.dataSurfaceGeometry->WarningDisplayed = true;
    1062              :             }
    1063              :         }
    1064              : 
    1065          226 :         int TotDetachedFixed = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Site:Detailed");
    1066          226 :         int TotDetachedBldg = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Building:Detailed");
    1067          226 :         int TotRectDetachedFixed = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Site");
    1068          226 :         int TotRectDetachedBldg = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Building");
    1069          226 :         int TotHTSurfs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "BuildingSurface:Detailed");
    1070          226 :         int TotDetailedWalls = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Wall:Detailed");
    1071          226 :         int TotDetailedRoofs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "RoofCeiling:Detailed");
    1072          226 :         int TotDetailedFloors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Floor:Detailed");
    1073          226 :         int TotHTSubs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "FenestrationSurface:Detailed");
    1074          226 :         int TotShdSubs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Zone:Detailed");
    1075          226 :         int TotOverhangs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Overhang");
    1076          226 :         int TotOverhangsProjection = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Overhang:Projection");
    1077          226 :         int TotFins = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Fin");
    1078          226 :         int TotFinsProjection = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Shading:Fin:Projection");
    1079          226 :         int TotRectWindows = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Window");
    1080          226 :         int TotRectDoors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Door");
    1081          226 :         int TotRectGlazedDoors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "GlazedDoor");
    1082          226 :         int TotRectIZWindows = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Window:Interzone");
    1083          226 :         int TotRectIZDoors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Door:Interzone");
    1084          226 :         int TotRectIZGlazedDoors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "GlazedDoor:Interzone");
    1085          226 :         int TotRectExtWalls = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Wall:Exterior");
    1086          226 :         int TotRectIntWalls = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Wall:Adiabatic");
    1087          226 :         int TotRectIZWalls = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Wall:Interzone");
    1088          226 :         int TotRectUGWalls = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Wall:Underground");
    1089          226 :         int TotRectRoofs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Roof");
    1090          226 :         int TotRectCeilings = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Ceiling:Adiabatic");
    1091          226 :         int TotRectIZCeilings = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Ceiling:Interzone");
    1092          226 :         int TotRectGCFloors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Floor:GroundContact");
    1093          226 :         int TotRectIntFloors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Floor:Adiabatic");
    1094          226 :         int TotRectIZFloors = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Floor:Interzone");
    1095              : 
    1096          226 :         state.dataSurface->TotOSC = 0;
    1097              : 
    1098          226 :         int TotIntMassSurfaces = GetNumIntMassSurfaces(state);
    1099              : 
    1100          452 :         state.dataSurface->TotSurfaces = (TotDetachedFixed + TotDetachedBldg + TotRectDetachedFixed + TotRectDetachedBldg) * 2 + TotHTSurfs +
    1101          226 :                                          TotHTSubs + TotShdSubs * 2 + TotIntMassSurfaces + TotOverhangs * 2 + TotOverhangsProjection * 2 +
    1102          226 :                                          TotFins * 4 + TotFinsProjection * 4 + TotDetailedWalls + TotDetailedRoofs + TotDetailedFloors +
    1103          226 :                                          TotRectWindows + TotRectDoors + TotRectGlazedDoors + TotRectIZWindows + TotRectIZDoors +
    1104          226 :                                          TotRectIZGlazedDoors + TotRectExtWalls + TotRectIntWalls + TotRectIZWalls + TotRectUGWalls + TotRectRoofs +
    1105          226 :                                          TotRectCeilings + TotRectIZCeilings + TotRectGCFloors + TotRectIntFloors + TotRectIZFloors;
    1106              : 
    1107          226 :         state.dataSurfaceGeometry->SurfaceTmp.allocate(state.dataSurface->TotSurfaces); // Allocate the Surface derived type appropriately
    1108          226 :         state.dataSurfaceGeometry->UniqueSurfaceNames.reserve(state.dataSurface->TotSurfaces);
    1109              :         // SurfaceTmp structure is allocated via derived type initialization.
    1110              : 
    1111          226 :         int NumSurfs = 0;
    1112          226 :         int AddedSubSurfaces = 0;
    1113          226 :         state.dataErrTracking->AskForSurfacesReport = true;
    1114              : 
    1115          226 :         GetDetShdSurfaceData(state, ErrorsFound, NumSurfs, TotDetachedFixed, TotDetachedBldg);
    1116              : 
    1117          226 :         GetRectDetShdSurfaceData(state, ErrorsFound, NumSurfs, TotRectDetachedFixed, TotRectDetachedBldg);
    1118              : 
    1119          226 :         GetHTSurfaceData(state,
    1120              :                          ErrorsFound,
    1121              :                          NumSurfs,
    1122              :                          TotHTSurfs,
    1123              :                          TotDetailedWalls,
    1124              :                          TotDetailedRoofs,
    1125              :                          TotDetailedFloors,
    1126          226 :                          state.dataSurfaceGeometry->BaseSurfCls,
    1127          226 :                          state.dataSurfaceGeometry->BaseSurfIDs,
    1128              :                          NeedToAddSurfaces);
    1129              : 
    1130          226 :         GetRectSurfaces(state,
    1131              :                         ErrorsFound,
    1132              :                         NumSurfs,
    1133              :                         TotRectExtWalls,
    1134              :                         TotRectIntWalls,
    1135              :                         TotRectIZWalls,
    1136              :                         TotRectUGWalls,
    1137              :                         TotRectRoofs,
    1138              :                         TotRectCeilings,
    1139              :                         TotRectIZCeilings,
    1140              :                         TotRectGCFloors,
    1141              :                         TotRectIntFloors,
    1142              :                         TotRectIZFloors,
    1143          226 :                         state.dataSurfaceGeometry->BaseSurfIDs,
    1144              :                         NeedToAddSurfaces);
    1145              : 
    1146          226 :         GetHTSubSurfaceData(state,
    1147              :                             ErrorsFound,
    1148              :                             NumSurfs,
    1149              :                             TotHTSubs,
    1150          226 :                             state.dataSurfaceGeometry->SubSurfCls,
    1151          226 :                             state.dataSurfaceGeometry->SubSurfIDs,
    1152              :                             AddedSubSurfaces,
    1153              :                             NeedToAddSubSurfaces);
    1154              : 
    1155          226 :         GetRectSubSurfaces(state,
    1156              :                            ErrorsFound,
    1157              :                            NumSurfs,
    1158              :                            TotRectWindows,
    1159              :                            TotRectDoors,
    1160              :                            TotRectGlazedDoors,
    1161              :                            TotRectIZWindows,
    1162              :                            TotRectIZDoors,
    1163              :                            TotRectIZGlazedDoors,
    1164          226 :                            state.dataSurfaceGeometry->SubSurfIDs,
    1165              :                            AddedSubSurfaces,
    1166              :                            NeedToAddSubSurfaces);
    1167              : 
    1168          226 :         GetAttShdSurfaceData(state, ErrorsFound, NumSurfs, TotShdSubs);
    1169              : 
    1170          226 :         GetSimpleShdSurfaceData(state, ErrorsFound, NumSurfs, TotOverhangs, TotOverhangsProjection, TotFins, TotFinsProjection);
    1171              : 
    1172          226 :         GetIntMassSurfaceData(state, ErrorsFound, NumSurfs);
    1173              : 
    1174          226 :         state.dataSurface->TotSurfaces = NumSurfs + AddedSubSurfaces + NeedToAddSurfaces + NeedToAddSubSurfaces;
    1175              : 
    1176          226 :         if (ErrorsFound) {
    1177            4 :             ShowFatalError(state, format("{}Errors discovered, program terminates.", RoutineName));
    1178              :         }
    1179              : 
    1180          224 :         state.dataSurface->Surface.allocate(state.dataSurface->TotSurfaces); // Allocate the Surface derived type appropriately
    1181          224 :         state.dataSurface->SurfaceWindow.allocate(state.dataSurface->TotSurfaces);
    1182          224 :         state.dataSurface->surfShades.allocate(state.dataSurface->TotSurfaces);
    1183          224 :         AllocateSurfaceArrays(state);
    1184          224 :         AllocateSurfaceWindows(state, state.dataSurface->TotSurfaces);
    1185              : 
    1186              :         // Have to make room for added surfaces, if needed
    1187          224 :         int FirstTotalSurfaces = NumSurfs + AddedSubSurfaces;
    1188          224 :         if (NeedToAddSurfaces + NeedToAddSubSurfaces > 0) {
    1189            5 :             state.dataSurfaceGeometry->SurfaceTmp.redimension(state.dataSurface->TotSurfaces);
    1190            5 :             CurNewSurf = FirstTotalSurfaces;
    1191              :         }
    1192              : 
    1193              :         // add the "need to add" surfaces
    1194              :         // Debug    write(outputfiledebug,*) ' need to add ',NeedtoAddSurfaces+NeedToAddSubSurfaces
    1195         2470 :         for (int SurfNum = 1; SurfNum <= FirstTotalSurfaces; ++SurfNum) {
    1196         2246 :             auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    1197         2246 :             if ((surfTemp.ExtBoundCond != unenteredAdjacentZoneSurface) && (surfTemp.ExtBoundCond != unenteredAdjacentSpaceSurface)) continue;
    1198              :             // Need to add surface
    1199           16 :             ++CurNewSurf;
    1200              :             // Debug    write(outputfiledebug,*) ' adding surface=',curnewsurf
    1201           16 :             auto &newSurf = state.dataSurfaceGeometry->SurfaceTmp(CurNewSurf);
    1202           16 :             newSurf = surfTemp;
    1203              :             //  Basic parameters are the same for both surfaces.
    1204           16 :             if (surfTemp.ExtBoundCond == unenteredAdjacentZoneSurface) {
    1205           12 :                 int Found = Util::FindItemInList(surfTemp.ExtBoundCondName, state.dataHeatBal->Zone, state.dataGlobal->NumOfZones);
    1206           12 :                 if (Found == 0) continue;
    1207           12 :                 newSurf.Zone = Found;
    1208           12 :                 auto &newZone = state.dataHeatBal->Zone(Found);
    1209           12 :                 newSurf.ZoneName = newZone.Name;
    1210           12 :                 assert(newZone.spaceIndexes.size() >= 1);
    1211           12 :                 newSurf.spaceNum = 0; // clear this here and set later
    1212            4 :             } else if (surfTemp.ExtBoundCond == unenteredAdjacentSpaceSurface) {
    1213            4 :                 int Found = Util::FindItemInList(surfTemp.ExtBoundCondName, state.dataHeatBal->space, state.dataGlobal->numSpaces);
    1214            4 :                 if (Found == 0) continue;
    1215            4 :                 newSurf.spaceNum = Found;
    1216            4 :                 int zoneNum = state.dataHeatBal->space(Found).zoneNum;
    1217            4 :                 newSurf.Zone = zoneNum;
    1218            4 :                 newSurf.ZoneName = state.dataHeatBal->Zone(zoneNum).Name;
    1219              :             }
    1220              :             // Reverse Construction
    1221           16 :             newSurf.Construction = DataHeatBalance::AssignReverseConstructionNumber(state, surfTemp.Construction, SurfError);
    1222           16 :             newSurf.ConstructionStoredInputValue = newSurf.Construction;
    1223              :             // Reverse Vertices
    1224           16 :             int NVert = surfTemp.Sides;
    1225           80 :             for (int Vert = 1; Vert <= surfTemp.Sides; ++Vert) {
    1226           64 :                 newSurf.Vertex(Vert) = surfTemp.Vertex(NVert);
    1227           64 :                 --NVert;
    1228              :             }
    1229           16 :             if (newSurf.Sides > 2) {
    1230           16 :                 Vectors::CreateNewellAreaVector(newSurf.Vertex, newSurf.Sides, newSurf.NewellAreaVector);
    1231           16 :                 newSurf.GrossArea = Vectors::VecLength(newSurf.NewellAreaVector);
    1232           16 :                 newSurf.Area = newSurf.GrossArea;
    1233           16 :                 newSurf.NetAreaShadowCalc = newSurf.Area;
    1234           16 :                 Vectors::CreateNewellSurfaceNormalVector(newSurf.Vertex, newSurf.Sides, newSurf.NewellSurfaceNormalVector);
    1235           16 :                 Vectors::DetermineAzimuthAndTilt(
    1236           16 :                     newSurf.Vertex, SurfWorldAz, SurfTilt, newSurf.lcsx, newSurf.lcsy, newSurf.lcsz, newSurf.NewellSurfaceNormalVector);
    1237           16 :                 newSurf.Azimuth = SurfWorldAz;
    1238           16 :                 newSurf.Tilt = SurfTilt;
    1239           16 :                 newSurf.convOrientation = Convect::GetSurfConvOrientation(newSurf.Tilt);
    1240              : 
    1241              :                 // Sine and cosine of azimuth and tilt
    1242           16 :                 newSurf.SinAzim = std::sin(SurfWorldAz * Constant::DegToRad);
    1243           16 :                 newSurf.CosAzim = std::cos(SurfWorldAz * Constant::DegToRad);
    1244           16 :                 newSurf.SinTilt = std::sin(SurfTilt * Constant::DegToRad);
    1245           16 :                 newSurf.CosTilt = std::cos(SurfTilt * Constant::DegToRad);
    1246              :                 // Outward normal unit vector (pointing away from room)
    1247           16 :                 newSurf.OutNormVec = newSurf.NewellSurfaceNormalVector;
    1248           64 :                 for (int n = 1; n <= 3; ++n) {
    1249           48 :                     if (std::abs(newSurf.OutNormVec(n) - 1.0) < 1.e-06) newSurf.OutNormVec(n) = +1.0;
    1250           48 :                     if (std::abs(newSurf.OutNormVec(n) + 1.0) < 1.e-06) newSurf.OutNormVec(n) = -1.0;
    1251           48 :                     if (std::abs(newSurf.OutNormVec(n)) < 1.e-06) newSurf.OutNormVec(n) = 0.0;
    1252              :                 }
    1253              : 
    1254              :                 // Can perform tests on this surface here
    1255           16 :                 newSurf.ViewFactorSky = 0.5 * (1.0 + newSurf.CosTilt);
    1256           16 :                 newSurf.ViewFactorGround = 0.5 * (1.0 - newSurf.CosTilt);
    1257              : 
    1258              :                 // The following IR view factors are modified in subr. SkyDifSolarShading if there are shadowing
    1259              :                 // surfaces
    1260           16 :                 newSurf.ViewFactorSkyIR = newSurf.ViewFactorSky;
    1261           16 :                 newSurf.ViewFactorGroundIR = 0.5 * (1.0 - newSurf.CosTilt);
    1262              :             }
    1263              : 
    1264              :             // Change Name
    1265           16 :             newSurf.Name = "iz-" + surfTemp.Name;
    1266              :             // Debug   write(outputfiledebug,*) ' new surf name=',TRIM(SurfaceTmp(CurNewSurf)%Name)
    1267              :             // Debug   write(outputfiledebug,*) ' new surf in zone=',TRIM(surfacetmp(curnewsurf)%zoneName)
    1268           16 :             newSurf.ExtBoundCond = unreconciledZoneSurface;
    1269           16 :             surfTemp.ExtBoundCond = unreconciledZoneSurface;
    1270           16 :             newSurf.ExtBoundCondName = surfTemp.Name;
    1271           16 :             surfTemp.ExtBoundCondName = newSurf.Name;
    1272           16 :             if (newSurf.Class == SurfaceClass::Roof || newSurf.Class == SurfaceClass::Wall || newSurf.Class == SurfaceClass::Floor) {
    1273              :                 // base surface
    1274           10 :                 if (surfTemp.Class == SurfaceClass::Roof) {
    1275            1 :                     newSurf.Class = SurfaceClass::Floor;
    1276              :                     // Debug          write(outputfiledebug,*) ' new surfaces is a floor'
    1277            9 :                 } else if (surfTemp.Class == SurfaceClass::Floor) {
    1278            3 :                     newSurf.Class = SurfaceClass::Roof;
    1279              :                     // Debug          write(outputfiledebug,*) ' new surfaces is a roof'
    1280              :                 }
    1281           10 :                 newSurf.BaseSurf = CurNewSurf;
    1282           10 :                 newSurf.BaseSurfName = newSurf.Name;
    1283              :                 // Debug        write(outputfiledebug,*) ' basesurf, extboundcondname=',TRIM(SurfaceTmp(CurNewSurf)%ExtBoundCondName)
    1284              :             } else {
    1285              :                 // subsurface
    1286              :                 int Found =
    1287            6 :                     Util::FindItemInList("iz-" + surfTemp.BaseSurfName, state.dataSurfaceGeometry->SurfaceTmp, FirstTotalSurfaces + CurNewSurf - 1);
    1288            6 :                 if (Found > 0) {
    1289            6 :                     newSurf.BaseSurfName = "iz-" + surfTemp.BaseSurfName;
    1290            6 :                     newSurf.BaseSurf = Found;
    1291            6 :                     auto &foundBaseSurf = state.dataSurfaceGeometry->SurfaceTmp(Found);
    1292            6 :                     foundBaseSurf.Area -= newSurf.Area;
    1293            6 :                     if (newSurf.Class == SurfaceClass::Window || newSurf.Class == SurfaceClass::GlassDoor) {
    1294            3 :                         foundBaseSurf.NetAreaShadowCalc -= newSurf.Area / newSurf.Multiplier;
    1295              :                     } else { // Door, TDD:Diffuser, TDD:DOME
    1296            3 :                         foundBaseSurf.NetAreaShadowCalc -= newSurf.Area;
    1297              :                     }
    1298            6 :                     newSurf.ExtBoundCond = foundBaseSurf.ExtBoundCond;
    1299            6 :                     newSurf.ExtBoundCondName = surfTemp.Name;
    1300            6 :                     newSurf.ExtSolar = foundBaseSurf.ExtSolar;
    1301            6 :                     newSurf.ExtWind = foundBaseSurf.ExtWind;
    1302            6 :                     newSurf.Zone = foundBaseSurf.Zone;
    1303            6 :                     newSurf.ZoneName = foundBaseSurf.ZoneName;
    1304            6 :                     newSurf.spaceNum = foundBaseSurf.spaceNum;
    1305            6 :                     newSurf.OSCPtr = foundBaseSurf.OSCPtr;
    1306              :                     // Debug        write(outputfiledebug,*) ' subsurf, extboundcondname=',TRIM(SurfaceTmp(CurNewSurf)%ExtBoundCondName)
    1307              :                     // Debug        write(outputfiledebug,*) ' subsurf, basesurf=',TRIM('iz-'//SurfaceTmp(SurfNum)%BaseSurfName)
    1308              :                 } else {
    1309            0 :                     ShowSevereError(state,
    1310            0 :                                     format("{}Adding unentered subsurface, could not find base surface=iz-{}", RoutineName, surfTemp.BaseSurfName));
    1311            0 :                     SurfError = true;
    1312              :                 }
    1313              :             }
    1314              :         }
    1315              :         //**********************************************************************************
    1316              :         // After all of the surfaces have been defined then the base surfaces for the
    1317              :         // sub-surfaces can be defined.  Loop through surfaces and match with the sub-surface
    1318              :         // names.
    1319         2486 :         for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    1320         2262 :             auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    1321         2262 :             if (!surfTemp.HeatTransSurf) continue;
    1322              : 
    1323         2178 :             int Found = 0;
    1324              :             // why are we doing this again?  this should have already been done.
    1325         2178 :             if (Util::SameString(surfTemp.BaseSurfName, surfTemp.Name)) {
    1326         1951 :                 Found = SurfNum;
    1327              :             } else {
    1328          227 :                 Found = Util::FindItemInList(surfTemp.BaseSurfName, state.dataSurfaceGeometry->SurfaceTmp, state.dataSurface->TotSurfaces);
    1329              :             }
    1330         2178 :             if (Found > 0) {
    1331         2178 :                 surfTemp.BaseSurf = Found;
    1332         2178 :                 if (SurfNum != Found) { // for subsurfaces
    1333          227 :                     if (surfTemp.HeatTransSurf) ++state.dataSurfaceGeometry->SurfaceTmp(Found).NumSubSurfaces;
    1334          227 :                     if (surfTemp.Class < SurfaceClass::Window || surfTemp.Class > SurfaceClass::TDD_Diffuser) {
    1335            0 :                         if (surfTemp.Class == SurfaceClass::None) {
    1336            0 :                             ShowSevereError(state, format("{}Invalid SubSurface detected, Surface={}", RoutineName, surfTemp.Name));
    1337              :                         } else {
    1338            0 :                             ShowSevereError(state,
    1339            0 :                                             format("{}Invalid SubSurface detected, Surface={}, class={} invalid class for subsurface",
    1340              :                                                    RoutineName,
    1341            0 :                                                    surfTemp.Name,
    1342            0 :                                                    state.dataSurfaceGeometry->BaseSurfCls(int(surfTemp.Class))));
    1343            0 :                             SurfError = true;
    1344              :                         }
    1345              :                     }
    1346              :                 }
    1347              :             }
    1348              : 
    1349              :         } // ...end of the Surface DO loop for finding BaseSurf
    1350              :         //**********************************************************************************
    1351              :         // The surfaces need to be hierarchical by space.  Input is allowed to be in any order.  In
    1352              :         // this section the surfaces are reordered into:
    1353              :         //    All shadowing surfaces (if mirrored, Mir- surface follows immediately after original)
    1354              :         //      Shading:Site
    1355              :         //      Shading:Building
    1356              :         //      Shading:space (and variants)
    1357              :         //    For each space:
    1358              :         //      Walls
    1359              :         //      Floors
    1360              :         //      Roofs/Ceilings
    1361              :         //      Internal Mass
    1362              :         //      Non-Window subsurfaces (including doors)
    1363              :         //      Window subsurfaces (including TubularDaylightingDiffusers)
    1364              :         //      TubularDaylightingDomes
    1365              :         //    After reordering, MovedSurfs should equal TotSurfaces
    1366              : 
    1367              :         // For reporting purposes, the legacy surface order is also saved in DataSurfaces::AllSurfaceListReportOrder:
    1368              :         //    All shadowing surfaces (if mirrored, Mir- surface follows immediately after original)
    1369              :         //      Shading:Site
    1370              :         //      Shading:Building
    1371              :         //      Shading:Zone (and variants)
    1372              :         //    For each zone:
    1373              :         //      Walls
    1374              :         //        subsurfaces for each wall (windows, doors, in input order, not sorted) follow the base surface
    1375              :         //      Floors
    1376              :         //        subsurfaces for each floor (windows, doors, in input order, not sorted) follow the base surface
    1377              :         //      Roofs/Ceilings
    1378              :         //        subsurfaces for each roof/ceiling (windows, doors, in input order, not sorted) follow the base surface
    1379              :         //      Internal Mass
    1380              :         //    After reordering, MovedSurfs should equal TotSurfaces
    1381              : 
    1382          224 :         MovedSurfs = 0;
    1383          224 :         Array1D<bool> SurfaceTmpClassMoved; // Tmp class is moved
    1384          224 :         SurfaceTmpClassMoved.dimension(state.dataSurface->TotSurfaces, false);
    1385          224 :         state.dataSurface->AllSurfaceListReportOrder.reserve(state.dataSurface->TotSurfaces);
    1386              : 
    1387          224 :         CreateMissingSpaces(state, state.dataSurfaceGeometry->SurfaceTmp);
    1388              : 
    1389              :         // Old SurfNum to New SurfNum
    1390              :         // Old = order in state.dataSurfaceGeometry->SurfaceTmp
    1391              :         // New = order in state.dataSurface->Surface
    1392          224 :         EPVector<int> oldToNewSurfNums;
    1393          224 :         oldToNewSurfNums.resize(state.dataSurface->TotSurfaces, -1);
    1394              : 
    1395              :         // Move all shading Surfaces to Front
    1396         2486 :         for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    1397         2262 :             auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    1398         2262 :             if (surfTemp.Class != SurfaceClass::Detached_F && surfTemp.Class != SurfaceClass::Detached_B && surfTemp.Class != SurfaceClass::Shading)
    1399         2178 :                 continue;
    1400              : 
    1401              :             //  A shading surface
    1402           84 :             ++MovedSurfs;
    1403              :             // Store list of moved surface numbers in reporting order
    1404           84 :             state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    1405           84 :             SurfaceTmpClassMoved(SurfNum) = true; //'Moved'
    1406           84 :             state.dataSurface->AllSurfaceListReportOrder.push_back(SurfNum);
    1407           84 :             oldToNewSurfNums(SurfNum) = MovedSurfs;
    1408              :         }
    1409              : 
    1410              :         //  For each zone
    1411              : 
    1412          578 :         for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
    1413          730 :             for (int spaceNum : state.dataHeatBal->Zone(ZoneNum).spaceIndexes) {
    1414              :                 // Group air boundary surfaces first within each space
    1415         6667 :                 for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    1416         6291 :                     auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    1417         6291 :                     if (SurfaceTmpClassMoved(SurfNum)) continue;
    1418         4085 :                     if (surfTemp.spaceNum != spaceNum) continue;
    1419         2178 :                     int constNum = surfTemp.Construction;
    1420         2178 :                     if (constNum == 0) continue;
    1421         2178 :                     if (!state.dataConstruction->Construct(constNum).TypeIsAirBoundary) continue;
    1422              : 
    1423              :                     //  An air boundary surface
    1424           42 :                     surfTemp.IsAirBoundarySurf = true;
    1425           42 :                     ++MovedSurfs;
    1426           42 :                     state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    1427              :                     //  If base Surface Type (Wall, Floor, Roof/Ceiling)
    1428           42 :                     if ((surfTemp.Class == state.dataSurfaceGeometry->BaseSurfIDs(1)) ||
    1429           47 :                         (surfTemp.Class == state.dataSurfaceGeometry->BaseSurfIDs(2)) ||
    1430            5 :                         (surfTemp.Class == state.dataSurfaceGeometry->BaseSurfIDs(3))) {
    1431              :                         // Store list of moved surface numbers in reporting order. We use the old position, we'll reconcile later
    1432              :                         // We don't do it for Air Door/Air Windows yet, we want them listed below each base surf they belong to
    1433           38 :                         state.dataSurface->AllSurfaceListReportOrder.push_back(SurfNum);
    1434              :                     }
    1435           42 :                     oldToNewSurfNums(SurfNum) = MovedSurfs;
    1436           42 :                     SurfaceTmpClassMoved(SurfNum) = true; //'Moved'
    1437              :                 }
    1438              : 
    1439              :                 //  For each Base Surface Type (Wall, Floor, Roof/Ceiling) - put these first
    1440              : 
    1441         1504 :                 for (const DataSurfaces::SurfaceClass Loop : state.dataSurfaceGeometry->BaseSurfIDs) {
    1442              : 
    1443        20001 :                     for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    1444        18873 :                         auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    1445              : 
    1446        18873 :                         if (SurfaceTmpClassMoved(SurfNum)) continue;
    1447         9444 :                         if (surfTemp.Zone == 0) continue;
    1448              : 
    1449         9444 :                         if (surfTemp.spaceNum != spaceNum) continue;
    1450         3723 :                         if (surfTemp.Class != Loop) continue;
    1451              : 
    1452         1897 :                         ++MovedSurfs;
    1453         1897 :                         state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    1454         1897 :                         oldToNewSurfNums(SurfNum) = MovedSurfs;
    1455         1897 :                         SurfaceTmpClassMoved(SurfNum) = true; // 'Moved'
    1456              :                         // Store list of moved surface numbers in order reporting order (subsurfaces follow their base surface)
    1457         1897 :                         state.dataSurface->AllSurfaceListReportOrder.push_back(SurfNum);
    1458              : 
    1459              :                         //  Find all subsurfaces to this surface - just to update Report them in order
    1460        41241 :                         for (int SubSurfNum = 1; SubSurfNum <= state.dataSurface->TotSurfaces; ++SubSurfNum) {
    1461              :                             // Gotta avoid pushing myself again!
    1462        39344 :                             if (SubSurfNum == SurfNum) continue;
    1463              :                             // We don't check if already moved, because we didn't add them to AllSurfaceListReportOrder above!
    1464        37447 :                             if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).Zone == 0) continue;
    1465        36287 :                             if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).BaseSurf != SurfNum) continue;
    1466              :                             // Add original sub-surface numbers as placeholders in surface list for reporting
    1467          227 :                             state.dataSurface->AllSurfaceListReportOrder.push_back(SubSurfNum);
    1468              :                         }
    1469              :                     }
    1470              :                 }
    1471              : 
    1472              :                 // Internal mass goes next
    1473         6667 :                 for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    1474         6291 :                     if (SurfaceTmpClassMoved(SurfNum)) continue;
    1475              : 
    1476         2146 :                     auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    1477         2146 :                     if (surfTemp.spaceNum != spaceNum) continue;
    1478          239 :                     if (surfTemp.Class != SurfaceClass::IntMass) continue;
    1479           16 :                     ++MovedSurfs;
    1480           16 :                     state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    1481           16 :                     oldToNewSurfNums(SurfNum) = MovedSurfs;
    1482           16 :                     SurfaceTmpClassMoved(SurfNum) = true; // 'Moved'
    1483              :                     // Store list of moved surface numbers in reporting order
    1484           16 :                     state.dataSurface->AllSurfaceListReportOrder.push_back(SurfNum);
    1485              :                 }
    1486              : 
    1487              :                 // Opaque door goes next
    1488         6667 :                 for (int SubSurfNum = 1; SubSurfNum <= state.dataSurface->TotSurfaces; ++SubSurfNum) {
    1489              : 
    1490         6291 :                     if (SurfaceTmpClassMoved(SubSurfNum)) continue;
    1491         2130 :                     if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).spaceNum != spaceNum) continue;
    1492          223 :                     if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).Class != SurfaceClass::Door) continue;
    1493              : 
    1494           21 :                     ++MovedSurfs;
    1495           21 :                     state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum);
    1496           21 :                     oldToNewSurfNums(SubSurfNum) = MovedSurfs;
    1497           21 :                     SurfaceTmpClassMoved(SubSurfNum) = true; // 'Moved'
    1498              :                 }
    1499              : 
    1500              :                 // The exterior window subsurfaces (includes SurfaceClass::Window and SurfaceClass::GlassDoor) goes next
    1501         6667 :                 for (int SubSurfNum = 1; SubSurfNum <= state.dataSurface->TotSurfaces; ++SubSurfNum) {
    1502              : 
    1503         6291 :                     if (SurfaceTmpClassMoved(SubSurfNum)) continue;
    1504         2109 :                     if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).spaceNum != spaceNum) continue;
    1505          202 :                     if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).ExtBoundCond > 0) continue; // Exterior window
    1506          225 :                     if ((state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).Class != SurfaceClass::Window) &&
    1507           23 :                         (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).Class != SurfaceClass::GlassDoor))
    1508           13 :                         continue;
    1509              : 
    1510          189 :                     ++MovedSurfs;
    1511          189 :                     state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum);
    1512          189 :                     oldToNewSurfNums(SubSurfNum) = MovedSurfs;
    1513          189 :                     SurfaceTmpClassMoved(SubSurfNum) = true; // 'Moved'
    1514              :                 }
    1515              : 
    1516              :                 // The interior window subsurfaces (includes SurfaceClass::Window and SurfaceClass::GlassDoor) goes next
    1517         6667 :                 for (int SubSurfNum = 1; SubSurfNum <= state.dataSurface->TotSurfaces; ++SubSurfNum) {
    1518              : 
    1519         6291 :                     if (SurfaceTmpClassMoved(SubSurfNum)) continue;
    1520         1920 :                     if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).spaceNum != spaceNum) continue;
    1521           13 :                     if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).ExtBoundCond <= 0) continue;
    1522            0 :                     if ((state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).Class != SurfaceClass::Window) &&
    1523            0 :                         (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).Class != SurfaceClass::GlassDoor))
    1524            0 :                         continue;
    1525              : 
    1526            0 :                     ++MovedSurfs;
    1527            0 :                     state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum);
    1528            0 :                     oldToNewSurfNums(SubSurfNum) = MovedSurfs;
    1529            0 :                     SurfaceTmpClassMoved(SubSurfNum) = true; // 'Moved'
    1530              :                 }
    1531              : 
    1532              :                 // The SurfaceClass::TDD_Diffuser (OriginalClass = Window) goes next
    1533         6667 :                 for (int SubSurfNum = 1; SubSurfNum <= state.dataSurface->TotSurfaces; ++SubSurfNum) {
    1534              : 
    1535         6291 :                     if (SurfaceTmpClassMoved(SubSurfNum)) continue;
    1536         1920 :                     if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).spaceNum != spaceNum) continue;
    1537           13 :                     if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).Class != SurfaceClass::TDD_Diffuser) continue;
    1538              : 
    1539            6 :                     ++MovedSurfs;
    1540            6 :                     state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum);
    1541            6 :                     oldToNewSurfNums(SubSurfNum) = MovedSurfs;
    1542            6 :                     SurfaceTmpClassMoved(SubSurfNum) = true; // 'Moved'
    1543              :                 }
    1544              : 
    1545              :                 // Last but not least, SurfaceClass::TDD_Dome
    1546         6667 :                 for (int SubSurfNum = 1; SubSurfNum <= state.dataSurface->TotSurfaces; ++SubSurfNum) {
    1547              : 
    1548         6291 :                     if (SurfaceTmpClassMoved(SubSurfNum)) continue;
    1549         1914 :                     if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).spaceNum != spaceNum) continue;
    1550            7 :                     if (state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum).Class != SurfaceClass::TDD_Dome) continue;
    1551              : 
    1552            7 :                     ++MovedSurfs;
    1553            7 :                     state.dataSurface->Surface(MovedSurfs) = state.dataSurfaceGeometry->SurfaceTmp(SubSurfNum);
    1554            7 :                     oldToNewSurfNums(SubSurfNum) = MovedSurfs;
    1555            7 :                     SurfaceTmpClassMoved(SubSurfNum) = true; // 'Moved'
    1556              :                 }
    1557              :             }
    1558              :         }
    1559              : 
    1560              :         // Validity checking
    1561          224 :         assert(state.dataSurface->TotSurfaces == MovedSurfs);
    1562          224 :         assert(state.dataSurface->TotSurfaces == static_cast<int>(state.dataSurface->AllSurfaceListReportOrder.size()));
    1563          224 :         assert(state.dataSurface->TotSurfaces == static_cast<int>(oldToNewSurfNums.size()));
    1564              : 
    1565              :         // Assert validity of indices
    1566         2486 :         assert(std::find_if(state.dataSurface->AllSurfaceListReportOrder.cbegin(), state.dataSurface->AllSurfaceListReportOrder.cend(), [](int i) {
    1567              :                    return i < 1;
    1568              :                }) == state.dataSurface->AllSurfaceListReportOrder.cend());
    1569              : 
    1570         2486 :         assert(std::find_if(oldToNewSurfNums.cbegin(), oldToNewSurfNums.cend(), [](int i) { return i < 1; }) == oldToNewSurfNums.cend());
    1571              : 
    1572          224 :         if (MovedSurfs != state.dataSurface->TotSurfaces) {
    1573            0 :             ShowSevereError(
    1574              :                 state,
    1575            0 :                 format("{}Reordered # of Surfaces ({}) not = Total # of Surfaces ({})", RoutineName, MovedSurfs, state.dataSurface->TotSurfaces));
    1576            0 :             SurfError = true;
    1577            0 :             for (int Loop = 1; Loop <= state.dataSurface->TotSurfaces; ++Loop) {
    1578            0 :                 if (!SurfaceTmpClassMoved(Loop) && state.dataSurfaceGeometry->SurfaceTmp(Loop).Class == SurfaceClass::Invalid) {
    1579            0 :                     ShowSevereError(state,
    1580            0 :                                     format("{}Error in Surface= \"{} indicated Zone=\"{}\"",
    1581              :                                            RoutineName,
    1582            0 :                                            state.dataSurfaceGeometry->SurfaceTmp(Loop).Name,
    1583            0 :                                            state.dataSurfaceGeometry->SurfaceTmp(Loop).ZoneName));
    1584              :                 }
    1585              :             }
    1586            0 :             ShowWarningError(
    1587            0 :                 state, format("{}Remaining surface checks will use \"reordered number of surfaces\", not number of original surfaces", RoutineName));
    1588              :         }
    1589              : 
    1590              :         // Realign the relationship: surface to base surface
    1591         2486 :         for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    1592         2262 :             auto &movedSurf = state.dataSurface->Surface(SurfNum);
    1593         2262 :             if (movedSurf.BaseSurf > 0) {
    1594         2178 :                 int newBaseSurfNum = oldToNewSurfNums(movedSurf.BaseSurf);
    1595         2178 :                 movedSurf.BaseSurf = newBaseSurfNum;
    1596              : 
    1597         2178 :                 if (newBaseSurfNum < 1) {
    1598            0 :                     ShowFatalError(
    1599              :                         state,
    1600            0 :                         format("{}Couldn't find the new Surface Number for surface index {} named '{}'. Looking for BaseSurf old index of {}",
    1601              :                                RoutineName,
    1602              :                                SurfNum,
    1603            0 :                                movedSurf.Name,
    1604            0 :                                movedSurf.BaseSurf));
    1605              :                 }
    1606              :             }
    1607         2262 :             auto &reportOrderNum = state.dataSurface->AllSurfaceListReportOrder[SurfNum - 1];
    1608         2262 :             if (reportOrderNum > 0) {
    1609         2262 :                 int newReportOrderNum = oldToNewSurfNums(reportOrderNum);
    1610         2262 :                 reportOrderNum = newReportOrderNum;
    1611              :             }
    1612              :         }
    1613              : 
    1614          224 :         state.dataSurfaceGeometry->SurfaceTmp.deallocate(); // DeAllocate the Temp Surface derived type
    1615              : 
    1616          224 :         createSpaceSurfaceLists(state);
    1617              : 
    1618              :         //  For each Base Surface Type (Wall, Floor, Roof)
    1619              : 
    1620          896 :         for (const DataSurfaces::SurfaceClass Loop : state.dataSurfaceGeometry->BaseSurfIDs) {
    1621         7458 :             for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    1622              : 
    1623         6786 :                 if (state.dataSurface->Surface(SurfNum).Zone == 0) continue;
    1624              : 
    1625         6534 :                 if (state.dataSurface->Surface(SurfNum).Class != Loop) continue;
    1626              : 
    1627              :                 //  Find all subsurfaces to this surface
    1628        41861 :                 for (int SubSurfNum = 1; SubSurfNum <= state.dataSurface->TotSurfaces; ++SubSurfNum) {
    1629              : 
    1630        39926 :                     if (SurfNum == SubSurfNum) continue;
    1631        37991 :                     if (state.dataSurface->Surface(SubSurfNum).Zone == 0) continue;
    1632        36831 :                     if (state.dataSurface->Surface(SubSurfNum).BaseSurf != SurfNum) continue;
    1633              : 
    1634              :                     // Check facing angle of Sub compared to base
    1635          227 :                     checkSubSurfAzTiltNorm(state, state.dataSurface->Surface(SurfNum), state.dataSurface->Surface(SubSurfNum), subSurfaceError);
    1636          227 :                     if (subSurfaceError) SurfError = true;
    1637              :                 }
    1638              :             }
    1639              :         }
    1640              : 
    1641              :         //**********************************************************************************
    1642              :         // Now, match up interzone surfaces
    1643          224 :         NonMatch = false;
    1644          224 :         izConstDiffMsg = false;
    1645         2486 :         for (int SurfNum = 1; SurfNum <= MovedSurfs; ++SurfNum) { // TotSurfaces
    1646              :             //  Clean up Shading Surfaces, make sure they don't go through here.
    1647         2262 :             if (!state.dataSurface->Surface(SurfNum).HeatTransSurf) continue;
    1648              :             //   If other surface, match it up
    1649              :             //  Both interzone and "internal" surfaces have this pointer set
    1650              :             //  Internal surfaces point to themselves, Interzone to another
    1651         2178 :             if (state.dataSurface->Surface(SurfNum).ExtBoundCond == unreconciledZoneSurface) {
    1652          440 :                 if (not_blank(state.dataSurface->Surface(SurfNum).ExtBoundCondName)) {
    1653          440 :                     int Found = 0;
    1654          440 :                     if (state.dataSurface->Surface(SurfNum).ExtBoundCondName == state.dataSurface->Surface(SurfNum).Name) {
    1655          245 :                         Found = SurfNum;
    1656              :                     } else {
    1657          195 :                         Found = Util::FindItemInList(state.dataSurface->Surface(SurfNum).ExtBoundCondName, state.dataSurface->Surface, MovedSurfs);
    1658              :                     }
    1659          440 :                     if (Found != 0) {
    1660          440 :                         state.dataSurface->Surface(SurfNum).ExtBoundCond = Found;
    1661              :                         // Check that matching surface is also "OtherZoneSurface"
    1662          633 :                         if (state.dataSurface->Surface(Found).ExtBoundCond <= 0 &&
    1663          193 :                             state.dataSurface->Surface(Found).ExtBoundCond != unreconciledZoneSurface) {
    1664            0 :                             ShowSevereError(state, format("{}Potential \"OtherZoneSurface\" is not matched correctly:", RoutineName));
    1665              : 
    1666            0 :                             ShowContinueError(state,
    1667            0 :                                               format("Surface={}, Zone={}",
    1668            0 :                                                      state.dataSurface->Surface(SurfNum).Name,
    1669            0 :                                                      state.dataSurface->Surface(SurfNum).ZoneName));
    1670            0 :                             ShowContinueError(state,
    1671            0 :                                               format("Nonmatched Other/InterZone Surface={}, Zone={}",
    1672            0 :                                                      state.dataSurface->Surface(Found).Name,
    1673            0 :                                                      state.dataSurface->Surface(Found).ZoneName));
    1674            0 :                             SurfError = true;
    1675              :                         }
    1676              :                         // Check that matching interzone surface has construction with reversed layers
    1677          440 :                         if (Found != SurfNum) { // Interzone surface
    1678              :                             // Make sure different zones too (CR 4110)
    1679          195 :                             if (state.dataSurface->Surface(SurfNum).spaceNum == state.dataSurface->Surface(Found).spaceNum) {
    1680            1 :                                 ++state.dataSurfaceGeometry->ErrCount2;
    1681            1 :                                 if (state.dataSurfaceGeometry->ErrCount2 == 1 && !state.dataGlobal->DisplayExtraWarnings) {
    1682            2 :                                     ShowWarningError(state,
    1683            2 :                                                      format("{}CAUTION -- Interspace surfaces are occurring in the same space(s).", RoutineName));
    1684            3 :                                     ShowContinueError(
    1685              :                                         state, "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on individual occurrences.");
    1686              :                                 }
    1687            1 :                                 if (state.dataGlobal->DisplayExtraWarnings) {
    1688            0 :                                     ShowWarningError(state, format("{}CAUTION -- Interspace surfaces are usually in different spaces", RoutineName));
    1689            0 :                                     ShowContinueError(state,
    1690            0 :                                                       format("Surface={}, Space={}, Zone={}",
    1691            0 :                                                              state.dataSurface->Surface(SurfNum).Name,
    1692            0 :                                                              state.dataHeatBal->space(state.dataSurface->Surface(SurfNum).spaceNum).Name,
    1693            0 :                                                              state.dataSurface->Surface(SurfNum).ZoneName));
    1694            0 :                                     ShowContinueError(state,
    1695            0 :                                                       format("Surface={}, Space={}, Zone={}",
    1696            0 :                                                              state.dataSurface->Surface(Found).Name,
    1697            0 :                                                              state.dataHeatBal->space(state.dataSurface->Surface(Found).spaceNum).Name,
    1698            0 :                                                              state.dataSurface->Surface(Found).ZoneName));
    1699              :                                 }
    1700              :                             }
    1701          195 :                             int ConstrNum = state.dataSurface->Surface(SurfNum).Construction;
    1702          195 :                             int ConstrNumFound = state.dataSurface->Surface(Found).Construction;
    1703          195 :                             if (ConstrNum <= 0 || ConstrNumFound <= 0) continue;
    1704          195 :                             if (state.dataConstruction->Construct(ConstrNum).ReverseConstructionNumLayersWarning &&
    1705            0 :                                 state.dataConstruction->Construct(ConstrNumFound).ReverseConstructionNumLayersWarning)
    1706            0 :                                 continue;
    1707          195 :                             if (state.dataConstruction->Construct(ConstrNum).ReverseConstructionLayersOrderWarning &&
    1708            0 :                                 state.dataConstruction->Construct(ConstrNumFound).ReverseConstructionLayersOrderWarning)
    1709            0 :                                 continue;
    1710          195 :                             TotLay = state.dataConstruction->Construct(ConstrNum).TotLayers;
    1711          195 :                             TotLayFound = state.dataConstruction->Construct(ConstrNumFound).TotLayers;
    1712          195 :                             if (TotLay != TotLayFound) { // Different number of layers
    1713              :                                 // match on like Uvalues (nominal)
    1714            0 :                                 if (std::abs(state.dataHeatBal->NominalU(ConstrNum) - state.dataHeatBal->NominalU(ConstrNumFound)) > 0.001) {
    1715            0 :                                     ShowSevereError(state,
    1716            0 :                                                     format("{}Construction {} of interzone surface {} does not have the same number of layers as the "
    1717              :                                                            "construction {} of adjacent surface {}",
    1718              :                                                            RoutineName,
    1719            0 :                                                            state.dataConstruction->Construct(ConstrNum).Name,
    1720            0 :                                                            state.dataSurface->Surface(SurfNum).Name,
    1721            0 :                                                            state.dataConstruction->Construct(ConstrNumFound).Name,
    1722            0 :                                                            state.dataSurface->Surface(Found).Name));
    1723            0 :                                     if (!state.dataConstruction->Construct(ConstrNum).ReverseConstructionNumLayersWarning ||
    1724            0 :                                         !state.dataConstruction->Construct(ConstrNumFound).ReverseConstructionNumLayersWarning) {
    1725            0 :                                         ShowContinueError(state, "...this problem for this pair will not be reported again.");
    1726            0 :                                         state.dataConstruction->Construct(ConstrNum).ReverseConstructionNumLayersWarning = true;
    1727            0 :                                         state.dataConstruction->Construct(ConstrNumFound).ReverseConstructionNumLayersWarning = true;
    1728              :                                     }
    1729            0 :                                     SurfError = true;
    1730              :                                 }
    1731              :                             } else { // Same number of layers; check for reverse layers
    1732              :                                 // check layers as number of layers is the same
    1733          195 :                                 izConstDiff = false;
    1734              :                                 // ok if same nominal U
    1735          195 :                                 CheckForReversedLayers(state, izConstDiff, ConstrNum, ConstrNumFound, TotLay);
    1736          195 :                                 if (izConstDiff &&
    1737            0 :                                     std::abs(state.dataHeatBal->NominalU(ConstrNum) - state.dataHeatBal->NominalU(ConstrNumFound)) > 0.001) {
    1738            0 :                                     ShowSevereError(state,
    1739            0 :                                                     format("{}Construction {} of interzone surface {} does not have the same materials in the "
    1740              :                                                            "reverse order as the construction {} of adjacent surface {}",
    1741              :                                                            RoutineName,
    1742            0 :                                                            state.dataConstruction->Construct(ConstrNum).Name,
    1743            0 :                                                            state.dataSurface->Surface(SurfNum).Name,
    1744            0 :                                                            state.dataConstruction->Construct(ConstrNumFound).Name,
    1745            0 :                                                            state.dataSurface->Surface(Found).Name));
    1746            0 :                                     ShowContinueError(state,
    1747              :                                                       "or the properties of the reversed layers are not correct due to differing layer front and "
    1748              :                                                       "back side values");
    1749            0 :                                     if (!state.dataConstruction->Construct(ConstrNum).ReverseConstructionLayersOrderWarning ||
    1750            0 :                                         !state.dataConstruction->Construct(ConstrNumFound).ReverseConstructionLayersOrderWarning) {
    1751            0 :                                         ShowContinueError(state, "...this problem for this pair will not be reported again.");
    1752            0 :                                         state.dataConstruction->Construct(ConstrNum).ReverseConstructionLayersOrderWarning = true;
    1753            0 :                                         state.dataConstruction->Construct(ConstrNumFound).ReverseConstructionLayersOrderWarning = true;
    1754              :                                     }
    1755            0 :                                     SurfError = true;
    1756          195 :                                 } else if (izConstDiff) {
    1757            0 :                                     ShowWarningError(state,
    1758            0 :                                                      format("{}Construction {} of interzone surface {} does not have the same materials in the "
    1759              :                                                             "reverse order as the construction {} of adjacent surface {}",
    1760              :                                                             RoutineName,
    1761            0 :                                                             state.dataConstruction->Construct(ConstrNum).Name,
    1762            0 :                                                             state.dataSurface->Surface(SurfNum).Name,
    1763            0 :                                                             state.dataConstruction->Construct(ConstrNumFound).Name,
    1764            0 :                                                             state.dataSurface->Surface(Found).Name));
    1765            0 :                                     ShowContinueError(state,
    1766              :                                                       "or the properties of the reversed layers are not correct due to differing layer front and "
    1767              :                                                       "back side values");
    1768            0 :                                     ShowContinueError(
    1769              :                                         state,
    1770            0 :                                         format("...but Nominal U values are similar, diff=[{:.4R}] ... simulation proceeds.",
    1771            0 :                                                std::abs(state.dataHeatBal->NominalU(ConstrNum) - state.dataHeatBal->NominalU(ConstrNumFound))));
    1772            0 :                                     if (!izConstDiffMsg) {
    1773            0 :                                         ShowContinueError(state,
    1774              :                                                           "...if the two zones are expected to have significantly different temperatures, the proper "
    1775              :                                                           "\"reverse\" construction should be created.");
    1776            0 :                                         izConstDiffMsg = true;
    1777              :                                     }
    1778            0 :                                     if (!state.dataConstruction->Construct(ConstrNum).ReverseConstructionLayersOrderWarning ||
    1779            0 :                                         !state.dataConstruction->Construct(ConstrNumFound).ReverseConstructionLayersOrderWarning) {
    1780            0 :                                         ShowContinueError(state, "...this problem for this pair will not be reported again.");
    1781            0 :                                         state.dataConstruction->Construct(ConstrNum).ReverseConstructionLayersOrderWarning = true;
    1782            0 :                                         state.dataConstruction->Construct(ConstrNumFound).ReverseConstructionLayersOrderWarning = true;
    1783              :                                     }
    1784              :                                 }
    1785              :                             }
    1786              : 
    1787              :                             // If significantly different areas -- this would not be good
    1788          195 :                             MultFound = state.dataHeatBal->Zone(state.dataSurface->Surface(Found).Zone).Multiplier *
    1789          195 :                                         state.dataHeatBal->Zone(state.dataSurface->Surface(Found).Zone).ListMultiplier;
    1790          195 :                             MultSurfNum = state.dataHeatBal->Zone(state.dataSurface->Surface(SurfNum).Zone).Multiplier *
    1791          195 :                                           state.dataHeatBal->Zone(state.dataSurface->Surface(SurfNum).Zone).ListMultiplier;
    1792          195 :                             if (state.dataSurface->Surface(Found).Area > 0.0) {
    1793          195 :                                 if (std::abs((state.dataSurface->Surface(Found).Area * MultFound -
    1794          195 :                                               state.dataSurface->Surface(SurfNum).Area * MultSurfNum) /
    1795          195 :                                              state.dataSurface->Surface(Found).Area * MultFound) > 0.02) { // 2% difference in areas
    1796            0 :                                     ++state.dataSurfaceGeometry->ErrCount4;
    1797            0 :                                     if (state.dataSurfaceGeometry->ErrCount4 == 1 && !state.dataGlobal->DisplayExtraWarnings) {
    1798            0 :                                         ShowWarningError(
    1799              :                                             state,
    1800            0 :                                             format("{}InterZone Surface Areas do not match as expected and might not satisfy conservation of energy:",
    1801              :                                                    RoutineName));
    1802            0 :                                         ShowContinueError(
    1803              :                                             state, "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on individual mismatches.");
    1804              :                                     }
    1805            0 :                                     if (state.dataGlobal->DisplayExtraWarnings) {
    1806            0 :                                         ShowWarningError(
    1807              :                                             state,
    1808            0 :                                             format("{}InterZone Surface Areas do not match as expected and might not satisfy conservation of energy:",
    1809              :                                                    RoutineName));
    1810              : 
    1811            0 :                                         if (MultFound == 1 && MultSurfNum == 1) {
    1812            0 :                                             ShowContinueError(state,
    1813            0 :                                                               format("  Area={:.1T} in Surface={}, Zone={}",
    1814            0 :                                                                      state.dataSurface->Surface(SurfNum).Area,
    1815            0 :                                                                      state.dataSurface->Surface(SurfNum).Name,
    1816            0 :                                                                      state.dataSurface->Surface(SurfNum).ZoneName));
    1817            0 :                                             ShowContinueError(state,
    1818            0 :                                                               format("  Area={:.1T} in Surface={}, Zone={}",
    1819            0 :                                                                      state.dataSurface->Surface(Found).Area,
    1820            0 :                                                                      state.dataSurface->Surface(Found).Name,
    1821            0 :                                                                      state.dataSurface->Surface(Found).ZoneName));
    1822              :                                         } else { // Show multiplier info
    1823            0 :                                             ShowContinueError(state,
    1824            0 :                                                               format("  Area={:.1T}, Multipliers={}, Total Area={:.1T} in Surface={} Zone={}",
    1825            0 :                                                                      state.dataSurface->Surface(SurfNum).Area,
    1826              :                                                                      MultSurfNum,
    1827            0 :                                                                      state.dataSurface->Surface(SurfNum).Area * MultSurfNum,
    1828            0 :                                                                      state.dataSurface->Surface(SurfNum).Name,
    1829            0 :                                                                      state.dataSurface->Surface(SurfNum).ZoneName));
    1830              : 
    1831            0 :                                             ShowContinueError(state,
    1832            0 :                                                               format("  Area={:.1T}, Multipliers={}, Total Area={:.1T} in Surface={} Zone={}",
    1833            0 :                                                                      state.dataSurface->Surface(Found).Area,
    1834              :                                                                      MultFound,
    1835            0 :                                                                      state.dataSurface->Surface(Found).Area * MultFound,
    1836            0 :                                                                      state.dataSurface->Surface(Found).Name,
    1837            0 :                                                                      state.dataSurface->Surface(Found).ZoneName));
    1838              :                                         }
    1839              :                                     }
    1840              :                                 }
    1841              :                             }
    1842              :                             // Check opposites Azimuth and Tilt
    1843              :                             // Tilt
    1844          195 :                             if (std::abs(std::abs(state.dataSurface->Surface(Found).Tilt + state.dataSurface->Surface(SurfNum).Tilt) - 180.0) > 1.0) {
    1845            0 :                                 ShowWarningError(state, format("{}InterZone Surface Tilts do not match as expected.", RoutineName));
    1846            0 :                                 ShowContinueError(state,
    1847            0 :                                                   format("  Tilt={:.1T} in Surface={}, Zone={}",
    1848            0 :                                                          state.dataSurface->Surface(SurfNum).Tilt,
    1849            0 :                                                          state.dataSurface->Surface(SurfNum).Name,
    1850            0 :                                                          state.dataSurface->Surface(SurfNum).ZoneName));
    1851            0 :                                 ShowContinueError(state,
    1852            0 :                                                   format("  Tilt={:.1T} in Surface={}, Zone={}",
    1853            0 :                                                          state.dataSurface->Surface(Found).Tilt,
    1854            0 :                                                          state.dataSurface->Surface(Found).Name,
    1855            0 :                                                          state.dataSurface->Surface(Found).ZoneName));
    1856              :                             }
    1857              :                             // check surface class match.  interzone surface.
    1858              : 
    1859          195 :                             if ((state.dataSurface->Surface(SurfNum).Class == SurfaceClass::Wall &&
    1860          390 :                                  state.dataSurface->Surface(Found).Class != SurfaceClass::Wall) ||
    1861          195 :                                 (state.dataSurface->Surface(SurfNum).Class != SurfaceClass::Wall &&
    1862           71 :                                  state.dataSurface->Surface(Found).Class == SurfaceClass::Wall)) {
    1863            0 :                                 ShowWarningError(state, format("{}InterZone Surface Classes do not match as expected.", RoutineName));
    1864            0 :                                 ShowContinueError(state,
    1865            0 :                                                   format("Surface=\"{}\", surface class={}",
    1866            0 :                                                          state.dataSurface->Surface(SurfNum).Name,
    1867            0 :                                                          cSurfaceClass(state.dataSurface->Surface(SurfNum).Class)));
    1868            0 :                                 ShowContinueError(state,
    1869            0 :                                                   format("Adjacent Surface=\"{}\", surface class={}",
    1870            0 :                                                          state.dataSurface->Surface(Found).Name,
    1871            0 :                                                          cSurfaceClass(state.dataSurface->Surface(Found).Class)));
    1872            0 :                                 ShowContinueError(state, "Other errors/warnings may follow about these surfaces.");
    1873              :                             }
    1874          195 :                             if ((state.dataSurface->Surface(SurfNum).Class == SurfaceClass::Roof &&
    1875          390 :                                  state.dataSurface->Surface(Found).Class != SurfaceClass::Floor) ||
    1876          195 :                                 (state.dataSurface->Surface(SurfNum).Class != SurfaceClass::Roof &&
    1877          170 :                                  state.dataSurface->Surface(Found).Class == SurfaceClass::Floor)) {
    1878            0 :                                 ShowWarningError(state, format("{}InterZone Surface Classes do not match as expected.", RoutineName));
    1879            0 :                                 ShowContinueError(state,
    1880            0 :                                                   format("Surface=\"{}\", surface class={}",
    1881            0 :                                                          state.dataSurface->Surface(SurfNum).Name,
    1882            0 :                                                          cSurfaceClass(state.dataSurface->Surface(SurfNum).Class)));
    1883            0 :                                 ShowContinueError(state,
    1884            0 :                                                   format("Adjacent Surface=\"{}\", surface class={}",
    1885            0 :                                                          state.dataSurface->Surface(Found).Name,
    1886            0 :                                                          cSurfaceClass(state.dataSurface->Surface(Found).Class)));
    1887            0 :                                 ShowContinueError(state, "Other errors/warnings may follow about these surfaces.");
    1888              :                             }
    1889          365 :                             if (state.dataSurface->Surface(SurfNum).Class != SurfaceClass::Roof &&
    1890          170 :                                 state.dataSurface->Surface(SurfNum).Class != SurfaceClass::Floor) {
    1891              :                                 // Walls, Windows, Doors, Glass Doors
    1892          137 :                                 if (state.dataSurface->Surface(SurfNum).Class != SurfaceClass::Wall) {
    1893              :                                     // Surface is a Door, Window or Glass Door
    1894           13 :                                     if (state.dataSurface->Surface(SurfNum).BaseSurf == 0) continue; // error detected elsewhere
    1895           26 :                                     if (state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Class == SurfaceClass::Roof ||
    1896           13 :                                         state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Class == SurfaceClass::Floor)
    1897            0 :                                         continue;
    1898              :                                 }
    1899          137 :                                 if (std::abs(std::abs(state.dataSurface->Surface(SurfNum).Azimuth - state.dataSurface->Surface(Found).Azimuth) -
    1900          137 :                                              180.0) > 1.0) {
    1901           24 :                                     if (std::abs(state.dataSurface->Surface(SurfNum).SinTilt) > 0.5 || state.dataGlobal->DisplayExtraWarnings) {
    1902              :                                         // if horizontal surfaces, then these are windows/doors/etc in those items.
    1903           24 :                                         ShowWarningError(state, format("{}InterZone Surface Azimuths do not match as expected.", RoutineName));
    1904           48 :                                         ShowContinueError(state,
    1905           48 :                                                           format("  Azimuth={:.1T}, Tilt={:.1T}, in Surface={}, Zone={}",
    1906           24 :                                                                  state.dataSurface->Surface(SurfNum).Azimuth,
    1907           24 :                                                                  state.dataSurface->Surface(SurfNum).Tilt,
    1908           24 :                                                                  state.dataSurface->Surface(SurfNum).Name,
    1909           24 :                                                                  state.dataSurface->Surface(SurfNum).ZoneName));
    1910           48 :                                         ShowContinueError(state,
    1911           48 :                                                           format("  Azimuth={:.1T}, Tilt={:.1T}, in Surface={}, Zone={}",
    1912           24 :                                                                  state.dataSurface->Surface(Found).Azimuth,
    1913           24 :                                                                  state.dataSurface->Surface(Found).Tilt,
    1914           24 :                                                                  state.dataSurface->Surface(Found).Name,
    1915           24 :                                                                  state.dataSurface->Surface(Found).ZoneName));
    1916           48 :                                         ShowContinueError(
    1917              :                                             state,
    1918           48 :                                             format("..surface class of first surface={}", cSurfaceClass(state.dataSurface->Surface(SurfNum).Class)));
    1919           48 :                                         ShowContinueError(
    1920              :                                             state,
    1921           48 :                                             format("..surface class of second surface={}", cSurfaceClass(state.dataSurface->Surface(Found).Class)));
    1922              :                                     }
    1923              :                                 }
    1924              :                             }
    1925              : 
    1926              :                             // Make sure exposures (Sun, Wind) are the same.....and are "not"
    1927          195 :                             if (state.dataSurface->Surface(SurfNum).ExtSolar || state.dataSurface->Surface(Found).ExtSolar) {
    1928            0 :                                 ShowWarningError(state, format("{}Interzone surfaces cannot be \"SunExposed\" -- removing SunExposed", RoutineName));
    1929            0 :                                 ShowContinueError(state,
    1930            0 :                                                   format("  Surface={}, Zone={}",
    1931            0 :                                                          state.dataSurface->Surface(SurfNum).Name,
    1932            0 :                                                          state.dataSurface->Surface(SurfNum).ZoneName));
    1933            0 :                                 ShowContinueError(state,
    1934            0 :                                                   format("  Surface={}, Zone={}",
    1935            0 :                                                          state.dataSurface->Surface(Found).Name,
    1936            0 :                                                          state.dataSurface->Surface(Found).ZoneName));
    1937            0 :                                 state.dataSurface->Surface(SurfNum).ExtSolar = false;
    1938            0 :                                 state.dataSurface->Surface(Found).ExtSolar = false;
    1939              :                             }
    1940          195 :                             if (state.dataSurface->Surface(SurfNum).ExtWind || state.dataSurface->Surface(Found).ExtWind) {
    1941            0 :                                 ShowWarningError(state,
    1942            0 :                                                  format("{}Interzone surfaces cannot be \"WindExposed\" -- removing WindExposed", RoutineName));
    1943            0 :                                 ShowContinueError(state,
    1944            0 :                                                   format("  Surface={}, Zone={}",
    1945            0 :                                                          state.dataSurface->Surface(SurfNum).Name,
    1946            0 :                                                          state.dataSurface->Surface(SurfNum).ZoneName));
    1947            0 :                                 ShowContinueError(state,
    1948            0 :                                                   format("  Surface={}, Zone={}",
    1949            0 :                                                          state.dataSurface->Surface(Found).Name,
    1950            0 :                                                          state.dataSurface->Surface(Found).ZoneName));
    1951            0 :                                 state.dataSurface->Surface(SurfNum).ExtWind = false;
    1952            0 :                                 state.dataSurface->Surface(Found).ExtWind = false;
    1953              :                             }
    1954              :                         }
    1955              :                         // Set opposing surface back to this one (regardless of error)
    1956          440 :                         state.dataSurface->Surface(Found).ExtBoundCond = SurfNum;
    1957              :                         // Check subsurfaces...  make sure base surface is also an interzone surface
    1958          440 :                         if (state.dataSurface->Surface(SurfNum).BaseSurf != SurfNum) { // Subsurface
    1959           26 :                             if ((state.dataSurface->Surface(SurfNum).ExtBoundCond != SurfNum) &&
    1960           13 :                                 not_blank(state.dataSurface->Surface(SurfNum).ExtBoundCondName)) {
    1961              :                                 // if not internal subsurface
    1962           13 :                                 if (state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond ==
    1963           13 :                                     state.dataSurface->Surface(SurfNum).BaseSurf) {
    1964              :                                     // base surface is not interzone surface
    1965            0 :                                     ShowSevereError(state,
    1966            0 :                                                     format("{}SubSurface=\"{}\" is an interzone subsurface.",
    1967              :                                                            RoutineName,
    1968            0 :                                                            state.dataSurface->Surface(SurfNum).Name));
    1969            0 :                                     ShowContinueError(state,
    1970            0 :                                                       format("..but the Base Surface is not an interzone surface, Surface=\"{}\".",
    1971            0 :                                                              state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Name));
    1972            0 :                                     SurfError = true;
    1973              :                                 }
    1974              :                             }
    1975              :                         }
    1976              :                     } else {
    1977              :                         //  Seems unlikely that an internal surface would be missing itself, so this message
    1978              :                         //  only indicates for adjacent (interzone) surfaces.
    1979            0 :                         ShowSevereError(state,
    1980            0 :                                         format("{}Adjacent Surface not found: {} adjacent to surface {}",
    1981              :                                                RoutineName,
    1982            0 :                                                state.dataSurface->Surface(SurfNum).ExtBoundCondName,
    1983            0 :                                                state.dataSurface->Surface(SurfNum).Name));
    1984            0 :                         NonMatch = true;
    1985            0 :                         SurfError = true;
    1986              :                     }
    1987            0 :                 } else if (state.dataSurface->Surface(SurfNum).BaseSurf != SurfNum) { // Subsurface
    1988            0 :                     if (state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond > 0 &&
    1989            0 :                         state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond !=
    1990            0 :                             state.dataSurface->Surface(SurfNum).BaseSurf) { // If Interzone surface, subsurface must be also.
    1991            0 :                         ShowSevereError(state, format("{}SubSurface on Interzone Surface must be an Interzone SubSurface.", RoutineName));
    1992            0 :                         ShowContinueError(state,
    1993            0 :                                           format("...OutsideFaceEnvironment is blank, in Surface={}", state.dataSurface->Surface(SurfNum).Name));
    1994            0 :                         SurfError = true;
    1995              :                     } else {
    1996            0 :                         ++state.dataSurfaceGeometry->ErrCount3;
    1997            0 :                         if (state.dataSurfaceGeometry->ErrCount3 == 1 && !state.dataGlobal->DisplayExtraWarnings) {
    1998            0 :                             ShowWarningError(state, format("{}Blank name for Outside Boundary Condition Objects.", RoutineName));
    1999            0 :                             ShowContinueError(state, "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on individual surfaces.");
    2000              :                         }
    2001            0 :                         if (state.dataGlobal->DisplayExtraWarnings) {
    2002            0 :                             ShowWarningError(state,
    2003            0 :                                              format("{}Blank name for Outside Boundary Condition Object, in surface={}",
    2004              :                                                     RoutineName,
    2005            0 :                                                     state.dataSurface->Surface(SurfNum).Name));
    2006            0 :                             ShowContinueError(state,
    2007            0 :                                               format("Resetting this surface to be an internal zone surface, zone={}",
    2008            0 :                                                      state.dataSurface->Surface(SurfNum).ZoneName));
    2009              :                         }
    2010            0 :                         state.dataSurface->Surface(SurfNum).ExtBoundCondName = state.dataSurface->Surface(SurfNum).Name;
    2011            0 :                         state.dataSurface->Surface(SurfNum).ExtBoundCond = SurfNum;
    2012              :                     }
    2013              :                 } else {
    2014            0 :                     ++state.dataSurfaceGeometry->ErrCount3;
    2015            0 :                     if (state.dataSurfaceGeometry->ErrCount3 == 1 && !state.dataGlobal->DisplayExtraWarnings) {
    2016            0 :                         ShowSevereError(state, format("{}Blank name for Outside Boundary Condition Objects.", RoutineName));
    2017            0 :                         ShowContinueError(state, "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on individual surfaces.");
    2018              :                     }
    2019            0 :                     if (state.dataGlobal->DisplayExtraWarnings) {
    2020            0 :                         ShowWarningError(state,
    2021            0 :                                          format("{}Blank name for Outside Boundary Condition Object, in surface={}",
    2022              :                                                 RoutineName,
    2023            0 :                                                 state.dataSurface->Surface(SurfNum).Name));
    2024            0 :                         ShowContinueError(state,
    2025            0 :                                           format("Resetting this surface to be an internal zone (adiabatic) surface, zone={}",
    2026            0 :                                                  state.dataSurface->Surface(SurfNum).ZoneName));
    2027              :                     }
    2028            0 :                     state.dataSurface->Surface(SurfNum).ExtBoundCondName = state.dataSurface->Surface(SurfNum).Name;
    2029            0 :                     state.dataSurface->Surface(SurfNum).ExtBoundCond = SurfNum;
    2030            0 :                     SurfError = true;
    2031              :                 }
    2032              :             }
    2033              : 
    2034              :         } // ...end of the Surface DO loop for finding BaseSurf
    2035          224 :         if (NonMatch) {
    2036            0 :             ShowSevereError(state, format("{}Non matching interzone surfaces found", RoutineName));
    2037              :         }
    2038              : 
    2039              :         //**********************************************************************************
    2040              :         // Warn about interzone surfaces that have adiabatic windows/vice versa
    2041          224 :         SubSurfaceSevereDisplayed = false;
    2042         2486 :         for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    2043         2262 :             if (!state.dataSurface->Surface(SurfNum).HeatTransSurf) continue;
    2044         2178 :             if (state.dataSurface->Surface(SurfNum).BaseSurf == SurfNum) continue; // base surface
    2045              :             // not base surface.  Check it.
    2046          227 :             if (state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond <= 0) { // exterior or other base surface
    2047          195 :                 if (state.dataSurface->Surface(SurfNum).ExtBoundCond !=
    2048          195 :                     state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond) { // should match base surface
    2049            0 :                     if (state.dataSurface->Surface(SurfNum).ExtBoundCond == SurfNum) {
    2050            0 :                         ShowSevereError(
    2051              :                             state,
    2052            0 :                             format("{}Subsurface=\"{}\" exterior condition [adiabatic surface] in a base surface=\"{}\" with exterior condition [{}]",
    2053              :                                    RoutineName,
    2054            0 :                                    state.dataSurface->Surface(SurfNum).Name,
    2055            0 :                                    state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Name,
    2056              :                                    DataSurfaces::cExtBoundCondition(
    2057            0 :                                        state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond)));
    2058            0 :                         SurfError = true;
    2059            0 :                     } else if (state.dataSurface->Surface(SurfNum).ExtBoundCond > 0) {
    2060            0 :                         ShowSevereError(
    2061              :                             state,
    2062            0 :                             format("{}Subsurface=\"{}\" exterior condition [interzone surface] in a base surface=\"{}\" with exterior condition [{}]",
    2063              :                                    RoutineName,
    2064            0 :                                    state.dataSurface->Surface(SurfNum).Name,
    2065            0 :                                    state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Name,
    2066              :                                    DataSurfaces::cExtBoundCondition(
    2067            0 :                                        state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond)));
    2068            0 :                         SurfError = true;
    2069            0 :                     } else if (state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond ==
    2070              :                                DataSurfaces::OtherSideCondModeledExt) {
    2071            0 :                         ShowWarningError(state,
    2072            0 :                                          format("{}Subsurface=\"{}\" exterior condition [{}] in a base surface=\"{}\" with exterior condition [{}]",
    2073              :                                                 RoutineName,
    2074            0 :                                                 state.dataSurface->Surface(SurfNum).Name,
    2075            0 :                                                 DataSurfaces::cExtBoundCondition(state.dataSurface->Surface(SurfNum).ExtBoundCond),
    2076            0 :                                                 state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Name,
    2077              :                                                 DataSurfaces::cExtBoundCondition(
    2078            0 :                                                     state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond)));
    2079            0 :                         ShowContinueError(state, "...SubSurface will not use the exterior condition model of the base surface.");
    2080              :                     } else {
    2081            0 :                         ShowSevereError(state,
    2082            0 :                                         format("{}Subsurface=\"{}\" exterior condition [{}] in a base surface=\"{}\" with exterior condition [{}]",
    2083              :                                                RoutineName,
    2084            0 :                                                state.dataSurface->Surface(SurfNum).Name,
    2085            0 :                                                DataSurfaces::cExtBoundCondition(state.dataSurface->Surface(SurfNum).ExtBoundCond),
    2086            0 :                                                state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Name,
    2087              :                                                DataSurfaces::cExtBoundCondition(
    2088            0 :                                                    state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond)));
    2089            0 :                         SurfError = true;
    2090              :                     }
    2091            0 :                     if (!SubSurfaceSevereDisplayed && SurfError) {
    2092            0 :                         ShowContinueError(state, "...calculations for heat balance would be compromised.");
    2093            0 :                         SubSurfaceSevereDisplayed = true;
    2094              :                     }
    2095              :                 }
    2096           32 :             } else if (state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).BaseSurf ==
    2097           32 :                        state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond) {
    2098              :                 // adiabatic surface. make sure subsurfaces match
    2099            0 :                 if (state.dataSurface->Surface(SurfNum).ExtBoundCond != SurfNum) { // not adiabatic surface
    2100            0 :                     if (state.dataSurface->Surface(SurfNum).ExtBoundCond > 0) {
    2101            0 :                         ShowSevereError(state,
    2102            0 :                                         format("{}Subsurface=\"{}\" exterior condition [interzone surface] in a base surface=\"{}\" with exterior "
    2103              :                                                "condition [adiabatic surface]",
    2104              :                                                RoutineName,
    2105            0 :                                                state.dataSurface->Surface(SurfNum).Name,
    2106            0 :                                                state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Name));
    2107              :                     } else {
    2108            0 :                         ShowSevereError(
    2109              :                             state,
    2110            0 :                             format("{}Subsurface=\"{}\" exterior condition [{}] in a base surface=\"{}\" with exterior condition [adiabatic surface]",
    2111              :                                    RoutineName,
    2112            0 :                                    state.dataSurface->Surface(SurfNum).Name,
    2113            0 :                                    DataSurfaces::cExtBoundCondition(state.dataSurface->Surface(SurfNum).ExtBoundCond),
    2114            0 :                                    state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Name));
    2115              :                     }
    2116            0 :                     if (!SubSurfaceSevereDisplayed) {
    2117            0 :                         ShowContinueError(state, "...calculations for heat balance would be compromised.");
    2118            0 :                         SubSurfaceSevereDisplayed = true;
    2119              :                     }
    2120            0 :                     SurfError = true;
    2121              :                 }
    2122           32 :             } else if (state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).ExtBoundCond > 0) { // interzone surface
    2123           32 :                 if (state.dataSurface->Surface(SurfNum).ExtBoundCond == SurfNum) {
    2124            0 :                     ShowSevereError(state,
    2125            0 :                                     format("{}Subsurface=\"{}\" is an adiabatic surface in an Interzone base surface=\"{}\"",
    2126              :                                            RoutineName,
    2127            0 :                                            state.dataSurface->Surface(SurfNum).Name,
    2128            0 :                                            state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).BaseSurf).Name));
    2129            0 :                     if (!SubSurfaceSevereDisplayed) {
    2130            0 :                         ShowContinueError(state, "...calculations for heat balance would be compromised.");
    2131            0 :                         SubSurfaceSevereDisplayed = true;
    2132              :                     }
    2133              :                     //        SurfError=.TRUE.
    2134              :                 }
    2135              :             }
    2136              :         }
    2137              : 
    2138          224 :         setSurfaceFirstLast(state);
    2139              : 
    2140              :         // Set up Floor Areas for Zones and Spaces
    2141          224 :         Real64 constexpr floorAreaTolerance(0.05);
    2142          224 :         Real64 constexpr floorAreaPercentTolerance(floorAreaTolerance * 100.0);
    2143          224 :         if (!SurfError) {
    2144          224 :             int ErrCount = 0;
    2145          600 :             for (auto &thisSpace : state.dataHeatBal->space) {
    2146          376 :                 auto &thisZone = state.dataHeatBal->Zone(thisSpace.zoneNum);
    2147          376 :                 Real64 calcFloorArea = 0.0; // Calculated floor area used for this space
    2148         2512 :                 for (int SurfNum = thisSpace.HTSurfaceFirst; SurfNum <= thisSpace.HTSurfaceLast; ++SurfNum) {
    2149         2136 :                     auto const &thisSurf = state.dataSurface->Surface(SurfNum);
    2150         2136 :                     if (thisSurf.Class == SurfaceClass::Floor) {
    2151          423 :                         thisZone.HasFloor = true;
    2152          423 :                         thisSpace.hasFloor = true;
    2153          423 :                         calcFloorArea += thisSurf.Area;
    2154              :                     }
    2155         2136 :                     if (thisSurf.Class == SurfaceClass::Roof) {
    2156          343 :                         thisZone.CeilingArea += thisSurf.Area;
    2157          343 :                         thisZone.HasRoof = true;
    2158              :                     }
    2159              :                 }
    2160          376 :                 if (thisSpace.userEnteredFloorArea != Constant::AutoCalculate) {
    2161              :                     // Check entered vs calculated
    2162            5 :                     if (thisSpace.userEnteredFloorArea > 0.0) { // User entered Space floor area,
    2163              :                         // produce message if not near calculated
    2164            5 :                         if (calcFloorArea > 0.0) {
    2165            5 :                             Real64 diffp = std::abs(calcFloorArea - thisSpace.userEnteredFloorArea) / thisSpace.userEnteredFloorArea;
    2166            5 :                             if (diffp > floorAreaTolerance) {
    2167            5 :                                 ++ErrCount;
    2168            5 :                                 if (ErrCount == 1 && !state.dataGlobal->DisplayExtraWarnings) {
    2169            6 :                                     ShowWarningError(
    2170              :                                         state,
    2171            6 :                                         format("{}Entered Space Floor Area(s) differ more than {:.0R}% from calculated Space Floor Area(s).",
    2172            6 :                                                std::string(RoutineName),
    2173              :                                                floorAreaPercentTolerance));
    2174            9 :                                     ShowContinueError(state,
    2175              :                                                       "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on individual Spaces.");
    2176              :                                 }
    2177            5 :                                 if (state.dataGlobal->DisplayExtraWarnings) {
    2178              :                                     // Warn user of using specified Space Floor Area
    2179            0 :                                     ShowWarningError(
    2180              :                                         state,
    2181            0 :                                         format("{}Entered Floor Area for Space=\"{}\" is {:.1R}% different from the calculated Floor Area.",
    2182            0 :                                                std::string(RoutineName),
    2183            0 :                                                thisSpace.Name,
    2184            0 :                                                diffp * 100.0));
    2185            0 :                                     ShowContinueError(state,
    2186            0 :                                                       format("Entered Space Floor Area={:.2R}, Calculated Space Floor Area={:.2R}, entered "
    2187              :                                                              "Floor Area will be used.",
    2188            0 :                                                              thisSpace.userEnteredFloorArea,
    2189              :                                                              calcFloorArea));
    2190              :                                 }
    2191              :                             }
    2192              :                         }
    2193            5 :                         thisSpace.FloorArea = thisSpace.userEnteredFloorArea;
    2194            5 :                         thisSpace.hasFloor = true;
    2195              :                     }
    2196              :                 } else {
    2197          371 :                     thisSpace.FloorArea = calcFloorArea;
    2198              :                 }
    2199              :             }
    2200          224 :             ErrCount = 0;
    2201          578 :             for (auto &thisZone : state.dataHeatBal->Zone) {
    2202              :                 // Calculate zone floor area as sum of space floor areas
    2203          354 :                 Real64 zoneCalcFloorArea = 0.0; // Calculated floor area excluding air boundary surfaces
    2204          730 :                 for (int spaceNum : thisZone.spaceIndexes) {
    2205          376 :                     zoneCalcFloorArea += state.dataHeatBal->space(spaceNum).FloorArea;
    2206          376 :                     thisZone.HasFloor |= state.dataHeatBal->space(spaceNum).hasFloor;
    2207              :                 }
    2208          354 :                 if (thisZone.UserEnteredFloorArea != Constant::AutoCalculate) {
    2209              :                     // Check entered vs calculated
    2210           10 :                     if (thisZone.UserEnteredFloorArea > 0.0) { // User entered zone floor area,
    2211              :                         // produce message if not near calculated
    2212            9 :                         if (zoneCalcFloorArea > 0.0) {
    2213            7 :                             Real64 diffp = std::abs(zoneCalcFloorArea - thisZone.UserEnteredFloorArea) / thisZone.UserEnteredFloorArea;
    2214            7 :                             if (diffp > 0.05) {
    2215            3 :                                 ++ErrCount;
    2216            3 :                                 if (ErrCount == 1 && !state.dataGlobal->DisplayExtraWarnings) {
    2217            4 :                                     ShowWarningError(
    2218              :                                         state,
    2219            4 :                                         format("{}Entered Zone Floor Area(s) differ more than {:.0R}% from the sum of the Space Floor Area(s).",
    2220            4 :                                                std::string(RoutineName),
    2221              :                                                floorAreaPercentTolerance));
    2222            6 :                                     ShowContinueError(state,
    2223              :                                                       "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on individual zones.");
    2224              :                                 }
    2225            3 :                                 if (state.dataGlobal->DisplayExtraWarnings) {
    2226              :                                     // Warn user of using specified Zone Floor Area
    2227            0 :                                     ShowWarningError(state,
    2228            0 :                                                      format("{}Entered Floor Area for Zone=\"{}\" is {:.1R}% different from the sum of the "
    2229              :                                                             "Space Floor Area(s).",
    2230            0 :                                                             std::string(RoutineName),
    2231            0 :                                                             thisZone.Name,
    2232            0 :                                                             diffp * 100.0));
    2233            0 :                                     ShowContinueError(state,
    2234            0 :                                                       format("Entered Zone Floor Area={:.2R}, Sum of Space Floor Area(s)={:.2R}",
    2235            0 :                                                              thisZone.UserEnteredFloorArea,
    2236              :                                                              zoneCalcFloorArea));
    2237            0 :                                     ShowContinueError(
    2238              :                                         state, "Entered Zone Floor Area will be used and Space Floor Area(s) will be adjusted proportionately.");
    2239              :                                 }
    2240              :                             }
    2241              :                         }
    2242            9 :                         thisZone.FloorArea = thisZone.UserEnteredFloorArea;
    2243            9 :                         thisZone.HasFloor = true;
    2244              : 
    2245              :                         // Adjust space floor areas to match zone floor area
    2246            9 :                         if (thisZone.numSpaces == 1) {
    2247              :                             // If the zone contains only one space, then set the Space area to the Zone area
    2248            8 :                             int spaceNum = thisZone.spaceIndexes(1);
    2249            8 :                             state.dataHeatBal->space(spaceNum).FloorArea = thisZone.FloorArea;
    2250            1 :                         } else if (zoneCalcFloorArea > 0.0) {
    2251              :                             // Adjust space areas proportionately
    2252            1 :                             Real64 areaRatio = thisZone.FloorArea / zoneCalcFloorArea;
    2253            3 :                             for (int spaceNum : thisZone.spaceIndexes) {
    2254            2 :                                 state.dataHeatBal->space(spaceNum).FloorArea *= areaRatio;
    2255              :                             }
    2256              :                         } else {
    2257            0 :                             if (state.dataGlobal->DisplayExtraWarnings) {
    2258              :                                 // Warn if calculated floor area was zero and there is more than one Space
    2259            0 :                                 ShowWarningError(
    2260              :                                     state,
    2261            0 :                                     format("{}Entered Floor Area entered for Zone=\"{}\" significantly different from sum of Space Floor Areas",
    2262              :                                            RoutineName,
    2263            0 :                                            thisZone.Name));
    2264            0 :                                 ShowContinueError(state,
    2265              :                                                   "But the sum of the Space Floor Areas is zero and there is more than one Space in the zone."
    2266              :                                                   "Unable to apportion the zone floor area. Space Floor Areas are zero.");
    2267              :                             }
    2268              :                         }
    2269              :                     } else {
    2270            1 :                         if (zoneCalcFloorArea > 0.0) thisZone.FloorArea = zoneCalcFloorArea;
    2271              :                     }
    2272              :                 } else {
    2273          344 :                     thisZone.FloorArea = zoneCalcFloorArea;
    2274              :                 }
    2275          354 :                 Real64 totSpacesFloorArea = 0.0;
    2276          730 :                 for (int spaceNum : thisZone.spaceIndexes) {
    2277          376 :                     totSpacesFloorArea += state.dataHeatBal->space(spaceNum).FloorArea;
    2278              :                 }
    2279          354 :                 if (totSpacesFloorArea > 0.0) {
    2280          674 :                     for (int spaceNum : thisZone.spaceIndexes) {
    2281          348 :                         state.dataHeatBal->space(spaceNum).fracZoneFloorArea = state.dataHeatBal->space(spaceNum).FloorArea / totSpacesFloorArea;
    2282              :                     }
    2283              :                 } // else leave fractions at zero
    2284              :             }
    2285              :         }
    2286              : 
    2287         2486 :         for (int SurfNum = 1; SurfNum <= MovedSurfs; ++SurfNum) { // TotSurfaces
    2288         2262 :             if (state.dataSurface->Surface(SurfNum).Area < 1.e-06) {
    2289            0 :                 ShowSevereError(state,
    2290            0 :                                 format("{}Zero or negative surface area[{:.5R}], Surface={}",
    2291              :                                        RoutineName,
    2292            0 :                                        state.dataSurface->Surface(SurfNum).Area,
    2293            0 :                                        state.dataSurface->Surface(SurfNum).Name));
    2294            0 :                 SurfError = true;
    2295              :             }
    2296         2262 :             if (state.dataSurface->Surface(SurfNum).Area >= 1.e-06 && state.dataSurface->Surface(SurfNum).Area < 0.001) {
    2297            0 :                 ShowWarningError(state,
    2298            0 :                                  format("{}Very small surface area[{:.5R}], Surface={}",
    2299              :                                         RoutineName,
    2300            0 :                                         state.dataSurface->Surface(SurfNum).Area,
    2301            0 :                                         state.dataSurface->Surface(SurfNum).Name));
    2302              :             }
    2303              :         }
    2304              : 
    2305         2486 :         for (int SurfNum = 1; SurfNum <= MovedSurfs; ++SurfNum) { // TotSurfaces
    2306         2262 :             auto &surf = state.dataSurface->Surface(SurfNum);
    2307              :             // GLASSDOORs and TDD:DIFFUSERs will be treated as windows in the subsequent heat transfer and daylighting
    2308              :             // calculations. Reset class to 'Window' after saving the original designation in SurfaceWindow.
    2309              : 
    2310         2262 :             surf.OriginalClass = surf.Class;
    2311              : 
    2312         2262 :             if (surf.Class == SurfaceClass::GlassDoor || surf.Class == SurfaceClass::TDD_Diffuser) surf.Class = SurfaceClass::Window;
    2313              : 
    2314         2262 :             if (surf.Class == SurfaceClass::TDD_Dome) {
    2315              :                 // Reset the TDD:DOME subsurface to act as a base surface that can shade and be shaded
    2316              :                 // NOTE: This must be set early so that subsequent shading calculations are done correctly
    2317            7 :                 surf.BaseSurf = SurfNum;
    2318              :             }
    2319              :         }
    2320              : 
    2321          224 :         auto &s_mat = state.dataMaterial;
    2322              : 
    2323              :         // I don't think this entire loop matters
    2324          224 :         errFlag = false;
    2325          224 :         if (!SurfError) {
    2326         2486 :             for (int SurfNum = 1; SurfNum <= MovedSurfs; ++SurfNum) { // TotSurfaces
    2327         2262 :                 auto &surf = state.dataSurface->Surface(SurfNum);
    2328         2262 :                 if (!surf.HasShadeControl) continue;
    2329              : 
    2330           11 :                 int ConstrNumSh = surf.activeShadedConstruction;
    2331           11 :                 if (ConstrNumSh <= 0) continue;
    2332              : 
    2333           11 :                 auto &winShadeCtrl = state.dataSurface->WindowShadingControl(surf.activeWindowShadingControl);
    2334           11 :                 if (!ANY_BLIND(winShadeCtrl.ShadingType)) continue;
    2335              :                 // use first item since others should be identical
    2336              : 
    2337            8 :                 auto &surfShade = state.dataSurface->surfShades(SurfNum);
    2338              :                 // TH 1/7/2010. CR 7930
    2339              :                 // The old code did not consider between-glass blind. Also there should not be two blinds - both interior and exterior
    2340              :                 // Use the new generic code (assuming only one blind) as follows
    2341           16 :                 for (int iMatNum = 1; iMatNum <= state.dataConstruction->Construct(ConstrNumSh).TotLayers; ++iMatNum) {
    2342           16 :                     auto *mat = s_mat->materials(state.dataConstruction->Construct(ConstrNumSh).LayerPoint(iMatNum));
    2343              : 
    2344           16 :                     if (mat->group != Material::Group::Blind) continue;
    2345              : 
    2346            8 :                     auto *matBlind = dynamic_cast<Material::MaterialBlind *>(mat);
    2347            8 :                     assert(matBlind != nullptr);
    2348              : 
    2349            8 :                     surfShade.blind.matNum = mat->Num;
    2350            8 :                     break;
    2351              :                 }
    2352              : 
    2353            8 :                 if (errFlag) {
    2354            0 :                     ErrorsFound = true;
    2355            0 :                     ShowContinueError(state, format("WindowShadingControl {} has errors, program will terminate.", winShadeCtrl.Name));
    2356              :                 }
    2357              : 
    2358            8 :                 if (winShadeCtrl.slatAngleControl != DataSurfaces::SlatAngleControl::Fixed) {
    2359            0 :                     surfShade.blind.movableSlats = true;
    2360            0 :                     state.dataSurface->AnyMovableSlat = true;
    2361            0 :                     state.dataHeatBalSurf->SurfMovSlatsIndexList.push_back(SurfNum);
    2362              :                 }
    2363              :             } // End of surface loop
    2364              : 
    2365              :             // final associate fenestration surfaces referenced in WindowShadingControl
    2366          224 :             FinalAssociateWindowShadingControlFenestration(state, ErrorsFound);
    2367          224 :             CheckWindowShadingControlSimilarForWindow(state, ErrorsFound);
    2368              :         }
    2369              : 
    2370              :         // Check for zones with not enough surfaces
    2371          578 :         for (auto &thisZone : state.dataHeatBal->Zone) {
    2372          354 :             int OpaqueHTSurfs = 0;        // Number of floors, walls and roofs in a zone
    2373          354 :             int OpaqueHTSurfsWithWin = 0; // Number of floors, walls and roofs with windows in a zone
    2374          354 :             int InternalMassSurfs = 0;    // Number of internal mass surfaces in a zone
    2375          354 :             int priorBaseSurfNum = 0;
    2376              : 
    2377          730 :             for (int spaceNum : thisZone.spaceIndexes) {
    2378          376 :                 auto const &thisSpace = state.dataHeatBal->space(spaceNum);
    2379          376 :                 if (thisSpace.HTSurfaceFirst == 0) continue; // Zone with no surfaces
    2380         2508 :                 for (int SurfNum = thisSpace.HTSurfaceFirst; SurfNum <= thisSpace.HTSurfaceLast; ++SurfNum) {
    2381         2136 :                     auto const &thisSurf = state.dataSurface->Surface(SurfNum);
    2382         2136 :                     if (thisSurf.Class == SurfaceClass::Floor || thisSurf.Class == SurfaceClass::Wall || thisSurf.Class == SurfaceClass::Roof)
    2383         1897 :                         ++OpaqueHTSurfs;
    2384         2136 :                     if (thisSurf.Class == SurfaceClass::IntMass) ++InternalMassSurfs;
    2385         2136 :                     if (thisSurf.Class == SurfaceClass::Window) {
    2386              :                         // Count base surface only once for multiple windows on a wall
    2387          195 :                         int thisBaseSurfNum = thisSurf.BaseSurf;
    2388          195 :                         if (thisBaseSurfNum != priorBaseSurfNum) {
    2389          144 :                             ++OpaqueHTSurfsWithWin;
    2390          144 :                             priorBaseSurfNum = thisBaseSurfNum;
    2391              :                         }
    2392              :                     }
    2393              :                 }
    2394              :             }
    2395          354 :             if (OpaqueHTSurfsWithWin == 1 && OpaqueHTSurfs == 1 && InternalMassSurfs == 0) {
    2396            0 :                 SurfError = true;
    2397            0 :                 ShowSevereError(state,
    2398            0 :                                 format("{}Zone {} has only one floor, wall or roof, and this surface has a window.", RoutineName, thisZone.Name));
    2399            0 :                 ShowContinueError(state, "Add more floors, walls or roofs, or an internal mass surface.");
    2400              :             }
    2401              :         }
    2402              : 
    2403              :         // set up vertex of centroid for each surface.
    2404          224 :         CalcSurfaceCentroid(state);
    2405              : 
    2406          224 :         SetupShadeSurfacesForSolarCalcs(state); // if shading surfaces are solar collectors or PV, then we need full solar calc.
    2407              : 
    2408          224 :         GetMovableInsulationData(state, ErrorsFound);
    2409              : 
    2410          224 :         if (state.dataSurface->CalcSolRefl) GetShadingSurfReflectanceData(state, ErrorsFound);
    2411              : 
    2412          224 :         LayNumOutside = 0;
    2413              : 
    2414         2486 :         for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    2415         2262 :             auto &surf = state.dataSurface->Surface(SurfNum);
    2416              :             // Check for EcoRoof and only 1 allowed to be used.
    2417         2262 :             if (surf.Construction > 0)
    2418         2178 :                 state.dataSurface->SurfExtEcoRoof(SurfNum) = state.dataConstruction->Construct(surf.Construction).TypeIsEcoRoof;
    2419         2262 :             if (!state.dataSurface->SurfExtEcoRoof(SurfNum)) continue;
    2420            0 :             if (LayNumOutside == 0) {
    2421            0 :                 LayNumOutside = state.dataConstruction->Construct(surf.Construction).LayerPoint(1);
    2422            0 :                 continue;
    2423              :             }
    2424            0 :             if (LayNumOutside != state.dataConstruction->Construct(surf.Construction).LayerPoint(1)) {
    2425            0 :                 ShowSevereError(state, format("{}Only one EcoRoof Material is currently allowed for all constructions.", RoutineName));
    2426            0 :                 ShowContinueError(state, format("... first material={}", s_mat->materials(LayNumOutside)->Name));
    2427            0 :                 ShowContinueError(state,
    2428            0 :                                   format("... conflicting Construction={} uses material={}",
    2429            0 :                                          state.dataConstruction->Construct(surf.Construction).Name,
    2430            0 :                                          s_mat->materials(state.dataConstruction->Construct(surf.Construction).LayerPoint(1))->Name));
    2431            0 :                 ErrorsFound = true;
    2432              :             }
    2433              :         }
    2434              : 
    2435              :         // Reserve space to avoid excess allocations
    2436          224 :         state.dataSurface->AllHTSurfaceList.reserve(state.dataSurface->TotSurfaces);
    2437          224 :         state.dataSurface->AllExtSolarSurfaceList.reserve(state.dataSurface->TotSurfaces);
    2438          224 :         state.dataSurface->AllShadowPossObstrSurfaceList.reserve(state.dataSurface->TotSurfaces);
    2439          224 :         state.dataSurface->AllIZSurfaceList.reserve(state.dataSurface->TotSurfaces);
    2440          224 :         state.dataSurface->AllHTNonWindowSurfaceList.reserve(state.dataSurface->TotSurfaces - state.dataSurface->TotWindows);
    2441          224 :         state.dataSurface->AllHTWindowSurfaceList.reserve(state.dataSurface->TotWindows);
    2442          224 :         state.dataSurface->AllExtSolWindowSurfaceList.reserve(state.dataSurface->TotWindows);
    2443          224 :         state.dataSurface->AllExtSolWinWithFrameSurfaceList.reserve(state.dataSurface->TotWindows);
    2444          224 :         state.dataSurface->AllHTKivaSurfaceList.reserve(state.dataSurface->TotSurfaces);
    2445              : 
    2446              :         // Set flag that determines whether a surface can be an exterior obstruction
    2447              :         // Also set associated surfaces for Kiva foundations and build heat transfer surface lists
    2448         2486 :         for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    2449         2262 :             auto &surf = state.dataSurface->Surface(SurfNum);
    2450         2262 :             surf.IsShadowPossibleObstruction = false;
    2451         2262 :             if (surf.ExtSolar) {
    2452              :                 // This may include some attached shading surfaces
    2453         1408 :                 state.dataSurface->AllExtSolarSurfaceList.push_back(SurfNum);
    2454              :             }
    2455         2262 :             if (surf.HeatTransSurf) {
    2456              :                 // Outside light shelves get tagged later as HeatTransSurf=true but they haven't been processed yet
    2457         2136 :                 state.dataSurface->AllHTSurfaceList.push_back(SurfNum);
    2458         2136 :                 int const zoneNum(surf.Zone);
    2459         2136 :                 auto &surfZone(state.dataHeatBal->Zone(zoneNum));
    2460         2136 :                 surfZone.ZoneHTSurfaceList.push_back(SurfNum);
    2461              :                 // Sort window vs non-window surfaces
    2462         2136 :                 if (surf.Class == DataSurfaces::SurfaceClass::Window) {
    2463          195 :                     state.dataSurface->AllHTWindowSurfaceList.push_back(SurfNum);
    2464          195 :                     surfZone.ZoneHTWindowSurfaceList.push_back(SurfNum);
    2465          195 :                     if (surf.ExtSolar) {
    2466          175 :                         state.dataSurface->AllExtSolWindowSurfaceList.push_back(SurfNum);
    2467          175 :                         if (surf.FrameDivider > 0) {
    2468           22 :                             state.dataSurface->AllExtSolWinWithFrameSurfaceList.push_back(SurfNum);
    2469              :                         }
    2470              :                     }
    2471              :                 } else {
    2472         1941 :                     state.dataSurface->AllHTNonWindowSurfaceList.push_back(SurfNum);
    2473         1941 :                     surfZone.ZoneHTNonWindowSurfaceList.push_back(SurfNum);
    2474              :                 }
    2475         2136 :                 int const surfExtBoundCond(surf.ExtBoundCond);
    2476              :                 // Build zone and interzone surface lists
    2477         2136 :                 if ((surfExtBoundCond > 0) && (surfExtBoundCond != SurfNum)) {
    2478          346 :                     state.dataSurface->AllIZSurfaceList.push_back(SurfNum);
    2479          346 :                     surfZone.ZoneIZSurfaceList.push_back(SurfNum);
    2480          346 :                     auto &adjZone(state.dataHeatBal->Zone(state.dataSurface->Surface(surfExtBoundCond).Zone));
    2481          346 :                     adjZone.ZoneHTSurfaceList.push_back(SurfNum);
    2482          346 :                     adjZone.ZoneIZSurfaceList.push_back(SurfNum);
    2483              :                     // Sort window vs non-window surfaces
    2484          346 :                     if (surf.Class == DataSurfaces::SurfaceClass::Window) {
    2485            6 :                         adjZone.ZoneHTWindowSurfaceList.push_back(SurfNum);
    2486              :                     } else {
    2487          340 :                         adjZone.ZoneHTNonWindowSurfaceList.push_back(SurfNum);
    2488              :                     }
    2489              :                 }
    2490              :             }
    2491              : 
    2492              :             // Exclude non-exterior heat transfer surfaces (but not OtherSideCondModeledExt = -4 CR7640)
    2493         2262 :             if (surf.HeatTransSurf && surf.ExtBoundCond > 0) continue;
    2494         1671 :             if (surf.HeatTransSurf && surf.ExtBoundCond == DataSurfaces::Ground) continue;
    2495         1552 :             if (surf.HeatTransSurf && surf.ExtBoundCond == DataSurfaces::KivaFoundation) {
    2496            0 :                 state.dataSurface->AllHTKivaSurfaceList.push_back(SurfNum);
    2497            0 :                 if (!ErrorsFound) state.dataSurfaceGeometry->kivaManager.foundationInputs[surf.OSCPtr].surfaces.push_back(SurfNum);
    2498            0 :                 continue;
    2499              :             }
    2500         1552 :             if (surf.HeatTransSurf && surf.ExtBoundCond == DataSurfaces::OtherSideCoefNoCalcExt) continue;
    2501         1552 :             if (surf.HeatTransSurf && surf.ExtBoundCond == DataSurfaces::OtherSideCoefCalcExt) continue;
    2502              :             // Exclude windows and doors, i.e., consider only their base surfaces as possible obstructions
    2503         1552 :             if (surf.Class == SurfaceClass::Window || surf.Class == SurfaceClass::Door) continue;
    2504              :             // Exclude duplicate shading surfaces
    2505         1354 :             if (surf.MirroredSurf) continue;
    2506              :             // Exclude air boundary surfaces
    2507         1312 :             if (surf.IsAirBoundarySurf) continue;
    2508              : 
    2509         1274 :             surf.IsShadowPossibleObstruction = true;
    2510         1274 :             state.dataSurface->AllShadowPossObstrSurfaceList.push_back(SurfNum);
    2511              :         } // for (SurfNum)
    2512              : 
    2513              :         // Check for IRT surfaces in invalid places.
    2514          224 :         if (std::any_of(state.dataConstruction->Construct.begin(),
    2515          224 :                         state.dataConstruction->Construct.end(),
    2516          767 :                         [](Construction::ConstructionProps const &e) { return e.TypeIsIRT; })) {
    2517            0 :             int iTmp1 = 0;
    2518            0 :             for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    2519            0 :                 auto &surf = state.dataSurface->Surface(SurfNum);
    2520            0 :                 if (!surf.HeatTransSurf) continue;                                   // ignore shading surfaces
    2521            0 :                 if (surf.ExtBoundCond > 0 && surf.ExtBoundCond != SurfNum) continue; // interzone, not adiabatic surface
    2522            0 :                 if (!state.dataConstruction->Construct(surf.Construction).TypeIsIRT) {
    2523            0 :                     continue;
    2524              :                 }
    2525            0 :                 if (!state.dataGlobal->DisplayExtraWarnings) {
    2526            0 :                     ++iTmp1;
    2527              :                 } else {
    2528            0 :                     ShowWarningError(state,
    2529            0 :                                      format("{}Surface=\"{}\" uses InfraredTransparent construction in a non-interzone surface. (illegal use)",
    2530              :                                             RoutineName,
    2531            0 :                                             surf.Name));
    2532              :                 }
    2533              :             }
    2534            0 :             if (iTmp1 > 0) {
    2535            0 :                 ShowWarningError(
    2536              :                     state,
    2537            0 :                     format("{}Surfaces use InfraredTransparent constructions {} in non-interzone surfaces. (illegal use)", RoutineName, iTmp1));
    2538            0 :                 ShowContinueError(state, "For explicit details on each use, use Output:Diagnostics,DisplayExtraWarnings;");
    2539              :             }
    2540              :         }
    2541              : 
    2542              :         // Populate SurfaceFilter lists
    2543         2464 :         for (int iSurfaceFilter = 1; iSurfaceFilter < static_cast<int>(DataSurfaces::SurfaceFilter::Num); ++iSurfaceFilter)
    2544         2240 :             state.dataSurface->SurfaceFilterLists[iSurfaceFilter].reserve(state.dataSurface->TotSurfaces);
    2545              : 
    2546         2486 :         for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    2547         2262 :             auto const &surf = state.dataSurface->Surface(SurfNum);
    2548         2262 :             if (!surf.HeatTransSurf) continue;
    2549         2136 :             if (surf.ExtBoundCond > 0) {
    2550          591 :                 state.dataSurface->SurfaceFilterLists[static_cast<int>(DataSurfaces::SurfaceFilter::AllInteriorSurfaces)].push_back(SurfNum);
    2551          591 :                 if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) {
    2552            6 :                     state.dataSurface->SurfaceFilterLists[static_cast<int>(DataSurfaces::SurfaceFilter::AllInteriorWindows)].push_back(SurfNum);
    2553          585 :                 } else if (surf.Class == SurfaceClass::Wall) {
    2554          306 :                     state.dataSurface->SurfaceFilterLists[static_cast<int>(DataSurfaces::SurfaceFilter::AllInteriorWalls)].push_back(SurfNum);
    2555          279 :                 } else if (surf.Class == SurfaceClass::Floor) {
    2556          185 :                     state.dataSurface->SurfaceFilterLists[static_cast<int>(DataSurfaces::SurfaceFilter::AllInteriorFloors)].push_back(SurfNum);
    2557           94 :                 } else if (surf.Class == SurfaceClass::Roof) {
    2558           62 :                     state.dataSurface->SurfaceFilterLists[static_cast<int>(DataSurfaces::SurfaceFilter::AllInteriorRoofs)].push_back(SurfNum);
    2559           62 :                     state.dataSurface->SurfaceFilterLists[static_cast<int>(DataSurfaces::SurfaceFilter::AllInteriorCeilings)].push_back(SurfNum);
    2560              :                 }
    2561              :             } else {
    2562         1545 :                 state.dataSurface->SurfaceFilterLists[static_cast<int>(DataSurfaces::SurfaceFilter::AllExteriorSurfaces)].push_back(SurfNum);
    2563         1545 :                 if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) {
    2564          196 :                     state.dataSurface->SurfaceFilterLists[static_cast<int>(DataSurfaces::SurfaceFilter::AllExteriorWindows)].push_back(SurfNum);
    2565         1349 :                 } else if (surf.Class == SurfaceClass::Wall) {
    2566          825 :                     state.dataSurface->SurfaceFilterLists[static_cast<int>(DataSurfaces::SurfaceFilter::AllExteriorWalls)].push_back(SurfNum);
    2567          524 :                 } else if (surf.Class == SurfaceClass::Floor) {
    2568          238 :                     state.dataSurface->SurfaceFilterLists[static_cast<int>(DataSurfaces::SurfaceFilter::AllExteriorFloors)].push_back(SurfNum);
    2569          286 :                 } else if (surf.Class == SurfaceClass::Roof) {
    2570          281 :                     state.dataSurface->SurfaceFilterLists[static_cast<int>(DataSurfaces::SurfaceFilter::AllExteriorRoofs)].push_back(SurfNum);
    2571          281 :                     state.dataSurface->SurfaceFilterLists[static_cast<int>(DataSurfaces::SurfaceFilter::AllInteriorCeilings)].push_back(SurfNum);
    2572              :                 }
    2573              :             }
    2574              :         } // for (SurfNum)
    2575              : 
    2576              :         // Note, could do same for Window Area and detecting if Interzone Surface in Zone
    2577              : 
    2578          224 :         if (state.dataSurfaceGeometry->Warning1Count > 0) {
    2579            0 :             ShowWarningMessage(state,
    2580            0 :                                format("{}Window dimensions differ from Window 5/6 data file dimensions, {} times.",
    2581              :                                       RoutineName,
    2582            0 :                                       state.dataSurfaceGeometry->Warning1Count));
    2583            0 :             ShowContinueError(state, "This will affect the frame heat transfer calculation if the frame in the Data File entry");
    2584            0 :             ShowContinueError(state, "is not uniform, i.e., has sections with different geometry and/or thermal properties.");
    2585            0 :             ShowContinueError(state, "For explicit details on each window, use Output:Diagnostics,DisplayExtraWarnings;");
    2586              :         }
    2587          224 :         if (state.dataSurfaceGeometry->Warning2Count > 0) {
    2588            0 :             ShowWarningMessage(state,
    2589            0 :                                format("{}Exterior Windows have been replaced with Window 5/6 two glazing systems, {} times.",
    2590              :                                       RoutineName,
    2591            0 :                                       state.dataSurfaceGeometry->Warning2Count));
    2592            0 :             ShowContinueError(state, "Note that originally entered dimensions are overridden.");
    2593            0 :             ShowContinueError(state, "For explicit details on each window, use Output:Diagnostics,DisplayExtraWarnings;");
    2594              :         }
    2595          224 :         if (state.dataSurfaceGeometry->Warning3Count > 0) {
    2596            0 :             ShowWarningMessage(state,
    2597            0 :                                format("{}Interior Windows have been replaced with Window 5/6 two glazing systems, {} times.",
    2598              :                                       RoutineName,
    2599            0 :                                       state.dataSurfaceGeometry->Warning3Count));
    2600            0 :             ShowContinueError(state, "Note that originally entered dimensions are overridden.");
    2601            0 :             ShowContinueError(state, "For explicit details on each window, use Output:Diagnostics,DisplayExtraWarnings;");
    2602              :         }
    2603              : 
    2604          224 :         if (state.dataErrTracking->TotalMultipliedWindows > 0) {
    2605            0 :             ShowWarningMessage(state,
    2606            0 :                                format("{}There are {} window/glass door(s) that may cause inaccurate shadowing due to Solar Distribution.",
    2607              :                                       RoutineName,
    2608            0 :                                       state.dataErrTracking->TotalMultipliedWindows));
    2609            0 :             ShowContinueError(state, "For explicit details on each window, use Output:Diagnostics,DisplayExtraWarnings;");
    2610            0 :             state.dataErrTracking->TotalWarningErrors += state.dataErrTracking->TotalMultipliedWindows;
    2611              :         }
    2612          224 :         if (state.dataErrTracking->TotalCoincidentVertices > 0) {
    2613            0 :             ShowWarningMessage(state,
    2614            0 :                                format("{}There are {} coincident/collinear vertices; These have been deleted unless the deletion would bring the "
    2615              :                                       "number of surface sides < 3.",
    2616              :                                       RoutineName,
    2617            0 :                                       state.dataErrTracking->TotalCoincidentVertices));
    2618            0 :             ShowContinueError(state, "For explicit details on each problem surface, use Output:Diagnostics,DisplayExtraWarnings;");
    2619            0 :             state.dataErrTracking->TotalWarningErrors += state.dataErrTracking->TotalCoincidentVertices;
    2620              :         }
    2621          224 :         if (state.dataErrTracking->TotalDegenerateSurfaces > 0) {
    2622            0 :             ShowSevereMessage(state,
    2623            0 :                               format("{}There are {} degenerate surfaces; Degenerate surfaces are those with number of sides < 3.",
    2624              :                                      RoutineName,
    2625            0 :                                      state.dataErrTracking->TotalDegenerateSurfaces));
    2626            0 :             ShowContinueError(state, "These surfaces should be deleted.");
    2627            0 :             ShowContinueError(state, "For explicit details on each problem surface, use Output:Diagnostics,DisplayExtraWarnings;");
    2628            0 :             state.dataErrTracking->TotalSevereErrors += state.dataErrTracking->TotalDegenerateSurfaces;
    2629              :         }
    2630              : 
    2631          224 :         GetHTSurfExtVentedCavityData(state, ErrorsFound);
    2632              : 
    2633          224 :         state.dataSurfaceGeometry->exposedFoundationPerimeter.getData(state, ErrorsFound);
    2634              : 
    2635          224 :         GetSurfaceHeatTransferAlgorithmOverrides(state, ErrorsFound);
    2636              : 
    2637              :         // Set up enclosures, process Air Boundaries if any
    2638          224 :         SetupEnclosuresAndAirBoundaries(state, state.dataViewFactor->EnclRadInfo, SurfaceGeometry::enclosureType::RadiantEnclosures, ErrorsFound);
    2639              : 
    2640          224 :         GetSurfaceGroundSurfsData(state, ErrorsFound);
    2641              : 
    2642          224 :         GetSurfaceSrdSurfsData(state, ErrorsFound);
    2643              : 
    2644          224 :         GetSurfaceLocalEnvData(state, ErrorsFound);
    2645              : 
    2646          224 :         if (SurfError || ErrorsFound) {
    2647            0 :             ErrorsFound = true;
    2648            0 :             ShowFatalError(state, format("{}Errors discovered, program terminates.", RoutineName));
    2649              :         }
    2650              : 
    2651          224 :         int TotShadSurf = TotDetachedFixed + TotDetachedBldg + TotRectDetachedFixed + TotRectDetachedBldg + TotShdSubs + TotOverhangs +
    2652          224 :                           TotOverhangsProjection + TotFins + TotFinsProjection;
    2653          224 :         int NumDElightCmplxFen = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Daylighting:DElight:ComplexFenestration");
    2654          224 :         if (TotShadSurf > 0 && (NumDElightCmplxFen > 0 || Dayltg::doesDayLightingUseDElight(state))) {
    2655            0 :             ShowWarningError(state, format("{}When using DElight daylighting the presence of exterior shading surfaces is ignored.", RoutineName));
    2656              :         }
    2657              : 
    2658         2486 :         for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; SurfNum++) {
    2659         2262 :             auto &surf = state.dataSurface->Surface(SurfNum);
    2660              :             // Initialize run time surface arrays
    2661         2262 :             state.dataSurface->SurfActiveConstruction(SurfNum) = surf.Construction;
    2662         2262 :             surf.RepresentativeCalcSurfNum = SurfNum;
    2663              :         }
    2664              : 
    2665              :         // Representative surface calculations: Assign representative heat transfer surfaces
    2666          224 :         if (state.dataSurface->UseRepresentativeSurfaceCalculations &&
    2667          224 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "ZoneProperty:UserViewFactors:BySurfaceName") == 0) {
    2668            0 :             for (int zoneNum = 1; zoneNum <= state.dataGlobal->NumOfZones; ++zoneNum) {
    2669            0 :                 for (int spaceNum : state.dataHeatBal->Zone(zoneNum).spaceIndexes) {
    2670            0 :                     auto const &thisSpace = state.dataHeatBal->space(spaceNum);
    2671            0 :                     for (int surfNum = thisSpace.HTSurfaceFirst; surfNum <= thisSpace.HTSurfaceLast; surfNum++) {
    2672            0 :                         auto &surface(state.dataSurface->Surface(surfNum));
    2673              :                         // Conditions where surface always needs to be unique
    2674            0 :                         bool forceUniqueSurface = surface.HasShadeControl ||
    2675            0 :                                                   state.dataSurface->SurfWinAirflowSource(surfNum) != DataSurfaces::WindowAirFlowSource::Invalid ||
    2676            0 :                                                   state.dataConstruction->Construct(surface.Construction).SourceSinkPresent ||
    2677            0 :                                                   surface.Class == SurfaceClass::TDD_Dome ||
    2678            0 :                                                   (surface.Class == SurfaceClass::Window &&
    2679            0 :                                                    (surface.OriginalClass == SurfaceClass::TDD_Diffuser ||
    2680            0 :                                                     state.dataSurface->SurfWinWindowModelType(surfNum) != DataSurfaces::WindowModel::Detailed ||
    2681            0 :                                                     state.dataWindowManager->inExtWindowModel->isExternalLibraryModel() ||
    2682            0 :                                                     state.dataConstruction->Construct(surface.Construction).isTCWindow));
    2683            0 :                         if (!forceUniqueSurface) {
    2684            0 :                             state.dataSurface->Surface(surfNum).set_representative_surface(state, surfNum);
    2685              :                         }
    2686              :                     }
    2687              :                 }
    2688              :             }
    2689              :         }
    2690              : 
    2691          224 :         if (SurfError || ErrorsFound) {
    2692            0 :             ErrorsFound = true;
    2693            0 :             ShowFatalError(state, format("{}Errors discovered, program terminates.", RoutineName));
    2694              :         }
    2695          224 :     }
    2696              : 
    2697          224 :     void CreateMissingSpaces(EnergyPlusData &state, Array1D<SurfaceGeometry::SurfaceData> &Surfaces)
    2698              :     {
    2699              :         static constexpr std::string_view RoutineName = "CreateMissingSpaces: ";
    2700              :         // Scan surfaces to see if Space was assigned in input
    2701          224 :         EPVector<bool> anySurfacesWithSpace;    // True if any surfaces in a zone do not have a space assigned in input
    2702          224 :         EPVector<bool> anySurfacesWithoutSpace; // True if any surfaces in a zone have a space assigned in input
    2703          224 :         anySurfacesWithSpace.resize(state.dataGlobal->NumOfZones, false);
    2704          224 :         anySurfacesWithoutSpace.resize(state.dataGlobal->NumOfZones, false);
    2705              : 
    2706         2486 :         for (int surfNum = 1; surfNum <= state.dataSurface->TotSurfaces; ++surfNum) {
    2707         2262 :             auto &thisSurf = Surfaces(surfNum);
    2708         2262 :             if (!thisSurf.HeatTransSurf) continue;                               // ignore shading surfaces
    2709         2178 :             if (thisSurf.Class == DataSurfaces::SurfaceClass::IntMass) continue; // skip internal mass surfaces for this check
    2710         2162 :             if (thisSurf.BaseSurf != surfNum) {
    2711              :                 // Set space for subsurfaces
    2712          227 :                 thisSurf.spaceNum = Surfaces(thisSurf.BaseSurf).spaceNum;
    2713              :             }
    2714         2162 :             if (thisSurf.spaceNum > 0) {
    2715          171 :                 anySurfacesWithSpace(thisSurf.Zone) = true;
    2716         1991 :             } else if (thisSurf.ExtBoundCond != unreconciledZoneSurface) {
    2717         1443 :                 anySurfacesWithoutSpace(thisSurf.Zone) = true;
    2718          548 :             } else if (thisSurf.Name.substr(0, 3) != "iz-") {
    2719              :                 // Only trigger a new space if the spaceless surface is not an autogenerated interzone surface
    2720          536 :                 anySurfacesWithoutSpace(thisSurf.Zone) = true;
    2721              :             }
    2722              :         }
    2723              : 
    2724              :         // Create any missing Spaces
    2725          578 :         for (int zoneNum = 1; zoneNum <= state.dataGlobal->NumOfZones; ++zoneNum) {
    2726          354 :             auto &thisZone = state.dataHeatBal->Zone(zoneNum);
    2727          354 :             if (anySurfacesWithoutSpace(zoneNum)) {
    2728              :                 // If any surfaces in the zone are not assigned to a space, may need to create a new space
    2729              :                 // Every zone has at least one space, created in HeatBalanceManager::GetSpaceData
    2730              :                 // If no surfaces have a space assigned, then the default space will be used, otherwise, create a new space
    2731          299 :                 if (anySurfacesWithSpace(zoneNum)) {
    2732              :                     // Add new space
    2733            0 :                     ++state.dataGlobal->numSpaces;
    2734            0 :                     assert(state.dataHeatBal->space.size() >= state.dataGlobal->numSpaces);
    2735            0 :                     state.dataHeatBal->space(state.dataGlobal->numSpaces).zoneNum = zoneNum;
    2736              :                     // Add to zone's list of spaces
    2737            0 :                     thisZone.spaceIndexes.emplace_back(state.dataGlobal->numSpaces);
    2738            0 :                     ++state.dataHeatBal->Zone(zoneNum).numSpaces;
    2739            0 :                     assert(state.dataHeatBal->Zone(zoneNum).numSpaces == int(state.dataHeatBal->Zone(zoneNum).spaceIndexes.size()));
    2740              :                     // If some surfaces in the zone are assigned to a space, the new space is the remainder of the zone
    2741            0 :                     state.dataHeatBal->space(state.dataGlobal->numSpaces).Name =
    2742            0 :                         thisZone.Name + "-REMAINDER"; // Make UPPERcase so it can be referenced in input
    2743            0 :                     state.dataHeatBal->space(state.dataGlobal->numSpaces).isRemainderSpace = true;
    2744            0 :                     state.dataHeatBal->space(state.dataGlobal->numSpaces).spaceType = "GENERAL";
    2745            0 :                     state.dataHeatBal->space(state.dataGlobal->numSpaces).spaceTypeNum = HeatBalanceManager::GetGeneralSpaceTypeNum(state);
    2746              :                 }
    2747              :             }
    2748              :         }
    2749              :         // Right-size space vector
    2750          224 :         state.dataHeatBal->space.resize(state.dataGlobal->numSpaces);
    2751              : 
    2752              :         // Assign Spaces to surfaces without one
    2753         2486 :         for (int surfNum = 1; surfNum <= state.dataSurface->TotSurfaces; ++surfNum) {
    2754         2262 :             auto &thisSurf = Surfaces(surfNum);
    2755         2262 :             if (!thisSurf.HeatTransSurf) continue; // ignore shading surfaces
    2756         2178 :             if (thisSurf.spaceNum == 0) {
    2757         2007 :                 int const numSpaces = state.dataHeatBal->Zone(thisSurf.Zone).numSpaces;
    2758         2007 :                 int const lastSpaceForZone = state.dataHeatBal->Zone(thisSurf.Zone).spaceIndexes(numSpaces);
    2759         2007 :                 thisSurf.spaceNum = lastSpaceForZone;
    2760         2007 :                 if ((thisSurf.ExtBoundCond == unreconciledZoneSurface) && (thisSurf.Name.substr(0, 3) == "iz-")) {
    2761           12 :                     if (state.dataHeatBal->Zone(thisSurf.Zone).numSpaces > 1) {
    2762              :                         // Only trigger warning if the spaceless surface is an autogenerated interzone surface
    2763            4 :                         ShowWarningError(state,
    2764            4 :                                          format("{}Surface=\"{}\" has Outside Boundary Condition=Zone, but Zone=\"{}\" has more than 1 Space.",
    2765              :                                                 RoutineName,
    2766            2 :                                                 thisSurf.Name.substr(3),
    2767            2 :                                                 thisSurf.ZoneName));
    2768            4 :                         ShowContinueError(state,
    2769            4 :                                           format("Auto-generated surface=\"{}\" will be assigned to Space=\"{}\"",
    2770            2 :                                                  thisSurf.Name,
    2771            2 :                                                  state.dataHeatBal->space(thisSurf.spaceNum).Name));
    2772            6 :                         ShowContinueError(state, "Use Outside Boundary Condition = Space to specify the exact Space for the outside boundary.");
    2773              :                     }
    2774              :                 }
    2775              :             }
    2776              :         }
    2777          224 :     }
    2778              : 
    2779          224 :     void createSpaceSurfaceLists(EnergyPlusData &state)
    2780              :     {
    2781              :         static constexpr std::string_view RoutineName("createSpaceSurfaceLists: ");
    2782              :         // Build Space surface lists now that all of the surface sorting is complete
    2783         2486 :         for (int surfNum = 1; surfNum <= state.dataSurface->TotSurfaces; ++surfNum) {
    2784         2262 :             auto &thisSurf = state.dataSurface->Surface(surfNum);
    2785         2262 :             if (!thisSurf.HeatTransSurf) continue; // ignore shading surfaces
    2786              :             // Add to Space's list of surfaces
    2787         2178 :             state.dataHeatBal->space(thisSurf.spaceNum).surfaces.emplace_back(surfNum);
    2788              :         }
    2789          600 :         for (int spaceNum = 1; spaceNum <= state.dataGlobal->numSpaces; ++spaceNum) {
    2790          376 :             if (int(state.dataHeatBal->space(spaceNum).surfaces.size()) == 0) {
    2791            3 :                 ShowWarningError(state, format("{}Space={} has no surfaces.", RoutineName, state.dataHeatBal->space(spaceNum).Name));
    2792              :             }
    2793              :         }
    2794          224 :     }
    2795              : 
    2796          224 :     void setSurfaceFirstLast(EnergyPlusData &state)
    2797              :     {
    2798              :         // Set Zone and Space Surface First/Last Pointers
    2799              :         // Space surface lists have been built earlier in createSpaceSurfaceLists
    2800          578 :         for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
    2801          730 :             for (int spaceNum : state.dataHeatBal->Zone(ZoneNum).spaceIndexes) {
    2802          376 :                 auto &thisSpace = state.dataHeatBal->space(spaceNum);
    2803         2554 :                 for (int SurfNum : thisSpace.surfaces) {
    2804         2178 :                     auto &surf = state.dataSurface->Surface(SurfNum);
    2805         2178 :                     if (thisSpace.AllSurfaceFirst == 0) {
    2806          373 :                         thisSpace.AllSurfaceFirst = SurfNum;
    2807              :                     }
    2808         2178 :                     thisSpace.AllSurfaceLast = SurfNum;
    2809              : 
    2810         2178 :                     if (surf.IsAirBoundarySurf) {
    2811           42 :                         surf.HeatTransSurf = false;
    2812           42 :                         continue;
    2813              :                     }
    2814              :                     // Non window surfaces are grouped next within each space
    2815         2136 :                     if (thisSpace.HTSurfaceFirst == 0) {
    2816          372 :                         thisSpace.HTSurfaceFirst = SurfNum;
    2817          372 :                         thisSpace.OpaqOrIntMassSurfaceFirst = SurfNum;
    2818          372 :                         thisSpace.OpaqOrWinSurfaceFirst = SurfNum;
    2819              :                     }
    2820         2136 :                     thisSpace.HTSurfaceLast = SurfNum;
    2821              : 
    2822              :                     // Window surfaces are grouped next within each space
    2823         2136 :                     if ((surf.Class == DataSurfaces::SurfaceClass::Window) || (surf.Class == DataSurfaces::SurfaceClass::GlassDoor) ||
    2824         1947 :                         (surf.Class == DataSurfaces::SurfaceClass::TDD_Diffuser)) {
    2825          195 :                         if (thisSpace.WindowSurfaceFirst == 0) {
    2826          112 :                             thisSpace.WindowSurfaceFirst = SurfNum;
    2827              :                         }
    2828          195 :                         thisSpace.WindowSurfaceLast = SurfNum;
    2829         1941 :                     } else if (surf.Class != DataSurfaces::SurfaceClass::TDD_Dome) {
    2830         1934 :                         thisSpace.OpaqOrIntMassSurfaceLast = SurfNum;
    2831              :                     }
    2832              : 
    2833              :                     // TDDDome surfaces are grouped last within each space
    2834         2136 :                     if (surf.Class == DataSurfaces::SurfaceClass::TDD_Dome) {
    2835            7 :                         if (thisSpace.TDDDomeFirst == 0) {
    2836            5 :                             thisSpace.TDDDomeFirst = SurfNum;
    2837              :                         }
    2838            7 :                         thisSpace.TDDDomeLast = SurfNum;
    2839              :                     } else {
    2840         2129 :                         thisSpace.OpaqOrWinSurfaceLast = SurfNum;
    2841              :                     }
    2842              :                 }
    2843          376 :                 state.dataHeatBal->Zone(ZoneNum).AllSurfaceLast = thisSpace.AllSurfaceLast;
    2844              :             }
    2845          354 :             int firstSpaceNum = state.dataHeatBal->Zone(ZoneNum).spaceIndexes(1);
    2846          354 :             state.dataHeatBal->Zone(ZoneNum).AllSurfaceFirst = state.dataHeatBal->space(firstSpaceNum).AllSurfaceFirst;
    2847              :         }
    2848          224 :     }
    2849              : 
    2850          235 :     void checkSubSurfAzTiltNorm(EnergyPlusData &state,
    2851              :                                 SurfaceData &baseSurface, // Base surface data (in)
    2852              :                                 SurfaceData &subSurface,  // Subsurface data (in)
    2853              :                                 bool &surfaceError        // True if surface azimuths or tilts differ by more than error tolerance
    2854              :     )
    2855              :     {
    2856          235 :         bool sameSurfNormal = false; // True if surface has the same surface normal within tolerance
    2857          235 :         Real64 constexpr warningTolerance = 30.0;
    2858          235 :         Real64 constexpr errorTolerance = 90.0;
    2859              : 
    2860          235 :         surfaceError = false; // True if surface has the same surface normal within tolerance
    2861              : 
    2862              :         // Check if base surface and subsurface have the same normal
    2863          235 :         Vectors::CompareTwoVectors(baseSurface.NewellSurfaceNormalVector, subSurface.NewellSurfaceNormalVector, sameSurfNormal, 0.001);
    2864          235 :         if (sameSurfNormal) { // copy lcs vectors
    2865              :                               // Prior logic tested for azimuth difference < 30 and then skipped this - this caused large diffs in
    2866              :                               // CmplxGlz_MeasuredDeflectionAndShading Restoring that check here but will require further investigation (MJW Dec 2015)
    2867              :                               // if (std::abs(baseSurface.Azimuth - subSurface.Azimuth) > warningTolerance) {
    2868          223 :             subSurface.lcsx = baseSurface.lcsx;
    2869          223 :             subSurface.lcsy = baseSurface.lcsy;
    2870          223 :             subSurface.lcsz = baseSurface.lcsz;
    2871              :             // }
    2872              :         } else {
    2873           12 :             bool baseSurfHoriz = false; // True if base surface is near horizontal
    2874              :             // // Not sure what this does, but keeping for now (MJW Dec 2015)
    2875              :             // if (std::abs(subSurface.Azimuth - 360.0) < 0.01) {
    2876              :             //     subSurface.Azimuth = 360.0 - subSurface.Azimuth;
    2877              :             // }
    2878              :             // if (std::abs(baseSurface.Azimuth - 360.0) < 0.01) {
    2879              :             //     baseSurface.Azimuth = 360.0 - baseSurface.Azimuth;
    2880              :             // }
    2881              : 
    2882              :             // Is base surface horizontal? If so, ignore azimuth differences
    2883           12 :             if (std::abs(baseSurface.Tilt) <= 1.0e-5 || std::abs(baseSurface.Tilt - 180.0) <= 1.0e-5) baseSurfHoriz = true;
    2884              : 
    2885           24 :             if (((General::rotAzmDiffDeg(baseSurface.Azimuth, subSurface.Azimuth) > errorTolerance) && !baseSurfHoriz) ||
    2886           12 :                 (std::abs(baseSurface.Tilt - subSurface.Tilt) > errorTolerance)) {
    2887            1 :                 surfaceError = true;
    2888            2 :                 ShowSevereError(
    2889              :                     state,
    2890            2 :                     format("checkSubSurfAzTiltNorm: Outward facing angle of subsurface differs more than {:.1R} degrees from base surface.",
    2891              :                            errorTolerance));
    2892            2 :                 ShowContinueError(state,
    2893            2 :                                   format("Subsurface=\"{}\" Tilt = {:.1R}  Azimuth = {:.1R}", subSurface.Name, subSurface.Tilt, subSurface.Azimuth));
    2894            2 :                 ShowContinueError(
    2895            2 :                     state, format("Base surface=\"{}\" Tilt = {:.1R}  Azimuth = {:.1R}", baseSurface.Name, baseSurface.Tilt, baseSurface.Azimuth));
    2896           20 :             } else if (((General::rotAzmDiffDeg(baseSurface.Azimuth, subSurface.Azimuth) > warningTolerance) && !baseSurfHoriz) ||
    2897            9 :                        (std::abs(baseSurface.Tilt - subSurface.Tilt) > warningTolerance)) {
    2898            5 :                 ++state.dataSurfaceGeometry->checkSubSurfAzTiltNormErrCount;
    2899            5 :                 if (state.dataSurfaceGeometry->checkSubSurfAzTiltNormErrCount == 1 && !state.dataGlobal->DisplayExtraWarnings) {
    2900           10 :                     ShowWarningError(state,
    2901           10 :                                      format("checkSubSurfAzTiltNorm: Some Outward Facing angles of subsurfaces differ more than {:.1R} "
    2902              :                                             "degrees from base surface.",
    2903              :                                             warningTolerance));
    2904           15 :                     ShowContinueError(state, "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on individual surfaces.");
    2905              :                 }
    2906            5 :                 if (state.dataGlobal->DisplayExtraWarnings) {
    2907            0 :                     ShowWarningError(
    2908              :                         state,
    2909            0 :                         format("checkSubSurfAzTiltNorm: Outward facing angle of subsurface differs more than {:.1R} degrees from base surface.",
    2910              :                                warningTolerance));
    2911            0 :                     ShowContinueError(
    2912            0 :                         state, format("Subsurface=\"{}\" Tilt = {:.1R}  Azimuth = {:.1R}", subSurface.Name, subSurface.Tilt, subSurface.Azimuth));
    2913            0 :                     ShowContinueError(
    2914              :                         state,
    2915            0 :                         format("Base surface=\"{}\" Tilt = {:.1R}  Azimuth = {:.1R}", baseSurface.Name, baseSurface.Tilt, baseSurface.Azimuth));
    2916              :                 }
    2917              :             }
    2918              :         }
    2919          235 :     }
    2920              : 
    2921          268 :     void GetGeometryParameters(EnergyPlusData &state, bool &ErrorsFound) // set to true if errors found during input
    2922              :     {
    2923              : 
    2924              :         // SUBROUTINE INFORMATION:
    2925              :         //       AUTHOR         Linda Lawrie
    2926              :         //       DATE WRITTEN   May 2000
    2927              : 
    2928              :         // PURPOSE OF THIS SUBROUTINE:
    2929              :         // This subroutine reads in the "Surface Geometry" parameters, verifies them,
    2930              :         // and sets "global" variables that will tell other routines how the surface
    2931              :         // vertices are expected in input.
    2932              : 
    2933              :         // REFERENCES:
    2934              :         // GlobalGeometryRules Definition
    2935              :         // GlobalGeometryRules,
    2936              :         //      \required-object
    2937              :         //      \unique-object
    2938              :         //  A1, \field Starting Vertex Position
    2939              :         //      \required-field
    2940              :         //      \note Specified as entry for a 4 sided surface/rectangle
    2941              :         //      \note Surfaces are specified as viewed from outside the surface
    2942              :         //      \note Shading surfaces as viewed from behind.  (towards what they are shading)
    2943              :         //      \type choice
    2944              :         //      \key UpperLeftCorner
    2945              :         //      \key LowerLeftCorner
    2946              :         //      \key UpperRightCorner
    2947              :         //      \key LowerRightCorner
    2948              :         //  A2, \field Vertex Entry Direction
    2949              :         //      \required-field
    2950              :         //      \type choice
    2951              :         //      \key Counterclockwise
    2952              :         //      \key Clockwise
    2953              :         //  A3, \field Coordinate System
    2954              :         //      \required-field
    2955              :         //      \note relative -- coordinates are entered relative to zone origin
    2956              :         //      \note world -- all coordinates entered are "absolute" for this facility
    2957              :         //      \note absolute -- same as world
    2958              :         //      \type choice
    2959              :         //      \key Relative
    2960              :         //      \key World
    2961              :         //      \key Absolute
    2962              :         //  A4, \field Daylighting Reference Point Coordinate System
    2963              :         //      \type choice
    2964              :         //      \key Relative
    2965              :         //      \default Relative
    2966              :         //      \note Relative -- coordinates are entered relative to zone origin
    2967              :         //      \key World
    2968              :         //      \note World -- all coordinates entered are "absolute" for this facility
    2969              :         //      \key Absolute
    2970              :         //      \note absolute -- same as world
    2971              :         //  A5; \field Rectangular Surface Coordinate System
    2972              :         //      \type choice
    2973              :         //      \key Relative
    2974              :         //      \default Relative
    2975              :         //      \note Relative -- Starting corner is entered relative to zone origin
    2976              :         //      \key World
    2977              :         //      \note World -- Starting corner is entered in "absolute"
    2978              :         //      \key Absolute
    2979              :         //      \note absolute -- same as world
    2980              : 
    2981              :         // SUBROUTINE PARAMETER DEFINITIONS:
    2982          268 :         static Array1D_string const FlCorners(4, {"UpperLeftCorner", "LowerLeftCorner", "LowerRightCorner", "UpperRightCorner"});
    2983              : 
    2984              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    2985          268 :         Array1D_string GAlphas(5);
    2986          268 :         Array1D<Real64> GNum(1);
    2987              : 
    2988          268 :         auto &s_ipsc = state.dataIPShortCut;
    2989              : 
    2990          268 :         s_ipsc->cCurrentModuleObject = "GlobalGeometryRules";
    2991          268 :         int NumStmt = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
    2992          268 :         std::string OutMsg = " Surface Geometry,";
    2993              : 
    2994              :         {
    2995          268 :             int const SELECT_CASE_var = NumStmt;
    2996              : 
    2997          268 :             if (SELECT_CASE_var == 1) {
    2998              :                 int NNum;
    2999              :                 int IOStat;
    3000              :                 int NAlphas;
    3001              :                 // This is the valid case
    3002          804 :                 state.dataInputProcessing->inputProcessor->getObjectItem(state,
    3003          268 :                                                                          s_ipsc->cCurrentModuleObject,
    3004              :                                                                          1,
    3005              :                                                                          GAlphas,
    3006              :                                                                          NAlphas,
    3007              :                                                                          GNum,
    3008              :                                                                          NNum,
    3009              :                                                                          IOStat,
    3010          268 :                                                                          s_ipsc->lNumericFieldBlanks,
    3011          268 :                                                                          s_ipsc->lAlphaFieldBlanks,
    3012          268 :                                                                          s_ipsc->cAlphaFieldNames,
    3013          268 :                                                                          s_ipsc->cNumericFieldNames);
    3014              : 
    3015              :                 // Even though these will be validated, set defaults in case error here -- wont
    3016              :                 // cause aborts in later surface gets (hopefully)
    3017          268 :                 state.dataSurface->Corner = DataSurfaces::UpperLeftCorner;
    3018          268 :                 state.dataSurface->WorldCoordSystem = true;
    3019          268 :                 state.dataSurface->CCW = true;
    3020              : 
    3021          268 :                 int Found = Util::FindItem(GAlphas(1), FlCorners, 4);
    3022          268 :                 if (Found == 0) {
    3023            0 :                     ShowSevereError(state, format("{}: Invalid {}={}", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaFieldNames(1), GAlphas(1)));
    3024            0 :                     ErrorsFound = true;
    3025              :                 } else {
    3026          268 :                     state.dataSurface->Corner = Found;
    3027          268 :                     OutMsg += FlCorners(state.dataSurface->Corner) + ',';
    3028              :                 }
    3029              : 
    3030          268 :                 bool OK = false;
    3031          268 :                 if (Util::SameString(GAlphas(2), "CCW") || Util::SameString(GAlphas(2), "Counterclockwise")) {
    3032          268 :                     state.dataSurface->CCW = true;
    3033          268 :                     OutMsg += "Counterclockwise,";
    3034          268 :                     OK = true;
    3035              :                 }
    3036          268 :                 if (Util::SameString(GAlphas(2), "CW") || Util::SameString(GAlphas(2), "Clockwise")) {
    3037            0 :                     state.dataSurface->CCW = false;
    3038            0 :                     OutMsg += "Clockwise,";
    3039            0 :                     OK = true;
    3040              :                 }
    3041          268 :                 if (!OK) {
    3042            0 :                     ShowSevereError(state, format("{}: Invalid {}={}", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaFieldNames(2), GAlphas(2)));
    3043            0 :                     ErrorsFound = true;
    3044              :                 }
    3045              : 
    3046          268 :                 OK = false;
    3047          268 :                 if (Util::SameString(GAlphas(3), "World") || Util::SameString(GAlphas(3), "Absolute")) {
    3048          102 :                     state.dataSurface->WorldCoordSystem = true;
    3049          102 :                     OutMsg += "WorldCoordinateSystem,";
    3050          102 :                     OK = true;
    3051              :                 }
    3052          268 :                 if (Util::SameString(GAlphas(3), "Relative")) {
    3053          166 :                     state.dataSurface->WorldCoordSystem = false;
    3054          166 :                     OutMsg += "RelativeCoordinateSystem,";
    3055          166 :                     OK = true;
    3056              :                 }
    3057          268 :                 if (!OK) {
    3058            0 :                     ShowWarningError(state, format("{}: Invalid {}={}", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaFieldNames(3), GAlphas(3)));
    3059            0 :                     ShowContinueError(state, format("{} defaults to \"WorldCoordinateSystem\"", s_ipsc->cAlphaFieldNames(3)));
    3060            0 :                     state.dataSurface->WorldCoordSystem = true;
    3061            0 :                     OutMsg += "WorldCoordinateSystem,";
    3062              :                 }
    3063              : 
    3064          268 :                 OK = false;
    3065          268 :                 if (Util::SameString(GAlphas(4), "World") || Util::SameString(GAlphas(4), "Absolute")) {
    3066            8 :                     state.dataSurface->DaylRefWorldCoordSystem = true;
    3067            8 :                     OutMsg += "WorldCoordinateSystem,";
    3068            8 :                     OK = true;
    3069              :                 }
    3070          268 :                 if (Util::SameString(GAlphas(4), "Relative") || GAlphas(4).empty()) {
    3071          260 :                     state.dataSurface->DaylRefWorldCoordSystem = false;
    3072          260 :                     OutMsg += "RelativeCoordinateSystem,";
    3073          260 :                     OK = true;
    3074              :                 }
    3075          268 :                 if (!OK) {
    3076            0 :                     ShowWarningError(state, format("{}: Invalid {}={}", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaFieldNames(4), GAlphas(4)));
    3077            0 :                     ShowContinueError(state, format("{} defaults to \"RelativeToZoneOrigin\"", s_ipsc->cAlphaFieldNames(4)));
    3078            0 :                     state.dataSurface->DaylRefWorldCoordSystem = false;
    3079            0 :                     OutMsg += "RelativeToZoneOrigin,";
    3080              :                 }
    3081              : 
    3082          268 :                 OK = false;
    3083          268 :                 if (Util::SameString(GAlphas(5), "World") || Util::SameString(GAlphas(5), "Absolute")) {
    3084            2 :                     state.dataSurfaceGeometry->RectSurfRefWorldCoordSystem = true;
    3085            2 :                     OutMsg += "WorldCoordinateSystem";
    3086            2 :                     OK = true;
    3087              :                 }
    3088          268 :                 if (Util::SameString(GAlphas(5), "Relative") || GAlphas(5).empty()) {
    3089          266 :                     state.dataSurfaceGeometry->RectSurfRefWorldCoordSystem = false;
    3090          266 :                     OutMsg += "RelativeToZoneOrigin";
    3091          266 :                     OK = true;
    3092              :                 }
    3093          268 :                 if (!OK) {
    3094            0 :                     ShowWarningError(state, format("{}: Invalid {}={}", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaFieldNames(5), GAlphas(5)));
    3095            0 :                     ShowContinueError(state, format("{} defaults to \"RelativeToZoneOrigin\"", s_ipsc->cAlphaFieldNames(5)));
    3096            0 :                     state.dataSurfaceGeometry->RectSurfRefWorldCoordSystem = false;
    3097            0 :                     OutMsg += "RelativeToZoneOrigin";
    3098              :                 }
    3099              : 
    3100            0 :             } else if (SELECT_CASE_var == 0) {
    3101              : 
    3102            0 :                 ShowSevereError(state, format("{}: Required object not found.", s_ipsc->cCurrentModuleObject));
    3103            0 :                 OutMsg += "None found in input";
    3104            0 :                 ErrorsFound = true;
    3105              : 
    3106              :             } else {
    3107              : 
    3108            0 :                 ShowSevereError(state, format("{}: Too many objects entered.  Only one allowed.", s_ipsc->cCurrentModuleObject));
    3109            0 :                 ErrorsFound = true;
    3110              :             }
    3111              :         }
    3112              : 
    3113          268 :         if (!state.dataSurface->WorldCoordSystem) {
    3114          166 :             if (state.dataSurface->DaylRefWorldCoordSystem) {
    3115            0 :                 ShowWarningError(state, format("{}: Potential mismatch of coordinate specifications.", s_ipsc->cCurrentModuleObject));
    3116            0 :                 ShowContinueError(state, format("{}=\"{}\"; while ", s_ipsc->cAlphaFieldNames(3), GAlphas(3)));
    3117            0 :                 ShowContinueError(state, format("{}=\"{}\".", s_ipsc->cAlphaFieldNames(4), GAlphas(4)));
    3118              :             }
    3119          166 :             if (state.dataSurfaceGeometry->RectSurfRefWorldCoordSystem) {
    3120            0 :                 ShowWarningError(state, format("{}: Potential mismatch of coordinate specifications.", s_ipsc->cCurrentModuleObject));
    3121            0 :                 ShowContinueError(state, format("{}=\"{}\"; while ", s_ipsc->cAlphaFieldNames(3), GAlphas(3)));
    3122            0 :                 ShowContinueError(state, format("{}=\"{}\".", s_ipsc->cAlphaFieldNames(5), GAlphas(5)));
    3123              :             }
    3124              :         } else {
    3125          102 :             bool RelWarning = false;
    3126          270 :             for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
    3127          168 :                 if (state.dataHeatBal->Zone(ZoneNum).OriginX != 0.0) RelWarning = true;
    3128          168 :                 if (state.dataHeatBal->Zone(ZoneNum).OriginY != 0.0) RelWarning = true;
    3129          168 :                 if (state.dataHeatBal->Zone(ZoneNum).OriginZ != 0.0) RelWarning = true;
    3130              :             }
    3131          102 :             if (RelWarning && !state.dataSurfaceGeometry->RectSurfRefWorldCoordSystem) {
    3132            4 :                 ShowWarningError(state,
    3133            4 :                                  format("{}: Potential mismatch of coordinate specifications. Note that the rectangular surfaces are relying on the "
    3134              :                                         "default SurfaceGeometry for 'Relative to zone' coordinate.",
    3135            2 :                                         s_ipsc->cCurrentModuleObject));
    3136            2 :                 ShowContinueError(state, format("{}=\"{}\"; while ", s_ipsc->cAlphaFieldNames(3), GAlphas(3)));
    3137            2 :                 if (GAlphas(5) == "RELATIVE") {
    3138            2 :                     ShowContinueError(state, format("{}=\"{}\".", s_ipsc->cAlphaFieldNames(5), GAlphas(5)));
    3139            0 :                 } else if (GAlphas(5) != "ABSOLUTE") {
    3140            0 :                     ShowContinueError(state, format("{}=\"defaults to RELATIVE\".", s_ipsc->cAlphaFieldNames(5)));
    3141              :                 }
    3142              :             }
    3143              :         }
    3144              : 
    3145          268 :         print(state.files.eio,
    3146              :               "! <Surface Geometry>,Starting Corner,Vertex Input Direction,Coordinate System,Daylight Reference "
    3147              :               "Point Coordinate System,Rectangular (Simple) Surface Coordinate System\n");
    3148          268 :         print(state.files.eio, "{}\n", OutMsg);
    3149          268 :     }
    3150              : 
    3151          227 :     void GetDetShdSurfaceData(EnergyPlusData &state,
    3152              :                               bool &ErrorsFound,          // Error flag indicator (true if errors found)
    3153              :                               int &SurfNum,               // Count of Current SurfaceNumber
    3154              :                               int const TotDetachedFixed, // Number of Fixed Detached Shading Surfaces to obtain
    3155              :                               int const TotDetachedBldg   // Number of Building Detached Shading Surfaces to obtain
    3156              :     )
    3157              :     {
    3158              :         // SUBROUTINE INFORMATION:
    3159              :         //       AUTHOR         Linda Lawrie
    3160              :         //       DATE WRITTEN   May 2000
    3161              : 
    3162              :         // PURPOSE OF THIS SUBROUTINE:
    3163              :         // This subroutine gets the Detached Shading Surface Data,
    3164              :         // checks it for errors, etc.
    3165              : 
    3166              :         static constexpr std::string_view routineName = "GetDetShdSurfaceData";
    3167              :         // SUBROUTINE PARAMETER DEFINITIONS:
    3168          227 :         static Array1D_string const cModuleObjects(2, {"Shading:Site:Detailed", "Shading:Building:Detailed"});
    3169              : 
    3170              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    3171              :         int IOStat;     // IO Status when calling get input subroutine
    3172              :         int NumAlphas;  // Number of material alpha names being passed
    3173              :         int NumNumbers; // Number of material properties being passed
    3174              :         int Loop;
    3175              :         int ItemsToGet;
    3176              :         SurfaceClass ClassItem;
    3177              :         int numSides;
    3178              :         Real64 SchedMinValue;
    3179              :         Real64 SchedMaxValue;
    3180              : 
    3181          227 :         auto &s_ipsc = state.dataIPShortCut;
    3182              : 
    3183          227 :         if ((TotDetachedFixed + TotDetachedBldg) > 0 && state.dataHeatBal->SolarDistribution == DataHeatBalance::Shadowing::Minimal) {
    3184            0 :             ShowWarningError(state, "Detached shading effects are ignored when Solar Distribution = MinimalShadowing");
    3185              :         }
    3186              : 
    3187          227 :         if ((TotDetachedFixed + TotDetachedBldg) == 0) return;
    3188              : 
    3189           27 :         for (int Item = 1; Item <= 2; ++Item) {
    3190              : 
    3191           18 :             s_ipsc->cCurrentModuleObject = cModuleObjects(Item);
    3192           18 :             if (Item == 1) {
    3193            9 :                 ItemsToGet = TotDetachedFixed;
    3194            9 :                 ClassItem = SurfaceClass::Detached_F;
    3195              :             } else { // IF (Item == 2) THEN
    3196            9 :                 ItemsToGet = TotDetachedBldg;
    3197            9 :                 ClassItem = SurfaceClass::Detached_B;
    3198              :             }
    3199              : 
    3200           18 :             state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, s_ipsc->cCurrentModuleObject, Loop, NumAlphas, NumNumbers);
    3201           18 :             if (NumAlphas != 2) {
    3202            0 :                 ShowSevereError(
    3203              :                     state,
    3204            0 :                     format("{}: Object Definition indicates not = 2 Alpha Objects, Number Indicated={}", s_ipsc->cCurrentModuleObject, NumAlphas));
    3205            0 :                 ErrorsFound = true;
    3206              :             }
    3207              : 
    3208           35 :             for (Loop = 1; Loop <= ItemsToGet; ++Loop) {
    3209           34 :                 state.dataInputProcessing->inputProcessor->getObjectItem(state,
    3210           17 :                                                                          s_ipsc->cCurrentModuleObject,
    3211              :                                                                          Loop,
    3212           17 :                                                                          s_ipsc->cAlphaArgs,
    3213              :                                                                          NumAlphas,
    3214           17 :                                                                          s_ipsc->rNumericArgs,
    3215              :                                                                          NumNumbers,
    3216              :                                                                          IOStat,
    3217           17 :                                                                          s_ipsc->lNumericFieldBlanks,
    3218           17 :                                                                          s_ipsc->lAlphaFieldBlanks,
    3219           17 :                                                                          s_ipsc->cAlphaFieldNames,
    3220           17 :                                                                          s_ipsc->cNumericFieldNames);
    3221              : 
    3222           17 :                 ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
    3223              : 
    3224           34 :                 if (GlobalNames::VerifyUniqueInterObjectName(state,
    3225           17 :                                                              state.dataSurfaceGeometry->UniqueSurfaceNames,
    3226           17 :                                                              s_ipsc->cAlphaArgs(1),
    3227           17 :                                                              s_ipsc->cCurrentModuleObject,
    3228           17 :                                                              s_ipsc->cAlphaFieldNames(1),
    3229              :                                                              ErrorsFound)) {
    3230            0 :                     continue;
    3231              :                 }
    3232              : 
    3233           17 :                 ++SurfNum;
    3234              : 
    3235           17 :                 auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    3236           17 :                 surfTemp.Name = s_ipsc->cAlphaArgs(1); // Set the Surface Name in the Derived Type
    3237           17 :                 surfTemp.Class = ClassItem;
    3238           17 :                 surfTemp.HeatTransSurf = false;
    3239           17 :                 surfTemp.ExtSolar = true;
    3240              :                 // Base transmittance of a shadowing (sub)surface
    3241              : 
    3242           17 :                 if (s_ipsc->lAlphaFieldBlanks(2)) {
    3243            5 :                     surfTemp.shadowSurfSched =
    3244              :                         nullptr; // Leaving this as nullptr rather than making AlwaysOff because the uses and tests are too varied
    3245           12 :                 } else if ((surfTemp.shadowSurfSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(2))) == nullptr) {
    3246            0 :                     ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2));
    3247            0 :                     ErrorsFound = true;
    3248           12 :                 } else if (!surfTemp.shadowSurfSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 1.0)) {
    3249            1 :                     Sched::ShowSevereBadMinMax(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2), Clusive::In, 0.0, Clusive::In, 1.0);
    3250            1 :                     ErrorsFound = true;
    3251              :                 } else {
    3252           11 :                     SchedMinValue = surfTemp.shadowSurfSched->getMinVal(state);
    3253           11 :                     surfTemp.SchedMinValue = SchedMinValue;
    3254           11 :                     SchedMaxValue = surfTemp.shadowSurfSched->getCurrentVal();
    3255           11 :                     if (SchedMinValue == 1.0) {
    3256              :                         // Set transparent for now, check for EMS actuators later in SolarShading::resetShadingSurfaceTransparency
    3257            1 :                         surfTemp.IsTransparent = true;
    3258              :                     }
    3259           11 :                     if (SchedMinValue < 0.0) {
    3260            0 :                         ShowSevereError(state,
    3261            0 :                                         format("{}=\"{}\", {}=\"{}\", has schedule values < 0.",
    3262            0 :                                                s_ipsc->cCurrentModuleObject,
    3263            0 :                                                surfTemp.Name,
    3264            0 :                                                s_ipsc->cAlphaFieldNames(2),
    3265            0 :                                                s_ipsc->cAlphaArgs(2)));
    3266            0 :                         ShowContinueError(state, "...Schedule values < 0 have no meaning for shading elements.");
    3267              :                     }
    3268           11 :                     if (SchedMaxValue > 0.0) {
    3269            2 :                         state.dataSolarShading->anyScheduledShadingSurface = true;
    3270              :                     }
    3271           11 :                     if (SchedMaxValue > 1.0) {
    3272            0 :                         ShowSevereError(state,
    3273            0 :                                         format("{}=\"{}\", {}=\"{}\", has schedule values > 1.",
    3274            0 :                                                s_ipsc->cCurrentModuleObject,
    3275            0 :                                                surfTemp.Name,
    3276            0 :                                                s_ipsc->cAlphaFieldNames(2),
    3277            0 :                                                s_ipsc->cAlphaArgs(2)));
    3278            0 :                         ShowContinueError(state, "...Schedule values > 1 have no meaning for shading elements.");
    3279              :                     }
    3280           11 :                     if (std::abs(SchedMinValue - SchedMaxValue) > Constant::OneMillionth) {
    3281            0 :                         state.dataSurface->ShadingTransmittanceVaries = true;
    3282              :                     }
    3283              :                 }
    3284           17 :                 if (s_ipsc->lNumericFieldBlanks(1) || s_ipsc->rNumericArgs(1) == Constant::AutoCalculate) {
    3285            0 :                     numSides = (NumNumbers - 1) / 3;
    3286            0 :                     surfTemp.Sides = numSides;
    3287            0 :                     if (mod(NumNumbers - 1, 3) != 0) {
    3288            0 :                         ShowWarningError(state,
    3289            0 :                                          format("{}=\"{}\", {}",
    3290            0 :                                                 s_ipsc->cCurrentModuleObject,
    3291            0 :                                                 surfTemp.Name,
    3292            0 :                                                 format("{} not even multiple of 3. Will read in {}", s_ipsc->cNumericFieldNames(1), surfTemp.Sides)));
    3293              :                     }
    3294            0 :                     if (numSides < 3) {
    3295            0 :                         ShowSevereError(state,
    3296            0 :                                         format("{}=\"{}\", {} (autocalculate) must be >= 3. Only {} provided.",
    3297            0 :                                                s_ipsc->cCurrentModuleObject,
    3298            0 :                                                surfTemp.Name,
    3299            0 :                                                s_ipsc->cNumericFieldNames(1),
    3300            0 :                                                surfTemp.Sides));
    3301            0 :                         ErrorsFound = true;
    3302            0 :                         continue;
    3303              :                     }
    3304              :                 } else {
    3305           17 :                     numSides = (NumNumbers - 1) / 3;
    3306           17 :                     surfTemp.Sides = s_ipsc->rNumericArgs(1);
    3307           17 :                     if (numSides > surfTemp.Sides) {
    3308            0 :                         ShowWarningError(state,
    3309            0 :                                          format("{}=\"{}\", field {}={}",
    3310            0 :                                                 s_ipsc->cCurrentModuleObject,
    3311            0 :                                                 surfTemp.Name,
    3312            0 :                                                 s_ipsc->cNumericFieldNames(1),
    3313            0 :                                                 fmt::to_string(surfTemp.Sides)));
    3314            0 :                         ShowContinueError(
    3315            0 :                             state, format("...but {} were entered. Only the indicated {} will be used.", numSides, s_ipsc->cNumericFieldNames(1)));
    3316              :                     }
    3317              :                 }
    3318           17 :                 surfTemp.Vertex.allocate(surfTemp.Sides);
    3319           68 :                 GetVertices(state, SurfNum, surfTemp.Sides, s_ipsc->rNumericArgs({2, _}));
    3320           17 :                 CheckConvexity(state, SurfNum, surfTemp.Sides);
    3321           17 :                 if (state.dataReportFlag->MakeMirroredDetachedShading) {
    3322           17 :                     MakeMirrorSurface(state, SurfNum);
    3323              :                 }
    3324              :             }
    3325              : 
    3326              :         } // Item Loop
    3327           17 :     }
    3328              : 
    3329          227 :     void GetRectDetShdSurfaceData(EnergyPlusData &state,
    3330              :                                   bool &ErrorsFound,              // Error flag indicator (true if errors found)
    3331              :                                   int &SurfNum,                   // Count of Current SurfaceNumber
    3332              :                                   int const TotRectDetachedFixed, // Number of Fixed Detached Shading Surfaces to obtain
    3333              :                                   int const TotRectDetachedBldg   // Number of Building Detached Shading Surfaces to obtain
    3334              :     )
    3335              :     {
    3336              : 
    3337              :         // SUBROUTINE INFORMATION:
    3338              :         //       AUTHOR         Linda Lawrie
    3339              :         //       DATE WRITTEN   January 2009
    3340              : 
    3341              :         // PURPOSE OF THIS SUBROUTINE:
    3342              :         // Gets the simple, rectangular detached surfaces.
    3343              : 
    3344              :         // SUBROUTINE PARAMETER DEFINITIONS:
    3345          227 :         static Array1D_string const cModuleObjects(2, {"Shading:Site", "Shading:Building"});
    3346              : 
    3347              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    3348              :         int IOStat;     // IO Status when calling get input subroutine
    3349              :         int NumAlphas;  // Number of material alpha names being passed
    3350              :         int NumNumbers; // Number of material properties being passed
    3351              :         int Loop;
    3352              :         int ItemsToGet;
    3353              :         SurfaceClass ClassItem;
    3354              : 
    3355          227 :         auto &s_ipsc = state.dataIPShortCut;
    3356              : 
    3357          227 :         if ((TotRectDetachedFixed + TotRectDetachedBldg) > 0 && state.dataHeatBal->SolarDistribution == DataHeatBalance::Shadowing::Minimal) {
    3358            0 :             ShowWarningError(state, "Detached shading effects are ignored when Solar Distribution = MinimalShadowing");
    3359              :         }
    3360              : 
    3361          227 :         if (TotRectDetachedFixed + TotRectDetachedBldg == 0) return;
    3362            3 :         for (int Item = 1; Item <= 2; ++Item) {
    3363              : 
    3364            2 :             s_ipsc->cCurrentModuleObject = cModuleObjects(Item);
    3365            2 :             if (Item == 1) {
    3366            1 :                 ItemsToGet = TotRectDetachedFixed;
    3367            1 :                 ClassItem = SurfaceClass::Detached_F;
    3368              :             } else { // IF (Item == 2) THEN
    3369            1 :                 ItemsToGet = TotRectDetachedBldg;
    3370            1 :                 ClassItem = SurfaceClass::Detached_B;
    3371              :             }
    3372              : 
    3373            2 :             state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, s_ipsc->cCurrentModuleObject, Loop, NumAlphas, NumNumbers);
    3374            2 :             if (NumAlphas != 1) {
    3375            0 :                 ShowSevereError(
    3376              :                     state,
    3377            0 :                     format("{}: Object Definition indicates not = 1 Alpha Objects, Number Indicated={}", s_ipsc->cCurrentModuleObject, NumAlphas));
    3378            0 :                 ErrorsFound = true;
    3379              :             }
    3380              : 
    3381            4 :             for (Loop = 1; Loop <= ItemsToGet; ++Loop) {
    3382            4 :                 state.dataInputProcessing->inputProcessor->getObjectItem(state,
    3383            2 :                                                                          s_ipsc->cCurrentModuleObject,
    3384              :                                                                          Loop,
    3385            2 :                                                                          s_ipsc->cAlphaArgs,
    3386              :                                                                          NumAlphas,
    3387            2 :                                                                          s_ipsc->rNumericArgs,
    3388              :                                                                          NumNumbers,
    3389              :                                                                          IOStat,
    3390            2 :                                                                          s_ipsc->lNumericFieldBlanks,
    3391            2 :                                                                          s_ipsc->lAlphaFieldBlanks,
    3392            2 :                                                                          s_ipsc->cAlphaFieldNames,
    3393            2 :                                                                          s_ipsc->cNumericFieldNames);
    3394              : 
    3395            4 :                 if (GlobalNames::VerifyUniqueInterObjectName(state,
    3396            2 :                                                              state.dataSurfaceGeometry->UniqueSurfaceNames,
    3397            2 :                                                              s_ipsc->cAlphaArgs(1),
    3398            2 :                                                              s_ipsc->cCurrentModuleObject,
    3399            2 :                                                              s_ipsc->cAlphaFieldNames(1),
    3400              :                                                              ErrorsFound)) {
    3401            0 :                     continue;
    3402              :                 }
    3403              : 
    3404            2 :                 ++SurfNum;
    3405              : 
    3406            2 :                 auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    3407            2 :                 surfTemp.Name = s_ipsc->cAlphaArgs(1); // Set the Surface Name in the Derived Type
    3408            2 :                 surfTemp.Class = ClassItem;
    3409            2 :                 surfTemp.HeatTransSurf = false;
    3410            2 :                 surfTemp.ExtSolar = true;
    3411              : 
    3412            2 :                 surfTemp.Azimuth = s_ipsc->rNumericArgs(1);
    3413            2 :                 if (surfTemp.Class == SurfaceClass::Detached_B && !state.dataSurface->WorldCoordSystem) {
    3414            0 :                     surfTemp.Azimuth += state.dataHeatBal->BuildingAzimuth;
    3415              :                 }
    3416            2 :                 if (surfTemp.Class == SurfaceClass::Detached_B) {
    3417            1 :                     surfTemp.Azimuth += state.dataHeatBal->BuildingRotationAppendixG;
    3418              :                 }
    3419            2 :                 surfTemp.Tilt = s_ipsc->rNumericArgs(2);
    3420            2 :                 surfTemp.convOrientation = Convect::GetSurfConvOrientation(surfTemp.Tilt);
    3421              : 
    3422            2 :                 surfTemp.Sides = 4;
    3423            2 :                 surfTemp.Vertex.allocate(surfTemp.Sides);
    3424              : 
    3425           12 :                 MakeRectangularVertices(state,
    3426              :                                         SurfNum,
    3427            2 :                                         s_ipsc->rNumericArgs(3),
    3428            2 :                                         s_ipsc->rNumericArgs(4),
    3429            2 :                                         s_ipsc->rNumericArgs(5),
    3430            2 :                                         s_ipsc->rNumericArgs(6),
    3431            2 :                                         s_ipsc->rNumericArgs(7),
    3432            2 :                                         state.dataSurfaceGeometry->RectSurfRefWorldCoordSystem);
    3433              : 
    3434            2 :                 if (surfTemp.Area <= 0.0) {
    3435            0 :                     ShowSevereError(
    3436              :                         state,
    3437            0 :                         format("{}=\"{}\", Surface Area <= 0.0; Entered Area={:.2T}", s_ipsc->cCurrentModuleObject, surfTemp.Name, surfTemp.Area));
    3438            0 :                     ErrorsFound = true;
    3439              :                 }
    3440              : 
    3441            2 :                 if (state.dataReportFlag->MakeMirroredDetachedShading) {
    3442            2 :                     MakeMirrorSurface(state, SurfNum);
    3443              :                 }
    3444              :             }
    3445              : 
    3446              :         } // Item Loop
    3447              :     }
    3448              : 
    3449          231 :     void GetHTSurfaceData(EnergyPlusData &state,
    3450              :                           bool &ErrorsFound,                 // Error flag indicator (true if errors found)
    3451              :                           int &SurfNum,                      // Count of Current SurfaceNumber
    3452              :                           int const TotHTSurfs,              // Number of Heat Transfer Base Surfaces to obtain
    3453              :                           int const TotDetailedWalls,        // Number of Wall:Detailed items to obtain
    3454              :                           int const TotDetailedRoofs,        // Number of RoofCeiling:Detailed items to obtain
    3455              :                           int const TotDetailedFloors,       // Number of Floor:Detailed items to obtain
    3456              :                           const Array1D_string &BaseSurfCls, // Valid Classes for Base Surfaces
    3457              :                           const Array1D<SurfaceClass> &BaseSurfIDs,
    3458              :                           int &NeedToAddSurfaces // Number of surfaces to add, based on unentered IZ surfaces
    3459              :     )
    3460              :     {
    3461              : 
    3462              :         // SUBROUTINE INFORMATION:
    3463              :         //       AUTHOR         Linda Lawrie
    3464              :         //       DATE WRITTEN   May 2000
    3465              : 
    3466              :         // PURPOSE OF THIS SUBROUTINE:
    3467              :         // This subroutine gets the HeatTransfer Surface Data, checks it for errors, etc.
    3468              : 
    3469              :         // REFERENCES:
    3470              :         // Heat Transfer Surface Definition
    3471              :         // BuildingSurface:Detailed,
    3472              :         //  \extensible:3 -- duplicate last set of x,y,z coordinates (last 3 fields), remembering to remove ; from "inner" fields.
    3473              :         //  \format vertices
    3474              :         //  A1 , \field Name
    3475              :         //       \required-field
    3476              :         //       \type alpha
    3477              :         //       \reference SurfaceNames
    3478              :         //       \reference SurfAndSubSurfNames
    3479              :         //       \reference AllHeatTranSurfNames
    3480              :         //       \reference HeatTranBaseSurfNames
    3481              :         //       \reference OutFaceEnvNames
    3482              :         //       \reference AllHeatTranAngFacNames
    3483              :         //       \reference RadGroupAndSurfNames
    3484              :         //       \reference SurfGroupAndHTSurfNames
    3485              :         //       \reference AllShadingAndHTSurfNames
    3486              :         //  A2 , \field Surface Type
    3487              :         //       \required-field
    3488              :         //       \type choice
    3489              :         //       \key Floor
    3490              :         //       \key Wall
    3491              :         //       \key Ceiling
    3492              :         //       \key Roof
    3493              :         //  A3 , \field Construction Name
    3494              :         //       \required-field
    3495              :         //       \note To be matched with a construction in this input file
    3496              :         //       \type object-list
    3497              :         //       \object-list ConstructionNames
    3498              :         //  A4 , \field Zone Name
    3499              :         //       \required-field
    3500              :         //       \note Zone the surface is a part of
    3501              :         //       \type object-list
    3502              :         //       \object-list ZoneNames
    3503              :         //  A5 , \field Outside Boundary Condition
    3504              :         //       \required-field
    3505              :         //       \type choice
    3506              :         //       \key Adiabatic
    3507              :         //       \key Surface
    3508              :         //       \key Zone
    3509              :         //       \key Outdoors
    3510              :         //       \key Ground
    3511              :         //       \key GroundFCfactorMethod
    3512              :         //       \key OtherSideCoefficients
    3513              :         //       \key OtherSideConditionsModel
    3514              :         //       \key GroundSlabPreprocessorAverage
    3515              :         //       \key GroundSlabPreprocessorCore
    3516              :         //       \key GroundSlabPreprocessorPerimeter
    3517              :         //       \key GroundBasementPreprocessorAverageWall
    3518              :         //       \key GroundBasementPreprocessorAverageFloor
    3519              :         //       \key GroundBasementPreprocessorUpperWall
    3520              :         //       \key GroundBasementPreprocessorLowerWall
    3521              :         //  A6,  \field Outside Boundary Condition Object
    3522              :         //       \type object-list
    3523              :         //       \object-list OutFaceEnvNames
    3524              :         //       \note Non-blank only if the field Outside Boundary Condition is Surface,
    3525              :         //       \note Zone, OtherSideCoefficients or OtherSideConditionsModel
    3526              :         //       \note If Surface, specify name of corresponding surface in adjacent zone or
    3527              :         //       \note specify current surface name for internal partition separating like zones
    3528              :         //       \note If Zone, specify the name of the corresponding zone and
    3529              :         //       \note the program will generate the corresponding interzone surface
    3530              :         //       \note If OtherSideCoefficients, specify name of SurfaceProperty:OtherSideCoefficients
    3531              :         //       \note If OtherSideConditionsModel, specify name of SurfaceProperty:OtherSideConditionsModel
    3532              :         //  A7 , \field Sun Exposure
    3533              :         //       \required-field
    3534              :         //       \type choice
    3535              :         //       \key SunExposed
    3536              :         //       \key NoSun
    3537              :         //       \default SunExposed
    3538              :         //  A8,  \field Wind Exposure
    3539              :         //       \required-field
    3540              :         //       \type choice
    3541              :         //       \key WindExposed
    3542              :         //       \key NoWind
    3543              :         //       \default WindExposed
    3544              :         //  N1,  \field View Factor to Ground
    3545              :         //       \type real
    3546              :         //       \note From the exterior of the surface
    3547              :         //       \note Unused if one uses the "reflections" options in Solar Distribution in Building input
    3548              :         //       \note unless a DaylightingDevice:Shelf or DaylightingDevice:Tubular object has been specified.
    3549              :         //       \note autocalculate will automatically calculate this value from the tilt of the surface
    3550              :         //       \autocalculatable
    3551              :         //       \minimum 0.0
    3552              :         //       \maximum 1.0
    3553              :         //       \default autocalculate
    3554              :         //  N2 , \field Number of Vertices
    3555              :         //       \note shown with 120 vertex coordinates -- extensible object
    3556              :         //       \note  "extensible" -- duplicate last set of x,y,z coordinates (last 3 fields),
    3557              :         //       \note remembering to remove ; from "inner" fields.
    3558              :         //       \note for clarity in any error messages, renumber the fields as well.
    3559              :         //       \note (and changing z terminator to a comma "," for all but last one which needs a semi-colon ";")
    3560              :         //       \autocalculatable
    3561              :         //       \minimum 3
    3562              :         //       \default autocalculate
    3563              :         //       \note vertices are given in GlobalGeometryRules coordinates -- if relative, all surface coordinates
    3564              :         //       \note are "relative" to the Zone Origin.  If world, then building and zone origins are used
    3565              :         //       \note for some internal calculations, but all coordinates are given in an "absolute" system.
    3566              :         //  N3-xx as indicated by the N3 value
    3567              : 
    3568              :         // Using/Aliasing
    3569              : 
    3570              :         // SUBROUTINE PARAMETER DEFINITIONS:
    3571          231 :         static Array1D_string const cModuleObjects(4, {"BuildingSurface:Detailed", "Wall:Detailed", "Floor:Detailed", "RoofCeiling:Detailed"});
    3572              : 
    3573              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    3574              :         int IOStat;          // IO Status when calling get input subroutine
    3575              :         int SurfaceNumAlpha; // Number of material alpha names being passed
    3576              :         int SurfaceNumProp;  // Number of material properties being passed
    3577              :         int ZoneNum;         // DO loop counter (zones)
    3578              :         int Found;           // For matching interzone surfaces
    3579              :         int Loop;
    3580              :         int ItemsToGet;
    3581              :         int ClassItem;
    3582              :         int ArgPointer;
    3583              :         int numSides;
    3584              : 
    3585          231 :         auto &s_ipsc = state.dataIPShortCut;
    3586              : 
    3587          231 :         GetOSCData(state, ErrorsFound);
    3588          231 :         GetOSCMData(state, ErrorsFound);
    3589          231 :         GetFoundationData(state, ErrorsFound);
    3590              : 
    3591          231 :         NeedToAddSurfaces = 0;
    3592         1155 :         for (int Item = 1; Item <= 4; ++Item) {
    3593              : 
    3594          924 :             s_ipsc->cCurrentModuleObject = cModuleObjects(Item);
    3595          924 :             if (Item == 1) {
    3596          231 :                 ItemsToGet = TotHTSurfs;
    3597          231 :                 ClassItem = 0;
    3598          693 :             } else if (Item == 2) {
    3599          231 :                 ItemsToGet = TotDetailedWalls;
    3600          231 :                 ClassItem = 1;
    3601          462 :             } else if (Item == 3) {
    3602          231 :                 ItemsToGet = TotDetailedFloors;
    3603          231 :                 ClassItem = 2;
    3604              :             } else { // IF (Item == 4) THEN
    3605          231 :                 ItemsToGet = TotDetailedRoofs;
    3606          231 :                 ClassItem = 3;
    3607              :             }
    3608              : 
    3609         1848 :             state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(
    3610          924 :                 state, s_ipsc->cCurrentModuleObject, Loop, SurfaceNumAlpha, SurfaceNumProp);
    3611          924 :             if (Item == 1) {
    3612          231 :                 if (SurfaceNumAlpha != 9) {
    3613            0 :                     ShowSevereError(state,
    3614            0 :                                     format("{}: Object Definition indicates not = 9 Alpha Objects, Number Indicated={}",
    3615            0 :                                            s_ipsc->cCurrentModuleObject,
    3616              :                                            SurfaceNumAlpha));
    3617            0 :                     ErrorsFound = true;
    3618              :                 }
    3619              :             } else {
    3620          693 :                 if (SurfaceNumAlpha != 8) {
    3621            0 :                     ShowSevereError(state,
    3622            0 :                                     format("{}: Object Definition indicates not = 8 Alpha Objects, Number Indicated={}",
    3623            0 :                                            s_ipsc->cCurrentModuleObject,
    3624              :                                            SurfaceNumAlpha));
    3625            0 :                     ErrorsFound = true;
    3626              :                 }
    3627              :             }
    3628              : 
    3629         2863 :             for (Loop = 1; Loop <= ItemsToGet; ++Loop) {
    3630         3878 :                 state.dataInputProcessing->inputProcessor->getObjectItem(state,
    3631         1939 :                                                                          s_ipsc->cCurrentModuleObject,
    3632              :                                                                          Loop,
    3633         1939 :                                                                          s_ipsc->cAlphaArgs,
    3634              :                                                                          SurfaceNumAlpha,
    3635         1939 :                                                                          s_ipsc->rNumericArgs,
    3636              :                                                                          SurfaceNumProp,
    3637              :                                                                          IOStat,
    3638         1939 :                                                                          s_ipsc->lNumericFieldBlanks,
    3639         1939 :                                                                          s_ipsc->lAlphaFieldBlanks,
    3640         1939 :                                                                          s_ipsc->cAlphaFieldNames,
    3641         1939 :                                                                          s_ipsc->cNumericFieldNames);
    3642              : 
    3643         3878 :                 if (GlobalNames::VerifyUniqueInterObjectName(state,
    3644         1939 :                                                              state.dataSurfaceGeometry->UniqueSurfaceNames,
    3645         1939 :                                                              s_ipsc->cAlphaArgs(1),
    3646         1939 :                                                              s_ipsc->cCurrentModuleObject,
    3647         1939 :                                                              s_ipsc->cAlphaFieldNames(1),
    3648              :                                                              ErrorsFound)) {
    3649            0 :                     continue;
    3650              :                 }
    3651              : 
    3652         1939 :                 ++SurfNum;
    3653              : 
    3654         1939 :                 auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    3655         1939 :                 surfTemp.Name = s_ipsc->cAlphaArgs(1); // Set the Surface Name in the Derived Type
    3656         1939 :                 ArgPointer = 2;
    3657         1939 :                 if (Item == 1) {
    3658         1939 :                     if (s_ipsc->cAlphaArgs(2) == "CEILING") s_ipsc->cAlphaArgs(2) = "ROOF";
    3659         1939 :                     ClassItem = Util::FindItemInList(s_ipsc->cAlphaArgs(2), BaseSurfCls, 3);
    3660         1939 :                     if (ClassItem == 0) {
    3661            0 :                         ShowSevereError(state,
    3662            0 :                                         format("{}=\"{}\", invalid {}=\"{}",
    3663            0 :                                                s_ipsc->cCurrentModuleObject,
    3664            0 :                                                surfTemp.Name,
    3665            0 :                                                s_ipsc->cAlphaFieldNames(2),
    3666            0 :                                                s_ipsc->cAlphaArgs(2)));
    3667            0 :                         ErrorsFound = true;
    3668              :                     } else {
    3669         1939 :                         surfTemp.Class = BaseSurfIDs(ClassItem);
    3670              :                     }
    3671         1939 :                     ++ArgPointer;
    3672              :                 } else {
    3673            0 :                     surfTemp.Class = BaseSurfIDs(ClassItem);
    3674              :                 }
    3675              : 
    3676         1939 :                 surfTemp.Construction =
    3677         1939 :                     Util::FindItemInList(s_ipsc->cAlphaArgs(ArgPointer), state.dataConstruction->Construct, state.dataHeatBal->TotConstructs);
    3678              : 
    3679         1939 :                 if (surfTemp.Construction == 0) {
    3680            2 :                     ErrorsFound = true;
    3681            4 :                     ShowSevereError(state,
    3682            8 :                                     format("{}=\"{}\", invalid {}=\"{}\".",
    3683            2 :                                            s_ipsc->cCurrentModuleObject,
    3684            2 :                                            surfTemp.Name,
    3685            2 :                                            s_ipsc->cAlphaFieldNames(ArgPointer),
    3686            2 :                                            s_ipsc->cAlphaArgs(ArgPointer)));
    3687         1937 :                 } else if (state.dataConstruction->Construct(surfTemp.Construction).TypeIsWindow) {
    3688            0 :                     ErrorsFound = true;
    3689            0 :                     ShowSevereError(state,
    3690            0 :                                     format("{}=\"{}\", invalid {}=\"{}\" - has Window materials.",
    3691            0 :                                            s_ipsc->cCurrentModuleObject,
    3692            0 :                                            surfTemp.Name,
    3693            0 :                                            s_ipsc->cAlphaFieldNames(ArgPointer),
    3694            0 :                                            s_ipsc->cAlphaArgs(ArgPointer)));
    3695            0 :                     if (Item == 1) {
    3696            0 :                         ShowContinueError(state, format("...because {}={}", s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2)));
    3697              :                     } else {
    3698            0 :                         ShowContinueError(state, format("...because Surface Type={}", BaseSurfCls(ClassItem)));
    3699              :                     }
    3700              :                 } else {
    3701         1937 :                     state.dataConstruction->Construct(surfTemp.Construction).IsUsed = true;
    3702         1937 :                     surfTemp.ConstructionStoredInputValue = surfTemp.Construction;
    3703              :                 }
    3704         1939 :                 surfTemp.HeatTransSurf = true;
    3705         1939 :                 surfTemp.BaseSurf = SurfNum;
    3706         1939 :                 surfTemp.BaseSurfName = surfTemp.Name;
    3707              : 
    3708         1939 :                 ++ArgPointer;
    3709         1939 :                 surfTemp.ZoneName = s_ipsc->cAlphaArgs(ArgPointer);
    3710         1939 :                 ZoneNum = Util::FindItemInList(surfTemp.ZoneName, state.dataHeatBal->Zone, state.dataGlobal->NumOfZones);
    3711              : 
    3712         1939 :                 if (ZoneNum != 0) {
    3713         1939 :                     surfTemp.Zone = ZoneNum;
    3714              :                 } else {
    3715            0 :                     ShowSevereError(state,
    3716            0 :                                     format("{}=\"{}\", invalid {}=\"{}\".",
    3717            0 :                                            s_ipsc->cCurrentModuleObject,
    3718            0 :                                            surfTemp.Name,
    3719            0 :                                            s_ipsc->cAlphaFieldNames(ArgPointer),
    3720            0 :                                            s_ipsc->cAlphaArgs(ArgPointer)));
    3721            0 :                     surfTemp.Class = SurfaceClass::Invalid;
    3722            0 :                     surfTemp.ZoneName = "Unknown Zone";
    3723            0 :                     ErrorsFound = true;
    3724              :                 }
    3725              : 
    3726         1939 :                 ++ArgPointer;
    3727         1939 :                 if (!s_ipsc->lAlphaFieldBlanks(ArgPointer)) {
    3728          162 :                     int spaceNum = Util::FindItemInList(s_ipsc->cAlphaArgs(ArgPointer), state.dataHeatBal->space);
    3729              : 
    3730          162 :                     if (spaceNum != 0) {
    3731          162 :                         surfTemp.spaceNum = spaceNum;
    3732          162 :                         if (surfTemp.Zone != state.dataHeatBal->space(spaceNum).zoneNum) {
    3733            0 :                             ShowSevereError(state,
    3734            0 :                                             format("{}=\"{}\", invalid {}=\"{}\" is not in the same zone as the surface.",
    3735            0 :                                                    s_ipsc->cCurrentModuleObject,
    3736            0 :                                                    surfTemp.Name,
    3737            0 :                                                    s_ipsc->cAlphaFieldNames(ArgPointer),
    3738            0 :                                                    s_ipsc->cAlphaArgs(ArgPointer)));
    3739            0 :                             surfTemp.Class = SurfaceClass::Invalid;
    3740            0 :                             ErrorsFound = true;
    3741              :                         }
    3742              :                     } else {
    3743            0 :                         ShowSevereError(state,
    3744            0 :                                         format("{}=\"{}\", invalid {}=\"{}\" not found.",
    3745            0 :                                                s_ipsc->cCurrentModuleObject,
    3746            0 :                                                surfTemp.Name,
    3747            0 :                                                s_ipsc->cAlphaFieldNames(ArgPointer),
    3748            0 :                                                s_ipsc->cAlphaArgs(ArgPointer)));
    3749            0 :                         surfTemp.Class = SurfaceClass::Invalid;
    3750            0 :                         ErrorsFound = true;
    3751              :                     }
    3752              :                 }
    3753              :                 // Get the ExteriorBoundaryCondition flag from input There are 4 conditions that
    3754              :                 // can take place. The conditions are set with a 0, -1, or -2, or all of the
    3755              :                 // zone names have to be looked at and generate the interzone array number
    3756         1939 :                 ++ArgPointer;
    3757         1939 :                 surfTemp.ExtBoundCondName = s_ipsc->cAlphaArgs(ArgPointer + 1);
    3758              : 
    3759         1939 :                 if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "Outdoors")) {
    3760         1228 :                     surfTemp.ExtBoundCond = DataSurfaces::ExternalEnvironment;
    3761          711 :                 } else if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "Adiabatic")) {
    3762          152 :                     surfTemp.ExtBoundCond = unreconciledZoneSurface;
    3763          152 :                     surfTemp.ExtBoundCondName = surfTemp.Name;
    3764              : 
    3765          559 :                 } else if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "Ground")) {
    3766          119 :                     surfTemp.ExtBoundCond = DataSurfaces::Ground;
    3767          119 :                     if (state.dataSurfaceGeometry->NoGroundTempObjWarning) {
    3768           44 :                         if (!state.dataEnvrn->GroundTempInputs[(int)DataEnvironment::GroundTempType::BuildingSurface]) {
    3769           72 :                             ShowWarningError(state,
    3770              :                                              "GetHTSurfaceData: Surfaces with interface to Ground found but no \"Ground Temperatures\" were input.");
    3771           36 :                             ShowContinueError(state, format("Found first in surface={}", s_ipsc->cAlphaArgs(1)));
    3772           72 :                             ShowContinueError(state,
    3773           72 :                                               format("Defaults, constant throughout the year of ({:.1R}) will be used.",
    3774           36 :                                                      state.dataEnvrn->GroundTemp[(int)DataEnvironment::GroundTempType::BuildingSurface]));
    3775              :                         }
    3776           44 :                         state.dataSurfaceGeometry->NoGroundTempObjWarning = false;
    3777              :                     }
    3778              : 
    3779              :                     // Added for FCfactor method
    3780          440 :                 } else if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "GroundFCfactorMethod")) {
    3781            0 :                     surfTemp.ExtBoundCond = DataSurfaces::GroundFCfactorMethod;
    3782            0 :                     if (state.dataSurfaceGeometry->NoFCGroundTempObjWarning) {
    3783            0 :                         if (!state.dataEnvrn->GroundTempInputs[(int)DataEnvironment::GroundTempType::FCFactorMethod]) {
    3784            0 :                             ShowSevereError(state,
    3785              :                                             "GetHTSurfaceData: Surfaces with interface to GroundFCfactorMethod found but no \"FC Ground "
    3786              :                                             "Temperatures\" were input.");
    3787            0 :                             ShowContinueError(state, format("Found first in surface={}", s_ipsc->cAlphaArgs(1)));
    3788            0 :                             ShowContinueError(state,
    3789              :                                               "Either add a \"Site:GroundTemperature:FCfactorMethod\" object or use a weather file with "
    3790              :                                               "Ground Temperatures.");
    3791            0 :                             ErrorsFound = true;
    3792            0 :                             state.dataSurfaceGeometry->NoFCGroundTempObjWarning = false;
    3793              :                         }
    3794              :                     }
    3795            0 :                     if (surfTemp.Construction > 0) {
    3796            0 :                         if (surfTemp.Class == SurfaceClass::Wall && !state.dataConstruction->Construct(surfTemp.Construction).TypeIsCfactorWall) {
    3797            0 :                             ShowSevereError(
    3798              :                                 state,
    3799            0 :                                 format("{}=\"{}\", invalid {}", s_ipsc->cCurrentModuleObject, surfTemp.Name, s_ipsc->cAlphaFieldNames(ArgPointer)));
    3800            0 :                             ShowContinueError(state,
    3801            0 :                                               format("Construction=\"{}\" is not type Construction:CfactorUndergroundWall.",
    3802            0 :                                                      state.dataConstruction->Construct(surfTemp.Construction).Name));
    3803            0 :                             ErrorsFound = true;
    3804              :                         }
    3805            0 :                         if (surfTemp.Class == SurfaceClass::Floor && !state.dataConstruction->Construct(surfTemp.Construction).TypeIsFfactorFloor) {
    3806            0 :                             ShowSevereError(
    3807              :                                 state,
    3808            0 :                                 format("{}=\"{}\", invalid {}", s_ipsc->cCurrentModuleObject, surfTemp.Name, s_ipsc->cAlphaFieldNames(ArgPointer)));
    3809            0 :                             ShowContinueError(state,
    3810            0 :                                               format("Construction=\"{}\" is not type Construction:FfactorGroundFloor.",
    3811            0 :                                                      state.dataConstruction->Construct(surfTemp.Construction).Name));
    3812            0 :                             ErrorsFound = true;
    3813              :                         }
    3814              :                     }
    3815              : 
    3816          440 :                 } else if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "OtherSideCoefficients")) {
    3817            0 :                     Found = Util::FindItemInList(surfTemp.ExtBoundCondName, state.dataSurface->OSC, state.dataSurface->TotOSC);
    3818            0 :                     if (Found == 0) {
    3819            0 :                         ShowSevereError(state,
    3820            0 :                                         format("{}=\"{}\", invalid {}=\"{}\".",
    3821            0 :                                                s_ipsc->cCurrentModuleObject,
    3822            0 :                                                surfTemp.Name,
    3823            0 :                                                s_ipsc->cAlphaFieldNames(ArgPointer + 1),
    3824            0 :                                                s_ipsc->cAlphaArgs(ArgPointer + 1)));
    3825            0 :                         ShowContinueError(state, " no OtherSideCoefficients of that name.");
    3826            0 :                         ErrorsFound = true;
    3827              :                     } else {
    3828            0 :                         surfTemp.OSCPtr = Found;
    3829            0 :                         if (state.dataSurface->OSC(Found).SurfFilmCoef > 0.0) {
    3830            0 :                             surfTemp.ExtBoundCond = DataSurfaces::OtherSideCoefCalcExt;
    3831              :                         } else {
    3832            0 :                             surfTemp.ExtBoundCond = DataSurfaces::OtherSideCoefNoCalcExt;
    3833              :                         }
    3834              :                     }
    3835              : 
    3836          440 :                 } else if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "Surface")) {
    3837              :                     // it has to be another surface which needs to be found
    3838              :                     // this will be found on the second pass through the surface input
    3839              :                     // for flagging, set the value to UnreconciledZoneSurface
    3840              :                     // name (ExtBoundCondName) will be validated later.
    3841          427 :                     surfTemp.ExtBoundCond = unreconciledZoneSurface;
    3842          427 :                     if (s_ipsc->lAlphaFieldBlanks(ArgPointer + 1)) {
    3843            0 :                         surfTemp.ExtBoundCondName = surfTemp.Name;
    3844            0 :                         ShowSevereError(state,
    3845            0 :                                         format("{}=\"{}\", invalid {}=<blank>.",
    3846            0 :                                                s_ipsc->cCurrentModuleObject,
    3847            0 :                                                surfTemp.Name,
    3848            0 :                                                s_ipsc->cAlphaFieldNames(ArgPointer + 1)));
    3849            0 :                         ShowContinueError(state, format("..{}=\"Surface\" must be non-blank.", s_ipsc->cAlphaFieldNames(ArgPointer)));
    3850            0 :                         ShowContinueError(state, "..This surface will become an adiabatic surface - no doors/windows allowed.");
    3851              :                     }
    3852              : 
    3853           13 :                 } else if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "Zone")) {
    3854              :                     // This is the code for an unmatched "other surface"
    3855              :                     // will be set up later.
    3856            8 :                     surfTemp.ExtBoundCond = unenteredAdjacentZoneSurface;
    3857              :                     // check OutsideFaceEnvironment for legal zone
    3858            8 :                     Found = Util::FindItemInList(surfTemp.ExtBoundCondName, state.dataHeatBal->Zone, state.dataGlobal->NumOfZones);
    3859            8 :                     ++NeedToAddSurfaces;
    3860              : 
    3861            8 :                     if (Found == 0) {
    3862            0 :                         ShowSevereError(state,
    3863            0 :                                         format("{}=\"{}\", invalid {}=\"{}\".",
    3864            0 :                                                s_ipsc->cCurrentModuleObject,
    3865            0 :                                                surfTemp.Name,
    3866            0 :                                                s_ipsc->cAlphaFieldNames(ArgPointer),
    3867            0 :                                                s_ipsc->cAlphaArgs(ArgPointer)));
    3868            0 :                         ShowContinueError(state, "..Referenced as Zone for this surface.");
    3869            0 :                         ErrorsFound = true;
    3870              :                     }
    3871              : 
    3872            5 :                 } else if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "Space")) {
    3873              :                     // This is the code for an unmatched "other surface"
    3874              :                     // will be set up later.
    3875            2 :                     state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCond = unenteredAdjacentSpaceSurface;
    3876              :                     // check OutsideFaceEnvironment for legal zone
    3877            2 :                     Found = Util::FindItemInList(
    3878            2 :                         state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ExtBoundCondName, state.dataHeatBal->space, state.dataGlobal->numSpaces);
    3879            2 :                     ++NeedToAddSurfaces;
    3880              : 
    3881            2 :                     if (Found == 0) {
    3882            0 :                         ShowSevereError(state,
    3883            0 :                                         format("{}=\"{}\", invalid {}=\"{}\".",
    3884            0 :                                                s_ipsc->cCurrentModuleObject,
    3885            0 :                                                state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name,
    3886            0 :                                                s_ipsc->cAlphaFieldNames(ArgPointer),
    3887            0 :                                                s_ipsc->cAlphaArgs(ArgPointer)));
    3888            0 :                         ShowContinueError(state, "..Referenced as Space for this surface.");
    3889            0 :                         ErrorsFound = true;
    3890              :                     }
    3891              : 
    3892            3 :                 } else if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "Foundation")) {
    3893              : 
    3894            0 :                     if (!state.dataWeather->WeatherFileExists) {
    3895            0 :                         ShowSevereError(
    3896              :                             state,
    3897            0 :                             format("{}=\"{}\", using \"Foundation\" type Outside Boundary Condition requires specification of a weather file",
    3898            0 :                                    s_ipsc->cCurrentModuleObject,
    3899            0 :                                    surfTemp.Name));
    3900            0 :                         ShowContinueError(state,
    3901              :                                           "Either place in.epw in the working directory or specify a weather file on the command line using -w "
    3902              :                                           "/path/to/weather.epw");
    3903            0 :                         ErrorsFound = true;
    3904              :                     }
    3905              : 
    3906              :                     // Find foundation object, if blank use default
    3907            0 :                     if (s_ipsc->lAlphaFieldBlanks(ArgPointer + 1)) {
    3908              : 
    3909            0 :                         if (!state.dataSurfaceGeometry->kivaManager.defaultAdded) {
    3910              :                             // Add default foundation if no other foundation object specified
    3911            0 :                             state.dataSurfaceGeometry->kivaManager.addDefaultFoundation();
    3912              :                         }
    3913            0 :                         surfTemp.OSCPtr =
    3914            0 :                             state.dataSurfaceGeometry->kivaManager.defaultIndex; // Reuse OSC pointer...shouldn't be used for non OSC surfaces anyway.
    3915              :                     } else {
    3916            0 :                         Found = state.dataSurfaceGeometry->kivaManager.findFoundation(surfTemp.ExtBoundCondName);
    3917            0 :                         if (Found != (int)state.dataSurfaceGeometry->kivaManager.foundationInputs.size()) {
    3918            0 :                             surfTemp.OSCPtr = Found;
    3919              :                         } else {
    3920            0 :                             ShowSevereError(state,
    3921            0 :                                             format("{}=\"{}\", invalid {}=\"{}\".",
    3922            0 :                                                    s_ipsc->cCurrentModuleObject,
    3923            0 :                                                    surfTemp.Name,
    3924            0 :                                                    s_ipsc->cAlphaFieldNames(ArgPointer + 1),
    3925            0 :                                                    s_ipsc->cAlphaArgs(ArgPointer + 1)));
    3926            0 :                             ErrorsFound = true;
    3927              :                         }
    3928              :                     }
    3929              : 
    3930            0 :                     if (state.dataConstruction->Construct(surfTemp.Construction).SourceSinkPresent) {
    3931            0 :                         ShowSevereError(
    3932              :                             state,
    3933            0 :                             format("{}=\"{}\", construction may not have an internal source/sink", s_ipsc->cCurrentModuleObject, surfTemp.Name));
    3934            0 :                         ErrorsFound = true;
    3935              :                     }
    3936            0 :                     surfTemp.ExtBoundCond = DataSurfaces::KivaFoundation;
    3937            3 :                 } else if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "OtherSideConditionsModel")) {
    3938            3 :                     Found = Util::FindItemInList(surfTemp.ExtBoundCondName, state.dataSurface->OSCM, state.dataSurface->TotOSCM);
    3939            3 :                     if (Found == 0) {
    3940            0 :                         ShowSevereError(state,
    3941            0 :                                         format("{}=\"{}\", invalid {}=\"{}\".",
    3942            0 :                                                s_ipsc->cCurrentModuleObject,
    3943            0 :                                                surfTemp.Name,
    3944            0 :                                                s_ipsc->cAlphaFieldNames(ArgPointer + 1),
    3945            0 :                                                s_ipsc->cAlphaArgs(ArgPointer + 1)));
    3946            0 :                         ErrorsFound = true;
    3947              :                     }
    3948            3 :                     surfTemp.OSCMPtr = Found;
    3949            3 :                     surfTemp.ExtBoundCond = DataSurfaces::OtherSideCondModeledExt;
    3950              : 
    3951            0 :                 } else if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "GroundSlabPreprocessorAverage") ||
    3952            0 :                            Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "GroundSlabPreprocessorCore") ||
    3953            0 :                            Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "GroundSlabPreprocessorPerimeter") ||
    3954            0 :                            Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "GroundBasementPreprocessorAverageFloor") ||
    3955            0 :                            Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "GroundBasementPreprocessorAverageWall") ||
    3956            0 :                            Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "GroundBasementPreprocessorUpperWall") ||
    3957            0 :                            Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "GroundBasementPreprocessorLowerWall")) {
    3958            0 :                     ShowSevereError(state,
    3959            0 :                                     format("{}=\"{}\", invalid {}=\"{}\".",
    3960            0 :                                            s_ipsc->cCurrentModuleObject,
    3961            0 :                                            surfTemp.Name,
    3962            0 :                                            s_ipsc->cAlphaFieldNames(ArgPointer),
    3963            0 :                                            s_ipsc->cAlphaArgs(ArgPointer)));
    3964            0 :                     ShowContinueError(state, "The ExpandObjects program has not been run or is not in your EnergyPlus.exe folder.");
    3965            0 :                     ErrorsFound = true;
    3966              : 
    3967              :                 } else {
    3968            0 :                     ShowSevereError(state,
    3969            0 :                                     format("{}=\"{}\", invalid {}=\"{}\".",
    3970            0 :                                            s_ipsc->cCurrentModuleObject,
    3971            0 :                                            surfTemp.Name,
    3972            0 :                                            s_ipsc->cAlphaFieldNames(ArgPointer),
    3973            0 :                                            s_ipsc->cAlphaArgs(ArgPointer)));
    3974            0 :                     ShowContinueError(state,
    3975              :                                       "Should be one of \"Outdoors\", \"Adiabatic\", Ground\", \"Surface\", \"OtherSideCoefficients\", "
    3976              :                                       "\"OtherSideConditionsModel\" or \"Zone\"");
    3977            0 :                     ErrorsFound = true;
    3978              :                 } // ... End of the ExtBoundCond logical IF Block
    3979              : 
    3980         1939 :                 ArgPointer += 2;
    3981              :                 // Set the logical flag for the exterior solar
    3982         1939 :                 if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "SunExposed")) {
    3983         1149 :                     if ((surfTemp.ExtBoundCond != DataSurfaces::ExternalEnvironment) &&
    3984            3 :                         (surfTemp.ExtBoundCond != DataSurfaces::OtherSideCondModeledExt)) {
    3985            0 :                         ShowWarningError(state,
    3986            0 :                                          format("{}=\"{}\", {}=\"{}\".",
    3987            0 :                                                 s_ipsc->cCurrentModuleObject,
    3988            0 :                                                 surfTemp.Name,
    3989            0 :                                                 s_ipsc->cAlphaFieldNames(ArgPointer),
    3990            0 :                                                 s_ipsc->cAlphaArgs(ArgPointer)));
    3991            0 :                         ShowContinueError(state, "..This surface is not exposed to External Environment.  Sun exposure has no effect.");
    3992              :                     } else {
    3993         1149 :                         surfTemp.ExtSolar = true;
    3994              :                     }
    3995          790 :                 } else if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "NoSun")) {
    3996          790 :                     surfTemp.ExtSolar = false;
    3997              :                 } else {
    3998            0 :                     ShowSevereError(state,
    3999            0 :                                     format("{}=\"{}\", invalid {}=\"{}\".",
    4000            0 :                                            s_ipsc->cCurrentModuleObject,
    4001            0 :                                            surfTemp.Name,
    4002            0 :                                            s_ipsc->cAlphaFieldNames(ArgPointer),
    4003            0 :                                            s_ipsc->cAlphaArgs(ArgPointer)));
    4004            0 :                     ErrorsFound = true;
    4005              :                 }
    4006              : 
    4007         1939 :                 ++ArgPointer;
    4008              :                 // Set the logical flag for the exterior wind
    4009         1939 :                 if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "WindExposed")) {
    4010         1163 :                     surfTemp.ExtWind = true;
    4011          776 :                 } else if (Util::SameString(s_ipsc->cAlphaArgs(ArgPointer), "NoWind")) {
    4012          776 :                     surfTemp.ExtWind = false;
    4013              :                 } else {
    4014            0 :                     ShowSevereError(state,
    4015            0 :                                     format("{}=\"{}\", invalid {}=\"{}\".",
    4016            0 :                                            s_ipsc->cCurrentModuleObject,
    4017            0 :                                            surfTemp.Name,
    4018            0 :                                            s_ipsc->cAlphaFieldNames(ArgPointer),
    4019            0 :                                            s_ipsc->cAlphaArgs(ArgPointer)));
    4020            0 :                     ErrorsFound = true;
    4021              :                 }
    4022              : 
    4023              :                 // Set the logical flag for the EcoRoof presented, this is only based on the flag in the construction type
    4024              :                 //                if (surfTemp.Construction > 0)
    4025              :                 //                    surfTemp.ExtEcoRoof =
    4026              :                 //                        state.dataConstruction->Construct(surfTemp.Construction).TypeIsEcoRoof;
    4027              : 
    4028         1939 :                 surfTemp.ViewFactorGround = s_ipsc->rNumericArgs(1);
    4029         1939 :                 if (s_ipsc->lNumericFieldBlanks(1)) surfTemp.ViewFactorGround = Constant::AutoCalculate;
    4030         1939 :                 if (s_ipsc->lNumericFieldBlanks(2) || s_ipsc->rNumericArgs(2) == Constant::AutoCalculate) {
    4031          175 :                     numSides = (SurfaceNumProp - 2) / 3;
    4032          175 :                     surfTemp.Sides = numSides;
    4033          175 :                     if (mod(SurfaceNumProp - 2, 3) != 0) {
    4034            0 :                         ShowWarningError(state,
    4035            0 :                                          format("{}=\"{}\", {}",
    4036            0 :                                                 s_ipsc->cCurrentModuleObject,
    4037            0 :                                                 surfTemp.Name,
    4038            0 :                                                 format("{} not even multiple of 3. Will read in {}", s_ipsc->cNumericFieldNames(2), surfTemp.Sides)));
    4039              :                     }
    4040          175 :                     if (numSides < 3) {
    4041            0 :                         ShowSevereError(state,
    4042            0 :                                         format("{}=\"{}\", {} (autocalculate) must be >= 3. Only {} provided.",
    4043            0 :                                                s_ipsc->cCurrentModuleObject,
    4044            0 :                                                surfTemp.Name,
    4045            0 :                                                s_ipsc->cNumericFieldNames(2),
    4046            0 :                                                surfTemp.Sides));
    4047            0 :                         ErrorsFound = true;
    4048            0 :                         continue;
    4049              :                     }
    4050              :                 } else {
    4051         1764 :                     numSides = (SurfaceNumProp - 2) / 3;
    4052         1764 :                     surfTemp.Sides = s_ipsc->rNumericArgs(2);
    4053         1764 :                     if (numSides > surfTemp.Sides) {
    4054            0 :                         ShowWarningError(state,
    4055            0 :                                          format("{}=\"{}\", field {}={}",
    4056            0 :                                                 s_ipsc->cCurrentModuleObject,
    4057            0 :                                                 surfTemp.Name,
    4058            0 :                                                 s_ipsc->cNumericFieldNames(2),
    4059            0 :                                                 fmt::to_string(surfTemp.Sides)));
    4060            0 :                         ShowContinueError(
    4061            0 :                             state, format("...but {} were entered. Only the indicated {} will be used.", numSides, s_ipsc->cNumericFieldNames(2)));
    4062              :                     }
    4063              :                 }
    4064         1939 :                 surfTemp.Vertex.allocate(surfTemp.Sides);
    4065         1939 :                 surfTemp.NewVertex.allocate(surfTemp.Sides);
    4066         7756 :                 GetVertices(state, SurfNum, surfTemp.Sides, s_ipsc->rNumericArgs({3, _}));
    4067         1939 :                 if (surfTemp.Area <= 0.0) {
    4068            0 :                     ShowSevereError(
    4069              :                         state,
    4070            0 :                         format("{}=\"{}\", Surface Area <= 0.0; Entered Area={:.2T}", s_ipsc->cCurrentModuleObject, surfTemp.Name, surfTemp.Area));
    4071            0 :                     ErrorsFound = true;
    4072              :                 }
    4073              : 
    4074         1939 :                 CheckConvexity(state, SurfNum, surfTemp.Sides);
    4075         1939 :                 if (Util::SameString(s_ipsc->cAlphaArgs(5), "Surface")) {
    4076            0 :                     if (surfTemp.Sides != static_cast<int>(surfTemp.Vertex.size())) {
    4077            0 :                         ShowSevereError(state,
    4078            0 :                                         format("{}=\"{}\", After CheckConvexity, mismatch between Sides ({}) and size of Vertex ({}).",
    4079            0 :                                                s_ipsc->cCurrentModuleObject,
    4080            0 :                                                surfTemp.Name,
    4081            0 :                                                surfTemp.Sides,
    4082            0 :                                                surfTemp.Vertex.size()));
    4083            0 :                         ShowContinueError(state, "CheckConvexity is used to verify the convexity of a surface and detect collinear points.");
    4084            0 :                         ErrorsFound = true;
    4085              :                     }
    4086              :                 }
    4087         1939 :                 if (surfTemp.Construction > 0) {
    4088              :                     // Check wall height for the CFactor walls
    4089              : 
    4090         1937 :                     if (surfTemp.Class == SurfaceClass::Wall && state.dataConstruction->Construct(surfTemp.Construction).TypeIsCfactorWall) {
    4091            0 :                         if (std::abs(surfTemp.Height - state.dataConstruction->Construct(surfTemp.Construction).Height) > 0.05) {
    4092            0 :                             ShowWarningError(
    4093              :                                 state,
    4094            0 :                                 format("{}=\"{}\", underground Wall Height = {:.2T}", s_ipsc->cCurrentModuleObject, surfTemp.Name, surfTemp.Height));
    4095            0 :                             ShowContinueError(state, "..which does not match its construction height.");
    4096              :                         }
    4097              :                     }
    4098              : 
    4099              :                     // Check area and perimeter for the FFactor floors
    4100         1937 :                     if (surfTemp.Class == SurfaceClass::Floor && state.dataConstruction->Construct(surfTemp.Construction).TypeIsFfactorFloor) {
    4101            0 :                         if (std::abs(surfTemp.Area - state.dataConstruction->Construct(surfTemp.Construction).Area) > 0.1) {
    4102            0 :                             ShowWarningError(
    4103              :                                 state,
    4104            0 :                                 format("{}=\"{}\", underground Floor Area = {:.2T}", s_ipsc->cCurrentModuleObject, surfTemp.Name, surfTemp.Area));
    4105            0 :                             ShowContinueError(state, "..which does not match its construction area.");
    4106              :                         }
    4107            0 :                         if (surfTemp.Perimeter < state.dataConstruction->Construct(surfTemp.Construction).PerimeterExposed - 0.1) {
    4108            0 :                             ShowWarningError(state,
    4109            0 :                                              format("{}=\"{}\", underground Floor Perimeter = {:.2T}",
    4110            0 :                                                     s_ipsc->cCurrentModuleObject,
    4111            0 :                                                     surfTemp.Name,
    4112            0 :                                                     surfTemp.Perimeter));
    4113            0 :                             ShowContinueError(state, "..which is less than its construction exposed perimeter.");
    4114              :                         }
    4115              :                     }
    4116              :                 }
    4117              :                 // Not sure if it's better to add this or guard in SolarShading.cc
    4118              :                 // surfTemp.shadowSurfSched = nullptr
    4119              :             }
    4120              :         } // Item Looop
    4121              :         // Check number of Vertex between base surface and Outside Boundary surface
    4122              :         int ExtSurfNum;
    4123         2200 :         for (int i = 1; i <= SurfNum; i++) {
    4124         2548 :             if (state.dataSurfaceGeometry->SurfaceTmp(i).ExtBoundCond == unreconciledZoneSurface &&
    4125          579 :                 state.dataSurfaceGeometry->SurfaceTmp(i).ExtBoundCondName != "") {
    4126          579 :                 ExtSurfNum = Util::FindItemInList(state.dataSurfaceGeometry->SurfaceTmp(i).ExtBoundCondName, state.dataSurfaceGeometry->SurfaceTmp);
    4127              :                 // If we cannot find the referenced surface
    4128          579 :                 if (ExtSurfNum == 0) {
    4129            2 :                     ShowSevereError(state,
    4130            2 :                                     format("{}=\"{}\" references an outside boundary surface that cannot be found:{}",
    4131            1 :                                            s_ipsc->cCurrentModuleObject,
    4132            1 :                                            state.dataSurfaceGeometry->SurfaceTmp(i).Name,
    4133            1 :                                            state.dataSurfaceGeometry->SurfaceTmp(i).ExtBoundCondName));
    4134            1 :                     ErrorsFound = true;
    4135              :                     // If vertex size mismatch
    4136         1156 :                 } else if (state.dataSurfaceGeometry->SurfaceTmp(i).Vertex.size() !=
    4137          578 :                            state.dataSurfaceGeometry->SurfaceTmp(ExtSurfNum).Vertex.size()) {
    4138            4 :                     ShowSevereError(state,
    4139            4 :                                     format("{}=\"{}\", Vertex size mismatch between base surface :{} and outside boundary surface: {}",
    4140            2 :                                            s_ipsc->cCurrentModuleObject,
    4141            2 :                                            state.dataSurfaceGeometry->SurfaceTmp(i).Name,
    4142            2 :                                            state.dataSurfaceGeometry->SurfaceTmp(i).Name,
    4143            2 :                                            state.dataSurfaceGeometry->SurfaceTmp(ExtSurfNum).Name));
    4144            4 :                     ShowContinueError(state,
    4145            4 :                                       format("The vertex sizes are {} for base surface and {} for outside boundary surface. Please check inputs.",
    4146            2 :                                              state.dataSurfaceGeometry->SurfaceTmp(i).Vertex.size(),
    4147            2 :                                              state.dataSurfaceGeometry->SurfaceTmp(ExtSurfNum).Vertex.size()));
    4148            2 :                     ErrorsFound = true;
    4149              :                 }
    4150              :             }
    4151              :         }
    4152         2170 :     }
    4153              : 
    4154          226 :     void GetRectSurfaces(EnergyPlusData &state,
    4155              :                          bool &ErrorsFound,                        // Error flag indicator (true if errors found)
    4156              :                          int &SurfNum,                             // Count of Current SurfaceNumber
    4157              :                          int const TotRectExtWalls,                // Number of Exterior Walls to obtain
    4158              :                          int const TotRectIntWalls,                // Number of Adiabatic Walls to obtain
    4159              :                          int const TotRectIZWalls,                 // Number of Interzone Walls to obtain
    4160              :                          int const TotRectUGWalls,                 // Number of Underground to obtain
    4161              :                          int const TotRectRoofs,                   // Number of Roofs to obtain
    4162              :                          int const TotRectCeilings,                // Number of Adiabatic Ceilings to obtain
    4163              :                          int const TotRectIZCeilings,              // Number of Interzone Ceilings to obtain
    4164              :                          int const TotRectGCFloors,                // Number of Floors with Ground Contact to obtain
    4165              :                          int const TotRectIntFloors,               // Number of Adiabatic Walls to obtain
    4166              :                          int const TotRectIZFloors,                // Number of Interzone Floors to obtain
    4167              :                          const Array1D<SurfaceClass> &BaseSurfIDs, // ID Assignments for valid surface classes
    4168              :                          int &NeedToAddSurfaces                    // Number of surfaces to add, based on unentered IZ surfaces
    4169              :     )
    4170              :     {
    4171              : 
    4172              :         // SUBROUTINE INFORMATION:
    4173              :         //       AUTHOR         Linda Lawrie
    4174              :         //       DATE WRITTEN   December 2008
    4175              : 
    4176              :         // PURPOSE OF THIS SUBROUTINE:
    4177              :         // Get simple (rectangular, LLC corner specified) walls
    4178              : 
    4179              :         // SUBROUTINE PARAMETER DEFINITIONS:
    4180              :         static Array1D_string const cModuleObjects(10,
    4181              :                                                    {"Wall:Exterior",
    4182              :                                                     "Wall:Adiabatic",
    4183              :                                                     "Wall:Interzone",
    4184              :                                                     "Wall:Underground",
    4185              :                                                     "Roof",
    4186              :                                                     "Ceiling:Adiabatic",
    4187              :                                                     "Ceiling:Interzone",
    4188              :                                                     "Floor:GroundContact",
    4189              :                                                     "Floor:Adiabatic",
    4190          226 :                                                     "Floor:Interzone"});
    4191              : 
    4192              :         int ItemsToGet;
    4193              :         int NumAlphas;
    4194              :         int NumNumbers;
    4195              :         int IOStat; // IO Status when calling get input subroutine
    4196              :         int Found;  // For matching base surfaces
    4197              :         bool GettingIZSurfaces;
    4198              :         int OtherSurfaceField;
    4199              :         int ExtBoundCondition;
    4200              :         int ClassItem;
    4201              :         int ZoneNum;
    4202              : 
    4203          226 :         auto &s_ipsc = state.dataIPShortCut;
    4204              : 
    4205         2486 :         for (int Item = 1; Item <= 10; ++Item) {
    4206              : 
    4207         2260 :             s_ipsc->cCurrentModuleObject = cModuleObjects(Item);
    4208         2260 :             if (Item == 1) {
    4209          226 :                 ItemsToGet = TotRectExtWalls;
    4210          226 :                 GettingIZSurfaces = false;
    4211          226 :                 OtherSurfaceField = 0;
    4212          226 :                 ExtBoundCondition = DataSurfaces::ExternalEnvironment;
    4213          226 :                 ClassItem = 1;
    4214         2034 :             } else if (Item == 2) {
    4215          226 :                 ItemsToGet = TotRectIntWalls;
    4216          226 :                 GettingIZSurfaces = false;
    4217          226 :                 OtherSurfaceField = 0;
    4218          226 :                 ExtBoundCondition = unreconciledZoneSurface;
    4219          226 :                 ClassItem = 1;
    4220         1808 :             } else if (Item == 3) {
    4221          226 :                 ItemsToGet = TotRectIZWalls;
    4222          226 :                 GettingIZSurfaces = true;
    4223          226 :                 OtherSurfaceField = 5;
    4224          226 :                 ExtBoundCondition = unreconciledZoneSurface;
    4225          226 :                 ClassItem = 1;
    4226         1582 :             } else if (Item == 4) {
    4227          226 :                 ItemsToGet = TotRectUGWalls;
    4228          226 :                 GettingIZSurfaces = false;
    4229          226 :                 OtherSurfaceField = 0;
    4230          226 :                 ExtBoundCondition = DataSurfaces::Ground;
    4231          226 :                 ClassItem = 1;
    4232         1356 :             } else if (Item == 5) {
    4233          226 :                 ItemsToGet = TotRectRoofs;
    4234          226 :                 GettingIZSurfaces = false;
    4235          226 :                 OtherSurfaceField = 0;
    4236          226 :                 ExtBoundCondition = DataSurfaces::ExternalEnvironment;
    4237          226 :                 ClassItem = 3;
    4238         1130 :             } else if (Item == 6) {
    4239          226 :                 ItemsToGet = TotRectCeilings;
    4240          226 :                 GettingIZSurfaces = false;
    4241          226 :                 OtherSurfaceField = 0;
    4242          226 :                 ExtBoundCondition = unreconciledZoneSurface;
    4243          226 :                 ClassItem = 3;
    4244          904 :             } else if (Item == 7) {
    4245          226 :                 ItemsToGet = TotRectIZCeilings;
    4246          226 :                 GettingIZSurfaces = false;
    4247          226 :                 OtherSurfaceField = 5;
    4248          226 :                 ExtBoundCondition = unreconciledZoneSurface;
    4249          226 :                 ClassItem = 3;
    4250          678 :             } else if (Item == 8) {
    4251          226 :                 ItemsToGet = TotRectGCFloors;
    4252          226 :                 GettingIZSurfaces = false;
    4253          226 :                 OtherSurfaceField = 0;
    4254          226 :                 ExtBoundCondition = DataSurfaces::Ground;
    4255          226 :                 ClassItem = 2;
    4256          452 :             } else if (Item == 9) {
    4257          226 :                 ItemsToGet = TotRectIntFloors;
    4258          226 :                 GettingIZSurfaces = false;
    4259          226 :                 OtherSurfaceField = 0;
    4260          226 :                 ExtBoundCondition = unreconciledZoneSurface;
    4261          226 :                 ClassItem = 2;
    4262              :             } else { // IF (Item == 10) THEN
    4263          226 :                 ItemsToGet = TotRectIZFloors;
    4264          226 :                 GettingIZSurfaces = true;
    4265          226 :                 OtherSurfaceField = 5;
    4266          226 :                 ExtBoundCondition = unreconciledZoneSurface;
    4267          226 :                 ClassItem = 2;
    4268              :             }
    4269              : 
    4270         2261 :             for (int Loop = 1; Loop <= ItemsToGet; ++Loop) {
    4271            2 :                 state.dataInputProcessing->inputProcessor->getObjectItem(state,
    4272            1 :                                                                          s_ipsc->cCurrentModuleObject,
    4273              :                                                                          Loop,
    4274            1 :                                                                          s_ipsc->cAlphaArgs,
    4275              :                                                                          NumAlphas,
    4276            1 :                                                                          s_ipsc->rNumericArgs,
    4277              :                                                                          NumNumbers,
    4278              :                                                                          IOStat,
    4279            1 :                                                                          s_ipsc->lNumericFieldBlanks,
    4280            1 :                                                                          s_ipsc->lAlphaFieldBlanks,
    4281            1 :                                                                          s_ipsc->cAlphaFieldNames,
    4282            1 :                                                                          s_ipsc->cNumericFieldNames);
    4283              : 
    4284            2 :                 if (GlobalNames::VerifyUniqueInterObjectName(state,
    4285            1 :                                                              state.dataSurfaceGeometry->UniqueSurfaceNames,
    4286            1 :                                                              s_ipsc->cAlphaArgs(1),
    4287            1 :                                                              s_ipsc->cCurrentModuleObject,
    4288            1 :                                                              s_ipsc->cAlphaFieldNames(1),
    4289              :                                                              ErrorsFound)) {
    4290            0 :                     continue;
    4291              :                 }
    4292              : 
    4293            1 :                 if (NumNumbers < 7) {
    4294            0 :                     ShowSevereError(
    4295              :                         state,
    4296            0 :                         format("{}=\"{}\", Too few number of numeric args=[{}].", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1), NumNumbers));
    4297            0 :                     ErrorsFound = true;
    4298              :                 }
    4299              : 
    4300            1 :                 ++SurfNum;
    4301              : 
    4302            1 :                 auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    4303            1 :                 surfTemp.Name = s_ipsc->cAlphaArgs(1);   // Set the Surface Name in the Derived Type
    4304            1 :                 surfTemp.Class = BaseSurfIDs(ClassItem); // Set class number
    4305              : 
    4306            1 :                 surfTemp.Construction =
    4307            1 :                     Util::FindItemInList(s_ipsc->cAlphaArgs(2), state.dataConstruction->Construct, state.dataHeatBal->TotConstructs);
    4308              : 
    4309            1 :                 if (surfTemp.Construction == 0) {
    4310            0 :                     ErrorsFound = true;
    4311            0 :                     ShowSevereError(state,
    4312            0 :                                     format("{}=\"{}\", invalid {}=\"{}\".",
    4313            0 :                                            s_ipsc->cCurrentModuleObject,
    4314            0 :                                            surfTemp.Name,
    4315            0 :                                            s_ipsc->cAlphaFieldNames(2),
    4316            0 :                                            s_ipsc->cAlphaArgs(2)));
    4317            1 :                 } else if (state.dataConstruction->Construct(surfTemp.Construction).TypeIsWindow) {
    4318            0 :                     ErrorsFound = true;
    4319            0 :                     ShowSevereError(state,
    4320            0 :                                     format("{}=\"{}\", invalid {}=\"{}\" - has Window materials.",
    4321            0 :                                            s_ipsc->cCurrentModuleObject,
    4322            0 :                                            surfTemp.Name,
    4323            0 :                                            s_ipsc->cAlphaFieldNames(3),
    4324            0 :                                            s_ipsc->cAlphaArgs(2)));
    4325            0 :                     ShowContinueError(state, format("...because {}={}", s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2)));
    4326              :                 } else {
    4327            1 :                     state.dataConstruction->Construct(surfTemp.Construction).IsUsed = true;
    4328            1 :                     surfTemp.ConstructionStoredInputValue = surfTemp.Construction;
    4329              :                 }
    4330            1 :                 surfTemp.HeatTransSurf = true;
    4331            1 :                 surfTemp.BaseSurf = SurfNum;
    4332            1 :                 surfTemp.BaseSurfName = surfTemp.Name;
    4333              : 
    4334            1 :                 surfTemp.ZoneName = s_ipsc->cAlphaArgs(3);
    4335            1 :                 ZoneNum = Util::FindItemInList(surfTemp.ZoneName, state.dataHeatBal->Zone, state.dataGlobal->NumOfZones);
    4336              : 
    4337            1 :                 if (ZoneNum != 0) {
    4338            1 :                     surfTemp.Zone = ZoneNum;
    4339              :                 } else {
    4340            0 :                     ShowSevereError(state,
    4341            0 :                                     format("{}=\"{}\", invalid {}=\"{}\".",
    4342            0 :                                            s_ipsc->cCurrentModuleObject,
    4343            0 :                                            surfTemp.Name,
    4344            0 :                                            s_ipsc->cAlphaFieldNames(3),
    4345            0 :                                            s_ipsc->cAlphaArgs(3)));
    4346            0 :                     surfTemp.Class = SurfaceClass::Invalid;
    4347            0 :                     surfTemp.ZoneName = "Unknown Zone";
    4348            0 :                     ErrorsFound = true;
    4349              :                 }
    4350              : 
    4351            1 :                 if (!s_ipsc->lAlphaFieldBlanks(4)) {
    4352            0 :                     int spaceNum = Util::FindItemInList(s_ipsc->cAlphaArgs(4), state.dataHeatBal->space);
    4353              : 
    4354            0 :                     if (spaceNum != 0) {
    4355            0 :                         surfTemp.spaceNum = spaceNum;
    4356              :                     } else {
    4357            0 :                         ShowSevereError(state,
    4358            0 :                                         format("{}=\"{}\", invalid {}=\"{}\".",
    4359            0 :                                                s_ipsc->cCurrentModuleObject,
    4360            0 :                                                surfTemp.Name,
    4361            0 :                                                s_ipsc->cAlphaFieldNames(4),
    4362            0 :                                                s_ipsc->cAlphaArgs(4)));
    4363            0 :                         surfTemp.Class = SurfaceClass::Invalid;
    4364            0 :                         ErrorsFound = true;
    4365              :                     }
    4366              :                 }
    4367              : 
    4368            1 :                 surfTemp.ExtBoundCond = ExtBoundCondition;
    4369            1 :                 if (surfTemp.Construction > 0) {
    4370            1 :                     if (surfTemp.Class == SurfaceClass::Wall && state.dataConstruction->Construct(surfTemp.Construction).TypeIsCfactorWall &&
    4371            0 :                         surfTemp.ExtBoundCond == DataSurfaces::Ground) {
    4372            0 :                         surfTemp.ExtBoundCond = DataSurfaces::GroundFCfactorMethod;
    4373            1 :                     } else if (state.dataConstruction->Construct(surfTemp.Construction).TypeIsCfactorWall) {
    4374            0 :                         ErrorsFound = true;
    4375            0 :                         ShowSevereError(state,
    4376            0 :                                         format("{}=\"{}\", Construction type is \"Construction:CfactorUndergroundWall\" but invalid for this object.",
    4377            0 :                                                s_ipsc->cCurrentModuleObject,
    4378            0 :                                                surfTemp.Name));
    4379              :                     }
    4380              : 
    4381            1 :                     if (surfTemp.Class == SurfaceClass::Floor && state.dataConstruction->Construct(surfTemp.Construction).TypeIsFfactorFloor &&
    4382            0 :                         surfTemp.ExtBoundCond == DataSurfaces::Ground) {
    4383            0 :                         surfTemp.ExtBoundCond = DataSurfaces::GroundFCfactorMethod;
    4384            1 :                     } else if (state.dataConstruction->Construct(surfTemp.Construction).TypeIsFfactorFloor) {
    4385            0 :                         ErrorsFound = true;
    4386            0 :                         ShowSevereError(state,
    4387            0 :                                         format("{}=\"{}\", Construction type is \"Construction:FfactorGroundFloor\" but invalid for this object.",
    4388            0 :                                                s_ipsc->cCurrentModuleObject,
    4389            0 :                                                surfTemp.Name));
    4390              :                     }
    4391              :                 }
    4392            1 :                 surfTemp.ExtSolar = false;
    4393            1 :                 surfTemp.ExtWind = false;
    4394            1 :                 surfTemp.ViewFactorGround = Constant::AutoCalculate;
    4395              : 
    4396            1 :                 if (surfTemp.ExtBoundCond == DataSurfaces::ExternalEnvironment) {
    4397            0 :                     surfTemp.ExtSolar = true;
    4398            0 :                     surfTemp.ExtWind = true;
    4399              : 
    4400              :                     // Set the logical flag for the EcoRoof presented, this is only based on the flag in the construction type
    4401              :                     //                    if (surfTemp.Construction > 0)
    4402              :                     //                        surfTemp.ExtEcoRoof =
    4403              :                     //                            state.dataConstruction->Construct(surfTemp.Construction).TypeIsEcoRoof;
    4404              : 
    4405            1 :                 } else if (surfTemp.ExtBoundCond == unreconciledZoneSurface) {
    4406            1 :                     if (GettingIZSurfaces) {
    4407            0 :                         surfTemp.ExtBoundCondName = s_ipsc->cAlphaArgs(OtherSurfaceField);
    4408            0 :                         Found = Util::FindItemInList(surfTemp.ExtBoundCondName, state.dataHeatBal->Zone, state.dataGlobal->NumOfZones);
    4409              :                         // see if match to zone, then it's an unentered other surface, else reconciled later
    4410            0 :                         if (Found > 0) {
    4411            0 :                             ++NeedToAddSurfaces;
    4412            0 :                             surfTemp.ExtBoundCond = unenteredAdjacentZoneSurface;
    4413              :                         }
    4414              :                     } else {
    4415            1 :                         surfTemp.ExtBoundCondName = surfTemp.Name;
    4416              :                     }
    4417              : 
    4418            0 :                 } else if (surfTemp.ExtBoundCond == DataSurfaces::Ground) {
    4419            0 :                     if (state.dataSurfaceGeometry->NoGroundTempObjWarning) {
    4420            0 :                         if (!state.dataEnvrn->GroundTempInputs[(int)DataEnvironment::GroundTempType::BuildingSurface]) {
    4421            0 :                             ShowWarningError(state,
    4422              :                                              "GetRectSurfaces: Surfaces with interface to Ground found but no \"Ground Temperatures\" were input.");
    4423            0 :                             ShowContinueError(state, format("Found first in surface={}", s_ipsc->cAlphaArgs(1)));
    4424            0 :                             ShowContinueError(state,
    4425            0 :                                               format("Defaults, constant throughout the year of ({:.1R}) will be used.",
    4426            0 :                                                      state.dataEnvrn->GroundTemp[(int)DataEnvironment::GroundTempType::BuildingSurface]));
    4427              :                         }
    4428            0 :                         state.dataSurfaceGeometry->NoGroundTempObjWarning = false;
    4429              :                     }
    4430              : 
    4431            0 :                 } else if (surfTemp.ExtBoundCond == DataSurfaces::GroundFCfactorMethod) {
    4432            0 :                     if (state.dataSurfaceGeometry->NoFCGroundTempObjWarning) {
    4433            0 :                         if (!state.dataEnvrn->GroundTempInputs[(int)DataEnvironment::GroundTempType::FCFactorMethod]) {
    4434            0 :                             ShowSevereError(state,
    4435              :                                             "GetRectSurfaces: Surfaces with interface to GroundFCfactorMethod found but no \"FC Ground "
    4436              :                                             "Temperatures\" were input.");
    4437            0 :                             ShowContinueError(state, format("Found first in surface={}", s_ipsc->cAlphaArgs(1)));
    4438            0 :                             ShowContinueError(state,
    4439              :                                               "Either add a \"Site:GroundTemperature:FCfactorMethod\" object or use a weather file with "
    4440              :                                               "Ground Temperatures.");
    4441            0 :                             ErrorsFound = true;
    4442            0 :                             state.dataSurfaceGeometry->NoFCGroundTempObjWarning = false;
    4443              :                         }
    4444              :                     }
    4445              : 
    4446              :                 } // ... End of the ExtBoundCond logical IF Block
    4447              : 
    4448            1 :                 surfTemp.Azimuth = s_ipsc->rNumericArgs(1);
    4449            1 :                 surfTemp.Tilt = s_ipsc->rNumericArgs(2);
    4450            1 :                 surfTemp.convOrientation = Convect::GetSurfConvOrientation(surfTemp.Tilt);
    4451            1 :                 if (!state.dataSurface->WorldCoordSystem) {
    4452            1 :                     if (ZoneNum != 0) {
    4453            1 :                         surfTemp.Azimuth += state.dataHeatBal->BuildingAzimuth + state.dataHeatBal->Zone(ZoneNum).RelNorth;
    4454              :                     }
    4455              :                 }
    4456            1 :                 if (ZoneNum != 0) {
    4457            1 :                     surfTemp.Azimuth += state.dataHeatBal->BuildingRotationAppendixG;
    4458              :                 }
    4459              : 
    4460            1 :                 surfTemp.Sides = 4;
    4461            1 :                 surfTemp.Vertex.allocate(surfTemp.Sides);
    4462              : 
    4463            6 :                 MakeRectangularVertices(state,
    4464              :                                         SurfNum,
    4465            1 :                                         s_ipsc->rNumericArgs(3),
    4466            1 :                                         s_ipsc->rNumericArgs(4),
    4467            1 :                                         s_ipsc->rNumericArgs(5),
    4468            1 :                                         s_ipsc->rNumericArgs(6),
    4469            1 :                                         s_ipsc->rNumericArgs(7),
    4470            1 :                                         state.dataSurfaceGeometry->RectSurfRefWorldCoordSystem);
    4471              : 
    4472            1 :                 if (surfTemp.Area <= 0.0) {
    4473            0 :                     ShowSevereError(
    4474              :                         state,
    4475            0 :                         format("{}=\"{}\", Surface Area <= 0.0; Entered Area={:.2T}", s_ipsc->cCurrentModuleObject, surfTemp.Name, surfTemp.Area));
    4476            0 :                     ErrorsFound = true;
    4477              :                 }
    4478              : 
    4479              :                 // Check wall height for the CFactor walls
    4480            1 :                 if (surfTemp.Class == SurfaceClass::Wall && surfTemp.ExtBoundCond == DataSurfaces::GroundFCfactorMethod) {
    4481            0 :                     if (std::abs(surfTemp.Height - state.dataConstruction->Construct(surfTemp.Construction).Height) > 0.05) {
    4482            0 :                         ShowWarningError(
    4483              :                             state,
    4484            0 :                             format("{}=\"{}\", underground Wall Height = {:.2T}", s_ipsc->cCurrentModuleObject, surfTemp.Name, surfTemp.Height));
    4485            0 :                         ShowContinueError(state, "..which deos not match its construction height.");
    4486              :                     }
    4487              :                 }
    4488              : 
    4489              :                 // Check area and perimeter for the FFactor floors
    4490            1 :                 if (surfTemp.Class == SurfaceClass::Floor && surfTemp.ExtBoundCond == DataSurfaces::GroundFCfactorMethod) {
    4491            0 :                     if (std::abs(surfTemp.Area - state.dataConstruction->Construct(surfTemp.Construction).Area) > 0.1) {
    4492            0 :                         ShowWarningError(
    4493            0 :                             state, format("{}=\"{}\", underground Floor Area = {:.2T}", s_ipsc->cCurrentModuleObject, surfTemp.Name, surfTemp.Area));
    4494            0 :                         ShowContinueError(state, "..which does not match its construction area.");
    4495              :                     }
    4496            0 :                     if (surfTemp.Perimeter < state.dataConstruction->Construct(surfTemp.Construction).PerimeterExposed - 0.1) {
    4497            0 :                         ShowWarningError(
    4498              :                             state,
    4499            0 :                             format(
    4500            0 :                                 "{}=\"{}\", underground Floor Perimeter = {:.2T}", s_ipsc->cCurrentModuleObject, surfTemp.Name, surfTemp.Perimeter));
    4501            0 :                         ShowContinueError(state, "..which is less than its construction exposed perimeter.");
    4502              :                     }
    4503              :                 }
    4504              :             } // Getting Items
    4505              :         }
    4506          226 :     }
    4507              : 
    4508            7 :     void MakeRectangularVertices(EnergyPlusData &state,
    4509              :                                  int const SurfNum,
    4510              :                                  Real64 const XCoord,
    4511              :                                  Real64 const YCoord,
    4512              :                                  Real64 const ZCoord,
    4513              :                                  Real64 const Length,
    4514              :                                  Real64 const Height,
    4515              :                                  bool const SurfWorldCoordSystem)
    4516              :     {
    4517              : 
    4518              :         // SUBROUTINE INFORMATION:
    4519              :         //       AUTHOR         Linda Lawrie
    4520              :         //       DATE WRITTEN   December 2008
    4521              : 
    4522              :         // PURPOSE OF THIS SUBROUTINE:
    4523              :         // This routine creates world/3d coordinates for rectangular surfaces using azimuth, tilt, LLC (X,Y,Z), length & height.
    4524              : 
    4525              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    4526              :         Real64 XLLC;
    4527              :         Real64 YLLC;
    4528              :         Real64 ZLLC;
    4529            7 :         Array1D<Real64> XX(4);
    4530            7 :         Array1D<Real64> YY(4);
    4531              :         Real64 Xb;
    4532              :         Real64 Yb;
    4533              :         Real64 Perimeter;
    4534              :         int Vrt;
    4535              : 
    4536            7 :         auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    4537              : 
    4538            7 :         if (surfTemp.Zone == 0 && (surfTemp.Class != SurfaceClass::Detached_F && surfTemp.Class != SurfaceClass::Detached_B)) return;
    4539              : 
    4540            7 :         surfTemp.Height = Height;
    4541            7 :         surfTemp.Width = Length;
    4542              : 
    4543            7 :         Real64 SurfAzimuth = surfTemp.Azimuth;
    4544            7 :         Real64 SurfTilt = surfTemp.Tilt;
    4545            7 :         Real64 CosSurfAzimuth = std::cos(SurfAzimuth * Constant::DegToRad);
    4546            7 :         Real64 SinSurfAzimuth = std::sin(SurfAzimuth * Constant::DegToRad);
    4547            7 :         Real64 CosSurfTilt = std::cos(SurfTilt * Constant::DegToRad);
    4548            7 :         Real64 SinSurfTilt = std::sin(SurfTilt * Constant::DegToRad);
    4549              : 
    4550            7 :         if (!SurfWorldCoordSystem) {
    4551            7 :             if (surfTemp.Zone > 0) {
    4552            5 :                 Xb = XCoord * state.dataSurfaceGeometry->CosZoneRelNorth(surfTemp.Zone) -
    4553            5 :                      YCoord * state.dataSurfaceGeometry->SinZoneRelNorth(surfTemp.Zone) + state.dataHeatBal->Zone(surfTemp.Zone).OriginX;
    4554            5 :                 Yb = XCoord * state.dataSurfaceGeometry->SinZoneRelNorth(surfTemp.Zone) +
    4555            5 :                      YCoord * state.dataSurfaceGeometry->CosZoneRelNorth(surfTemp.Zone) + state.dataHeatBal->Zone(surfTemp.Zone).OriginY;
    4556            5 :                 XLLC = Xb * state.dataSurfaceGeometry->CosBldgRelNorth - Yb * state.dataSurfaceGeometry->SinBldgRelNorth;
    4557            5 :                 YLLC = Xb * state.dataSurfaceGeometry->SinBldgRelNorth + Yb * state.dataSurfaceGeometry->CosBldgRelNorth;
    4558            5 :                 ZLLC = ZCoord + state.dataHeatBal->Zone(surfTemp.Zone).OriginZ;
    4559              :             } else {
    4560            2 :                 if (surfTemp.Class == SurfaceClass::Detached_B) {
    4561            1 :                     Xb = XCoord;
    4562            1 :                     Yb = YCoord;
    4563            1 :                     XLLC = Xb * state.dataSurfaceGeometry->CosBldgRelNorth - Yb * state.dataSurfaceGeometry->SinBldgRelNorth;
    4564            1 :                     YLLC = Xb * state.dataSurfaceGeometry->SinBldgRelNorth + Yb * state.dataSurfaceGeometry->CosBldgRelNorth;
    4565            1 :                     ZLLC = ZCoord;
    4566              :                 } else {
    4567            1 :                     XLLC = XCoord;
    4568            1 :                     YLLC = YCoord;
    4569            1 :                     ZLLC = ZCoord;
    4570              :                 }
    4571              :             }
    4572              :         } else {
    4573              :             // for world coordinates, only rotate for appendix G
    4574            0 :             Xb = XCoord;
    4575            0 :             Yb = YCoord;
    4576            0 :             ZLLC = ZCoord;
    4577            0 :             if (surfTemp.Class != SurfaceClass::Detached_F) {
    4578            0 :                 XLLC = Xb * state.dataSurfaceGeometry->CosBldgRotAppGonly - Yb * state.dataSurfaceGeometry->SinBldgRotAppGonly;
    4579            0 :                 YLLC = Xb * state.dataSurfaceGeometry->SinBldgRotAppGonly + Yb * state.dataSurfaceGeometry->CosBldgRotAppGonly;
    4580              :             } else {
    4581            0 :                 XLLC = Xb;
    4582            0 :                 YLLC = Yb;
    4583              :             }
    4584              :         }
    4585              : 
    4586            7 :         XX(1) = 0.0;
    4587            7 :         XX(2) = 0.0;
    4588            7 :         XX(3) = Length;
    4589            7 :         XX(4) = Length;
    4590            7 :         YY(1) = Height;
    4591            7 :         YY(4) = Height;
    4592            7 :         YY(3) = 0.0;
    4593            7 :         YY(2) = 0.0;
    4594              : 
    4595           35 :         for (int n = 1; n <= surfTemp.Sides; ++n) {
    4596           28 :             Vrt = n;
    4597           28 :             surfTemp.Vertex(Vrt).x = XLLC - XX(n) * CosSurfAzimuth - YY(n) * CosSurfTilt * SinSurfAzimuth;
    4598           28 :             surfTemp.Vertex(Vrt).y = YLLC + XX(n) * SinSurfAzimuth - YY(n) * CosSurfTilt * CosSurfAzimuth;
    4599           28 :             surfTemp.Vertex(Vrt).z = ZLLC + YY(n) * SinSurfTilt;
    4600              :         }
    4601              : 
    4602            7 :         Vectors::CreateNewellAreaVector(surfTemp.Vertex, surfTemp.Sides, surfTemp.NewellAreaVector);
    4603            7 :         surfTemp.GrossArea = Vectors::VecLength(surfTemp.NewellAreaVector);
    4604            7 :         surfTemp.Area = surfTemp.GrossArea;
    4605            7 :         surfTemp.NetAreaShadowCalc = surfTemp.Area;
    4606            7 :         Vectors::CreateNewellSurfaceNormalVector(surfTemp.Vertex, surfTemp.Sides, surfTemp.NewellSurfaceNormalVector);
    4607            7 :         Vectors::DetermineAzimuthAndTilt(
    4608            7 :             surfTemp.Vertex, SurfAzimuth, SurfTilt, surfTemp.lcsx, surfTemp.lcsy, surfTemp.lcsz, surfTemp.NewellSurfaceNormalVector);
    4609            7 :         surfTemp.Azimuth = SurfAzimuth;
    4610            7 :         surfTemp.Tilt = SurfTilt;
    4611            7 :         surfTemp.convOrientation = Convect::GetSurfConvOrientation(surfTemp.Tilt);
    4612              :         // Sine and cosine of azimuth and tilt
    4613            7 :         surfTemp.SinAzim = SinSurfAzimuth;
    4614            7 :         surfTemp.CosAzim = CosSurfAzimuth;
    4615            7 :         surfTemp.SinTilt = SinSurfTilt;
    4616            7 :         surfTemp.CosTilt = CosSurfTilt;
    4617            7 :         surfTemp.ViewFactorGround = 0.5 * (1.0 - surfTemp.CosTilt);
    4618              :         // Outward normal unit vector (pointing away from room)
    4619              : 
    4620            7 :         surfTemp.OutNormVec = surfTemp.NewellSurfaceNormalVector;
    4621           28 :         for (int n = 1; n <= 3; ++n) {
    4622           21 :             if (std::abs(surfTemp.OutNormVec(n) - 1.0) < 1.e-06) surfTemp.OutNormVec(n) = +1.0;
    4623           21 :             if (std::abs(surfTemp.OutNormVec(n) + 1.0) < 1.e-06) surfTemp.OutNormVec(n) = -1.0;
    4624           21 :             if (std::abs(surfTemp.OutNormVec(n)) < 1.e-06) surfTemp.OutNormVec(n) = 0.0;
    4625              :         }
    4626              : 
    4627              :         // Can perform tests on this surface here
    4628            7 :         surfTemp.ViewFactorSky = 0.5 * (1.0 + surfTemp.CosTilt);
    4629              :         // The following IR view factors are modified in subr. SkyDifSolarShading if there are shadowing
    4630              :         // surfaces
    4631            7 :         surfTemp.ViewFactorSkyIR = surfTemp.ViewFactorSky;
    4632            7 :         surfTemp.ViewFactorGroundIR = 0.5 * (1.0 - surfTemp.CosTilt);
    4633              : 
    4634            7 :         Perimeter = distance(surfTemp.Vertex(surfTemp.Sides), surfTemp.Vertex(1));
    4635           28 :         for (Vrt = 2; Vrt <= surfTemp.Sides; ++Vrt) {
    4636           21 :             Perimeter += distance(surfTemp.Vertex(Vrt), surfTemp.Vertex(Vrt - 1));
    4637              :         }
    4638            7 :         surfTemp.Perimeter = Perimeter;
    4639              : 
    4640              :         // Call to transform vertices
    4641              : 
    4642            7 :         TransformVertsByAspect(state, SurfNum, surfTemp.Sides);
    4643            7 :     }
    4644              : 
    4645          226 :     void GetHTSubSurfaceData(EnergyPlusData &state,
    4646              :                              bool &ErrorsFound,                       // Error flag indicator (true if errors found)
    4647              :                              int &SurfNum,                            // Count of Current SurfaceNumber
    4648              :                              int const TotHTSubs,                     // Number of Heat Transfer SubSurfaces to obtain
    4649              :                              const Array1D_string &SubSurfCls,        // Valid Classes for Sub Surfaces
    4650              :                              const Array1D<SurfaceClass> &SubSurfIDs, // ID Assignments for valid sub surface classes
    4651              :                              int &AddedSubSurfaces,                   // Subsurfaces added when windows reference Window5
    4652              :                              int &NeedToAddSurfaces                   // Number of surfaces to add, based on unentered IZ surfaces
    4653              :     )
    4654              :     {
    4655              : 
    4656              :         // SUBROUTINE INFORMATION:
    4657              :         //       AUTHOR         Linda Lawrie
    4658              :         //       DATE WRITTEN   May 2000
    4659              :         //       MODIFIED       August 2012 - line up subsurfaces with base surface types
    4660              : 
    4661              :         // PURPOSE OF THIS SUBROUTINE:
    4662              :         // This subroutine gets the HeatTransfer Sub Surface Data, checks it for errors, etc.
    4663              : 
    4664              :         // REFERENCES:
    4665              :         // Heat Transfer Subsurface Definition
    4666              :         // FenestrationSurface:Detailed,
    4667              :         //        \min-fields 19
    4668              :         //        \memo Used for windows, doors, glass doors, tubular daylighting devices
    4669              :         //        \format vertices
    4670              :         //   A1 , \field Name
    4671              :         //        \required-field
    4672              :         //        \type alpha
    4673              :         //   A2 , \field Surface Type
    4674              :         //        \required-field
    4675              :         //        \type choice
    4676              :         //        \key Window
    4677              :         //        \key Door
    4678              :         //        \key GlassDoor
    4679              :         //        \key TubularDaylightDome
    4680              :         //        \key TubularDaylightDiffuser
    4681              :         //   A3 , \field Construction Name
    4682              :         //        \required-field
    4683              :         //        \note To be matched with a construction in this input file
    4684              :         //        \type object-list
    4685              :         //        \object-list ConstructionNames
    4686              :         //   A4 , \field Building Surface Name
    4687              :         //        \required-field
    4688              :         //        \type object-list
    4689              :         //        \object-list SurfaceNames
    4690              :         //   A5,  \field Outside Boundary Condition Object
    4691              :         //        \type object-list
    4692              :         //        \object-list OutFaceEnvNames
    4693              :         //        \note Non-blank only if base surface field Outside Boundary Condition is
    4694              :         //        \note Surface or OtherSideCoefficients
    4695              :         //        \note If Base Surface's Surface, specify name of corresponding subsurface in adjacent zone or
    4696              :         //        \note specify current subsurface name for internal partition separating like zones
    4697              :         //        \note If OtherSideCoefficients, specify name of SurfaceProperty:OtherSideCoefficients
    4698              :         //        \note  or leave blank to inherit Base Surface's OtherSide Coefficients
    4699              :         //   N1, \field View Factor to Ground
    4700              :         //        \type real
    4701              :         //        \note From the exterior of the surface
    4702              :         //        \note Unused if one uses the "reflections" options in Solar Distribution in Building input
    4703              :         //        \note unless a DaylightingDevice:Shelf or DaylightingDevice:Tubular object has been specified.
    4704              :         //        \note autocalculate will automatically calculate this value from the tilt of the surface
    4705              :         //        \autocalculatable
    4706              :         //        \minimum 0.0
    4707              :         //        \maximum 1.0
    4708              :         //        \default autocalculate
    4709              :         //   A6, \field Frame and Divider Name
    4710              :         //        \note Enter the name of a WindowProperty:FrameAndDivider object
    4711              :         //        \type object-list
    4712              :         //        \object-list WindowFrameAndDividerNames
    4713              :         //        \note Used only for exterior windows (rectangular) and glass doors.
    4714              :         //        \note Unused for triangular windows.
    4715              :         //        \note If not specified (blank), window or glass door has no frame or divider
    4716              :         //        \note and no beam solar reflection from reveal surfaces.
    4717              :         //   N2 , \field Multiplier
    4718              :         //        \note Used only for Surface Type = WINDOW, GLASSDOOR or DOOR
    4719              :         //        \note Non-integer values will be truncated to integer
    4720              :         //        \default 1.0
    4721              :         //        \minimum 1.0
    4722              :         //   N3 , \field Number of Vertices
    4723              :         //        \minimum 3
    4724              :         //        \maximum 4
    4725              :         //        \autocalculatable
    4726              :         //        \default autocalculate
    4727              :         //        \note vertices are given in GlobalGeometryRules coordinates -- if relative, all surface coordinates
    4728              :         //        \note are "relative" to the Zone Origin.  If world, then building and zone origins are used
    4729              :         //        \note for some internal calculations, but all coordinates are given in an "absolute" system.
    4730              :         //  N4-15 as indicated by the N3 value
    4731              : 
    4732              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    4733              :         int IOStat;          // IO Status when calling get input subroutine
    4734              :         int SurfaceNumAlpha; // Number of material alpha names being passed
    4735              :         int SurfaceNumProp;  // Number of material properties being passed
    4736              :         int Found;           // For matching interzone surfaces
    4737              :         int Loop;
    4738              :         int ValidChk;
    4739              :         int numSides;
    4740              : 
    4741          226 :         auto &s_ipsc = state.dataIPShortCut;
    4742              : 
    4743          226 :         GetWindowShadingControlData(state, ErrorsFound);
    4744          226 :         s_ipsc->cCurrentModuleObject = "FenestrationSurface:Detailed";
    4745          226 :         state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, s_ipsc->cCurrentModuleObject, Loop, SurfaceNumAlpha, SurfaceNumProp);
    4746              : 
    4747          226 :         if (SurfaceNumAlpha != 6) {
    4748            0 :             ShowSevereError(
    4749              :                 state,
    4750            0 :                 format("{}: Object Definition indicates not = 6 Alpha Objects, Number Indicated={}", s_ipsc->cCurrentModuleObject, SurfaceNumAlpha));
    4751            0 :             ErrorsFound = true;
    4752              :         }
    4753              : 
    4754          226 :         if (SurfaceNumProp != 15) {
    4755            0 :             ShowSevereError(
    4756              :                 state,
    4757            0 :                 format("{}: Object Definition indicates > 15 Numeric Objects, Number Indicated={}", s_ipsc->cCurrentModuleObject, SurfaceNumAlpha));
    4758            0 :             ErrorsFound = true;
    4759              :         }
    4760          226 :         NeedToAddSurfaces = 0;
    4761              : 
    4762          441 :         for (Loop = 1; Loop <= TotHTSubs; ++Loop) {
    4763          430 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    4764          215 :                                                                      s_ipsc->cCurrentModuleObject,
    4765              :                                                                      Loop,
    4766          215 :                                                                      s_ipsc->cAlphaArgs,
    4767              :                                                                      SurfaceNumAlpha,
    4768          215 :                                                                      s_ipsc->rNumericArgs,
    4769              :                                                                      SurfaceNumProp,
    4770              :                                                                      IOStat,
    4771          215 :                                                                      s_ipsc->lNumericFieldBlanks,
    4772          215 :                                                                      s_ipsc->lAlphaFieldBlanks,
    4773          215 :                                                                      s_ipsc->cAlphaFieldNames,
    4774          215 :                                                                      s_ipsc->cNumericFieldNames);
    4775              : 
    4776          430 :             if (GlobalNames::VerifyUniqueInterObjectName(state,
    4777          215 :                                                          state.dataSurfaceGeometry->UniqueSurfaceNames,
    4778          215 :                                                          s_ipsc->cAlphaArgs(1),
    4779          215 :                                                          s_ipsc->cCurrentModuleObject,
    4780          215 :                                                          s_ipsc->cAlphaFieldNames(1),
    4781              :                                                          ErrorsFound)) {
    4782            0 :                 continue;
    4783              :             }
    4784              : 
    4785          215 :             ++SurfNum;
    4786              : 
    4787          215 :             auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    4788              : 
    4789          215 :             if (SurfaceNumProp < 12) {
    4790            0 :                 ShowSevereError(
    4791            0 :                     state, format("{}=\"{}\", Too few number of numeric args=[{}].", s_ipsc->cCurrentModuleObject, surfTemp.Name, SurfaceNumProp));
    4792            0 :                 ErrorsFound = true;
    4793              :             }
    4794              : 
    4795          215 :             surfTemp.Name = s_ipsc->cAlphaArgs(1); // Set the Surface Name in the Derived Type
    4796          215 :             ValidChk = Util::FindItemInList(s_ipsc->cAlphaArgs(2), SubSurfCls, 6);
    4797          215 :             if (ValidChk == 0) {
    4798            0 :                 ShowSevereError(state,
    4799            0 :                                 format("{}=\"{}\", invalid {}=\"{}",
    4800            0 :                                        s_ipsc->cCurrentModuleObject,
    4801            0 :                                        surfTemp.Name,
    4802            0 :                                        s_ipsc->cAlphaFieldNames(2),
    4803            0 :                                        s_ipsc->cAlphaArgs(2)));
    4804            0 :                 ErrorsFound = true;
    4805              :             } else {
    4806          215 :                 surfTemp.Class = SubSurfIDs(ValidChk); // Set class number
    4807              :             }
    4808              : 
    4809          215 :             surfTemp.Construction = Util::FindItemInList(s_ipsc->cAlphaArgs(3), state.dataConstruction->Construct, state.dataHeatBal->TotConstructs);
    4810              : 
    4811          215 :             if (surfTemp.Construction == 0) {
    4812            2 :                 ShowSevereError(state,
    4813            4 :                                 format("{}=\"{}\", invalid {}=\"{}\".",
    4814            1 :                                        s_ipsc->cCurrentModuleObject,
    4815            1 :                                        surfTemp.Name,
    4816            1 :                                        s_ipsc->cAlphaFieldNames(3),
    4817            1 :                                        s_ipsc->cAlphaArgs(3)));
    4818            1 :                 ErrorsFound = true;
    4819            1 :                 continue;
    4820              :             } else {
    4821          214 :                 state.dataConstruction->Construct(surfTemp.Construction).IsUsed = true;
    4822          214 :                 surfTemp.ConstructionStoredInputValue = surfTemp.Construction;
    4823              :             }
    4824              : 
    4825          214 :             if (surfTemp.Class == SurfaceClass::Window || surfTemp.Class == SurfaceClass::GlassDoor || surfTemp.Class == SurfaceClass::TDD_Diffuser ||
    4826           26 :                 surfTemp.Class == SurfaceClass::TDD_Dome) {
    4827              : 
    4828          195 :                 if (surfTemp.Construction != 0) {
    4829          195 :                     auto const &construction = state.dataConstruction->Construct(surfTemp.Construction);
    4830          195 :                     if (!construction.TypeIsWindow && !construction.TypeIsAirBoundary) {
    4831            0 :                         ErrorsFound = true;
    4832            0 :                         ShowSevereError(state,
    4833            0 :                                         format("{}=\"{}\" has an opaque surface construction; it should have a window construction.",
    4834            0 :                                                s_ipsc->cCurrentModuleObject,
    4835            0 :                                                surfTemp.Name));
    4836              :                     }
    4837          195 :                     if (state.dataConstruction->Construct(surfTemp.Construction).SourceSinkPresent) {
    4838            0 :                         ErrorsFound = true;
    4839            0 :                         ShowSevereError(
    4840              :                             state,
    4841            0 :                             format("{}=\"{}\": Windows are not allowed to have embedded sources/sinks", s_ipsc->cCurrentModuleObject, surfTemp.Name));
    4842              :                     }
    4843              :                 }
    4844              : 
    4845          214 :             } else if (surfTemp.Construction != 0) {
    4846           19 :                 if (state.dataConstruction->Construct(surfTemp.Construction).TypeIsWindow) {
    4847            0 :                     ErrorsFound = true;
    4848            0 :                     ShowSevereError(state,
    4849            0 :                                     format("{}=\"{}\", invalid {}=\"{}\" - has Window materials.",
    4850            0 :                                            s_ipsc->cCurrentModuleObject,
    4851            0 :                                            surfTemp.Name,
    4852            0 :                                            s_ipsc->cAlphaFieldNames(3),
    4853            0 :                                            s_ipsc->cAlphaArgs(3)));
    4854            0 :                     ShowContinueError(state, format("...because {}={}", s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2)));
    4855              :                 }
    4856              :             }
    4857              : 
    4858          214 :             surfTemp.HeatTransSurf = true;
    4859              : 
    4860          214 :             surfTemp.BaseSurfName = s_ipsc->cAlphaArgs(4);
    4861              :             //  The subsurface inherits properties from the base surface
    4862              :             //  Exterior conditions, Zone, etc.
    4863              :             //  We can figure out the base surface though, because they've all been entered
    4864          214 :             Found = Util::FindItemInList(surfTemp.BaseSurfName, state.dataSurfaceGeometry->SurfaceTmp, state.dataSurface->TotSurfaces);
    4865          214 :             if (Found > 0) {
    4866          214 :                 surfTemp.BaseSurf = Found;
    4867          214 :                 surfTemp.ExtBoundCond = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCond;
    4868          214 :                 surfTemp.ExtBoundCondName = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCondName;
    4869          214 :                 surfTemp.ExtSolar = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtSolar;
    4870          214 :                 surfTemp.ExtWind = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtWind;
    4871          214 :                 surfTemp.Zone = state.dataSurfaceGeometry->SurfaceTmp(Found).Zone;
    4872          214 :                 surfTemp.ZoneName = state.dataSurfaceGeometry->SurfaceTmp(Found).ZoneName;
    4873          214 :                 surfTemp.OSCPtr = state.dataSurfaceGeometry->SurfaceTmp(Found).OSCPtr;
    4874          234 :                 if (state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCond == unreconciledZoneSurface &&
    4875           20 :                     state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCondName ==
    4876           20 :                         state.dataSurfaceGeometry->SurfaceTmp(Found).Name) { // Adiabatic surface, no windows or doors allowed
    4877            0 :                     ShowSevereError(state,
    4878            0 :                                     format("{}=\"{}\", invalid {}=\"{}\".",
    4879            0 :                                            s_ipsc->cCurrentModuleObject,
    4880            0 :                                            surfTemp.Name,
    4881            0 :                                            s_ipsc->cAlphaFieldNames(4),
    4882            0 :                                            s_ipsc->cAlphaArgs(4)));
    4883            0 :                     ShowContinueError(state, "... adiabatic surfaces cannot have windows or doors.");
    4884            0 :                     ShowContinueError(state,
    4885              :                                       "... no solar transmission will result for these windows or doors. You must have interior windows or doors on "
    4886              :                                       "Interzone surfaces for transmission to result.");
    4887              :                 }
    4888              :             } else {
    4889            0 :                 ShowSevereError(state,
    4890            0 :                                 format("{}=\"{}\", invalid {}=\"{}",
    4891            0 :                                        s_ipsc->cCurrentModuleObject,
    4892            0 :                                        surfTemp.Name,
    4893            0 :                                        s_ipsc->cAlphaFieldNames(4),
    4894            0 :                                        s_ipsc->cAlphaArgs(4)));
    4895            0 :                 surfTemp.ZoneName = "Unknown Zone";
    4896            0 :                 ErrorsFound = true;
    4897              :             }
    4898          214 :             if (surfTemp.Class == SurfaceClass::TDD_Dome || surfTemp.Class == SurfaceClass::TDD_Diffuser) {
    4899           13 :                 surfTemp.ExtBoundCond = DataSurfaces::ExternalEnvironment;
    4900              :             }
    4901              : 
    4902          214 :             if (surfTemp.ExtBoundCond == DataSurfaces::ExternalEnvironment) {
    4903          194 :                 if (!s_ipsc->lAlphaFieldBlanks(5)) {
    4904            0 :                     ShowWarningError(state,
    4905            0 :                                      format("{}=\"{}\", invalid field {}", s_ipsc->cCurrentModuleObject, surfTemp.Name, s_ipsc->cAlphaFieldNames(5)));
    4906            0 :                     ShowContinueError(
    4907              :                         state,
    4908            0 :                         format("...when Base surface uses \"Outdoors\" as {}, subsurfaces need to be blank to inherit the outdoor characteristics.",
    4909            0 :                                s_ipsc->cAlphaFieldNames(5)));
    4910            0 :                     ShowContinueError(state, "...Surface external characteristics changed to reflect base surface.");
    4911              :                 }
    4912              :             }
    4913              : 
    4914          214 :             if (surfTemp.ExtBoundCond == unreconciledZoneSurface) { // "Surface" Base Surface
    4915           14 :                 if (!s_ipsc->lAlphaFieldBlanks(5)) {
    4916           14 :                     surfTemp.ExtBoundCondName = s_ipsc->cAlphaArgs(5);
    4917              :                 } else {
    4918            0 :                     ShowSevereError(state,
    4919            0 :                                     format("{}=\"{}\", invalid blank {}", s_ipsc->cCurrentModuleObject, surfTemp.Name, s_ipsc->cAlphaFieldNames(5)));
    4920            0 :                     ShowContinueError(
    4921              :                         state,
    4922            0 :                         format("...when Base surface uses \"Surface\" as {}, subsurfaces must also specify specific surfaces in the adjacent zone.",
    4923            0 :                                s_ipsc->cAlphaFieldNames(5)));
    4924            0 :                     surfTemp.ExtBoundCondName = s_ipsc->cAlphaArgs(5); // putting it as blank will not confuse things later.
    4925            0 :                     ErrorsFound = true;
    4926              :                 }
    4927              :             }
    4928              : 
    4929          214 :             if ((surfTemp.ExtBoundCond == unenteredAdjacentZoneSurface) ||
    4930          210 :                 (surfTemp.ExtBoundCond == unenteredAdjacentSpaceSurface)) { // "Zone" - unmatched interior surface
    4931            6 :                 ++NeedToAddSurfaces;
    4932              :                 // ignoring window5datafiles for now -- will need to add.
    4933              :             }
    4934              : 
    4935          214 :             if (surfTemp.ExtBoundCond == DataSurfaces::OtherSideCoefNoCalcExt || surfTemp.ExtBoundCond == DataSurfaces::OtherSideCoefCalcExt) {
    4936            0 :                 if (!s_ipsc->lAlphaFieldBlanks(5)) { // Otherside Coef special Name
    4937            0 :                     Found = Util::FindItemInList(s_ipsc->cAlphaArgs(5), state.dataSurface->OSC, state.dataSurface->TotOSC);
    4938            0 :                     if (Found == 0) {
    4939            0 :                         ShowSevereError(state,
    4940            0 :                                         format("{}=\"{}\", invalid {}=\"{}\".",
    4941            0 :                                                s_ipsc->cCurrentModuleObject,
    4942            0 :                                                surfTemp.Name,
    4943            0 :                                                s_ipsc->cAlphaFieldNames(5),
    4944            0 :                                                s_ipsc->cAlphaArgs(5)));
    4945            0 :                         ShowContinueError(state, "...base surface requires that this subsurface have OtherSideCoefficients -- not found.");
    4946            0 :                         ErrorsFound = true;
    4947              :                     } else { // found
    4948              :                         // The following allows for a subsurface that has different characteristics than
    4949              :                         // the base surface with OtherSide Coeff -- do we want that or is it an error?
    4950            0 :                         surfTemp.OSCPtr = Found;
    4951            0 :                         surfTemp.ExtBoundCondName = s_ipsc->cAlphaArgs(5);
    4952            0 :                         if (state.dataSurface->OSC(Found).SurfFilmCoef > 0.0) {
    4953            0 :                             surfTemp.ExtBoundCond = DataSurfaces::OtherSideCoefCalcExt;
    4954              :                         } else {
    4955            0 :                             surfTemp.ExtBoundCond = DataSurfaces::OtherSideCoefNoCalcExt;
    4956              :                         }
    4957              :                     }
    4958              :                 }
    4959              :             }
    4960              : 
    4961          214 :             if (surfTemp.ExtBoundCond == DataSurfaces::OtherSideCondModeledExt) {
    4962            0 :                 surfTemp.ExtBoundCond = DataSurfaces::ExternalEnvironment;
    4963              :             }
    4964              : 
    4965          214 :             if (surfTemp.ExtBoundCondName == BlankString) {
    4966          188 :                 surfTemp.ExtBoundCondName = surfTemp.Name;
    4967              :             }
    4968          214 :             surfTemp.ViewFactorGround = s_ipsc->rNumericArgs(1);
    4969          214 :             if (s_ipsc->lNumericFieldBlanks(1)) surfTemp.ViewFactorGround = Constant::AutoCalculate;
    4970              : 
    4971          214 :             if (s_ipsc->lNumericFieldBlanks(3) || s_ipsc->rNumericArgs(3) == Constant::AutoCalculate) {
    4972           14 :                 s_ipsc->rNumericArgs(3) = (SurfaceNumProp - 3) / 3;
    4973           14 :                 surfTemp.Sides = s_ipsc->rNumericArgs(3);
    4974           14 :                 if (mod(SurfaceNumProp - 3, 3) != 0) {
    4975            0 :                     ShowWarningError(state,
    4976            0 :                                      format("{}=\"{}\", {}",
    4977            0 :                                             s_ipsc->cCurrentModuleObject,
    4978            0 :                                             surfTemp.Name,
    4979            0 :                                             format("{} not even multiple of 3. Will read in {}", s_ipsc->cNumericFieldNames(3), surfTemp.Sides)));
    4980              :                 }
    4981           14 :                 if (s_ipsc->rNumericArgs(3) < 3) {
    4982            0 :                     ShowSevereError(state,
    4983            0 :                                     format("{}=\"{}\", {} (autocalculate) must be >= 3. Only {} provided.",
    4984            0 :                                            s_ipsc->cCurrentModuleObject,
    4985            0 :                                            surfTemp.Name,
    4986            0 :                                            s_ipsc->cNumericFieldNames(3),
    4987            0 :                                            surfTemp.Sides));
    4988            0 :                     ErrorsFound = true;
    4989            0 :                     continue;
    4990              :                 }
    4991              :             } else {
    4992          200 :                 numSides = (SurfaceNumProp - 2) / 3;
    4993          200 :                 surfTemp.Sides = s_ipsc->rNumericArgs(3);
    4994          200 :                 if (numSides > surfTemp.Sides) {
    4995            0 :                     ShowWarningError(state,
    4996            0 :                                      format("{}=\"{}\", field {}={}",
    4997            0 :                                             s_ipsc->cCurrentModuleObject,
    4998            0 :                                             surfTemp.Name,
    4999            0 :                                             s_ipsc->cNumericFieldNames(3),
    5000            0 :                                             fmt::to_string(surfTemp.Sides)));
    5001            0 :                     ShowContinueError(state,
    5002            0 :                                       format("...but {} were entered. Only the indicated {} will be used.", numSides, s_ipsc->cNumericFieldNames(3)));
    5003              :                 }
    5004              :             }
    5005          214 :             surfTemp.Vertex.allocate(surfTemp.Sides);
    5006          214 :             if (surfTemp.Class == SurfaceClass::Window || surfTemp.Class == SurfaceClass::GlassDoor || surfTemp.Class == SurfaceClass::Door)
    5007          201 :                 surfTemp.Multiplier = int(s_ipsc->rNumericArgs(2));
    5008              :             // Only windows, glass doors and doors can have Multiplier > 1:
    5009          227 :             if ((surfTemp.Class != SurfaceClass::Window && surfTemp.Class != SurfaceClass::GlassDoor && surfTemp.Class != SurfaceClass::Door) &&
    5010           13 :                 s_ipsc->rNumericArgs(2) > 1.0) {
    5011            0 :                 ShowWarningError(state,
    5012            0 :                                  format("{}=\"{}\", invalid {}=[{:.1T}].",
    5013            0 :                                         s_ipsc->cCurrentModuleObject,
    5014            0 :                                         surfTemp.Name,
    5015            0 :                                         s_ipsc->cNumericFieldNames(2),
    5016            0 :                                         s_ipsc->rNumericArgs(2)));
    5017            0 :                 ShowContinueError(state,
    5018            0 :                                   format("...because {}={} multiplier will be set to 1.0.", s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2)));
    5019            0 :                 surfTemp.Multiplier = 1.0;
    5020              :             }
    5021              : 
    5022          856 :             GetVertices(state, SurfNum, surfTemp.Sides, s_ipsc->rNumericArgs({4, _}));
    5023              : 
    5024          214 :             CheckConvexity(state, SurfNum, surfTemp.Sides);
    5025          214 :             surfTemp.windowShadingControlList.clear();
    5026          214 :             surfTemp.activeWindowShadingControl = 0;
    5027          214 :             surfTemp.HasShadeControl = false;
    5028              : 
    5029          214 :             surfTemp.shadedConstructionList.clear();
    5030          214 :             surfTemp.activeShadedConstruction = 0;
    5031          214 :             surfTemp.shadedStormWinConstructionList.clear();
    5032              : 
    5033          214 :             if (surfTemp.Class == SurfaceClass::Window || surfTemp.Class == SurfaceClass::GlassDoor || surfTemp.Class == SurfaceClass::TDD_Diffuser ||
    5034           26 :                 surfTemp.Class == SurfaceClass::TDD_Dome) {
    5035              : 
    5036          195 :                 if (surfTemp.ExtBoundCond == DataSurfaces::OtherSideCoefNoCalcExt || surfTemp.ExtBoundCond == DataSurfaces::OtherSideCoefCalcExt) {
    5037            0 :                     ShowSevereError(
    5038              :                         state,
    5039            0 :                         format("{}=\"{}\", Other side coefficients are not allowed with windows.", s_ipsc->cCurrentModuleObject, surfTemp.Name));
    5040            0 :                     ErrorsFound = true;
    5041              :                 }
    5042              : 
    5043          195 :                 if (surfTemp.ExtBoundCond == DataSurfaces::Ground) {
    5044            0 :                     ShowSevereError(state,
    5045            0 :                                     format("{}=\"{}\", Exterior boundary condition = Ground is not allowed with windows.",
    5046            0 :                                            s_ipsc->cCurrentModuleObject,
    5047            0 :                                            surfTemp.Name));
    5048            0 :                     ErrorsFound = true;
    5049              :                 }
    5050              : 
    5051          195 :                 if (surfTemp.ExtBoundCond == DataSurfaces::KivaFoundation) {
    5052            0 :                     ShowSevereError(state,
    5053            0 :                                     format("{}=\"{}\", Exterior boundary condition = Foundation is not allowed with windows.",
    5054            0 :                                            s_ipsc->cCurrentModuleObject,
    5055            0 :                                            surfTemp.Name));
    5056            0 :                     ErrorsFound = true;
    5057              :                 }
    5058              : 
    5059          195 :                 InitialAssociateWindowShadingControlFenestration(state, ErrorsFound, SurfNum);
    5060              : 
    5061          195 :                 CheckWindowShadingControlFrameDivider(state, "GetHTSubSurfaceData", ErrorsFound, SurfNum, 6);
    5062              : 
    5063          195 :                 if (surfTemp.Sides == 3) { // Triangular window
    5064            1 :                     if (!s_ipsc->cAlphaArgs(6).empty()) {
    5065            0 :                         ShowWarningError(state,
    5066            0 :                                          format("{}=\"{}\", invalid {}=\"{}\".",
    5067            0 :                                                 s_ipsc->cCurrentModuleObject,
    5068            0 :                                                 surfTemp.Name,
    5069            0 :                                                 s_ipsc->cAlphaFieldNames(6),
    5070            0 :                                                 s_ipsc->cAlphaArgs(6)));
    5071            0 :                         ShowContinueError(state, ".. because it is a triangular window and cannot have a frame or divider or reveal reflection.");
    5072            0 :                         ShowContinueError(state, "Frame, divider and reveal reflection will be ignored for this window.");
    5073              :                     }
    5074            1 :                     surfTemp.FrameDivider = 0;
    5075              :                 } // End of check if window is triangular or rectangular
    5076              : 
    5077              :             } // check on non-opaquedoor subsurfaces
    5078              : 
    5079          214 :             CheckSubSurfaceMiscellaneous(
    5080          214 :                 state, "GetHTSubSurfaceData", ErrorsFound, SurfNum, s_ipsc->cAlphaArgs(1), s_ipsc->cAlphaArgs(3), AddedSubSurfaces);
    5081              : 
    5082              :         } // End of main loop over subsurfaces
    5083          440 :     }
    5084              : 
    5085          226 :     void GetRectSubSurfaces(EnergyPlusData &state,
    5086              :                             bool &ErrorsFound,                       // Error flag indicator (true if errors found)
    5087              :                             int &SurfNum,                            // Count of Current SurfaceNumber
    5088              :                             int const TotWindows,                    // Number of Window SubSurfaces to obtain
    5089              :                             int const TotDoors,                      // Number of Door SubSurfaces to obtain
    5090              :                             int const TotGlazedDoors,                // Number of Glass Door SubSurfaces to obtain
    5091              :                             int const TotIZWindows,                  // Number of Interzone Window SubSurfaces to obtain
    5092              :                             int const TotIZDoors,                    // Number of Interzone Door SubSurfaces to obtain
    5093              :                             int const TotIZGlazedDoors,              // Number of Interzone Glass Door SubSurfaces to obtain
    5094              :                             const Array1D<SurfaceClass> &SubSurfIDs, // ID Assignments for valid sub surface classes
    5095              :                             int &AddedSubSurfaces,                   // Subsurfaces added when windows reference Window5
    5096              :                             int &NeedToAddSubSurfaces                // Number of surfaces to add, based on unentered IZ surfaces
    5097              :     )
    5098              :     {
    5099              : 
    5100              :         // SUBROUTINE INFORMATION:
    5101              :         //       AUTHOR         Linda Lawrie
    5102              :         //       DATE WRITTEN   December 2008
    5103              : 
    5104              :         // PURPOSE OF THIS SUBROUTINE:
    5105              :         // Get simple (rectangular, relative origin to base surface) windows, doors, glazed doors.
    5106              : 
    5107              :         // SUBROUTINE PARAMETER DEFINITIONS:
    5108          226 :         static Array1D_string const cModuleObjects(6, {"Window", "Door", "GlazedDoor", "Window:Interzone", "Door:Interzone", "GlazedDoor:Interzone"});
    5109              : 
    5110              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    5111              :         int ItemsToGet;
    5112              :         int Loop;
    5113              :         int NumAlphas;
    5114              :         int NumNumbers;
    5115              :         int IOStat; // IO Status when calling get input subroutine
    5116              :         int Found;  // For matching base surfaces
    5117              :         bool GettingIZSurfaces;
    5118              :         int FrameField;
    5119              :         int OtherSurfaceField;
    5120              :         int ClassItem;
    5121              :         int IZFound;
    5122              : 
    5123          226 :         auto &s_ipsc = state.dataIPShortCut;
    5124         1582 :         for (int Item = 1; Item <= 6; ++Item) {
    5125              : 
    5126         1356 :             s_ipsc->cCurrentModuleObject = cModuleObjects(Item);
    5127         1356 :             if (Item == 1) {
    5128          226 :                 ItemsToGet = TotWindows;
    5129          226 :                 GettingIZSurfaces = false;
    5130          226 :                 FrameField = 5;
    5131          226 :                 OtherSurfaceField = 0;
    5132          226 :                 ClassItem = 1;
    5133         1130 :             } else if (Item == 2) {
    5134          226 :                 ItemsToGet = TotDoors;
    5135          226 :                 GettingIZSurfaces = false;
    5136          226 :                 FrameField = 0;
    5137          226 :                 OtherSurfaceField = 0;
    5138          226 :                 ClassItem = 2;
    5139          904 :             } else if (Item == 3) {
    5140          226 :                 ItemsToGet = TotGlazedDoors;
    5141          226 :                 GettingIZSurfaces = false;
    5142          226 :                 FrameField = 5;
    5143          226 :                 OtherSurfaceField = 0;
    5144          226 :                 ClassItem = 3;
    5145          678 :             } else if (Item == 4) {
    5146          226 :                 ItemsToGet = TotIZWindows;
    5147          226 :                 GettingIZSurfaces = true;
    5148          226 :                 FrameField = 0;
    5149          226 :                 OtherSurfaceField = 4;
    5150          226 :                 ClassItem = 1;
    5151          452 :             } else if (Item == 5) {
    5152          226 :                 ItemsToGet = TotIZDoors;
    5153          226 :                 GettingIZSurfaces = true;
    5154          226 :                 FrameField = 0;
    5155          226 :                 OtherSurfaceField = 4;
    5156          226 :                 ClassItem = 2;
    5157              :             } else { // Item = 6
    5158          226 :                 ItemsToGet = TotIZGlazedDoors;
    5159          226 :                 GettingIZSurfaces = true;
    5160          226 :                 FrameField = 0;
    5161          226 :                 OtherSurfaceField = 4;
    5162          226 :                 ClassItem = 3;
    5163              :             }
    5164              : 
    5165         1365 :             for (Loop = 1; Loop <= ItemsToGet; ++Loop) {
    5166           18 :                 state.dataInputProcessing->inputProcessor->getObjectItem(state,
    5167            9 :                                                                          s_ipsc->cCurrentModuleObject,
    5168              :                                                                          Loop,
    5169            9 :                                                                          s_ipsc->cAlphaArgs,
    5170              :                                                                          NumAlphas,
    5171            9 :                                                                          s_ipsc->rNumericArgs,
    5172              :                                                                          NumNumbers,
    5173              :                                                                          IOStat,
    5174            9 :                                                                          s_ipsc->lNumericFieldBlanks,
    5175            9 :                                                                          s_ipsc->lAlphaFieldBlanks,
    5176            9 :                                                                          s_ipsc->cAlphaFieldNames,
    5177            9 :                                                                          s_ipsc->cNumericFieldNames);
    5178              : 
    5179           18 :                 if (GlobalNames::VerifyUniqueInterObjectName(state,
    5180            9 :                                                              state.dataSurfaceGeometry->UniqueSurfaceNames,
    5181            9 :                                                              s_ipsc->cAlphaArgs(1),
    5182            9 :                                                              s_ipsc->cCurrentModuleObject,
    5183            9 :                                                              s_ipsc->cAlphaFieldNames(1),
    5184              :                                                              ErrorsFound)) {
    5185            0 :                     continue;
    5186              :                 }
    5187              : 
    5188            9 :                 if (NumNumbers < 5) {
    5189            0 :                     ShowSevereError(
    5190              :                         state,
    5191            0 :                         format("{}=\"{}\", Too few number of numeric args=[{}].", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1), NumNumbers));
    5192            0 :                     ErrorsFound = true;
    5193              :                 }
    5194              : 
    5195            9 :                 ++SurfNum;
    5196            9 :                 auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    5197              : 
    5198            9 :                 surfTemp.Name = s_ipsc->cAlphaArgs(1);  // Set the Surface Name in the Derived Type
    5199            9 :                 surfTemp.Class = SubSurfIDs(ClassItem); // Set class number
    5200              : 
    5201            9 :                 surfTemp.Construction =
    5202            9 :                     Util::FindItemInList(s_ipsc->cAlphaArgs(2), state.dataConstruction->Construct, state.dataHeatBal->TotConstructs);
    5203              : 
    5204            9 :                 if (surfTemp.Construction == 0) {
    5205            0 :                     ErrorsFound = true;
    5206            0 :                     ShowSevereError(state,
    5207            0 :                                     format("{}=\"{}\", invalid {}=\"{}\".",
    5208            0 :                                            s_ipsc->cCurrentModuleObject,
    5209            0 :                                            surfTemp.Name,
    5210            0 :                                            s_ipsc->cAlphaFieldNames(2),
    5211            0 :                                            s_ipsc->cAlphaArgs(2)));
    5212              :                 } else {
    5213            9 :                     state.dataConstruction->Construct(surfTemp.Construction).IsUsed = true;
    5214            9 :                     surfTemp.ConstructionStoredInputValue = surfTemp.Construction;
    5215              :                 }
    5216              : 
    5217            9 :                 if (surfTemp.Class == SurfaceClass::Window || surfTemp.Class == SurfaceClass::GlassDoor) {
    5218              : 
    5219            8 :                     if (surfTemp.Construction != 0) {
    5220            8 :                         auto const &construction = state.dataConstruction->Construct(surfTemp.Construction);
    5221              : 
    5222            8 :                         if (!construction.TypeIsWindow && !construction.TypeIsAirBoundary) {
    5223            0 :                             ErrorsFound = true;
    5224            0 :                             ShowSevereError(state,
    5225            0 :                                             format("{}=\"{}\" has an opaque surface construction; it should have a window construction.",
    5226            0 :                                                    s_ipsc->cCurrentModuleObject,
    5227            0 :                                                    surfTemp.Name));
    5228              :                         }
    5229            8 :                         if (state.dataConstruction->Construct(surfTemp.Construction).SourceSinkPresent) {
    5230            0 :                             ErrorsFound = true;
    5231            0 :                             ShowSevereError(state,
    5232            0 :                                             format("{}=\"{}\": Windows are not allowed to have embedded sources/sinks",
    5233            0 :                                                    s_ipsc->cCurrentModuleObject,
    5234            0 :                                                    surfTemp.Name));
    5235              :                         }
    5236              :                     }
    5237              : 
    5238            9 :                 } else if (surfTemp.Construction != 0) {
    5239            1 :                     if (state.dataConstruction->Construct(surfTemp.Construction).TypeIsWindow) {
    5240            0 :                         ErrorsFound = true;
    5241            0 :                         ShowSevereError(state,
    5242            0 :                                         format("{}=\"{}\", invalid {}=\"{}\" - has Window materials.",
    5243            0 :                                                s_ipsc->cCurrentModuleObject,
    5244            0 :                                                surfTemp.Name,
    5245            0 :                                                s_ipsc->cAlphaFieldNames(2),
    5246            0 :                                                s_ipsc->cAlphaArgs(2)));
    5247              :                     }
    5248              :                 }
    5249              : 
    5250            9 :                 surfTemp.HeatTransSurf = true;
    5251              : 
    5252            9 :                 surfTemp.BaseSurfName = s_ipsc->cAlphaArgs(3);
    5253              :                 //  The subsurface inherits properties from the base surface
    5254              :                 //  Exterior conditions, Zone, etc.
    5255              :                 //  We can figure out the base surface though, because they've all been entered
    5256            9 :                 Found = Util::FindItemInList(surfTemp.BaseSurfName, state.dataSurfaceGeometry->SurfaceTmp, state.dataSurface->TotSurfaces);
    5257            9 :                 if (Found > 0) {
    5258            9 :                     surfTemp.BaseSurf = Found;
    5259            9 :                     surfTemp.ExtBoundCond = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCond;
    5260            9 :                     surfTemp.ExtBoundCondName = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCondName;
    5261            9 :                     surfTemp.ExtSolar = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtSolar;
    5262            9 :                     surfTemp.ExtWind = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtWind;
    5263            9 :                     surfTemp.Tilt = state.dataSurfaceGeometry->SurfaceTmp(Found).Tilt;
    5264            9 :                     surfTemp.convOrientation = Convect::GetSurfConvOrientation(surfTemp.Tilt);
    5265            9 :                     surfTemp.Azimuth = state.dataSurfaceGeometry->SurfaceTmp(Found).Azimuth;
    5266            9 :                     surfTemp.Zone = state.dataSurfaceGeometry->SurfaceTmp(Found).Zone;
    5267            9 :                     surfTemp.ZoneName = state.dataSurfaceGeometry->SurfaceTmp(Found).ZoneName;
    5268            9 :                     surfTemp.OSCPtr = state.dataSurfaceGeometry->SurfaceTmp(Found).OSCPtr;
    5269            9 :                     surfTemp.ViewFactorGround = state.dataSurfaceGeometry->SurfaceTmp(Found).ViewFactorGround;
    5270            9 :                     surfTemp.ViewFactorSky = state.dataSurfaceGeometry->SurfaceTmp(Found).ViewFactorSky;
    5271              :                 } else {
    5272            0 :                     ShowSevereError(state,
    5273            0 :                                     format("{}=\"{}\", invalid {}=\"{}",
    5274            0 :                                            s_ipsc->cCurrentModuleObject,
    5275            0 :                                            surfTemp.Name,
    5276            0 :                                            s_ipsc->cAlphaFieldNames(3),
    5277            0 :                                            s_ipsc->cAlphaArgs(3)));
    5278            0 :                     surfTemp.ZoneName = "Unknown Zone";
    5279            0 :                     ErrorsFound = true;
    5280            0 :                     continue;
    5281              :                 }
    5282            9 :                 if (state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCond == unreconciledZoneSurface &&
    5283            0 :                     state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCondName ==
    5284            0 :                         state.dataSurfaceGeometry->SurfaceTmp(Found).Name) { // Adiabatic surface, no windows or doors allowed
    5285            0 :                     ShowSevereError(state,
    5286            0 :                                     format("{}=\"{}\", invalid {}=\"{}\".",
    5287            0 :                                            s_ipsc->cCurrentModuleObject,
    5288            0 :                                            surfTemp.Name,
    5289            0 :                                            s_ipsc->cAlphaFieldNames(3),
    5290            0 :                                            s_ipsc->cAlphaArgs(3)));
    5291            0 :                     ShowContinueError(state, "... adiabatic surfaces cannot have windows or doors.");
    5292            0 :                     ShowContinueError(state,
    5293              :                                       "... no solar transmission will result for these windows or doors. You must have interior windows or doors on "
    5294              :                                       "Interzone surfaces for transmission to result.");
    5295              :                 }
    5296              : 
    5297            9 :                 if (surfTemp.ExtBoundCond == unreconciledZoneSurface) { // "Surface" Base Surface
    5298            0 :                     if (!GettingIZSurfaces) {
    5299            0 :                         ShowSevereError(state, format("{}=\"{}\", invalid use of object", s_ipsc->cCurrentModuleObject, surfTemp.Name));
    5300            0 :                         ShowContinueError(
    5301              :                             state,
    5302            0 :                             format(
    5303              :                                 "...when Base surface uses \"Surface\" as {}, subsurfaces must also specify specific surfaces in the adjacent zone.",
    5304            0 :                                 s_ipsc->cAlphaFieldNames(5)));
    5305            0 :                         ShowContinueError(state, format("...Please use {}:Interzone to enter this surface.", s_ipsc->cCurrentModuleObject));
    5306            0 :                         surfTemp.ExtBoundCondName = BlankString; // putting it as blank will not confuse things later.
    5307            0 :                         ErrorsFound = true;
    5308              :                     }
    5309              :                 }
    5310              : 
    5311            9 :                 if (surfTemp.ExtBoundCond == unreconciledZoneSurface) { // "Surface" Base Surface
    5312            0 :                     if (GettingIZSurfaces) {
    5313            0 :                         surfTemp.ExtBoundCondName = s_ipsc->cAlphaArgs(OtherSurfaceField);
    5314            0 :                         IZFound = Util::FindItemInList(surfTemp.ExtBoundCondName, state.dataHeatBal->Zone, state.dataGlobal->NumOfZones);
    5315            0 :                         if (IZFound > 0) surfTemp.ExtBoundCond = unenteredAdjacentZoneSurface;
    5316              :                     } else { // Interior Window
    5317            0 :                         surfTemp.ExtBoundCondName = surfTemp.Name;
    5318              :                     }
    5319              :                 }
    5320              : 
    5321              :                 // This is the parent's property:
    5322            9 :                 if (surfTemp.ExtBoundCond == unenteredAdjacentZoneSurface) { // OtherZone - unmatched interior surface
    5323            0 :                     if (GettingIZSurfaces) {
    5324            0 :                         ++NeedToAddSubSurfaces;
    5325              :                     } else { // Interior Window
    5326            0 :                         ShowSevereError(state,
    5327            0 :                                         format("{}=\"{}\", invalid Interzone Surface, specify {}:InterZone",
    5328            0 :                                                s_ipsc->cCurrentModuleObject,
    5329            0 :                                                surfTemp.Name,
    5330            0 :                                                s_ipsc->cCurrentModuleObject));
    5331            0 :                         ShowContinueError(state, "...when base surface is an interzone surface, subsurface must also be an interzone surface.");
    5332            0 :                         ++NeedToAddSubSurfaces;
    5333            0 :                         ErrorsFound = true;
    5334              :                     }
    5335              :                 }
    5336              : 
    5337            9 :                 if (GettingIZSurfaces) {
    5338            0 :                     if (s_ipsc->lAlphaFieldBlanks(OtherSurfaceField)) {
    5339              :                         // blank -- set it up for unentered adjacent zone
    5340            0 :                         if (surfTemp.ExtBoundCond == unenteredAdjacentZoneSurface) {                                   // already set but need Zone
    5341            0 :                             surfTemp.ExtBoundCondName = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCondName; // base surface has it
    5342            0 :                         } else if (surfTemp.ExtBoundCond == unreconciledZoneSurface) {
    5343            0 :                             surfTemp.ExtBoundCondName = state.dataSurfaceGeometry->SurfaceTmp(Found).ZoneName; // base surface has it
    5344            0 :                             surfTemp.ExtBoundCond = unenteredAdjacentZoneSurface;
    5345              :                         } else { // not correct boundary condition for interzone subsurface
    5346            0 :                             ShowSevereError(
    5347              :                                 state,
    5348            0 :                                 format("{}=\"{}\", invalid Base Surface type for Interzone Surface", s_ipsc->cCurrentModuleObject, surfTemp.Name));
    5349            0 :                             ShowContinueError(state,
    5350              :                                               "...when base surface is not an interzone surface, subsurface must also not be an interzone surface.");
    5351            0 :                             ErrorsFound = true;
    5352              :                         }
    5353              :                     }
    5354              :                 }
    5355              : 
    5356            9 :                 if (surfTemp.ExtBoundCond == DataSurfaces::OtherSideCondModeledExt) {
    5357            0 :                     surfTemp.ExtBoundCond = DataSurfaces::ExternalEnvironment;
    5358              :                 }
    5359              : 
    5360              :                 //      SurfaceTmp(SurfNum)%ViewFactorGround = AutoCalculate
    5361              : 
    5362            9 :                 surfTemp.Sides = 4;
    5363            9 :                 surfTemp.Vertex.allocate(surfTemp.Sides);
    5364            9 :                 if (surfTemp.Class == SurfaceClass::Window || surfTemp.Class == SurfaceClass::GlassDoor || surfTemp.Class == SurfaceClass::Door) {
    5365            9 :                     surfTemp.Multiplier = int(s_ipsc->rNumericArgs(1));
    5366            0 :                 } else if (s_ipsc->rNumericArgs(1) > 1.0) {
    5367            0 :                     ShowWarningError(state,
    5368            0 :                                      format("{}=\"{}\", invalid {}=[{:.1T}].",
    5369            0 :                                             s_ipsc->cCurrentModuleObject,
    5370            0 :                                             surfTemp.Name,
    5371            0 :                                             s_ipsc->cNumericFieldNames(1),
    5372            0 :                                             s_ipsc->rNumericArgs(1)));
    5373            0 :                     ShowContinueError(state,
    5374            0 :                                       format("...because {}={} multiplier will be set to 1.0.", s_ipsc->cAlphaFieldNames(1), s_ipsc->cAlphaArgs(1)));
    5375            0 :                     surfTemp.Multiplier = 1.0;
    5376              :                 }
    5377              : 
    5378           36 :                 MakeRelativeRectangularVertices(state,
    5379              :                                                 surfTemp.BaseSurf,
    5380              :                                                 SurfNum,
    5381            9 :                                                 s_ipsc->rNumericArgs(2),
    5382            9 :                                                 s_ipsc->rNumericArgs(3),
    5383            9 :                                                 s_ipsc->rNumericArgs(4),
    5384            9 :                                                 s_ipsc->rNumericArgs(5));
    5385              : 
    5386            9 :                 if (surfTemp.Area <= 0.0) {
    5387            0 :                     ShowSevereError(
    5388              :                         state,
    5389            0 :                         format("{}=\"{}\", Surface Area <= 0.0; Entered Area={:.2T}", s_ipsc->cCurrentModuleObject, surfTemp.Name, surfTemp.Area));
    5390            0 :                     ErrorsFound = true;
    5391              :                 }
    5392              : 
    5393            9 :                 surfTemp.windowShadingControlList.clear();
    5394            9 :                 surfTemp.activeWindowShadingControl = 0;
    5395            9 :                 surfTemp.HasShadeControl = false;
    5396              : 
    5397            9 :                 surfTemp.shadedConstructionList.clear();
    5398            9 :                 surfTemp.activeShadedConstruction = 0;
    5399            9 :                 surfTemp.shadedStormWinConstructionList.clear();
    5400              : 
    5401            9 :                 InitialAssociateWindowShadingControlFenestration(state, ErrorsFound, SurfNum);
    5402              : 
    5403            9 :                 if (!GettingIZSurfaces && (surfTemp.Class == SurfaceClass::Window || surfTemp.Class == SurfaceClass::GlassDoor)) {
    5404              : 
    5405            8 :                     if (surfTemp.ExtBoundCond == DataSurfaces::OtherSideCoefNoCalcExt ||
    5406            8 :                         surfTemp.ExtBoundCond == DataSurfaces::OtherSideCoefCalcExt) {
    5407            0 :                         ShowSevereError(
    5408              :                             state,
    5409            0 :                             format("{}=\"{}\", Other side coefficients are not allowed with windows.", s_ipsc->cCurrentModuleObject, surfTemp.Name));
    5410            0 :                         ErrorsFound = true;
    5411              :                     }
    5412              : 
    5413            8 :                     if (surfTemp.ExtBoundCond == DataSurfaces::Ground) {
    5414            0 :                         ShowSevereError(state,
    5415            0 :                                         format("{}=\"{}\", Exterior boundary condition = Ground is not allowed with windows.",
    5416            0 :                                                s_ipsc->cCurrentModuleObject,
    5417            0 :                                                surfTemp.Name));
    5418            0 :                         ErrorsFound = true;
    5419              :                     }
    5420              : 
    5421            8 :                     CheckWindowShadingControlFrameDivider(state, "GetRectSubSurfaces", ErrorsFound, SurfNum, FrameField);
    5422              : 
    5423              :                 } // check on non-opaquedoor subsurfaces
    5424              : 
    5425            9 :                 CheckSubSurfaceMiscellaneous(
    5426            9 :                     state, "GetRectSubSurfaces", ErrorsFound, SurfNum, s_ipsc->cAlphaArgs(1), s_ipsc->cAlphaArgs(2), AddedSubSurfaces);
    5427              : 
    5428              :             } // Getting Items
    5429              :         }
    5430          226 :     }
    5431              : 
    5432          203 :     void CheckWindowShadingControlFrameDivider(EnergyPlusData &state,
    5433              :                                                std::string_view const cRoutineName, // routine name calling this one (for error messages)
    5434              :                                                bool &ErrorsFound,                   // true if errors have been found or are found here
    5435              :                                                int const SurfNum,                   // current surface number
    5436              :                                                int const FrameField                 // field number for frame/divider
    5437              :     )
    5438              :     {
    5439              : 
    5440              :         // SUBROUTINE INFORMATION:
    5441              :         //       AUTHOR         Linda Lawrie
    5442              :         //       DATE WRITTEN   December 2008
    5443              : 
    5444              :         // PURPOSE OF THIS SUBROUTINE:
    5445              :         // This routine performs checks on WindowShadingControl settings and Frame/Divider Settings.
    5446              : 
    5447              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    5448              :         int ConstrNumSh;    // Construction number with Shade
    5449              :         int ShDevNum;       // Shading Device number
    5450              :         int Lay;            // Layer number
    5451              :         int TotGlassLayers; // Number of glass layers in window construction
    5452              :         int TotLayers;      // Number of layers in unshaded construction
    5453              :         int TotShLayers;    // Number of layers in shaded construction
    5454              :         int MatGap;         // Gap material number
    5455              :         int MatGap1;        // Material number of gap to left (outer side) of between-glass shade/blind
    5456              :         int MatGap2;        // Material number of gap to right (inner side) of between-glass shade/blind
    5457              :         int MatSh;          // Between-glass shade/blind material number
    5458              :         Real64 MatGapCalc;  // Calculated MatGap diff for shaded vs non-shaded constructions
    5459              : 
    5460              :         // If WindowShadingControl has been specified for this window --
    5461              :         // Set shaded construction number if shaded construction was specified in WindowShadingControl.
    5462              :         // Otherwise, create shaded construction if WindowShadingControl for this window has
    5463              :         // interior or exterior shade/blind (but not between-glass shade/blind) specified.
    5464              : 
    5465          203 :         auto &s_ipsc = state.dataIPShortCut;
    5466          203 :         auto &s_mat = state.dataMaterial;
    5467              : 
    5468          203 :         auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    5469              : 
    5470          214 :         for (std::size_t shadeControlIndex = 0; shadeControlIndex < surfTemp.windowShadingControlList.size(); ++shadeControlIndex) {
    5471           11 :             int WSCPtr = surfTemp.windowShadingControlList[shadeControlIndex];
    5472           11 :             ConstrNumSh = 0;
    5473           11 :             if (!ErrorsFound && surfTemp.HasShadeControl) {
    5474           11 :                 ConstrNumSh = surfTemp.shadedConstructionList[shadeControlIndex];
    5475           11 :                 if (ConstrNumSh > 0) {
    5476           11 :                     surfTemp.activeShadedConstruction = ConstrNumSh;
    5477            0 :                 } else if (ANY_INTERIOR_SHADE_BLIND(state.dataSurface->WindowShadingControl(WSCPtr).ShadingType) ||
    5478            0 :                            ANY_EXTERIOR_SHADE_BLIND_SCREEN(state.dataSurface->WindowShadingControl(WSCPtr).ShadingType)) {
    5479            0 :                     ShDevNum = state.dataSurface->WindowShadingControl(WSCPtr).ShadingDevice;
    5480            0 :                     if (ShDevNum > 0) {
    5481            0 :                         CreateShadedWindowConstruction(state, SurfNum, WSCPtr, ShDevNum, shadeControlIndex);
    5482            0 :                         ConstrNumSh = surfTemp.activeShadedConstruction;
    5483              :                     }
    5484              :                 }
    5485              :             }
    5486              : 
    5487              :             // Error checks for shades and blinds
    5488              : 
    5489           11 :             int ConstrNum = surfTemp.Construction;
    5490           11 :             if (!ErrorsFound && WSCPtr > 0 && ConstrNum > 0 && ConstrNumSh > 0) {
    5491              : 
    5492           11 :                 if (ANY_INTERIOR_SHADE_BLIND(state.dataSurface->WindowShadingControl(WSCPtr).ShadingType)) {
    5493            9 :                     TotLayers = state.dataConstruction->Construct(ConstrNum).TotLayers;
    5494            9 :                     TotShLayers = state.dataConstruction->Construct(ConstrNumSh).TotLayers;
    5495            9 :                     if (TotShLayers - 1 != TotLayers) {
    5496            0 :                         ShowWarningError(
    5497              :                             state,
    5498              :                             "WindowShadingControl: Interior shade or blind: Potential problem in match of unshaded/shaded constructions, "
    5499              :                             "shaded should have 1 more layers than unshaded.");
    5500            0 :                         ShowContinueError(state, format("Unshaded construction={}", state.dataConstruction->Construct(ConstrNum).Name));
    5501            0 :                         ShowContinueError(state, format("Shaded construction={}", state.dataConstruction->Construct(ConstrNumSh).Name));
    5502            0 :                         ShowContinueError(state,
    5503              :                                           "If preceding two constructions are same name, you have likely specified a WindowShadingControl (Field #3) "
    5504              :                                           "with the Window Construction rather than a shaded construction.");
    5505              :                     }
    5506           18 :                     for (Lay = 1; Lay <= state.dataConstruction->Construct(ConstrNum).TotLayers; ++Lay) {
    5507            9 :                         if (state.dataConstruction->Construct(ConstrNum).LayerPoint(Lay) !=
    5508            9 :                             state.dataConstruction->Construct(ConstrNumSh).LayerPoint(Lay)) {
    5509            0 :                             ErrorsFound = true;
    5510            0 :                             ShowSevereError(state,
    5511            0 :                                             format(" The glass and gas layers in the shaded and unshaded constructions do not match for window={}",
    5512            0 :                                                    surfTemp.Name));
    5513            0 :                             ShowContinueError(state, format("Unshaded construction={}", state.dataConstruction->Construct(ConstrNum).Name));
    5514            0 :                             ShowContinueError(state, format("Shaded construction={}", state.dataConstruction->Construct(ConstrNumSh).Name));
    5515            0 :                             break;
    5516              :                         }
    5517              :                     }
    5518              :                 }
    5519              : 
    5520           11 :                 if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(state.dataSurface->WindowShadingControl(WSCPtr).ShadingType)) {
    5521            0 :                     TotLayers = state.dataConstruction->Construct(ConstrNum).TotLayers;
    5522            0 :                     TotShLayers = state.dataConstruction->Construct(ConstrNumSh).TotLayers;
    5523            0 :                     if (TotShLayers - 1 != TotLayers) {
    5524            0 :                         ShowWarningError(state,
    5525              :                                          "WindowShadingControl: Exterior shade, screen or blind: Potential problem in match of unshaded/shaded "
    5526              :                                          "constructions, shaded should have 1 more layer than unshaded.");
    5527            0 :                         ShowContinueError(state, format("Unshaded construction={}", state.dataConstruction->Construct(ConstrNum).Name));
    5528            0 :                         ShowContinueError(state, format("Shaded construction={}", state.dataConstruction->Construct(ConstrNumSh).Name));
    5529            0 :                         ShowContinueError(
    5530              :                             state,
    5531              :                             "If preceding two constructions have the same name, you have likely specified a WindowShadingControl (Field "
    5532              :                             "#3) with the Window Construction rather than a shaded construction.");
    5533              :                     }
    5534            0 :                     for (Lay = 1; Lay <= state.dataConstruction->Construct(ConstrNum).TotLayers; ++Lay) {
    5535            0 :                         if (state.dataConstruction->Construct(ConstrNum).LayerPoint(Lay) !=
    5536            0 :                             state.dataConstruction->Construct(ConstrNumSh).LayerPoint(Lay + 1)) {
    5537            0 :                             ErrorsFound = true;
    5538            0 :                             ShowSevereError(state,
    5539            0 :                                             format(" The glass and gas layers in the shaded and unshaded constructions do not match for window={}",
    5540            0 :                                                    surfTemp.Name));
    5541            0 :                             ShowContinueError(state, format("Unshaded construction={}", state.dataConstruction->Construct(ConstrNum).Name));
    5542            0 :                             ShowContinueError(state, format("Shaded construction={}", state.dataConstruction->Construct(ConstrNumSh).Name));
    5543            0 :                             break;
    5544              :                         }
    5545              :                     }
    5546              :                 }
    5547              : 
    5548           11 :                 if (ANY_BETWEENGLASS_SHADE_BLIND(state.dataSurface->WindowShadingControl(WSCPtr).ShadingType)) {
    5549              :                     // Divider not allowed with between-glass shade or blind
    5550            0 :                     if (surfTemp.FrameDivider > 0) {
    5551            0 :                         if (state.dataSurface->FrameDivider(surfTemp.FrameDivider).DividerWidth > 0.0) {
    5552            0 :                             ShowWarningError(state, format("A divider cannot be specified for window {}", surfTemp.Name));
    5553            0 :                             ShowContinueError(state, ", which has a between-glass shade or blind.");
    5554            0 :                             ShowContinueError(state, "Calculation will proceed without the divider for this window.");
    5555            0 :                             state.dataSurface->FrameDivider(surfTemp.FrameDivider).DividerWidth = 0.0;
    5556              :                         }
    5557              :                     }
    5558              :                     // Check consistency of gap widths between unshaded and shaded constructions
    5559            0 :                     TotGlassLayers = state.dataConstruction->Construct(ConstrNum).TotGlassLayers;
    5560            0 :                     TotLayers = state.dataConstruction->Construct(ConstrNum).TotLayers;
    5561            0 :                     TotShLayers = state.dataConstruction->Construct(ConstrNumSh).TotLayers;
    5562            0 :                     if (TotShLayers - 2 != TotLayers) {
    5563            0 :                         ShowWarningError(
    5564              :                             state,
    5565              :                             "WindowShadingControl: Between Glass Shade/Blind: Potential problem in match of unshaded/shaded constructions, "
    5566              :                             "shaded should have 2 more layers than unshaded.");
    5567            0 :                         ShowContinueError(state, format("Unshaded construction={}", state.dataConstruction->Construct(ConstrNum).Name));
    5568            0 :                         ShowContinueError(state, format("Shaded construction={}", state.dataConstruction->Construct(ConstrNumSh).Name));
    5569            0 :                         ShowContinueError(state,
    5570              :                                           "If preceding two constructions are same name, you have likely specified a WindowShadingControl (Field #3) "
    5571              :                                           "with the Window Construction rather than a shaded construction.");
    5572              :                     }
    5573            0 :                     if (state.dataConstruction->Construct(ConstrNum).LayerPoint(TotLayers) !=
    5574            0 :                         state.dataConstruction->Construct(ConstrNumSh).LayerPoint(TotShLayers)) {
    5575            0 :                         ShowSevereError(state, format("{}: Mis-match in unshaded/shaded inside layer materials.  These should match.", cRoutineName));
    5576            0 :                         ShowContinueError(state,
    5577            0 :                                           format("Unshaded construction={}, Material={}",
    5578            0 :                                                  state.dataConstruction->Construct(ConstrNum).Name,
    5579            0 :                                                  s_mat->materials(state.dataConstruction->Construct(ConstrNum).LayerPoint(TotLayers))->Name));
    5580            0 :                         ShowContinueError(state,
    5581            0 :                                           format("Shaded construction={}, Material={}",
    5582            0 :                                                  state.dataConstruction->Construct(ConstrNumSh).Name,
    5583            0 :                                                  s_mat->materials(state.dataConstruction->Construct(ConstrNumSh).LayerPoint(TotShLayers))->Name));
    5584            0 :                         ErrorsFound = true;
    5585              :                     }
    5586            0 :                     if (state.dataConstruction->Construct(ConstrNum).LayerPoint(1) != state.dataConstruction->Construct(ConstrNumSh).LayerPoint(1)) {
    5587            0 :                         ShowSevereError(state, format("{}: Mis-match in unshaded/shaded inside layer materials.  These should match.", cRoutineName));
    5588            0 :                         ShowContinueError(state,
    5589            0 :                                           format("Unshaded construction={}, Material={}",
    5590            0 :                                                  state.dataConstruction->Construct(ConstrNum).Name,
    5591            0 :                                                  s_mat->materials(state.dataConstruction->Construct(ConstrNum).LayerPoint(1))->Name));
    5592            0 :                         ShowContinueError(state,
    5593            0 :                                           format("Shaded construction={}, Material={}",
    5594            0 :                                                  state.dataConstruction->Construct(ConstrNumSh).Name,
    5595            0 :                                                  s_mat->materials(state.dataConstruction->Construct(ConstrNumSh).LayerPoint(1))->Name));
    5596            0 :                         ErrorsFound = true;
    5597              :                     }
    5598            0 :                     if (TotGlassLayers == 2 || TotGlassLayers == 3) {
    5599            0 :                         MatGap = state.dataConstruction->Construct(ConstrNum).LayerPoint(2 * TotGlassLayers - 2);
    5600            0 :                         MatGap1 = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(2 * TotGlassLayers - 2);
    5601            0 :                         MatGap2 = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(2 * TotGlassLayers);
    5602            0 :                         MatSh = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(2 * TotGlassLayers - 1);
    5603            0 :                         if (state.dataSurface->WindowShadingControl(WSCPtr).ShadingType == DataSurfaces::WinShadingType::BGBlind) {
    5604            0 :                             MatGapCalc = std::abs(s_mat->materials(MatGap)->Thickness -
    5605            0 :                                                   (s_mat->materials(MatGap1)->Thickness + s_mat->materials(MatGap2)->Thickness));
    5606            0 :                             if (MatGapCalc > 0.001) {
    5607            0 :                                 ShowSevereError(state,
    5608            0 :                                                 format("{}: The gap width(s) for the unshaded window construction {}",
    5609              :                                                        cRoutineName,
    5610            0 :                                                        state.dataConstruction->Construct(ConstrNum).Name));
    5611            0 :                                 ShowContinueError(state,
    5612            0 :                                                   "are inconsistent with the gap widths for shaded window construction " +
    5613            0 :                                                       state.dataConstruction->Construct(ConstrNumSh).Name);
    5614            0 :                                 ShowContinueError(state, "for window " + surfTemp.Name + ", which has a between-glass blind.");
    5615            0 :                                 ShowContinueError(
    5616              :                                     state,
    5617            0 :                                     format("..Material={} thickness={:.3R} -", s_mat->materials(MatGap)->Name, s_mat->materials(MatGap)->Thickness));
    5618            0 :                                 ShowContinueError(state,
    5619            0 :                                                   format("..( Material={} thickness={:.3R} +",
    5620            0 :                                                          s_mat->materials(MatGap1)->Name,
    5621            0 :                                                          s_mat->materials(MatGap1)->Thickness));
    5622            0 :                                 ShowContinueError(state,
    5623            0 :                                                   format("..Material={} thickness={:.3R} )=[{:.3R}] >.001",
    5624            0 :                                                          s_mat->materials(MatGap2)->Name,
    5625            0 :                                                          s_mat->materials(MatGap2)->Thickness,
    5626              :                                                          MatGapCalc));
    5627            0 :                                 ErrorsFound = true;
    5628              :                             }
    5629              :                         } else { // Between-glass shade
    5630            0 :                             MatGapCalc = std::abs(
    5631            0 :                                 s_mat->materials(MatGap)->Thickness -
    5632            0 :                                 (s_mat->materials(MatGap1)->Thickness + s_mat->materials(MatGap2)->Thickness + s_mat->materials(MatSh)->Thickness));
    5633            0 :                             if (MatGapCalc > 0.001) {
    5634            0 :                                 ShowSevereError(state,
    5635            0 :                                                 format("{}: The gap width(s) for the unshaded window construction {}",
    5636              :                                                        cRoutineName,
    5637            0 :                                                        state.dataConstruction->Construct(ConstrNum).Name));
    5638            0 :                                 ShowContinueError(state,
    5639            0 :                                                   "are inconsistent with the gap widths for shaded window construction " +
    5640            0 :                                                       state.dataConstruction->Construct(ConstrNumSh).Name);
    5641            0 :                                 ShowContinueError(state, "for window " + surfTemp.Name + ", which has a between-glass shade.");
    5642            0 :                                 ShowContinueError(
    5643              :                                     state,
    5644            0 :                                     format("..Material={} thickness={:.3R} -", s_mat->materials(MatGap)->Name, s_mat->materials(MatGap)->Thickness));
    5645            0 :                                 ShowContinueError(state,
    5646            0 :                                                   format("...( Material={} thickness={:.3R} +",
    5647            0 :                                                          s_mat->materials(MatGap1)->Name,
    5648            0 :                                                          s_mat->materials(MatGap1)->Thickness));
    5649            0 :                                 ShowContinueError(state,
    5650            0 :                                                   format("..Material={} thickness={:.3R} +",
    5651            0 :                                                          s_mat->materials(MatGap2)->Name,
    5652            0 :                                                          s_mat->materials(MatGap2)->Thickness));
    5653            0 :                                 ShowContinueError(state,
    5654            0 :                                                   format("..Material={} thickness={:.3R} )=[{:.3R}] >.001",
    5655            0 :                                                          s_mat->materials(MatSh)->Name,
    5656            0 :                                                          s_mat->materials(MatSh)->Thickness,
    5657              :                                                          MatGapCalc));
    5658            0 :                                 ErrorsFound = true;
    5659              :                             }
    5660              :                         }
    5661              :                     }
    5662              :                 }
    5663              :             }
    5664              :         }
    5665              : 
    5666          203 :         if (surfTemp.Sides != 3) { // Rectangular Window
    5667              :             // Initialize the FrameDivider number for this window. W5FrameDivider will be positive if
    5668              :             // this window's construction came from the Window5 data file and that construction had an
    5669              :             // associated frame or divider. It will be zero if the window's construction is not from the
    5670              :             // Window5 data file, or the construction is from the data file, but the construction has no
    5671              :             // associated frame or divider. Note that if there is a FrameDivider candidate for this
    5672              :             // window from the Window5 data file it is used instead of the window's input FrameDivider.
    5673              : 
    5674          202 :             if (surfTemp.Construction != 0) {
    5675          202 :                 surfTemp.FrameDivider = state.dataConstruction->Construct(surfTemp.Construction).W5FrameDivider;
    5676              : 
    5677              :                 // Warning if FrameAndDivider for this window is over-ridden by one from Window5 Data File
    5678          202 :                 if (surfTemp.FrameDivider > 0 && !s_ipsc->lAlphaFieldBlanks(FrameField)) {
    5679            0 :                     ShowSevereError(state,
    5680            0 :                                     format("{}=\"{}\", {}=\"{}\"",
    5681            0 :                                            s_ipsc->cCurrentModuleObject,
    5682            0 :                                            surfTemp.Name,
    5683            0 :                                            s_ipsc->cAlphaFieldNames(FrameField),
    5684            0 :                                            s_ipsc->cAlphaArgs(FrameField)));
    5685            0 :                     ShowContinueError(state,
    5686            0 :                                       format("will be replaced with FrameAndDivider from Window5 Data File entry {}",
    5687            0 :                                              state.dataConstruction->Construct(surfTemp.Construction).Name));
    5688              :                 }
    5689              : 
    5690          202 :                 if (!s_ipsc->lAlphaFieldBlanks(FrameField) && surfTemp.FrameDivider == 0) {
    5691           24 :                     surfTemp.FrameDivider = Util::FindItemInList(s_ipsc->cAlphaArgs(FrameField), state.dataSurface->FrameDivider);
    5692           24 :                     if (surfTemp.FrameDivider == 0) {
    5693            0 :                         if (!state.dataConstruction->Construct(surfTemp.Construction).WindowTypeEQL) {
    5694            0 :                             ShowSevereError(state,
    5695            0 :                                             format("{}=\"{}\", invalid {}=\"{}\"",
    5696            0 :                                                    s_ipsc->cCurrentModuleObject,
    5697            0 :                                                    surfTemp.Name,
    5698            0 :                                                    s_ipsc->cAlphaFieldNames(FrameField),
    5699            0 :                                                    s_ipsc->cAlphaArgs(FrameField)));
    5700            0 :                             ErrorsFound = true;
    5701              :                         } else {
    5702            0 :                             ShowSevereError(state,
    5703            0 :                                             format("{}=\"{}\", invalid {}=\"{}\"",
    5704            0 :                                                    s_ipsc->cCurrentModuleObject,
    5705            0 :                                                    surfTemp.Name,
    5706            0 :                                                    s_ipsc->cAlphaFieldNames(FrameField),
    5707            0 :                                                    s_ipsc->cAlphaArgs(FrameField)));
    5708            0 :                             ShowContinueError(state, "...Frame/Divider is not supported in Equivalent Layer Window model.");
    5709              :                         }
    5710              :                     }
    5711              :                     // Divider not allowed with between-glass shade or blind
    5712           26 :                     for (int WSCPtr : surfTemp.windowShadingControlList) {
    5713            2 :                         if (!ErrorsFound && WSCPtr > 0 && ConstrNumSh > 0) {
    5714            2 :                             if (ANY_BETWEENGLASS_SHADE_BLIND(state.dataSurface->WindowShadingControl(WSCPtr).ShadingType)) {
    5715            0 :                                 if (surfTemp.FrameDivider > 0) {
    5716            0 :                                     if (state.dataSurface->FrameDivider(surfTemp.FrameDivider).DividerWidth > 0.0) {
    5717            0 :                                         ShowSevereError(state,
    5718            0 :                                                         format("{}=\"{}\", invalid {}=\"{}\"",
    5719            0 :                                                                s_ipsc->cCurrentModuleObject,
    5720            0 :                                                                surfTemp.Name,
    5721            0 :                                                                s_ipsc->cAlphaFieldNames(FrameField),
    5722            0 :                                                                s_ipsc->cAlphaArgs(FrameField)));
    5723            0 :                                         ShowContinueError(state,
    5724              :                                                           "Divider cannot be specified because the construction has a between-glass shade or blind.");
    5725            0 :                                         ShowContinueError(state, "Calculation will proceed without the divider for this window.");
    5726            0 :                                         ShowContinueError(
    5727              :                                             state,
    5728            0 :                                             format("Divider width = [{:.2R}].", state.dataSurface->FrameDivider(surfTemp.FrameDivider).DividerWidth));
    5729            0 :                                         state.dataSurface->FrameDivider(surfTemp.FrameDivider).DividerWidth = 0.0;
    5730              :                                     }
    5731              :                                 } // End of check if window has divider
    5732              :                             }     // End of check if window has a between-glass shade or blind
    5733              :                         }         // End of check if window has a shaded construction
    5734              :                     }             // end of looping through window shading controls of window
    5735              :                 }                 // End of check if window has an associated FrameAndDivider
    5736              :             }                     // End of check if window has a construction
    5737              :         }
    5738              : 
    5739          203 :         if (state.dataConstruction->Construct(surfTemp.Construction).WindowTypeEQL) {
    5740            7 :             if (surfTemp.FrameDivider > 0) {
    5741              :                 // Equivalent Layer window does not have frame/divider model
    5742            4 :                 ShowSevereError(state,
    5743            8 :                                 format("{}=\"{}\", invalid {}=\"{}\"",
    5744            2 :                                        s_ipsc->cCurrentModuleObject,
    5745            2 :                                        surfTemp.Name,
    5746            2 :                                        s_ipsc->cAlphaFieldNames(FrameField),
    5747            2 :                                        s_ipsc->cAlphaArgs(FrameField)));
    5748            4 :                 ShowContinueError(state, "Frame/Divider is not supported in Equivalent Layer Window model.");
    5749            2 :                 surfTemp.FrameDivider = 0;
    5750              :             }
    5751              :         }
    5752          203 :     }
    5753              : 
    5754          223 :     void CheckSubSurfaceMiscellaneous(EnergyPlusData &state,
    5755              :                                       std::string_view const cRoutineName,       // routine name calling this one (for error messages)
    5756              :                                       bool &ErrorsFound,                         // true if errors have been found or are found here
    5757              :                                       int const SurfNum,                         // current surface number
    5758              :                                       std::string const &SubSurfaceName,         // name of the surface
    5759              :                                       std::string const &SubSurfaceConstruction, // name of the construction
    5760              :                                       int &AddedSubSurfaces)
    5761              :     {
    5762              : 
    5763              :         // SUBROUTINE INFORMATION:
    5764              :         //       AUTHOR         Linda Lawrie
    5765              :         //       DATE WRITTEN   December 2008
    5766              : 
    5767              :         // PURPOSE OF THIS SUBROUTINE:
    5768              :         // This routine performs miscellaneous checks on subsurfaces: Windows, GlassDoors, Doors, Tubular Devices.
    5769              : 
    5770          223 :         auto &s_mat = state.dataMaterial;
    5771              :         // Warning if window has multiplier > 1 and SolarDistribution = FullExterior or FullInteriorExterior
    5772              : 
    5773          223 :         auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    5774           43 :         if ((surfTemp.Class == SurfaceClass::Window || surfTemp.Class == SurfaceClass::GlassDoor) &&
    5775          449 :             static_cast<int>(state.dataHeatBal->SolarDistribution) > static_cast<int>(DataHeatBalance::Shadowing::Minimal) &&
    5776          183 :             surfTemp.Multiplier > 1.0) {
    5777            0 :             if (state.dataGlobal->DisplayExtraWarnings) {
    5778            0 :                 ShowWarningError(state, format("{}: A Multiplier > 1.0 for window/glass door {}", cRoutineName, surfTemp.Name));
    5779            0 :                 ShowContinueError(state, "in conjunction with SolarDistribution = FullExterior or FullInteriorExterior");
    5780            0 :                 ShowContinueError(state, "can cause inaccurate shadowing on the window and/or");
    5781            0 :                 ShowContinueError(state, "inaccurate interior solar distribution from the window.");
    5782              :             }
    5783            0 :             ++state.dataErrTracking->TotalMultipliedWindows;
    5784              :         }
    5785              : 
    5786              :         //  Require that a construction referenced by a surface that is a window
    5787              :         //  NOT have a shading device layer; use WindowShadingControl to specify a shading device.
    5788              : 
    5789          223 :         int ConstrNum = surfTemp.Construction;
    5790          223 :         if (ConstrNum > 0) {
    5791          223 :             int NumShades = 0;
    5792          595 :             for (int Lay = 1; Lay <= state.dataConstruction->Construct(ConstrNum).TotLayers; ++Lay) {
    5793          372 :                 int LayerPtr = state.dataConstruction->Construct(ConstrNum).LayerPoint(Lay);
    5794          372 :                 if (LayerPtr == 0) continue; // Error is caught already, will terminate later
    5795          744 :                 if (s_mat->materials(LayerPtr)->group == Material::Group::Shade || s_mat->materials(LayerPtr)->group == Material::Group::Blind ||
    5796          372 :                     s_mat->materials(LayerPtr)->group == Material::Group::Screen)
    5797            0 :                     ++NumShades;
    5798              :             }
    5799          223 :             if (NumShades != 0) {
    5800            0 :                 ShowSevereError(state, format("{}: Window \"{}\" must not directly reference", cRoutineName, SubSurfaceName));
    5801            0 :                 ShowContinueError(state, format("a Construction (i.e, \"{}\") with a shading device.", SubSurfaceConstruction));
    5802            0 :                 ShowContinueError(state, "Use WindowShadingControl to specify a shading device for a window.");
    5803            0 :                 ErrorsFound = true;
    5804              :             }
    5805              :         }
    5806              : 
    5807              :         // Disallow glass transmittance dirt factor for interior windows and glass doors
    5808              : 
    5809          223 :         if (surfTemp.ExtBoundCond != DataSurfaces::ExternalEnvironment &&
    5810           20 :             (surfTemp.Class == SurfaceClass::Window || surfTemp.Class == SurfaceClass::GlassDoor)) {
    5811            5 :             ConstrNum = surfTemp.Construction;
    5812            5 :             if (ConstrNum > 0) {
    5813            8 :                 for (int Lay = 1; Lay <= state.dataConstruction->Construct(ConstrNum).TotLayers; ++Lay) {
    5814            3 :                     int LayerPtr = state.dataConstruction->Construct(ConstrNum).LayerPoint(Lay);
    5815            3 :                     auto const *mat = s_mat->materials(LayerPtr);
    5816            3 :                     if (mat->group != Material::Group::Glass) continue;
    5817              : 
    5818            3 :                     if (dynamic_cast<Material::MaterialGlass const *>(mat)->GlassTransDirtFactor < 1.0) {
    5819            0 :                         ShowSevereError(state, format("{}: Interior Window or GlassDoor {} has a glass layer with", cRoutineName, SubSurfaceName));
    5820            0 :                         ShowContinueError(state, "Dirt Correction Factor for Solar and Visible Transmittance < 1.0");
    5821            0 :                         ShowContinueError(state, "A value less than 1.0 for this factor is only allowed for exterior windows and glass doors.");
    5822            0 :                         ErrorsFound = true;
    5823              :                     }
    5824              :                 }
    5825              :             }
    5826              :         }
    5827              : 
    5828              :         // If this is a window with a construction from the Window5DataFile, call routine that will
    5829              :         // (1) if one glazing system on Data File, give warning message if window height or width
    5830              :         //     differ by more than 10% from those of the glazing system on the Data File;
    5831              :         // (2) if two glazing systems (separated by a mullion) on Data File, create a second window
    5832              :         //     and adjust the dimensions of the original and second windows to those on the Data File
    5833              : 
    5834          223 :         if (surfTemp.Construction != 0) {
    5835              : 
    5836          223 :             if (state.dataConstruction->Construct(surfTemp.Construction).FromWindow5DataFile) {
    5837              : 
    5838            0 :                 ModifyWindow(state, SurfNum, ErrorsFound, AddedSubSurfaces);
    5839              : 
    5840              :             } else {
    5841              :                 // Calculate net area for base surface (note that ModifyWindow, above, adjusts net area of
    5842              :                 // base surface for case where window construction is from Window5 Data File
    5843              :                 // In case there is in error in this window's base surface (i.e. none)..
    5844          223 :                 if (surfTemp.BaseSurf > 0) {
    5845          223 :                     state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).Area -= surfTemp.Area;
    5846              : 
    5847              :                     // Subtract TDD:DIFFUSER area from other side interzone surface
    5848          229 :                     if ((surfTemp.Class == SurfaceClass::TDD_Diffuser) &&
    5849            6 :                         not_blank(
    5850            6 :                             state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).ExtBoundCondName)) { // Base surface is an interzone surface
    5851              :                         // Lookup interzone surface of the base surface
    5852              :                         // (Interzone surfaces have not been assigned yet, but all base surfaces should already be loaded.)
    5853            6 :                         int Found = Util::FindItemInList(state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).ExtBoundCondName,
    5854            6 :                                                          state.dataSurfaceGeometry->SurfaceTmp,
    5855              :                                                          SurfNum);
    5856            6 :                         if (Found != 0) state.dataSurfaceGeometry->SurfaceTmp(Found).Area -= surfTemp.Area;
    5857              :                     }
    5858          223 :                     if (state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).Area <= 0.0) {
    5859            0 :                         ShowSevereError(state,
    5860            0 :                                         format("{}: Surface Openings have too much area for base surface={}",
    5861              :                                                cRoutineName,
    5862            0 :                                                state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).Name));
    5863            0 :                         ShowContinueError(state, format("Opening Surface creating error={}", surfTemp.Name));
    5864            0 :                         ErrorsFound = true;
    5865              :                     }
    5866              :                     // Net area of base surface with unity window multipliers (used in shadowing checks)
    5867              :                     // For Windows, Glass Doors and Doors, just one area is subtracted.  For the rest, should be
    5868              :                     // full area.
    5869          223 :                     if (surfTemp.Class == SurfaceClass::Window || surfTemp.Class == SurfaceClass::GlassDoor) {
    5870          190 :                         state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).NetAreaShadowCalc -= surfTemp.Area / surfTemp.Multiplier;
    5871           33 :                     } else if (surfTemp.Class == SurfaceClass::Door) { // Door, TDD:Diffuser, TDD:DOME
    5872           20 :                         state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).NetAreaShadowCalc -= surfTemp.Area / surfTemp.Multiplier;
    5873              :                     } else {
    5874           13 :                         state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).NetAreaShadowCalc -= surfTemp.Area;
    5875              :                     }
    5876              :                 }
    5877              :             }
    5878              :         }
    5879          223 :     }
    5880              : 
    5881           14 :     void MakeRelativeRectangularVertices(EnergyPlusData &state,
    5882              :                                          int const BaseSurfNum, // Base surface
    5883              :                                          int const SurfNum,
    5884              :                                          Real64 const XCoord,
    5885              :                                          Real64 const ZCoord,
    5886              :                                          Real64 const Length,
    5887              :                                          Real64 const Height)
    5888              :     {
    5889              : 
    5890              :         // SUBROUTINE INFORMATION:
    5891              :         //       AUTHOR         Linda Lawrie
    5892              :         //       DATE WRITTEN   December 2008
    5893              : 
    5894              :         // PURPOSE OF THIS SUBROUTINE:
    5895              :         // This routine creates world/3d coordinates for rectangular surfaces using relative X and Z, length & height.
    5896              : 
    5897              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    5898           14 :         Array1D<Real64> XX(4);
    5899           14 :         Array1D<Real64> YY(4);
    5900              :         Real64 Perimeter;
    5901              :         int Vrt;
    5902              : 
    5903           14 :         if (BaseSurfNum == 0) return; // invalid base surface, don't bother
    5904              : 
    5905              :         // Tilt and Facing (Azimuth) will be same as the Base Surface
    5906              : 
    5907           14 :         auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    5908           14 :         surfTemp.Height = Height;
    5909           14 :         surfTemp.Width = Length;
    5910              : 
    5911           14 :         Real64 SurfAzimuth = surfTemp.Azimuth;
    5912           14 :         Real64 SurfTilt = surfTemp.Tilt;
    5913           14 :         Real64 CosSurfAzimuth = std::cos(SurfAzimuth * Constant::DegToRad);
    5914           14 :         Real64 SinSurfAzimuth = std::sin(SurfAzimuth * Constant::DegToRad);
    5915           14 :         Real64 CosSurfTilt = std::cos(SurfTilt * Constant::DegToRad);
    5916           14 :         Real64 SinSurfTilt = std::sin(SurfTilt * Constant::DegToRad);
    5917           14 :         Real64 BaseCosSurfAzimuth = state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosAzim;
    5918           14 :         Real64 BaseSinSurfAzimuth = state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).SinAzim;
    5919           14 :         Real64 BaseCosSurfTilt = state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosTilt;
    5920           14 :         Real64 BaseSinSurfTilt = state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).SinTilt;
    5921              : 
    5922           14 :         Real64 XLLC = state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).x - XCoord * BaseCosSurfAzimuth -
    5923           14 :                       ZCoord * BaseCosSurfTilt * BaseSinSurfAzimuth;
    5924           14 :         Real64 YLLC = state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).y + XCoord * BaseSinSurfAzimuth -
    5925           14 :                       ZCoord * BaseCosSurfTilt * BaseCosSurfAzimuth;
    5926           14 :         Real64 ZLLC = state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).z + ZCoord * BaseSinSurfTilt;
    5927              : 
    5928           14 :         XX(1) = 0.0;
    5929           14 :         XX(2) = 0.0;
    5930           14 :         XX(3) = Length;
    5931           14 :         XX(4) = Length;
    5932           14 :         YY(1) = Height;
    5933           14 :         YY(4) = Height;
    5934           14 :         YY(3) = 0.0;
    5935           14 :         YY(2) = 0.0;
    5936              : 
    5937           70 :         for (int n = 1; n <= surfTemp.Sides; ++n) {
    5938           56 :             Vrt = n;
    5939           56 :             surfTemp.Vertex(Vrt).x = XLLC - XX(n) * CosSurfAzimuth - YY(n) * CosSurfTilt * SinSurfAzimuth;
    5940           56 :             surfTemp.Vertex(Vrt).y = YLLC + XX(n) * SinSurfAzimuth - YY(n) * CosSurfTilt * CosSurfAzimuth;
    5941           56 :             surfTemp.Vertex(Vrt).z = ZLLC + YY(n) * SinSurfTilt;
    5942              :         }
    5943              : 
    5944           14 :         Vectors::CreateNewellAreaVector(surfTemp.Vertex, surfTemp.Sides, surfTemp.NewellAreaVector);
    5945           14 :         surfTemp.GrossArea = Vectors::VecLength(surfTemp.NewellAreaVector);
    5946           14 :         surfTemp.Area = surfTemp.GrossArea;
    5947           14 :         surfTemp.NetAreaShadowCalc = surfTemp.Area;
    5948           14 :         Vectors::CreateNewellSurfaceNormalVector(surfTemp.Vertex, surfTemp.Sides, surfTemp.NewellSurfaceNormalVector);
    5949           14 :         Vectors::DetermineAzimuthAndTilt(
    5950           14 :             surfTemp.Vertex, SurfAzimuth, SurfTilt, surfTemp.lcsx, surfTemp.lcsy, surfTemp.lcsz, surfTemp.NewellSurfaceNormalVector);
    5951           14 :         surfTemp.Azimuth = SurfAzimuth;
    5952           14 :         surfTemp.Tilt = SurfTilt;
    5953           14 :         surfTemp.convOrientation = Convect::GetSurfConvOrientation(surfTemp.Tilt);
    5954              :         // Sine and cosine of azimuth and tilt
    5955           14 :         surfTemp.SinAzim = SinSurfAzimuth;
    5956           14 :         surfTemp.CosAzim = CosSurfAzimuth;
    5957           14 :         surfTemp.SinTilt = SinSurfTilt;
    5958           14 :         surfTemp.CosTilt = CosSurfTilt;
    5959           14 :         if (surfTemp.Class != SurfaceClass::Window && surfTemp.Class != SurfaceClass::GlassDoor && surfTemp.Class != SurfaceClass::Door)
    5960            5 :             surfTemp.ViewFactorGround = 0.5 * (1.0 - surfTemp.CosTilt);
    5961              :         // Outward normal unit vector (pointing away from room)
    5962           14 :         surfTemp.OutNormVec = surfTemp.NewellSurfaceNormalVector;
    5963           56 :         for (int n = 1; n <= 3; ++n) {
    5964           42 :             if (std::abs(surfTemp.OutNormVec(n) - 1.0) < 1.e-06) surfTemp.OutNormVec(n) = +1.0;
    5965           42 :             if (std::abs(surfTemp.OutNormVec(n) + 1.0) < 1.e-06) surfTemp.OutNormVec(n) = -1.0;
    5966           42 :             if (std::abs(surfTemp.OutNormVec(n)) < 1.e-06) surfTemp.OutNormVec(n) = 0.0;
    5967              :         }
    5968              : 
    5969              :         //  IF (SurfaceTmp(SurfNum)%Class == SurfaceClass::Roof .and. SurfTilt > 80.) THEN
    5970              :         //    WRITE(TiltString,'(F5.1)') SurfTilt
    5971              :         //    TiltString=ADJUSTL(TiltString)
    5972              :         //    CALL ShowWarningError(state, format("Roof/Ceiling Tilt={}{}{}{}{}{}{}{}{}{} for Surface={}{}{}, in
    5973              :         //    Zone={}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}", //TRIM(TiltString)//',,
    5974              :         //    much, greater, than, expected, tilt, of, 0,'//, &, //, //TRIM(SurfaceTmp(SurfNum)%Name)//, &, //, //TRIM(SurfaceTmp(SurfNum)%ZoneName)),
    5975              :         //    //, ENDIF, //, IF, (SurfaceTmp(SurfNum)%Class, ==, SurfaceClass::Floor, .and., SurfTilt, <, 170.), THEN, //, WRITE(TiltString,'(F5.1)'),
    5976              :         //    SurfTilt, //, TiltString=ADJUSTL(TiltString), //, CALL, ShowWarningError(state, 'Floor Tilt='//TRIM(TiltString)//', much less than
    5977              :         //    expected tilt of 180,'//   &
    5978              :         //                          ' for Surface='//TRIM(SurfaceTmp(SurfNum)%Name)//  &
    5979              :         //                          ', in Zone='//TRIM(SurfaceTmp(SurfNum)%ZoneName)), //, ENDIF, if,
    5980              :         //                          (surfTemp.Class, ==, SurfaceClass::Window, ||,
    5981              :         //                          surfTemp.Class, ==, SurfaceClass::GlassDoor, ||,
    5982              :         //                          surfTemp.Class, ==, SurfaceClass::Door),
    5983              :         //                          surfTemp.Area, *=,
    5984              :         //                          surfTemp.Multiplier;, //, Can, perform, tests, on, this, surface, here,
    5985              :         //                          surfTemp.ViewFactorSky, =, 0.5, *, (1.0,
    5986              :         //                          surfTemp.CosTilt));
    5987              :         // The following IR view factors are modified in subr. SkyDifSolarShading if there are shadowing
    5988              :         // surfaces
    5989           14 :         surfTemp.ViewFactorSkyIR = surfTemp.ViewFactorSky;
    5990           14 :         surfTemp.ViewFactorGroundIR = 0.5 * (1.0 - surfTemp.CosTilt);
    5991              : 
    5992           14 :         Perimeter = distance(surfTemp.Vertex(surfTemp.Sides), surfTemp.Vertex(1));
    5993           56 :         for (Vrt = 2; Vrt <= surfTemp.Sides; ++Vrt) {
    5994           42 :             Perimeter += distance(surfTemp.Vertex(Vrt), surfTemp.Vertex(Vrt - 1));
    5995              :         }
    5996           14 :         surfTemp.Perimeter = Perimeter;
    5997              : 
    5998              :         // Call to transform vertices
    5999              : 
    6000           14 :         TransformVertsByAspect(state, SurfNum, surfTemp.Sides);
    6001           14 :     }
    6002              : 
    6003          226 :     void GetAttShdSurfaceData(EnergyPlusData &state,
    6004              :                               bool &ErrorsFound,   // Error flag indicator (true if errors found)
    6005              :                               int &SurfNum,        // Count of Current SurfaceNumber
    6006              :                               int const TotShdSubs // Number of Attached Shading SubSurfaces to obtain
    6007              :     )
    6008              :     {
    6009              :         // SUBROUTINE INFORMATION:
    6010              :         //       AUTHOR         Linda Lawrie
    6011              :         //       DATE WRITTEN   May 2000
    6012              : 
    6013              :         // PURPOSE OF THIS SUBROUTINE:
    6014              :         // This subroutine gets the HeatTransfer Surface Data,
    6015              :         // checks it for errors, etc.
    6016              : 
    6017              :         static constexpr std::string_view routineName = "GetAttShdSurfaceData";
    6018              : 
    6019              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    6020              :         int IOStat;     // IO Status when calling get input subroutine
    6021              :         int NumAlphas;  // Number of alpha names being passed
    6022              :         int NumNumbers; // Number of properties being passed
    6023              :         int Found;      // For matching interzone surfaces
    6024              :         int Loop;
    6025              :         Real64 SchedMinValue;
    6026              :         Real64 SchedMaxValue;
    6027              : 
    6028          226 :         auto &s_ipsc = state.dataIPShortCut;
    6029              : 
    6030          226 :         if (TotShdSubs > 0 && state.dataHeatBal->SolarDistribution == DataHeatBalance::Shadowing::Minimal) {
    6031            0 :             ShowWarningError(state, "Shading effects of Fins and Overhangs are ignored when Solar Distribution = MinimalShadowing");
    6032              :         }
    6033          226 :         s_ipsc->cCurrentModuleObject = "Shading:Zone:Detailed";
    6034          226 :         state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, s_ipsc->cCurrentModuleObject, Loop, NumAlphas, NumNumbers);
    6035          226 :         if (NumAlphas != 3) {
    6036            0 :             ShowSevereError(
    6037            0 :                 state, format("{}: Object Definition indicates not = 3 Alpha Objects, Number Indicated={}", s_ipsc->cCurrentModuleObject, NumAlphas));
    6038            0 :             ErrorsFound = true;
    6039              :         }
    6040              : 
    6041          250 :         for (Loop = 1; Loop <= TotShdSubs; ++Loop) {
    6042           48 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    6043           24 :                                                                      s_ipsc->cCurrentModuleObject,
    6044              :                                                                      Loop,
    6045           24 :                                                                      s_ipsc->cAlphaArgs,
    6046              :                                                                      NumAlphas,
    6047           24 :                                                                      s_ipsc->rNumericArgs,
    6048              :                                                                      NumNumbers,
    6049              :                                                                      IOStat,
    6050           24 :                                                                      s_ipsc->lNumericFieldBlanks,
    6051           24 :                                                                      s_ipsc->lAlphaFieldBlanks,
    6052           24 :                                                                      s_ipsc->cAlphaFieldNames,
    6053           24 :                                                                      s_ipsc->cNumericFieldNames);
    6054              : 
    6055           24 :             ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
    6056              : 
    6057           48 :             if (GlobalNames::VerifyUniqueInterObjectName(state,
    6058           24 :                                                          state.dataSurfaceGeometry->UniqueSurfaceNames,
    6059           24 :                                                          s_ipsc->cAlphaArgs(1),
    6060           24 :                                                          s_ipsc->cCurrentModuleObject,
    6061           24 :                                                          s_ipsc->cAlphaFieldNames(1),
    6062              :                                                          ErrorsFound)) {
    6063            0 :                 continue;
    6064              :             }
    6065              : 
    6066           24 :             ++SurfNum;
    6067           24 :             auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    6068              : 
    6069           24 :             surfTemp.Name = s_ipsc->cAlphaArgs(1); // Set the Surface Name in the Derived Type
    6070           24 :             surfTemp.Class = SurfaceClass::Shading;
    6071           24 :             surfTemp.HeatTransSurf = false;
    6072           24 :             surfTemp.BaseSurfName = s_ipsc->cAlphaArgs(2);
    6073              :             //  The subsurface inherits properties from the base surface
    6074              :             //  Exterior conditions, Zone, etc.
    6075              :             //  We can figure out the base surface though, because they've all been entered
    6076           24 :             Found = Util::FindItemInList(surfTemp.BaseSurfName, state.dataSurfaceGeometry->SurfaceTmp, state.dataSurface->TotSurfaces);
    6077           24 :             if (Found > 0) {
    6078              :                 // SurfaceTmp(SurfNum)%BaseSurf=Found
    6079           24 :                 surfTemp.ExtBoundCond = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCond;
    6080           24 :                 surfTemp.ExtSolar = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtSolar;
    6081           24 :                 surfTemp.ExtWind = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtWind;
    6082           24 :                 surfTemp.Zone = state.dataSurfaceGeometry->SurfaceTmp(Found).Zone; // Necessary to do relative coordinates in GetVertices below
    6083           24 :                 surfTemp.ZoneName = state.dataSurfaceGeometry->SurfaceTmp(Found).ZoneName; // Necessary to have surface drawn in OutputReports
    6084              :             } else {
    6085            0 :                 ShowSevereError(state,
    6086            0 :                                 format("{}=\"{}\", invalid {}=\"{}",
    6087            0 :                                        s_ipsc->cCurrentModuleObject,
    6088            0 :                                        surfTemp.Name,
    6089            0 :                                        s_ipsc->cAlphaFieldNames(2),
    6090            0 :                                        s_ipsc->cAlphaArgs(2)));
    6091            0 :                 ErrorsFound = true;
    6092              :             }
    6093           24 :             if (surfTemp.ExtBoundCond == unenteredAdjacentZoneSurface) {
    6094            0 :                 ShowSevereError(state,
    6095            0 :                                 format("{}=\"{}\", invalid {}=\"{}",
    6096            0 :                                        s_ipsc->cCurrentModuleObject,
    6097            0 :                                        surfTemp.Name,
    6098            0 :                                        s_ipsc->cAlphaFieldNames(2),
    6099            0 :                                        s_ipsc->cAlphaArgs(2)));
    6100            0 :                 ShowContinueError(state, "...trying to attach a shading device to an interzone surface.");
    6101            0 :                 ErrorsFound = true;
    6102              : 
    6103            0 :                 surfTemp.ExtBoundCond = DataSurfaces::ExternalEnvironment; // reset so program won't crash during "add surfaces"
    6104              :             }
    6105           24 :             if (surfTemp.ExtBoundCond == unreconciledZoneSurface) {
    6106            0 :                 ShowSevereError(state,
    6107            0 :                                 format("{}=\"{}\", invalid {}=\"{}",
    6108            0 :                                        s_ipsc->cCurrentModuleObject,
    6109            0 :                                        surfTemp.Name,
    6110            0 :                                        s_ipsc->cAlphaFieldNames(2),
    6111            0 :                                        s_ipsc->cAlphaArgs(2)));
    6112            0 :                 ShowContinueError(state, "...trying to attach a shading device to an interior surface.");
    6113            0 :                 ErrorsFound = true;
    6114              : 
    6115            0 :                 surfTemp.ExtBoundCond = DataSurfaces::ExternalEnvironment; // reset so program won't crash during "add surfaces"
    6116              :             }
    6117              : 
    6118           24 :             if (s_ipsc->lAlphaFieldBlanks(3)) {
    6119              :                 // Defaults to constant-0.0, but leave this as nullptr for now
    6120           23 :             } else if ((surfTemp.shadowSurfSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(3))) == nullptr) {
    6121            0 :                 ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3));
    6122            0 :                 ErrorsFound = true;
    6123           23 :             } else if (!surfTemp.shadowSurfSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 1.0)) {
    6124            1 :                 Sched::ShowSevereBadMinMax(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3), Clusive::In, 0.0, Clusive::In, 1.0);
    6125            1 :                 ErrorsFound = true;
    6126              :             } else {
    6127              : 
    6128           22 :                 SchedMinValue = surfTemp.shadowSurfSched->getMinVal(state);
    6129           22 :                 surfTemp.SchedMinValue = SchedMinValue;
    6130           22 :                 SchedMaxValue = surfTemp.shadowSurfSched->getMaxVal(state);
    6131           22 :                 if (SchedMinValue == 1.0) {
    6132              :                     // Set transparent for now, check for EMS actuators later in SolarShading::resetShadingSurfaceTransparency
    6133            1 :                     surfTemp.IsTransparent = true;
    6134              :                 }
    6135           22 :                 if (SchedMaxValue > 0.0) {
    6136           13 :                     state.dataSolarShading->anyScheduledShadingSurface = true;
    6137              :                 }
    6138           22 :                 if (SchedMaxValue - SchedMinValue > Constant::OneMillionth) {
    6139           11 :                     state.dataSurface->ShadingTransmittanceVaries = true;
    6140              :                 }
    6141              :             }
    6142              : 
    6143           24 :             if (s_ipsc->lNumericFieldBlanks(1) || s_ipsc->rNumericArgs(1) == Constant::AutoCalculate) {
    6144            0 :                 s_ipsc->rNumericArgs(1) = (NumNumbers - 1) / 3;
    6145            0 :                 surfTemp.Sides = s_ipsc->rNumericArgs(1);
    6146            0 :                 if (mod(NumNumbers - 1, 3) != 0) {
    6147            0 :                     ShowWarningError(state,
    6148            0 :                                      format("{}=\"{}\", {}",
    6149            0 :                                             s_ipsc->cCurrentModuleObject,
    6150            0 :                                             surfTemp.Name,
    6151            0 :                                             format("{} not even multiple of 3. Will read in {}", s_ipsc->cNumericFieldNames(1), surfTemp.Sides)));
    6152              :                 }
    6153            0 :                 if (s_ipsc->rNumericArgs(1) < 3) {
    6154            0 :                     ShowSevereError(state,
    6155            0 :                                     format("{}=\"{}\", {} (autocalculate) must be >= 3. Only {} provided.",
    6156            0 :                                            s_ipsc->cCurrentModuleObject,
    6157            0 :                                            surfTemp.Name,
    6158            0 :                                            s_ipsc->cNumericFieldNames(1),
    6159            0 :                                            surfTemp.Sides));
    6160            0 :                     ErrorsFound = true;
    6161            0 :                     continue;
    6162              :                 }
    6163              :             } else {
    6164           24 :                 surfTemp.Sides = s_ipsc->rNumericArgs(1);
    6165              :             }
    6166           24 :             surfTemp.Vertex.allocate(surfTemp.Sides);
    6167           96 :             GetVertices(state, SurfNum, surfTemp.Sides, s_ipsc->rNumericArgs({2, _}));
    6168           24 :             CheckConvexity(state, SurfNum, surfTemp.Sides);
    6169              :             //    IF (SurfaceTmp(SurfNum)%Sides == 3) THEN
    6170              :             //      CALL ShowWarningError(state, TRIM(s_ipsc->cCurrentModuleObject)//'="'//TRIM(SurfaceTmp(SurfNum)%Name)//  &
    6171              :             //                        ' should not be triangular.')
    6172              :             //      CALL ShowContinueError(state, '...Check results carefully.')
    6173              :             //      ErrorsFound=.TRUE.
    6174              :             //    ENDIF
    6175              :             // Reset surface to be "detached"
    6176           24 :             surfTemp.BaseSurf = 0;
    6177              :             //    SurfaceTmp(SurfNum)%BaseSurfName='  '
    6178           24 :             surfTemp.Zone = 0;
    6179              :             // SurfaceTmp(SurfNum)%ZoneName='  '
    6180           24 :             if (state.dataReportFlag->MakeMirroredAttachedShading) {
    6181           24 :                 MakeMirrorSurface(state, SurfNum);
    6182              :             }
    6183              :         }
    6184          250 :     }
    6185              : 
    6186          226 :     void GetSimpleShdSurfaceData(EnergyPlusData &state,
    6187              :                                  bool &ErrorsFound,                // Error flag indicator (true if errors found)
    6188              :                                  int &SurfNum,                     // Count of Current SurfaceNumber
    6189              :                                  int const TotOverhangs,           // Number of Overhangs to obtain
    6190              :                                  int const TotOverhangsProjection, // Number of Overhangs (projection) to obtain
    6191              :                                  int const TotFins,                // Number of Fins to obtain
    6192              :                                  int const TotFinsProjection       // Number of Fins (projection) to obtain
    6193              :     )
    6194              :     {
    6195              : 
    6196              :         // SUBROUTINE INFORMATION:
    6197              :         //       AUTHOR         Linda Lawrie
    6198              :         //       DATE WRITTEN   January 2009
    6199              : 
    6200              :         // PURPOSE OF THIS SUBROUTINE:
    6201              :         // Get simple overhang and fin descriptions.
    6202              : 
    6203              :         // SUBROUTINE PARAMETER DEFINITIONS:
    6204          226 :         static Array1D_string const cModuleObjects(4, {"Shading:Overhang", "Shading:Overhang:Projection", "Shading:Fin", "Shading:Fin:Projection"});
    6205              : 
    6206              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    6207              :         int ItemsToGet;
    6208              :         int NumAlphas;
    6209              :         int NumNumbers;
    6210              :         int IOStat; // IO Status when calling get input subroutine
    6211              :         Real64 Depth;
    6212              :         Real64 Length;
    6213              :         Real64 Xp;
    6214              :         Real64 Yp;
    6215              :         Real64 Zp;
    6216              :         Real64 XLLC;
    6217              :         Real64 YLLC;
    6218              :         int BaseSurfNum;
    6219              :         Real64 TiltAngle;
    6220              :         bool MakeFin;
    6221              : 
    6222          226 :         auto &s_ipsc = state.dataIPShortCut;
    6223              : 
    6224          228 :         if ((TotOverhangs + TotOverhangsProjection + TotFins + TotFinsProjection) > 0 &&
    6225            2 :             state.dataHeatBal->SolarDistribution == DataHeatBalance::Shadowing::Minimal) {
    6226            0 :             ShowWarningError(state, "Shading effects of Fins and Overhangs are ignored when Solar Distribution = MinimalShadowing");
    6227              :         }
    6228         1130 :         for (int Item = 1; Item <= 4; ++Item) {
    6229              : 
    6230          904 :             s_ipsc->cCurrentModuleObject = cModuleObjects(Item);
    6231          904 :             if (Item == 1) {
    6232          226 :                 ItemsToGet = TotOverhangs;
    6233          678 :             } else if (Item == 2) {
    6234          226 :                 ItemsToGet = TotOverhangsProjection;
    6235          452 :             } else if (Item == 3) {
    6236          226 :                 ItemsToGet = TotFins;
    6237              :             } else { // ! (Item == 4) THEN
    6238          226 :                 ItemsToGet = TotFinsProjection;
    6239              :             }
    6240              : 
    6241          909 :             for (int Loop = 1; Loop <= ItemsToGet; ++Loop) {
    6242           10 :                 state.dataInputProcessing->inputProcessor->getObjectItem(state,
    6243            5 :                                                                          s_ipsc->cCurrentModuleObject,
    6244              :                                                                          Loop,
    6245            5 :                                                                          s_ipsc->cAlphaArgs,
    6246              :                                                                          NumAlphas,
    6247            5 :                                                                          s_ipsc->rNumericArgs,
    6248              :                                                                          NumNumbers,
    6249              :                                                                          IOStat,
    6250            5 :                                                                          s_ipsc->lNumericFieldBlanks,
    6251            5 :                                                                          s_ipsc->lAlphaFieldBlanks,
    6252            5 :                                                                          s_ipsc->cAlphaFieldNames,
    6253            5 :                                                                          s_ipsc->cNumericFieldNames);
    6254              : 
    6255           10 :                 if (GlobalNames::VerifyUniqueInterObjectName(state,
    6256            5 :                                                              state.dataSurfaceGeometry->UniqueSurfaceNames,
    6257            5 :                                                              s_ipsc->cAlphaArgs(1),
    6258            5 :                                                              s_ipsc->cCurrentModuleObject,
    6259            5 :                                                              s_ipsc->cAlphaFieldNames(1),
    6260              :                                                              ErrorsFound)) {
    6261            0 :                     continue;
    6262              :                 }
    6263              : 
    6264            5 :                 ++SurfNum;
    6265            5 :                 auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    6266              : 
    6267            5 :                 surfTemp.Name = s_ipsc->cAlphaArgs(1); // Set the Surface Name in the Derived Type
    6268            5 :                 surfTemp.Class = SurfaceClass::Shading;
    6269            5 :                 surfTemp.HeatTransSurf = false;
    6270              :                 // this object references a window or door....
    6271            5 :                 int Found = Util::FindItemInList(s_ipsc->cAlphaArgs(2), state.dataSurfaceGeometry->SurfaceTmp, state.dataSurface->TotSurfaces);
    6272            5 :                 if (Found > 0) {
    6273            5 :                     BaseSurfNum = state.dataSurfaceGeometry->SurfaceTmp(Found).BaseSurf;
    6274            5 :                     surfTemp.BaseSurfName = state.dataSurfaceGeometry->SurfaceTmp(Found).BaseSurfName;
    6275            5 :                     surfTemp.ExtBoundCond = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCond;
    6276            5 :                     surfTemp.ExtSolar = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtSolar;
    6277            5 :                     surfTemp.ExtWind = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtWind;
    6278            5 :                     surfTemp.Zone = state.dataSurfaceGeometry->SurfaceTmp(Found).Zone; // Necessary to do relative coordinates in GetVertices below
    6279            5 :                     surfTemp.ZoneName = state.dataSurfaceGeometry->SurfaceTmp(Found).ZoneName; // Necessary to have surface drawn in OutputReports
    6280              :                 } else {
    6281            0 :                     ShowSevereError(state,
    6282            0 :                                     format("{}=\"{}\", invalid {}=\"{}",
    6283            0 :                                            s_ipsc->cCurrentModuleObject,
    6284            0 :                                            surfTemp.Name,
    6285            0 :                                            s_ipsc->cAlphaFieldNames(2),
    6286            0 :                                            s_ipsc->cAlphaArgs(2)));
    6287            0 :                     ErrorsFound = true;
    6288            0 :                     continue;
    6289              :                 }
    6290            5 :                 if (surfTemp.ExtBoundCond == unenteredAdjacentZoneSurface) {
    6291            0 :                     ShowSevereError(state,
    6292            0 :                                     format("{}=\"{}\", invalid {}=\"{}",
    6293            0 :                                            s_ipsc->cCurrentModuleObject,
    6294            0 :                                            surfTemp.Name,
    6295            0 :                                            s_ipsc->cAlphaFieldNames(2),
    6296            0 :                                            s_ipsc->cAlphaArgs(2)));
    6297            0 :                     ShowContinueError(state, "...trying to attach a shading device to an interzone surface.");
    6298            0 :                     ErrorsFound = true;
    6299            0 :                     surfTemp.ExtBoundCond = DataSurfaces::ExternalEnvironment; // reset so program won't crash during "add surfaces"
    6300              :                 }
    6301            5 :                 if (surfTemp.ExtBoundCond == unreconciledZoneSurface) {
    6302            0 :                     ShowSevereError(state,
    6303            0 :                                     format("{}=\"{}\", invalid {}=\"{}",
    6304            0 :                                            s_ipsc->cCurrentModuleObject,
    6305            0 :                                            surfTemp.Name,
    6306            0 :                                            s_ipsc->cAlphaFieldNames(2),
    6307            0 :                                            s_ipsc->cAlphaArgs(2)));
    6308            0 :                     ShowContinueError(state, "...trying to attach a shading device to an interior surface.");
    6309            0 :                     ErrorsFound = true;
    6310            0 :                     surfTemp.ExtBoundCond = DataSurfaces::ExternalEnvironment; // reset so program won't crash during "add surfaces"
    6311              :                 }
    6312              : 
    6313            5 :                 surfTemp.shadowSurfSched = nullptr;
    6314              : 
    6315              :                 //===== Overhang =====
    6316              : 
    6317            5 :                 if (Item < 3) {
    6318              :                     //  Found is the surface window or door.
    6319              :                     //   N1,  \field Height above Window or Door
    6320              :                     //        \units m
    6321              :                     //   N2,  \field Tilt Angle from Window/Door
    6322              :                     //        \units deg
    6323              :                     //        \default 90
    6324              :                     //        \minimum 0
    6325              :                     //        \maximum 180
    6326              :                     //   N3,  \field Left extension from Window/Door Width
    6327              :                     //        \units m
    6328              :                     //   N4,  \field Right extension from Window/Door Width
    6329              :                     //        \note N3 + N4 + Window/Door Width is Overhang Length
    6330              :                     //        \units m
    6331              :                     //   N5;  \field Depth
    6332              :                     //        \units m
    6333              :                     // for projection option:
    6334              :                     //   N5;  \field Depth as Fraction of Window/Door Height
    6335              :                     //        \units m
    6336            3 :                     Length = s_ipsc->rNumericArgs(3) + s_ipsc->rNumericArgs(4) + state.dataSurfaceGeometry->SurfaceTmp(Found).Width;
    6337            3 :                     if (Item == 1) {
    6338            2 :                         Depth = s_ipsc->rNumericArgs(5);
    6339            1 :                     } else if (Item == 2) {
    6340            1 :                         Depth = s_ipsc->rNumericArgs(5) * state.dataSurfaceGeometry->SurfaceTmp(Found).Height;
    6341              :                     }
    6342              : 
    6343            3 :                     if (Length * Depth <= 0.0) {
    6344            0 :                         ShowSevereError(state,
    6345            0 :                                         format("{}=\"{}\", illegal surface area=[{:.2R}]. Surface will NOT be entered.",
    6346            0 :                                                s_ipsc->cCurrentModuleObject,
    6347            0 :                                                s_ipsc->cAlphaArgs(1),
    6348            0 :                                                Length * Depth));
    6349            0 :                         continue;
    6350              :                     }
    6351              : 
    6352            3 :                     TiltAngle = state.dataSurfaceGeometry->SurfaceTmp(Found).Tilt + s_ipsc->rNumericArgs(2);
    6353            3 :                     surfTemp.Tilt = TiltAngle;
    6354            3 :                     surfTemp.convOrientation = Convect::GetSurfConvOrientation(surfTemp.Tilt);
    6355            3 :                     surfTemp.Azimuth = state.dataSurfaceGeometry->SurfaceTmp(Found).Azimuth;
    6356              : 
    6357              :                     // Make it relative to surface origin.....
    6358            3 :                     Xp = state.dataSurfaceGeometry->SurfaceTmp(Found).Vertex(2).x - state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).x;
    6359            3 :                     Yp = state.dataSurfaceGeometry->SurfaceTmp(Found).Vertex(2).y - state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).y;
    6360            3 :                     Zp = state.dataSurfaceGeometry->SurfaceTmp(Found).Vertex(2).z - state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).z;
    6361              : 
    6362            3 :                     XLLC = -Xp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosAzim +
    6363            3 :                            Yp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).SinAzim;
    6364              : 
    6365            3 :                     YLLC =
    6366            3 :                         -Xp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).SinAzim *
    6367            3 :                             state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosTilt -
    6368            3 :                         Yp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosAzim * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosTilt +
    6369            3 :                         Zp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).SinTilt;
    6370              : 
    6371            3 :                     surfTemp.Sides = 4;
    6372            3 :                     surfTemp.Vertex.allocate(surfTemp.Sides);
    6373              : 
    6374            6 :                     MakeRelativeRectangularVertices(state,
    6375              :                                                     BaseSurfNum,
    6376              :                                                     SurfNum,
    6377            3 :                                                     XLLC - s_ipsc->rNumericArgs(3),
    6378            3 :                                                     YLLC + state.dataSurfaceGeometry->SurfaceTmp(Found).Height + s_ipsc->rNumericArgs(1),
    6379              :                                                     Length,
    6380              :                                                     Depth);
    6381              : 
    6382              :                     // Reset surface to be "detached"
    6383              :                     //    SurfaceTmp(SurfNum)%BaseSurfName='  '
    6384              :                     //    SurfaceTmp(SurfNum)%ZoneName='  '
    6385              : 
    6386            3 :                     surfTemp.BaseSurf = 0;
    6387            3 :                     surfTemp.Zone = 0;
    6388              : 
    6389              :                     // and mirror
    6390            3 :                     if (state.dataReportFlag->MakeMirroredAttachedShading) {
    6391            3 :                         MakeMirrorSurface(state, SurfNum);
    6392              :                     }
    6393              : 
    6394              :                 } else { // Fins
    6395              : 
    6396              :                     //===== Fins =====
    6397              : 
    6398              :                     //===== Left Fin =====
    6399              : 
    6400              :                     //   N1,  \field Left Extension from Window/Door
    6401              :                     //        \units m
    6402              :                     //   N2,  \field Left Distance Above Top of Window
    6403              :                     //        \units m
    6404              :                     //   N3,  \field Left Distance Below Bottom of Window
    6405              :                     //        \units m
    6406              :                     //        \note N2 + N3 + height of Window/Door is height of Fin
    6407              :                     //   N4,  \field Left Tilt Angle from Window/Door
    6408              :                     //        \units deg
    6409              :                     //        \default 90
    6410              :                     //        \minimum 0
    6411              :                     //        \maximum 180
    6412              :                     //   N5,  \field Left Depth
    6413              :                     //        \units m
    6414              :                     // for projection option:
    6415              :                     //   N5,  \field Left Depth as Fraction of Window/Door Width
    6416              :                     //        \units m
    6417            2 :                     surfTemp.Name = surfTemp.Name + " Left";
    6418            2 :                     Length = s_ipsc->rNumericArgs(2) + s_ipsc->rNumericArgs(3) + state.dataSurfaceGeometry->SurfaceTmp(Found).Height;
    6419            2 :                     if (Item == 3) {
    6420            0 :                         Depth = s_ipsc->rNumericArgs(5);
    6421            2 :                     } else if (Item == 4) {
    6422            2 :                         Depth = s_ipsc->rNumericArgs(5) * state.dataSurfaceGeometry->SurfaceTmp(Found).Width;
    6423              :                     }
    6424              : 
    6425            2 :                     MakeFin = true;
    6426            2 :                     if (Length * Depth <= 0.0) {
    6427            2 :                         ShowWarningError(state,
    6428            3 :                                          format("{}=Left Fin of \"{}\", illegal surface area=[{:.2R}]. Surface will NOT be entered.",
    6429            1 :                                                 s_ipsc->cCurrentModuleObject,
    6430            1 :                                                 s_ipsc->cAlphaArgs(1),
    6431            1 :                                                 Length * Depth));
    6432            1 :                         MakeFin = false;
    6433              :                     }
    6434              : 
    6435            2 :                     if (MakeFin) {
    6436            1 :                         TiltAngle = state.dataSurfaceGeometry->SurfaceTmp(Found).Tilt;
    6437            1 :                         surfTemp.Tilt = TiltAngle;
    6438            1 :                         surfTemp.convOrientation = Convect::GetSurfConvOrientation(surfTemp.Tilt);
    6439            1 :                         surfTemp.Azimuth = state.dataSurfaceGeometry->SurfaceTmp(Found).Azimuth - (180.0 - s_ipsc->rNumericArgs(4));
    6440              : 
    6441              :                         // Make it relative to surface origin.....
    6442              : 
    6443            1 :                         Xp =
    6444            1 :                             state.dataSurfaceGeometry->SurfaceTmp(Found).Vertex(2).x - state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).x;
    6445            1 :                         Yp =
    6446            1 :                             state.dataSurfaceGeometry->SurfaceTmp(Found).Vertex(2).y - state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).y;
    6447            1 :                         Zp =
    6448            1 :                             state.dataSurfaceGeometry->SurfaceTmp(Found).Vertex(2).z - state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).z;
    6449              : 
    6450            1 :                         XLLC = -Xp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosAzim +
    6451            1 :                                Yp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).SinAzim;
    6452              : 
    6453            1 :                         YLLC = -Xp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).SinAzim *
    6454            1 :                                    state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosTilt -
    6455            1 :                                Yp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosAzim *
    6456            1 :                                    state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosTilt +
    6457            1 :                                Zp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).SinTilt;
    6458              : 
    6459            1 :                         surfTemp.CosAzim = std::cos(surfTemp.Azimuth * Constant::DegToRad);
    6460            1 :                         surfTemp.SinAzim = std::sin(surfTemp.Azimuth * Constant::DegToRad);
    6461            1 :                         surfTemp.CosTilt = std::cos(surfTemp.Tilt * Constant::DegToRad);
    6462            1 :                         surfTemp.SinTilt = std::sin(surfTemp.Tilt * Constant::DegToRad);
    6463              : 
    6464            1 :                         surfTemp.Sides = 4;
    6465            1 :                         surfTemp.Vertex.allocate(surfTemp.Sides);
    6466              : 
    6467            3 :                         MakeRelativeRectangularVertices(
    6468            1 :                             state, BaseSurfNum, SurfNum, XLLC - s_ipsc->rNumericArgs(1), YLLC - s_ipsc->rNumericArgs(3), -Depth, Length);
    6469              : 
    6470              :                         // Reset surface to be "detached"
    6471              :                         //    SurfaceTmp(SurfNum)%BaseSurfName='  '
    6472              :                         //    SurfaceTmp(SurfNum)%ZoneName='  '
    6473              : 
    6474            1 :                         surfTemp.BaseSurf = 0;
    6475            1 :                         surfTemp.Zone = 0;
    6476              : 
    6477              :                         // and mirror
    6478            1 :                         if (state.dataReportFlag->MakeMirroredAttachedShading) {
    6479            1 :                             MakeMirrorSurface(state, SurfNum);
    6480              :                         }
    6481              :                     } else {
    6482            1 :                         --SurfNum;
    6483              :                     }
    6484              : 
    6485              :                     //===== Right Fin =====
    6486              : 
    6487              :                     //   N6,  \field Right Extension from Window/Door
    6488              :                     //        \units m
    6489              :                     //   N7,  \field Right Distance Above Top of Window
    6490              :                     //        \units m
    6491              :                     //   N8,  \field Right Distance Below Bottom of Window
    6492              :                     //        \note N7 + N8 + height of Window/Door is height of Fin
    6493              :                     //        \units m
    6494              :                     //   N9,  \field Right Tilt Angle from Window/Door
    6495              :                     //        \units deg
    6496              :                     //        \default 90
    6497              :                     //        \minimum 0
    6498              :                     //        \maximum 180
    6499              :                     //   N10; \field Right Depth
    6500              :                     //        \units m
    6501              :                     // for projection option:
    6502              :                     //   N10; \field Right Depth as Fraction of Window/Door Width
    6503              :                     //        \units m
    6504              : 
    6505            2 :                     ++SurfNum;
    6506            2 :                     auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    6507            2 :                     surfTemp.Name = s_ipsc->cAlphaArgs(1) + " Right"; // Set the Surface Name in the Derived Type
    6508            2 :                     surfTemp.Class = SurfaceClass::Shading;
    6509            2 :                     surfTemp.HeatTransSurf = false;
    6510            2 :                     BaseSurfNum = state.dataSurfaceGeometry->SurfaceTmp(Found).BaseSurf;
    6511            2 :                     surfTemp.BaseSurfName = state.dataSurfaceGeometry->SurfaceTmp(Found).BaseSurfName;
    6512            2 :                     surfTemp.ExtBoundCond = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtBoundCond;
    6513            2 :                     surfTemp.ExtSolar = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtSolar;
    6514            2 :                     surfTemp.ExtWind = state.dataSurfaceGeometry->SurfaceTmp(Found).ExtWind;
    6515            2 :                     surfTemp.Zone = state.dataSurfaceGeometry->SurfaceTmp(Found).Zone; // Necessary to do relative coordinates in GetVertices below
    6516            2 :                     surfTemp.ZoneName = state.dataSurfaceGeometry->SurfaceTmp(Found).ZoneName; // Necessary to have surface drawn in OutputReports
    6517              : 
    6518            2 :                     surfTemp.shadowSurfSched = nullptr;
    6519            2 :                     Length = s_ipsc->rNumericArgs(7) + s_ipsc->rNumericArgs(8) + state.dataSurfaceGeometry->SurfaceTmp(Found).Height;
    6520            2 :                     if (Item == 3) {
    6521            0 :                         Depth = s_ipsc->rNumericArgs(10);
    6522            2 :                     } else if (Item == 4) {
    6523            2 :                         Depth = s_ipsc->rNumericArgs(10) * state.dataSurfaceGeometry->SurfaceTmp(Found).Width;
    6524              :                     }
    6525              : 
    6526            2 :                     MakeFin = true;
    6527            2 :                     if (Length * Depth <= 0.0) {
    6528            2 :                         ShowWarningError(state,
    6529            3 :                                          format("{}=Right Fin of \"{}\", illegal surface area=[{:.2R}]. Surface will NOT be entered.",
    6530            1 :                                                 s_ipsc->cCurrentModuleObject,
    6531            1 :                                                 s_ipsc->cAlphaArgs(1),
    6532            1 :                                                 Length * Depth));
    6533            1 :                         MakeFin = false;
    6534              :                     }
    6535              : 
    6536            2 :                     if (MakeFin) {
    6537              :                         // Make it relative to surface origin.....
    6538              : 
    6539            1 :                         Xp =
    6540            1 :                             state.dataSurfaceGeometry->SurfaceTmp(Found).Vertex(2).x - state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).x;
    6541            1 :                         Yp =
    6542            1 :                             state.dataSurfaceGeometry->SurfaceTmp(Found).Vertex(2).y - state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).y;
    6543            1 :                         Zp =
    6544            1 :                             state.dataSurfaceGeometry->SurfaceTmp(Found).Vertex(2).z - state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).Vertex(2).z;
    6545              : 
    6546            1 :                         XLLC = -Xp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosAzim +
    6547            1 :                                Yp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).SinAzim;
    6548              : 
    6549            1 :                         YLLC = -Xp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).SinAzim *
    6550            1 :                                    state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosTilt -
    6551            1 :                                Yp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosAzim *
    6552            1 :                                    state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).CosTilt +
    6553            1 :                                Zp * state.dataSurfaceGeometry->SurfaceTmp(BaseSurfNum).SinTilt;
    6554              : 
    6555            1 :                         TiltAngle = state.dataSurfaceGeometry->SurfaceTmp(Found).Tilt;
    6556            1 :                         surfTemp.Tilt = TiltAngle;
    6557            1 :                         surfTemp.convOrientation = Convect::GetSurfConvOrientation(surfTemp.Tilt);
    6558            1 :                         surfTemp.Azimuth = state.dataSurfaceGeometry->SurfaceTmp(Found).Azimuth - (180.0 - s_ipsc->rNumericArgs(9));
    6559            1 :                         surfTemp.CosAzim = std::cos(surfTemp.Azimuth * Constant::DegToRad);
    6560            1 :                         surfTemp.SinAzim = std::sin(surfTemp.Azimuth * Constant::DegToRad);
    6561            1 :                         surfTemp.CosTilt = std::cos(surfTemp.Tilt * Constant::DegToRad);
    6562            1 :                         surfTemp.SinTilt = std::sin(surfTemp.Tilt * Constant::DegToRad);
    6563              : 
    6564            1 :                         surfTemp.Sides = 4;
    6565            1 :                         surfTemp.Vertex.allocate(surfTemp.Sides);
    6566              : 
    6567            3 :                         MakeRelativeRectangularVertices(state,
    6568              :                                                         BaseSurfNum,
    6569              :                                                         SurfNum,
    6570            1 :                                                         XLLC + state.dataSurfaceGeometry->SurfaceTmp(Found).Width + s_ipsc->rNumericArgs(6),
    6571            1 :                                                         YLLC - s_ipsc->rNumericArgs(8),
    6572              :                                                         -Depth,
    6573              :                                                         Length);
    6574              : 
    6575              :                         // Reset surface to be "detached"
    6576              :                         //    SurfaceTmp(SurfNum)%BaseSurfName='  '
    6577              :                         //    SurfaceTmp(SurfNum)%ZoneName='  '
    6578              : 
    6579            1 :                         surfTemp.BaseSurf = 0;
    6580            1 :                         surfTemp.Zone = 0;
    6581              : 
    6582              :                         // and mirror
    6583            1 :                         if (state.dataReportFlag->MakeMirroredAttachedShading) {
    6584            1 :                             MakeMirrorSurface(state, SurfNum);
    6585              :                         }
    6586              :                     } else {
    6587            1 :                         --SurfNum;
    6588              :                     }
    6589              :                 }
    6590              :             }
    6591              :         }
    6592          226 :     }
    6593              : 
    6594          227 :     void GetIntMassSurfaceData(EnergyPlusData &state,
    6595              :                                bool &ErrorsFound, // Error flag indicator (true if errors found)
    6596              :                                int &SurfNum       // Count of Current SurfaceNumber
    6597              :     )
    6598              :     {
    6599              : 
    6600              :         // SUBROUTINE INFORMATION:
    6601              :         //       AUTHOR         Linda Lawrie
    6602              :         //       DATE WRITTEN   May 2000
    6603              : 
    6604              :         // PURPOSE OF THIS SUBROUTINE:
    6605              :         // This subroutine gets the Internal Surface Data,
    6606              :         // checks it for errors, etc.
    6607              : 
    6608              :         // REFERENCES:
    6609              :         // Internal Mass Surface Definition
    6610              :         // Surface:HeatTransfer:InternalMass,
    6611              :         //       \note used to describe internal zone surface area that does not need to be part of geometric representation
    6612              :         //  A1 , \field User Supplied Surface Name
    6613              :         //       \type alpha
    6614              :         //       \reference SurfaceNames
    6615              :         //  A2 , \field Construction Name of the Surface
    6616              :         //       \note To be matched with a construction in this input file
    6617              :         //       \type object-list
    6618              :         //       \object-list ConstructionNames
    6619              :         //  A3 , \field Interior Environment
    6620              :         //       \note Zone the surface is a part of
    6621              :         //       \type object-list
    6622              :         //       \object-list ZoneNames
    6623              :         //  N1,  \field View factor to Person (to people?)
    6624              :         //       \type real
    6625              :         //       \note from the interior of the surface
    6626              :         //  N2 ; \field Surface area
    6627              :         //       \units m2
    6628              : 
    6629              :         // SUBROUTINE PARAMETER DEFINITIONS:
    6630              :         static constexpr std::string_view RoutineName("GetIntMassSurfaceData: ");
    6631              : 
    6632              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    6633              :         int IOStat;          // IO Status when calling get input subroutine
    6634              :         int SurfaceNumAlpha; // Number of material alpha names being passed
    6635              :         int SurfaceNumArg;   // Number of material properties being passed
    6636              : 
    6637          227 :         auto &s_ipsc = state.dataIPShortCut;
    6638          227 :         s_ipsc->cCurrentModuleObject = "InternalMass";
    6639          227 :         int TotIntMass = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
    6640          227 :         if (TotIntMass == 0) return;
    6641              : 
    6642            9 :         state.dataSurface->IntMassObjects.allocate(TotIntMass);
    6643              : 
    6644              :         // scan for use of Zone lists in InternalMass objects
    6645            9 :         bool errFlag = false;
    6646            9 :         int NumIntMassSurfaces = 0;
    6647           28 :         for (int Item = 1; Item <= TotIntMass; ++Item) {
    6648           38 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    6649           19 :                                                                      s_ipsc->cCurrentModuleObject,
    6650              :                                                                      Item,
    6651           19 :                                                                      s_ipsc->cAlphaArgs,
    6652              :                                                                      SurfaceNumAlpha,
    6653           19 :                                                                      s_ipsc->rNumericArgs,
    6654              :                                                                      SurfaceNumArg,
    6655              :                                                                      IOStat,
    6656           19 :                                                                      s_ipsc->lNumericFieldBlanks,
    6657           19 :                                                                      s_ipsc->lAlphaFieldBlanks,
    6658           19 :                                                                      s_ipsc->cAlphaFieldNames,
    6659           19 :                                                                      s_ipsc->cNumericFieldNames);
    6660              : 
    6661           38 :             if (GlobalNames::VerifyUniqueInterObjectName(state,
    6662           19 :                                                          state.dataSurfaceGeometry->UniqueSurfaceNames,
    6663           19 :                                                          s_ipsc->cAlphaArgs(1),
    6664           19 :                                                          s_ipsc->cCurrentModuleObject,
    6665           19 :                                                          s_ipsc->cAlphaFieldNames(1),
    6666              :                                                          ErrorsFound)) {
    6667            0 :                 continue;
    6668              :             }
    6669              : 
    6670           19 :             state.dataSurface->IntMassObjects(Item).Name = s_ipsc->cAlphaArgs(1);
    6671           19 :             state.dataSurface->IntMassObjects(Item).GrossArea = s_ipsc->rNumericArgs(1);
    6672           19 :             state.dataSurface->IntMassObjects(Item).Construction =
    6673           19 :                 Util::FindItemInList(s_ipsc->cAlphaArgs(2), state.dataConstruction->Construct, state.dataHeatBal->TotConstructs);
    6674           19 :             state.dataSurface->IntMassObjects(Item).ZoneOrZoneListName = s_ipsc->cAlphaArgs(3);
    6675           19 :             int Item1 = Util::FindItemInList(s_ipsc->cAlphaArgs(3), state.dataHeatBal->Zone, state.dataGlobal->NumOfZones);
    6676           19 :             int ZLItem = 0;
    6677           19 :             if (Item1 == 0 && state.dataHeatBal->NumOfZoneLists > 0)
    6678            3 :                 ZLItem = Util::FindItemInList(s_ipsc->cAlphaArgs(3), state.dataHeatBal->ZoneList);
    6679           19 :             if (Item1 > 0) {
    6680           16 :                 if (s_ipsc->lAlphaFieldBlanks(4)) {
    6681           16 :                     ++NumIntMassSurfaces;
    6682              :                 }
    6683           16 :                 state.dataSurface->IntMassObjects(Item).NumOfZones = 1;
    6684           16 :                 state.dataSurface->IntMassObjects(Item).ZoneListActive = false;
    6685           16 :                 state.dataSurface->IntMassObjects(Item).ZoneOrZoneListPtr = Item1;
    6686            3 :             } else if (ZLItem > 0) {
    6687            3 :                 NumIntMassSurfaces += state.dataHeatBal->ZoneList(ZLItem).NumOfZones;
    6688            3 :                 state.dataSurface->IntMassObjects(Item).NumOfZones = state.dataHeatBal->ZoneList(ZLItem).NumOfZones;
    6689            3 :                 state.dataSurface->IntMassObjects(Item).ZoneListActive = true;
    6690            3 :                 state.dataSurface->IntMassObjects(Item).ZoneOrZoneListPtr = ZLItem;
    6691            0 :             } else if (state.dataIPShortCut->lAlphaFieldBlanks(4)) {
    6692              :                 // If Space or SpaceList Name is blank, then throw error.
    6693            0 :                 ShowSevereError(state,
    6694            0 :                                 format("{}=\"{}\" invalid {}=\"{}\" not found.",
    6695            0 :                                        s_ipsc->cCurrentModuleObject,
    6696            0 :                                        s_ipsc->cAlphaArgs(1),
    6697            0 :                                        s_ipsc->cAlphaFieldNames(3),
    6698            0 :                                        s_ipsc->cAlphaArgs(3)));
    6699            0 :                 ++SurfNum;
    6700            0 :                 auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    6701            0 :                 surfTemp.Class = SurfaceClass::Invalid;
    6702            0 :                 surfTemp.ZoneName = "Unknown Zone";
    6703            0 :                 ErrorsFound = true;
    6704            0 :                 errFlag = true;
    6705              :             }
    6706              : 
    6707           19 :             if (!s_ipsc->lAlphaFieldBlanks(4)) {
    6708            0 :                 state.dataSurface->IntMassObjects(Item).spaceOrSpaceListName = s_ipsc->cAlphaArgs(4);
    6709            0 :                 Item1 = Util::FindItemInList(s_ipsc->cAlphaArgs(4), state.dataHeatBal->space);
    6710            0 :                 int SLItem = 0;
    6711            0 :                 if (Item1 == 0 && int(state.dataHeatBal->spaceList.size()) > 0)
    6712            0 :                     SLItem = Util::FindItemInList(s_ipsc->cAlphaArgs(4), state.dataHeatBal->spaceList);
    6713            0 :                 if (Item1 > 0) {
    6714            0 :                     ++NumIntMassSurfaces;
    6715            0 :                     state.dataSurface->IntMassObjects(Item).numOfSpaces = 1;
    6716            0 :                     state.dataSurface->IntMassObjects(Item).spaceListActive = false;
    6717            0 :                     state.dataSurface->IntMassObjects(Item).spaceOrSpaceListPtr = Item1;
    6718            0 :                     state.dataSurface->IntMassObjects(Item).NumOfZones = 1;
    6719            0 :                     state.dataSurface->IntMassObjects(Item).ZoneListActive = false;
    6720            0 :                     state.dataSurface->IntMassObjects(Item).ZoneOrZoneListPtr = state.dataHeatBal->space(Item1).zoneNum;
    6721            0 :                 } else if (SLItem > 0) {
    6722            0 :                     int numOfSpaces = int(state.dataHeatBal->spaceList(SLItem).numListSpaces);
    6723            0 :                     NumIntMassSurfaces += numOfSpaces;
    6724            0 :                     state.dataSurface->IntMassObjects(Item).numOfSpaces = numOfSpaces;
    6725            0 :                     state.dataSurface->IntMassObjects(Item).spaceListActive = true;
    6726            0 :                     state.dataSurface->IntMassObjects(Item).spaceOrSpaceListPtr = SLItem;
    6727              :                 } else {
    6728            0 :                     ShowSevereError(state,
    6729            0 :                                     format("{}=\"{}\" invalid {}=\"{}\" not found.",
    6730            0 :                                            s_ipsc->cCurrentModuleObject,
    6731            0 :                                            s_ipsc->cAlphaArgs(1),
    6732            0 :                                            s_ipsc->cAlphaFieldNames(4),
    6733            0 :                                            s_ipsc->cAlphaArgs(4)));
    6734            0 :                     ++SurfNum;
    6735            0 :                     auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    6736            0 :                     surfTemp.Class = SurfaceClass::Invalid;
    6737            0 :                     ErrorsFound = true;
    6738            0 :                     errFlag = true;
    6739              :                 }
    6740              :             }
    6741              : 
    6742           19 :             if (errFlag) {
    6743            0 :                 ShowSevereError(state, format("{}Errors with invalid names in {} objects.", RoutineName, s_ipsc->cCurrentModuleObject));
    6744            0 :                 ShowContinueError(state, "...These will not be read in.  Other errors may occur.");
    6745            0 :                 NumIntMassSurfaces = 0;
    6746              :             }
    6747              : 
    6748           19 :             if (state.dataSurface->IntMassObjects(Item).Construction == 0) {
    6749            0 :                 ErrorsFound = true;
    6750            0 :                 ShowSevereError(state,
    6751            0 :                                 format("{}=\"{}\", {} not found={}",
    6752            0 :                                        s_ipsc->cCurrentModuleObject,
    6753            0 :                                        s_ipsc->cAlphaArgs(1),
    6754            0 :                                        s_ipsc->cAlphaFieldNames(2),
    6755            0 :                                        s_ipsc->cAlphaArgs(2)));
    6756           19 :             } else if (state.dataConstruction->Construct(state.dataSurface->IntMassObjects(Item).Construction).TypeIsWindow) {
    6757            0 :                 ErrorsFound = true;
    6758            0 :                 ShowSevereError(state,
    6759            0 :                                 format("{}=\"{}\", invalid {}=\"{}\" - has Window materials.",
    6760            0 :                                        s_ipsc->cCurrentModuleObject,
    6761            0 :                                        s_ipsc->cAlphaArgs(1),
    6762            0 :                                        s_ipsc->cAlphaFieldNames(2),
    6763            0 :                                        s_ipsc->cAlphaArgs(2)));
    6764              :             } else {
    6765           19 :                 state.dataConstruction->Construct(state.dataSurface->IntMassObjects(Item).Construction).IsUsed = true;
    6766              :             }
    6767              :         }
    6768              : 
    6769            9 :         if (NumIntMassSurfaces > 0) {
    6770           28 :             for (int Loop = 1; Loop <= TotIntMass; ++Loop) {
    6771           19 :                 int numberOfZonesOrSpaces = 1;
    6772           19 :                 if (state.dataSurface->IntMassObjects(Loop).ZoneListActive) {
    6773            3 :                     numberOfZonesOrSpaces = state.dataSurface->IntMassObjects(Loop).NumOfZones;
    6774           16 :                 } else if (state.dataSurface->IntMassObjects(Loop).spaceListActive) {
    6775            0 :                     numberOfZonesOrSpaces = state.dataSurface->IntMassObjects(Loop).numOfSpaces;
    6776              :                 }
    6777              : 
    6778           59 :                 for (int Item1 = 1; Item1 <= numberOfZonesOrSpaces; ++Item1) {
    6779              : 
    6780           40 :                     ++SurfNum;
    6781              : 
    6782           40 :                     auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    6783           40 :                     surfTemp.Construction = state.dataSurface->IntMassObjects(Loop).Construction;
    6784           40 :                     if (!state.dataSurface->IntMassObjects(Loop).ZoneListActive && !state.dataSurface->IntMassObjects(Loop).spaceListActive) {
    6785           16 :                         surfTemp.Zone = state.dataSurface->IntMassObjects(Loop).ZoneOrZoneListPtr;
    6786           16 :                         surfTemp.spaceNum = state.dataSurface->IntMassObjects(Loop).spaceOrSpaceListPtr;
    6787           16 :                         surfTemp.Name = state.dataSurface->IntMassObjects(Loop).Name;
    6788           16 :                         surfTemp.Class = SurfaceClass::IntMass;
    6789           16 :                         surfTemp.ZoneName = state.dataSurface->IntMassObjects(Loop).ZoneOrZoneListName;
    6790           16 :                         surfTemp.HeatTransSurf = true;
    6791              :                     } else {
    6792           24 :                         int ZoneNum = 0; // index to a zone
    6793           24 :                         if (state.dataSurface->IntMassObjects(Loop).ZoneListActive) {
    6794           72 :                             General::CheckCreatedZoneItemName(
    6795              :                                 state,
    6796              :                                 RoutineName,
    6797           24 :                                 s_ipsc->cCurrentModuleObject,
    6798              :                                 state.dataHeatBal
    6799           24 :                                     ->Zone(state.dataHeatBal->ZoneList(state.dataSurface->IntMassObjects(Loop).ZoneOrZoneListPtr).Zone(Item1))
    6800           24 :                                     .Name,
    6801           24 :                                 state.dataHeatBal->ZoneList(state.dataSurface->IntMassObjects(Loop).ZoneOrZoneListPtr).MaxZoneNameLength,
    6802           24 :                                 state.dataSurface->IntMassObjects(Loop).Name,
    6803           24 :                                 state.dataSurfaceGeometry->SurfaceTmp,
    6804           24 :                                 SurfNum - 1,
    6805           24 :                                 surfTemp.Name,
    6806              :                                 errFlag);
    6807              : 
    6808           24 :                             ZoneNum = state.dataHeatBal->ZoneList(state.dataSurface->IntMassObjects(Loop).ZoneOrZoneListPtr).Zone(Item1);
    6809            0 :                         } else if (state.dataSurface->IntMassObjects(Loop).spaceListActive) {
    6810            0 :                             int spaceNum = state.dataHeatBal->spaceList(state.dataSurface->IntMassObjects(Loop).spaceOrSpaceListPtr).spaces(Item1);
    6811            0 :                             ZoneNum = state.dataHeatBal->space(spaceNum).zoneNum;
    6812            0 :                             const std::string spaceName = state.dataHeatBal->space(spaceNum).Name;
    6813            0 :                             surfTemp.Name = spaceName + ' ' + state.dataSurface->IntMassObjects(Loop).Name;
    6814            0 :                             surfTemp.spaceNum = spaceNum;
    6815            0 :                         }
    6816           24 :                         surfTemp.Zone = ZoneNum;
    6817           24 :                         surfTemp.Class = SurfaceClass::IntMass;
    6818           24 :                         surfTemp.ZoneName = state.dataHeatBal->Zone(ZoneNum).Name;
    6819           24 :                         surfTemp.HeatTransSurf = true;
    6820           24 :                         if (errFlag) ErrorsFound = true;
    6821              :                     }
    6822              : 
    6823           40 :                     if (state.dataSurface->IntMassObjects(Loop).Construction > 0) {
    6824           40 :                         if (state.dataConstruction->Construct(state.dataSurface->IntMassObjects(Loop).Construction).IsUsed) {
    6825           40 :                             surfTemp.ConstructionStoredInputValue = state.dataSurface->IntMassObjects(Loop).Construction;
    6826              :                         }
    6827              :                     }
    6828           40 :                     surfTemp.GrossArea = state.dataSurface->IntMassObjects(Loop).GrossArea;
    6829           40 :                     surfTemp.Area = surfTemp.GrossArea;
    6830           40 :                     surfTemp.NetAreaShadowCalc = surfTemp.Area;
    6831           40 :                     surfTemp.Width = surfTemp.Area;
    6832           40 :                     surfTemp.Height = 1.0;
    6833           40 :                     surfTemp.Tilt = 90.0;
    6834           40 :                     surfTemp.convOrientation = Convect::GetSurfConvOrientation(surfTemp.Tilt);
    6835           40 :                     surfTemp.CosTilt = 0.0; // Tuned Was std::cos( 90.0 * DegToRadians )
    6836           40 :                     surfTemp.SinTilt = 1.0; // Tuned Was std::sin( 90.0 * DegToRadians )
    6837           40 :                     surfTemp.Azimuth = 0.0;
    6838           40 :                     surfTemp.CosAzim = 1.0; // Tuned Was std::cos( 0.0 )
    6839           40 :                     surfTemp.SinAzim = 0.0; // Tuned Was std::sin( 0.0 )
    6840              :                     // Outward normal unit vector (pointing away from room)
    6841           40 :                     surfTemp.OutNormVec = surfTemp.lcsz;
    6842           40 :                     surfTemp.ViewFactorSky = 0.5;
    6843           40 :                     surfTemp.ExtSolar = false;
    6844           40 :                     surfTemp.ExtWind = false;
    6845           40 :                     surfTemp.BaseSurf = SurfNum;
    6846           40 :                     surfTemp.BaseSurfName = surfTemp.Name;
    6847           40 :                     surfTemp.ExtBoundCondName = surfTemp.Name;
    6848           40 :                     surfTemp.ExtBoundCond = unreconciledZoneSurface;
    6849              :                 }
    6850              :             }
    6851              :         }
    6852              :     }
    6853              : 
    6854          228 :     int GetNumIntMassSurfaces(EnergyPlusData &state) // Number of Internal Mass Surfaces to obtain
    6855              : 
    6856              :     {
    6857              :         // Counts internal mass surfaces applied to zones and zone lists
    6858              : 
    6859              :         int IOStat;          // IO Status when calling get input subroutine
    6860              :         int SurfaceNumAlpha; // Number of material alpha names being passed
    6861              :         int SurfaceNumArg;   // Number of material properties being passed
    6862              : 
    6863          228 :         auto &s_ipsc = state.dataIPShortCut;
    6864          228 :         s_ipsc->cCurrentModuleObject = "InternalMass";
    6865              : 
    6866          228 :         int NumIntMassSurf = 0;
    6867          228 :         int TotIntMass = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "InternalMass");
    6868              : 
    6869          228 :         if (TotIntMass == 0) return NumIntMassSurf;
    6870              :         // scan for zones and zone lists in InternalMass objects
    6871           32 :         for (int Item = 1; Item <= TotIntMass; ++Item) {
    6872           44 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    6873           22 :                                                                      s_ipsc->cCurrentModuleObject,
    6874              :                                                                      Item,
    6875           22 :                                                                      s_ipsc->cAlphaArgs,
    6876              :                                                                      SurfaceNumAlpha,
    6877           22 :                                                                      s_ipsc->rNumericArgs,
    6878              :                                                                      SurfaceNumArg,
    6879              :                                                                      IOStat,
    6880           22 :                                                                      s_ipsc->lNumericFieldBlanks,
    6881           22 :                                                                      s_ipsc->lAlphaFieldBlanks,
    6882           22 :                                                                      s_ipsc->cAlphaFieldNames,
    6883           22 :                                                                      s_ipsc->cNumericFieldNames);
    6884              : 
    6885           22 :             int Item1 = Util::FindItemInList(s_ipsc->cAlphaArgs(3), state.dataHeatBal->Zone, state.dataGlobal->NumOfZones);
    6886           22 :             int ZLItem = 0;
    6887           22 :             if (Item1 == 0 && state.dataHeatBal->NumOfZoneLists > 0)
    6888            6 :                 ZLItem = Util::FindItemInList(s_ipsc->cAlphaArgs(3), state.dataHeatBal->ZoneList);
    6889           22 :             if (Item1 > 0) {
    6890           16 :                 if (s_ipsc->lAlphaFieldBlanks(4)) {
    6891           16 :                     ++NumIntMassSurf;
    6892              :                 }
    6893            6 :             } else if (ZLItem > 0) {
    6894            6 :                 NumIntMassSurf += state.dataHeatBal->ZoneList(ZLItem).NumOfZones;
    6895              :             }
    6896              : 
    6897           22 :             if (!s_ipsc->lAlphaFieldBlanks(4)) {
    6898            0 :                 Item1 = Util::FindItemInList(s_ipsc->cAlphaArgs(4), state.dataHeatBal->space);
    6899            0 :                 int SLItem = 0;
    6900            0 :                 if (Item1 == 0 && int(state.dataHeatBal->spaceList.size()) > 0)
    6901            0 :                     SLItem = Util::FindItemInList(s_ipsc->cAlphaArgs(4), state.dataHeatBal->spaceList);
    6902            0 :                 if (Item1 > 0) {
    6903            0 :                     ++NumIntMassSurf;
    6904            0 :                 } else if (SLItem > 0) {
    6905            0 :                     int numOfSpaces = int(state.dataHeatBal->spaceList(SLItem).numListSpaces);
    6906            0 :                     NumIntMassSurf += numOfSpaces;
    6907              :                 }
    6908              :             }
    6909              :         }
    6910           10 :         NumIntMassSurf = max(NumIntMassSurf, TotIntMass);
    6911           10 :         return NumIntMassSurf;
    6912              :     }
    6913              : 
    6914            0 :     void GetShadingSurfReflectanceData(EnergyPlusData &state, bool &ErrorsFound) // If errors found in input
    6915              :     {
    6916              : 
    6917              :         // SUBROUTINE INFORMATION:
    6918              :         //       AUTHOR         Fred Winkelmann
    6919              :         //       DATE WRITTEN   Sept 2003
    6920              : 
    6921              :         // PURPOSE OF THIS SUBROUTINE:
    6922              :         // Gets data for a Shading Surface Reflectance object.  This is only called when the
    6923              :         // Solar Distribution is to be calculated for reflectances.
    6924              : 
    6925              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    6926              :         int IOStat;                       // IO Status when calling get input subroutine
    6927              :         int NumAlpha;                     // Number of alpha names being passed
    6928              :         int NumProp;                      // Number of properties being passed
    6929              :         int TotShadingSurfaceReflectance; // Total Shading Surface Reflectance statements
    6930              :         int Loop;                         // DO loop index
    6931              :         int SurfNum;                      // Surface number
    6932              :         int GlConstrNum;                  // Glazing construction number
    6933              :         bool WrongSurfaceType;
    6934              : 
    6935            0 :         auto &s_ipsc = state.dataIPShortCut;
    6936              :         // For shading surfaces, initialize value of reflectance values to default values. These values
    6937              :         // may be overridden below for shading surfaces with an associated Shading Surface Reflectance object.
    6938            0 :         for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    6939            0 :             auto const &surf = state.dataSurface->Surface(SurfNum);
    6940            0 :             if (!(surf.Class == SurfaceClass::Shading || surf.Class == SurfaceClass::Detached_F || surf.Class == SurfaceClass::Detached_B ||
    6941            0 :                   surf.Class == SurfaceClass::Overhang || surf.Class == SurfaceClass::Fin))
    6942            0 :                 continue;
    6943            0 :             state.dataSurface->SurfShadowDiffuseSolRefl(SurfNum) = 0.2;
    6944            0 :             state.dataSurface->SurfShadowDiffuseVisRefl(SurfNum) = 0.2;
    6945            0 :             state.dataSurface->SurfShadowGlazingFrac(SurfNum) = 0.0;
    6946            0 :             state.dataSurface->SurfShadowGlazingConstruct(SurfNum) = 0;
    6947              :         }
    6948              : 
    6949              :         // Get the total number of Shading Surface Reflectance objects
    6950            0 :         s_ipsc->cCurrentModuleObject = "ShadingProperty:Reflectance";
    6951            0 :         TotShadingSurfaceReflectance = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
    6952              :         //  IF(TotShadingSurfaceReflectance.EQ.0) RETURN
    6953              : 
    6954            0 :         for (Loop = 1; Loop <= TotShadingSurfaceReflectance; ++Loop) {
    6955              : 
    6956            0 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    6957            0 :                                                                      s_ipsc->cCurrentModuleObject,
    6958              :                                                                      Loop,
    6959            0 :                                                                      s_ipsc->cAlphaArgs,
    6960              :                                                                      NumAlpha,
    6961            0 :                                                                      s_ipsc->rNumericArgs,
    6962              :                                                                      NumProp,
    6963              :                                                                      IOStat,
    6964            0 :                                                                      s_ipsc->lNumericFieldBlanks,
    6965            0 :                                                                      s_ipsc->lAlphaFieldBlanks,
    6966            0 :                                                                      s_ipsc->cAlphaFieldNames,
    6967            0 :                                                                      s_ipsc->cNumericFieldNames);
    6968            0 :             SurfNum = Util::FindItemInList(s_ipsc->cAlphaArgs(1), state.dataSurface->Surface, state.dataSurface->TotSurfaces);
    6969            0 :             if (SurfNum == 0) {
    6970            0 :                 ShowWarningError(state, format("{}=\"{}\", invalid specification", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
    6971            0 :                 ShowContinueError(state, format(".. not found {}=\"{}\".", s_ipsc->cAlphaFieldNames(1), s_ipsc->cAlphaArgs(1)));
    6972              :                 //      ErrorsFound =.TRUE.
    6973            0 :                 continue;
    6974              :             }
    6975              : 
    6976              :             // Check that associated surface is a shading surface
    6977            0 :             WrongSurfaceType = false;
    6978            0 :             auto const &surf = state.dataSurface->Surface(SurfNum);
    6979            0 :             if (!(surf.Class == SurfaceClass::Shading || surf.Class == SurfaceClass::Detached_F || surf.Class == SurfaceClass::Detached_B ||
    6980            0 :                   surf.Class == SurfaceClass::Overhang || surf.Class == SurfaceClass::Fin))
    6981            0 :                 WrongSurfaceType = true;
    6982            0 :             if (WrongSurfaceType) {
    6983            0 :                 ShowSevereError(
    6984              :                     state,
    6985            0 :                     format("GetShadingSurfReflectanceData: {}=\"{}\", surface is not a shading surface.", s_ipsc->cCurrentModuleObject, surf.Name));
    6986            0 :                 ErrorsFound = true;
    6987            0 :                 continue;
    6988              :             }
    6989              : 
    6990              :             // If associated surface is a shading surface, set reflectance values
    6991            0 :             state.dataSurface->SurfShadowGlazingFrac(SurfNum) = s_ipsc->rNumericArgs(3);
    6992            0 :             state.dataSurface->SurfShadowDiffuseSolRefl(SurfNum) = (1.0 - s_ipsc->rNumericArgs(3)) * s_ipsc->rNumericArgs(1);
    6993            0 :             state.dataSurface->SurfShadowDiffuseVisRefl(SurfNum) = (1.0 - s_ipsc->rNumericArgs(3)) * s_ipsc->rNumericArgs(2);
    6994            0 :             if (s_ipsc->rNumericArgs(3) > 0.0) {
    6995            0 :                 GlConstrNum = Util::FindItemInList(s_ipsc->cAlphaArgs(2), state.dataConstruction->Construct, state.dataHeatBal->TotConstructs);
    6996            0 :                 if (GlConstrNum == 0) {
    6997            0 :                     ShowSevereError(state,
    6998            0 :                                     format("{}=\"{}\", {} not found={}",
    6999            0 :                                            s_ipsc->cCurrentModuleObject,
    7000            0 :                                            state.dataSurface->Surface(SurfNum).Name,
    7001            0 :                                            s_ipsc->cAlphaFieldNames(2),
    7002            0 :                                            s_ipsc->cAlphaArgs(2)));
    7003            0 :                     ErrorsFound = true;
    7004              :                 } else {
    7005            0 :                     state.dataConstruction->Construct(GlConstrNum).IsUsed = true;
    7006              :                 }
    7007            0 :                 state.dataSurface->SurfShadowGlazingConstruct(SurfNum) = GlConstrNum;
    7008              :             }
    7009            0 :             SurfNum = Util::FindItemInList("Mir-" + s_ipsc->cAlphaArgs(1), state.dataSurface->Surface, state.dataSurface->TotSurfaces);
    7010            0 :             if (SurfNum == 0) continue;
    7011            0 :             state.dataSurface->SurfShadowGlazingFrac(SurfNum) = s_ipsc->rNumericArgs(3);
    7012            0 :             state.dataSurface->SurfShadowDiffuseSolRefl(SurfNum) = (1.0 - s_ipsc->rNumericArgs(3)) * s_ipsc->rNumericArgs(1);
    7013            0 :             state.dataSurface->SurfShadowDiffuseVisRefl(SurfNum) = (1.0 - s_ipsc->rNumericArgs(3)) * s_ipsc->rNumericArgs(2);
    7014            0 :             if (s_ipsc->rNumericArgs(3) > 0.0) {
    7015            0 :                 GlConstrNum = Util::FindItemInList(s_ipsc->cAlphaArgs(2), state.dataConstruction->Construct, state.dataHeatBal->TotConstructs);
    7016            0 :                 if (GlConstrNum != 0) {
    7017            0 :                     state.dataConstruction->Construct(GlConstrNum).IsUsed = true;
    7018              :                 }
    7019            0 :                 state.dataSurface->SurfShadowGlazingConstruct(SurfNum) = GlConstrNum;
    7020              :             }
    7021              : 
    7022              :         } // End of loop over Shading Surface Reflectance objects
    7023              : 
    7024              :         // Write reflectance values to .eio file.
    7025            0 :         print(state.files.eio,
    7026              :               "! <ShadingProperty Reflectance>,Shading Surface Name,Shading Type,Diffuse Solar Reflectance, Diffuse "
    7027              :               "Visible Reflectance,Surface Glazing Fraction,Surface Glazing Construction\n");
    7028              : 
    7029            0 :         for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    7030            0 :             auto const &surf = state.dataSurface->Surface(SurfNum);
    7031            0 :             if (!(surf.Class == SurfaceClass::Shading || surf.Class == SurfaceClass::Detached_F || surf.Class == SurfaceClass::Detached_B ||
    7032            0 :                   surf.Class == SurfaceClass::Overhang || surf.Class == SurfaceClass::Fin))
    7033            0 :                 continue;
    7034              : 
    7035            0 :             constexpr std::string_view fmt = "ShadingProperty Reflectance,{},{},{:.2R},{:.2R},{:.2R}, {}\n";
    7036            0 :             if (state.dataSurface->SurfShadowGlazingConstruct(SurfNum) != 0) {
    7037            0 :                 print(state.files.eio,
    7038              :                       fmt,
    7039            0 :                       surf.Name,
    7040            0 :                       cSurfaceClass(surf.Class),
    7041            0 :                       state.dataSurface->SurfShadowDiffuseSolRefl(SurfNum),
    7042            0 :                       state.dataSurface->SurfShadowDiffuseVisRefl(SurfNum),
    7043            0 :                       state.dataSurface->SurfShadowGlazingFrac(SurfNum),
    7044            0 :                       state.dataConstruction->Construct(state.dataSurface->SurfShadowGlazingConstruct(SurfNum)).Name);
    7045              :             } else {
    7046            0 :                 print(state.files.eio,
    7047              :                       fmt,
    7048            0 :                       surf.Name,
    7049            0 :                       cSurfaceClass(surf.Class),
    7050            0 :                       state.dataSurface->SurfShadowDiffuseSolRefl(SurfNum),
    7051            0 :                       state.dataSurface->SurfShadowDiffuseVisRefl(SurfNum),
    7052            0 :                       state.dataSurface->SurfShadowGlazingFrac(SurfNum),
    7053              :                       "N/A");
    7054              :             }
    7055              :         }
    7056            0 :     }
    7057              : 
    7058          224 :     void GetHTSurfExtVentedCavityData(EnergyPlusData &state, bool &ErrorsFound) // Error flag indicator (true if errors found)
    7059              :     {
    7060              : 
    7061              :         // SUBROUTINE INFORMATION:
    7062              :         //       AUTHOR         BGriffith
    7063              :         //       DATE WRITTEN   January 2005
    7064              : 
    7065              :         // PURPOSE OF THIS SUBROUTINE:
    7066              :         // load input data for Exterior Vented Cavity Special case for heat transfer surfaces
    7067              : 
    7068              :         // METHODOLOGY EMPLOYED:
    7069              :         // usual E+ input processes
    7070              : 
    7071              :         // REFERENCES:
    7072              :         // derived from SUBROUTINE GetTranspiredCollectorInput
    7073              : 
    7074              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    7075              :         int Item;          // Item to be "gotten"
    7076              :         int NumAlphas;     // Number of Alphas for each GetObjectItem call
    7077              :         int NumNumbers;    // Number of Numbers for each GetObjectItem call
    7078              :         int MaxNumAlphas;  // argument for call to GetObjectDefMaxArgs
    7079              :         int MaxNumNumbers; // argument for call to GetObjectDefMaxArgs
    7080              :         int Dummy;         // argument for call to GetObjectDefMaxArgs
    7081              :         int IOStatus;      // Used in GetObjectItem
    7082              :         int Found;
    7083              :         int AlphaOffset; // local temp var
    7084          224 :         std::string Roughness;
    7085              :         int ThisSurf;                   // do loop counter
    7086              :         Real64 AvgAzimuth;              // temp for error checking
    7087              :         Real64 AvgTilt;                 // temp for error checking
    7088          224 :         constexpr Real64 AZITOL = 15.0; // Degree Azimuth Angle Tolerance
    7089          224 :         constexpr Real64 TILTOL = 10.0; // Degree Tilt Angle Tolerance
    7090              :         int SurfID;                     // local surface "pointer"
    7091              : 
    7092          224 :         auto &s_ipsc = state.dataIPShortCut;
    7093          224 :         s_ipsc->cCurrentModuleObject = "SurfaceProperty:ExteriorNaturalVentedCavity";
    7094          224 :         state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, s_ipsc->cCurrentModuleObject, Dummy, MaxNumAlphas, MaxNumNumbers);
    7095              : 
    7096          224 :         if (MaxNumNumbers != 8) {
    7097            0 :             ShowSevereError(
    7098              :                 state,
    7099            0 :                 format("{}: Object Definition indicates not = 8 Number Objects, Number Indicated={}", s_ipsc->cCurrentModuleObject, MaxNumNumbers));
    7100            0 :             ErrorsFound = true;
    7101              :         }
    7102              : 
    7103          224 :         state.dataSurface->TotExtVentCav = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
    7104              : 
    7105          224 :         state.dataHeatBal->ExtVentedCavity.allocate(state.dataSurface->TotExtVentCav);
    7106              : 
    7107          224 :         for (Item = 1; Item <= state.dataSurface->TotExtVentCav; ++Item) {
    7108            0 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    7109            0 :                                                                      s_ipsc->cCurrentModuleObject,
    7110              :                                                                      Item,
    7111            0 :                                                                      s_ipsc->cAlphaArgs,
    7112              :                                                                      NumAlphas,
    7113            0 :                                                                      s_ipsc->rNumericArgs,
    7114              :                                                                      NumNumbers,
    7115              :                                                                      IOStatus,
    7116            0 :                                                                      s_ipsc->lNumericFieldBlanks,
    7117            0 :                                                                      s_ipsc->lAlphaFieldBlanks,
    7118            0 :                                                                      s_ipsc->cAlphaFieldNames,
    7119            0 :                                                                      s_ipsc->cNumericFieldNames);
    7120              :             // first handle cAlphaArgs
    7121            0 :             bool ErrorInName = false;
    7122            0 :             bool IsBlank = false;
    7123              : 
    7124            0 :             Util::VerifyName(state,
    7125            0 :                              s_ipsc->cAlphaArgs(1),
    7126            0 :                              state.dataHeatBal->ExtVentedCavity,
    7127              :                              Item - 1,
    7128              :                              ErrorInName,
    7129              :                              IsBlank,
    7130            0 :                              s_ipsc->cCurrentModuleObject + " Name");
    7131            0 :             if (ErrorInName) {
    7132            0 :                 ShowContinueError(state, "...cannot not duplicate other names");
    7133            0 :                 ErrorsFound = true;
    7134            0 :                 continue;
    7135              :             }
    7136            0 :             state.dataHeatBal->ExtVentedCavity(Item).Name = s_ipsc->cAlphaArgs(1);
    7137              : 
    7138            0 :             state.dataHeatBal->ExtVentedCavity(Item).OSCMName = s_ipsc->cAlphaArgs(2);
    7139            0 :             if (!s_ipsc->lAlphaFieldBlanks(2)) {
    7140            0 :                 Found = Util::FindItemInList(state.dataHeatBal->ExtVentedCavity(Item).OSCMName, state.dataSurface->OSCM, state.dataSurface->TotOSCM);
    7141            0 :                 if (Found == 0) {
    7142            0 :                     ShowSevereError(state,
    7143            0 :                                     format("{}=\"{}\", invalid {}=\"{}\".",
    7144            0 :                                            s_ipsc->cCurrentModuleObject,
    7145            0 :                                            state.dataHeatBal->ExtVentedCavity(Item).Name,
    7146            0 :                                            s_ipsc->cAlphaFieldNames(2),
    7147            0 :                                            s_ipsc->cAlphaArgs(2)));
    7148            0 :                     ErrorsFound = true;
    7149              :                 }
    7150              :             } else {
    7151            0 :                 Found = 0;
    7152            0 :                 ShowSevereError(state,
    7153            0 :                                 format("{}=\"{}\", invalid {} cannot be blank.",
    7154            0 :                                        s_ipsc->cCurrentModuleObject,
    7155            0 :                                        state.dataHeatBal->ExtVentedCavity(Item).Name,
    7156            0 :                                        s_ipsc->cAlphaFieldNames(2)));
    7157            0 :                 ErrorsFound = true;
    7158              :             }
    7159            0 :             state.dataHeatBal->ExtVentedCavity(Item).OSCMPtr = Found;
    7160              : 
    7161            0 :             Roughness = s_ipsc->cAlphaArgs(3);
    7162              :             // Select the correct Number for the associated ascii name for the roughness type
    7163            0 :             if (Util::SameString(Roughness, "VerySmooth")) {
    7164            0 :                 state.dataHeatBal->ExtVentedCavity(Item).BaffleRoughness = Material::SurfaceRoughness::VerySmooth;
    7165            0 :             } else if (Util::SameString(Roughness, "Smooth")) {
    7166            0 :                 state.dataHeatBal->ExtVentedCavity(Item).BaffleRoughness = Material::SurfaceRoughness::Smooth;
    7167            0 :             } else if (Util::SameString(Roughness, "MediumSmooth")) {
    7168            0 :                 state.dataHeatBal->ExtVentedCavity(Item).BaffleRoughness = Material::SurfaceRoughness::MediumSmooth;
    7169            0 :             } else if (Util::SameString(Roughness, "MediumRough")) {
    7170            0 :                 state.dataHeatBal->ExtVentedCavity(Item).BaffleRoughness = Material::SurfaceRoughness::MediumRough;
    7171            0 :             } else if (Util::SameString(Roughness, "Rough")) {
    7172            0 :                 state.dataHeatBal->ExtVentedCavity(Item).BaffleRoughness = Material::SurfaceRoughness::Rough;
    7173            0 :             } else if (Util::SameString(Roughness, "VeryRough")) {
    7174            0 :                 state.dataHeatBal->ExtVentedCavity(Item).BaffleRoughness = Material::SurfaceRoughness::VeryRough;
    7175              :             } // TODO: fix this after creating FindEnumeratedValueIndex()
    7176              : 
    7177              :             // Was it set?
    7178            0 :             if (state.dataHeatBal->ExtVentedCavity(Item).BaffleRoughness == Material::SurfaceRoughness::Invalid) {
    7179            0 :                 ShowSevereError(state,
    7180            0 :                                 format("{}=\"{}\", invalid {}=\"{}",
    7181            0 :                                        s_ipsc->cCurrentModuleObject,
    7182            0 :                                        state.dataHeatBal->ExtVentedCavity(Item).Name,
    7183            0 :                                        s_ipsc->cAlphaFieldNames(3),
    7184            0 :                                        s_ipsc->cAlphaArgs(3)));
    7185            0 :                 ErrorsFound = true;
    7186              :             }
    7187              : 
    7188            0 :             AlphaOffset = 3;
    7189            0 :             state.dataHeatBal->ExtVentedCavity(Item).NumSurfs = NumAlphas - AlphaOffset;
    7190            0 :             if (state.dataHeatBal->ExtVentedCavity(Item).NumSurfs == 0) {
    7191            0 :                 ShowSevereError(state,
    7192            0 :                                 format("{}=\"{}\", no underlying surfaces specified. Must have at least one.",
    7193            0 :                                        s_ipsc->cCurrentModuleObject,
    7194            0 :                                        state.dataHeatBal->ExtVentedCavity(Item).Name));
    7195            0 :                 ErrorsFound = true;
    7196            0 :                 continue;
    7197              :             }
    7198            0 :             state.dataHeatBal->ExtVentedCavity(Item).SurfPtrs.allocate(state.dataHeatBal->ExtVentedCavity(Item).NumSurfs);
    7199            0 :             state.dataHeatBal->ExtVentedCavity(Item).SurfPtrs = 0;
    7200            0 :             for (ThisSurf = 1; ThisSurf <= state.dataHeatBal->ExtVentedCavity(Item).NumSurfs; ++ThisSurf) {
    7201            0 :                 Found = Util::FindItemInList(s_ipsc->cAlphaArgs(ThisSurf + AlphaOffset), state.dataSurface->Surface, state.dataSurface->TotSurfaces);
    7202            0 :                 if (Found == 0) {
    7203            0 :                     ShowSevereError(state,
    7204            0 :                                     format("{}=\"{}\", invalid {}=\"{}",
    7205            0 :                                            s_ipsc->cCurrentModuleObject,
    7206            0 :                                            state.dataHeatBal->ExtVentedCavity(Item).Name,
    7207            0 :                                            s_ipsc->cAlphaFieldNames(ThisSurf + AlphaOffset),
    7208            0 :                                            s_ipsc->cAlphaArgs(ThisSurf + AlphaOffset)));
    7209            0 :                     ErrorsFound = true;
    7210            0 :                     continue;
    7211              :                 }
    7212              :                 // check that surface is appropriate, Heat transfer, Sun, Wind,
    7213            0 :                 if (!state.dataSurface->Surface(Found).HeatTransSurf) {
    7214            0 :                     ShowSevereError(state,
    7215            0 :                                     format("{}=\"{}\", invalid {}=\"{}",
    7216            0 :                                            s_ipsc->cCurrentModuleObject,
    7217            0 :                                            state.dataHeatBal->ExtVentedCavity(Item).Name,
    7218            0 :                                            s_ipsc->cAlphaFieldNames(ThisSurf + AlphaOffset),
    7219            0 :                                            s_ipsc->cAlphaArgs(ThisSurf + AlphaOffset)));
    7220            0 :                     ShowContinueError(state, "...because it is not a Heat Transfer Surface.");
    7221            0 :                     ErrorsFound = true;
    7222            0 :                     continue;
    7223              :                 }
    7224            0 :                 if (!state.dataSurface->Surface(Found).ExtSolar) {
    7225            0 :                     ShowSevereError(state,
    7226            0 :                                     format("{}=\"{}\", invalid {}=\"{}",
    7227            0 :                                            s_ipsc->cCurrentModuleObject,
    7228            0 :                                            state.dataHeatBal->ExtVentedCavity(Item).Name,
    7229            0 :                                            s_ipsc->cAlphaFieldNames(ThisSurf + AlphaOffset),
    7230            0 :                                            s_ipsc->cAlphaArgs(ThisSurf + AlphaOffset)));
    7231            0 :                     ShowContinueError(state, "...because it is not exposed to Sun.");
    7232            0 :                     ErrorsFound = true;
    7233            0 :                     continue;
    7234              :                 }
    7235            0 :                 if (!state.dataSurface->Surface(Found).ExtWind) {
    7236            0 :                     ShowSevereError(state,
    7237            0 :                                     format("{}=\"{}\", invalid {}=\"{}",
    7238            0 :                                            s_ipsc->cCurrentModuleObject,
    7239            0 :                                            state.dataHeatBal->ExtVentedCavity(Item).Name,
    7240            0 :                                            s_ipsc->cAlphaFieldNames(ThisSurf + AlphaOffset),
    7241            0 :                                            s_ipsc->cAlphaArgs(ThisSurf + AlphaOffset)));
    7242            0 :                     ShowContinueError(state, "...because it is not exposed to Wind.");
    7243            0 :                     ErrorsFound = true;
    7244            0 :                     continue;
    7245              :                 }
    7246            0 :                 if (state.dataSurface->Surface(Found).ExtBoundCond != DataSurfaces::OtherSideCondModeledExt) {
    7247            0 :                     ShowSevereError(state,
    7248            0 :                                     format("{}=\"{}\", is invalid", s_ipsc->cCurrentModuleObject, state.dataHeatBal->ExtVentedCavity(Item).Name));
    7249            0 :                     ShowContinueError(state,
    7250            0 :                                       format("...because {}=\"{}\".",
    7251            0 :                                              s_ipsc->cAlphaFieldNames(ThisSurf + AlphaOffset),
    7252            0 :                                              s_ipsc->cAlphaArgs(ThisSurf + AlphaOffset)));
    7253            0 :                     ShowContinueError(state, "...is not an OtherSideConditionedModel surface.");
    7254            0 :                     ErrorsFound = true;
    7255            0 :                     continue;
    7256              :                 }
    7257            0 :                 state.dataHeatBal->ExtVentedCavity(Item).SurfPtrs(ThisSurf) = Found;
    7258              : 
    7259              :                 // now set info in Surface structure
    7260            0 :                 state.dataSurface->SurfExtCavNum(Found) = Item;
    7261            0 :                 state.dataSurface->SurfExtCavityPresent(Found) = true;
    7262              :             }
    7263              : 
    7264            0 :             if (ErrorsFound) continue; // previous inner do loop may have detected problems that need to be cycle'd again to avoid crash
    7265              : 
    7266              :             // now that we should have all the surfaces, do some preparations and checks.
    7267              : 
    7268              :             // are they all similar tilt and azimuth? Issue warnings so people can do it if they really want
    7269            0 :             Real64 const surfaceArea(sum_sub(state.dataSurface->Surface, &SurfaceData::Area, state.dataHeatBal->ExtVentedCavity(Item).SurfPtrs));
    7270              :             //            AvgAzimuth = sum( Surface( ExtVentedCavity( Item ).SurfPtrs ).Azimuth * Surface( ExtVentedCavity( Item ).SurfPtrs
    7271              :             //).Area
    7272              :             //)
    7273              :             ///  sum(  Surface( ExtVentedCavity( Item ).SurfPtrs ).Area ); //Autodesk:F2C++ Array subscript usage: Replaced by below
    7274            0 :             AvgAzimuth = sum_product_sub(state.dataSurface->Surface,
    7275              :                                          &SurfaceData::Azimuth,
    7276              :                                          &SurfaceData::Area,
    7277            0 :                                          state.dataHeatBal->ExtVentedCavity(Item).SurfPtrs) /
    7278              :                          surfaceArea; // Autodesk:F2C++ Functions handle array subscript usage
    7279              :             //            AvgTilt = sum( Surface( ExtVentedCavity( Item ).SurfPtrs ).Tilt * Surface( ExtVentedCavity( Item ).SurfPtrs ).Area )
    7280              :             //            /
    7281              :             // sum(  Surface( ExtVentedCavity( Item ).SurfPtrs ).Area ); //Autodesk:F2C++ Array subscript usage: Replaced by below
    7282            0 :             AvgTilt = sum_product_sub(
    7283            0 :                           state.dataSurface->Surface, &SurfaceData::Tilt, &SurfaceData::Area, state.dataHeatBal->ExtVentedCavity(Item).SurfPtrs) /
    7284              :                       surfaceArea; // Autodesk:F2C++ Functions handle array subscript usage
    7285            0 :             for (ThisSurf = 1; ThisSurf <= state.dataHeatBal->ExtVentedCavity(Item).NumSurfs; ++ThisSurf) {
    7286            0 :                 SurfID = state.dataHeatBal->ExtVentedCavity(Item).SurfPtrs(ThisSurf);
    7287            0 :                 if (General::rotAzmDiffDeg(state.dataSurface->Surface(SurfID).Azimuth, AvgAzimuth) > AZITOL) {
    7288            0 :                     ShowWarningError(state,
    7289            0 :                                      format("{}=\"{}, Surface {} has Azimuth different from others in the associated group.",
    7290            0 :                                             s_ipsc->cCurrentModuleObject,
    7291            0 :                                             state.dataHeatBal->ExtVentedCavity(Item).Name,
    7292            0 :                                             state.dataSurface->Surface(SurfID).Name));
    7293              :                 }
    7294            0 :                 if (std::abs(state.dataSurface->Surface(SurfID).Tilt - AvgTilt) > TILTOL) {
    7295            0 :                     ShowWarningError(state,
    7296            0 :                                      format("{}=\"{}, Surface {} has Tilt different from others in the associated group.",
    7297            0 :                                             s_ipsc->cCurrentModuleObject,
    7298            0 :                                             state.dataHeatBal->ExtVentedCavity(Item).Name,
    7299            0 :                                             state.dataSurface->Surface(SurfID).Name));
    7300              :                 }
    7301              : 
    7302              :                 // test that there are no windows.  Now allow windows
    7303              :                 // If (Surface(SurfID)%GrossArea >  Surface(SurfID)%Area) Then
    7304              :                 //      Call ShowWarningError(state, 'Surface '//TRIM(Surface(SurfID)%name)//' has a subsurface whose area is not being ' &
    7305              :                 //         //'subtracted in the group of surfaces associated with '//TRIM(ExtVentedCavity(Item)%Name))
    7306              :                 // endif
    7307              :             }
    7308            0 :             state.dataHeatBal->ExtVentedCavity(Item).Tilt = AvgTilt;
    7309            0 :             state.dataHeatBal->ExtVentedCavity(Item).Azimuth = AvgAzimuth;
    7310              : 
    7311              :             // find area weighted centroid.
    7312              :             //            ExtVentedCavity( Item ).Centroid.z = sum( Surface( ExtVentedCavity( Item ).SurfPtrs ).Centroid.z * Surface(
    7313              :             // ExtVentedCavity(  Item
    7314              :             //).SurfPtrs ).Area ) / sum( Surface( ExtVentedCavity( Item ).SurfPtrs ).Area ); //Autodesk:F2C++ Array subscript usage: Replaced
    7315              :             // by below
    7316            0 :             state.dataHeatBal->ExtVentedCavity(Item).Centroid.z = sum_product_sub(state.dataSurface->Surface,
    7317              :                                                                                   &SurfaceData::Centroid,
    7318              :                                                                                   &Vector::z,
    7319            0 :                                                                                   state.dataSurface->Surface,
    7320              :                                                                                   &SurfaceData::Area,
    7321            0 :                                                                                   state.dataHeatBal->ExtVentedCavity(Item).SurfPtrs) /
    7322              :                                                                   surfaceArea; // Autodesk:F2C++ Functions handle array subscript usage
    7323              : 
    7324              :             // now handle rNumericArgs from input object
    7325            0 :             state.dataHeatBal->ExtVentedCavity(Item).Porosity = s_ipsc->rNumericArgs(1);
    7326            0 :             state.dataHeatBal->ExtVentedCavity(Item).LWEmitt = s_ipsc->rNumericArgs(2);
    7327            0 :             state.dataHeatBal->ExtVentedCavity(Item).SolAbsorp = s_ipsc->rNumericArgs(3);
    7328            0 :             state.dataHeatBal->ExtVentedCavity(Item).HdeltaNPL = s_ipsc->rNumericArgs(4);
    7329            0 :             state.dataHeatBal->ExtVentedCavity(Item).PlenGapThick = s_ipsc->rNumericArgs(5);
    7330            0 :             if (state.dataHeatBal->ExtVentedCavity(Item).PlenGapThick <= 0.0) {
    7331            0 :                 ShowSevereError(state, format("{}=\"{}\", invalid .", s_ipsc->cCurrentModuleObject, state.dataHeatBal->ExtVentedCavity(Item).Name));
    7332            0 :                 ErrorsFound = true;
    7333            0 :                 ShowContinueError(
    7334              :                     state,
    7335            0 :                     format("...because field \"{}\" must be greater than Zero=[{:.2T}].", s_ipsc->cNumericFieldNames(5), s_ipsc->rNumericArgs(5)));
    7336            0 :                 continue;
    7337              :             }
    7338            0 :             state.dataHeatBal->ExtVentedCavity(Item).AreaRatio = s_ipsc->rNumericArgs(6);
    7339            0 :             state.dataHeatBal->ExtVentedCavity(Item).Cv = s_ipsc->rNumericArgs(7);
    7340            0 :             state.dataHeatBal->ExtVentedCavity(Item).Cd = s_ipsc->rNumericArgs(8);
    7341              : 
    7342              :             // Fill out data we now know
    7343              :             // sum areas of HT surface areas
    7344              :             //            ExtVentedCavity( Item ).ProjArea = sum( Surface( ExtVentedCavity( Item ).SurfPtrs ).Area ); //Autodesk:F2C++ Array
    7345              :             // subscript  usage: Replaced by below
    7346            0 :             state.dataHeatBal->ExtVentedCavity(Item).ProjArea = surfaceArea;
    7347            0 :             if (state.dataHeatBal->ExtVentedCavity(Item).ProjArea <= 0.0) {
    7348            0 :                 ShowSevereError(state, format("{}=\"{}\", invalid .", s_ipsc->cCurrentModuleObject, state.dataHeatBal->ExtVentedCavity(Item).Name));
    7349            0 :                 ErrorsFound = true;
    7350            0 :                 ShowContinueError(state,
    7351            0 :                                   format("...because gross area of underlying surfaces must be greater than Zero=[{:.2T}].",
    7352            0 :                                          state.dataHeatBal->ExtVentedCavity(Item).ProjArea));
    7353            0 :                 continue;
    7354              :             }
    7355            0 :             state.dataHeatBal->ExtVentedCavity(Item).ActualArea =
    7356            0 :                 state.dataHeatBal->ExtVentedCavity(Item).ProjArea * state.dataHeatBal->ExtVentedCavity(Item).AreaRatio;
    7357              : 
    7358            0 :             SetupOutputVariable(state,
    7359              :                                 "Surface Exterior Cavity Baffle Surface Temperature",
    7360              :                                 Constant::Units::C,
    7361            0 :                                 state.dataHeatBal->ExtVentedCavity(Item).Tbaffle,
    7362              :                                 OutputProcessor::TimeStepType::System,
    7363              :                                 OutputProcessor::StoreType::Average,
    7364            0 :                                 state.dataHeatBal->ExtVentedCavity(Item).Name);
    7365            0 :             SetupOutputVariable(state,
    7366              :                                 "Surface Exterior Cavity Air Drybulb Temperature",
    7367              :                                 Constant::Units::C,
    7368            0 :                                 state.dataHeatBal->ExtVentedCavity(Item).TAirCav,
    7369              :                                 OutputProcessor::TimeStepType::System,
    7370              :                                 OutputProcessor::StoreType::Average,
    7371            0 :                                 state.dataHeatBal->ExtVentedCavity(Item).Name);
    7372            0 :             SetupOutputVariable(state,
    7373              :                                 "Surface Exterior Cavity Total Natural Ventilation Air Change Rate",
    7374              :                                 Constant::Units::ach,
    7375            0 :                                 state.dataHeatBal->ExtVentedCavity(Item).PassiveACH,
    7376              :                                 OutputProcessor::TimeStepType::System,
    7377              :                                 OutputProcessor::StoreType::Average,
    7378            0 :                                 state.dataHeatBal->ExtVentedCavity(Item).Name);
    7379            0 :             SetupOutputVariable(state,
    7380              :                                 "Surface Exterior Cavity Total Natural Ventilation Mass Flow Rate",
    7381              :                                 Constant::Units::kg_s,
    7382            0 :                                 state.dataHeatBal->ExtVentedCavity(Item).PassiveMdotVent,
    7383              :                                 OutputProcessor::TimeStepType::System,
    7384              :                                 OutputProcessor::StoreType::Average,
    7385            0 :                                 state.dataHeatBal->ExtVentedCavity(Item).Name);
    7386            0 :             SetupOutputVariable(state,
    7387              :                                 "Surface Exterior Cavity Natural Ventilation from Wind Mass Flow Rate",
    7388              :                                 Constant::Units::kg_s,
    7389            0 :                                 state.dataHeatBal->ExtVentedCavity(Item).PassiveMdotWind,
    7390              :                                 OutputProcessor::TimeStepType::System,
    7391              :                                 OutputProcessor::StoreType::Average,
    7392            0 :                                 state.dataHeatBal->ExtVentedCavity(Item).Name);
    7393            0 :             SetupOutputVariable(state,
    7394              :                                 "Surface Exterior Cavity Natural Ventilation from Buoyancy Mass Flow Rate",
    7395              :                                 Constant::Units::kg_s,
    7396            0 :                                 state.dataHeatBal->ExtVentedCavity(Item).PassiveMdotTherm,
    7397              :                                 OutputProcessor::TimeStepType::System,
    7398              :                                 OutputProcessor::StoreType::Average,
    7399            0 :                                 state.dataHeatBal->ExtVentedCavity(Item).Name);
    7400              :         }
    7401          224 :     }
    7402              : 
    7403          224 :     void ExposedFoundationPerimeter::getData(EnergyPlusData &state, bool &ErrorsFound)
    7404              :     {
    7405              : 
    7406              :         static constexpr std::string_view routineName = "ExposedFoundationPerimeter::getData";
    7407              :         int IOStatus; // Used in GetObjectItem
    7408              :         int NumAlphas;
    7409              :         int NumNumbers;
    7410              : 
    7411          224 :         Real64 constexpr tolerance = 1e-6;
    7412              : 
    7413          224 :         auto &s_ipsc = state.dataIPShortCut;
    7414              : 
    7415          224 :         s_ipsc->cCurrentModuleObject = "SurfaceProperty:ExposedFoundationPerimeter";
    7416          224 :         int numObjects = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
    7417              : 
    7418          224 :         for (int obj = 1; obj <= numObjects; ++obj) {
    7419            0 :             int alpF = 1;
    7420            0 :             int numF = 1;
    7421            0 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    7422            0 :                                                                      s_ipsc->cCurrentModuleObject,
    7423              :                                                                      obj,
    7424            0 :                                                                      s_ipsc->cAlphaArgs,
    7425              :                                                                      NumAlphas,
    7426            0 :                                                                      s_ipsc->rNumericArgs,
    7427              :                                                                      NumNumbers,
    7428              :                                                                      IOStatus,
    7429            0 :                                                                      s_ipsc->lNumericFieldBlanks,
    7430            0 :                                                                      s_ipsc->lAlphaFieldBlanks,
    7431            0 :                                                                      s_ipsc->cAlphaFieldNames,
    7432            0 :                                                                      s_ipsc->cNumericFieldNames);
    7433              : 
    7434            0 :             ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(alpF)};
    7435              : 
    7436            0 :             int Found = Util::FindItemInList(s_ipsc->cAlphaArgs(alpF), state.dataSurface->Surface, state.dataSurface->TotSurfaces);
    7437            0 :             if (Found == 0) {
    7438            0 :                 ShowSevereError(state, format("{}=\"{}\", did not find matching surface", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
    7439            0 :                 ErrorsFound = true;
    7440              :             }
    7441            0 :             alpF++;
    7442            0 :             if (state.dataSurface->Surface(Found).Class != SurfaceClass::Floor) {
    7443            0 :                 ShowWarningError(
    7444            0 :                     state, format("{}: {}, surface is not a floor surface", s_ipsc->cCurrentModuleObject, state.dataSurface->Surface(Found).Name));
    7445            0 :                 ShowContinueError(state, format("{} will not be used", s_ipsc->cCurrentModuleObject));
    7446            0 :                 continue;
    7447              :             }
    7448              : 
    7449              :             // Choose calculation method
    7450              : 
    7451              :             enum class CalculationMethod
    7452              :             {
    7453              :                 Invalid = -1,
    7454              :                 TotalExposedPerimeter,
    7455              :                 ExposedPerimeterFraction,
    7456              :                 Bysegment,
    7457              :                 Num
    7458              :             };
    7459              : 
    7460            0 :             constexpr std::array<std::string_view, static_cast<int>(CalculationMethod::Num)> CalculationMethodUC = {
    7461              :                 "TOTALEXPOSEDPERIMETER", "EXPOSEDPERIMETERFRACTION", "BYSEGMENT"};
    7462            0 :             CalculationMethod calculationMethod = static_cast<CalculationMethod>(getEnumValue(CalculationMethodUC, s_ipsc->cAlphaArgs(alpF)));
    7463            0 :             if (calculationMethod != CalculationMethod::TotalExposedPerimeter && calculationMethod != CalculationMethod::ExposedPerimeterFraction &&
    7464            0 :                 calculationMethod != CalculationMethod::Bysegment) {
    7465            0 :                 ShowSevereError(state,
    7466            0 :                                 format("{}=\"{}\", {} is not a valid choice for {}",
    7467            0 :                                        s_ipsc->cCurrentModuleObject,
    7468            0 :                                        s_ipsc->cAlphaArgs(1),
    7469              :                                        calculationMethod,
    7470            0 :                                        s_ipsc->cAlphaFieldNames(alpF)));
    7471            0 :                 ErrorsFound = true;
    7472              :             }
    7473            0 :             alpF++;
    7474              : 
    7475            0 :             Data data;
    7476            0 :             data.useDetailedExposedPerimeter = true;
    7477              : 
    7478            0 :             if (!s_ipsc->lNumericFieldBlanks(numF)) {
    7479            0 :                 if (calculationMethod == CalculationMethod::TotalExposedPerimeter) {
    7480            0 :                     data.exposedFraction = s_ipsc->rNumericArgs(numF) / state.dataSurface->Surface(Found).Perimeter;
    7481            0 :                     if (data.exposedFraction > 1 + tolerance) {
    7482            0 :                         ShowWarningError(state,
    7483            0 :                                          format("{}: {}, {} is greater than the perimeter of {}",
    7484            0 :                                                 s_ipsc->cCurrentModuleObject,
    7485            0 :                                                 state.dataSurface->Surface(Found).Name,
    7486            0 :                                                 s_ipsc->cNumericFieldNames(numF),
    7487            0 :                                                 state.dataSurface->Surface(Found).Name));
    7488            0 :                         ShowContinueError(state,
    7489            0 :                                           format("{} perimeter = {}, {} exposed perimeter = {}",
    7490            0 :                                                  state.dataSurface->Surface(Found).Name,
    7491            0 :                                                  state.dataSurface->Surface(Found).Perimeter,
    7492            0 :                                                  s_ipsc->cCurrentModuleObject,
    7493            0 :                                                  s_ipsc->rNumericArgs(numF)));
    7494            0 :                         ShowContinueError(
    7495              :                             state,
    7496            0 :                             format("{} will be set equal to {} perimeter", s_ipsc->cNumericFieldNames(numF), state.dataSurface->Surface(Found).Name));
    7497            0 :                         data.exposedFraction = 1.0;
    7498              :                     }
    7499              : 
    7500            0 :                     data.useDetailedExposedPerimeter = false;
    7501              :                 } else {
    7502            0 :                     ShowWarningError(state,
    7503            0 :                                      format("{}: {}, {} set as calculation method, but a value has been set for {}. This value will be ignored.",
    7504            0 :                                             s_ipsc->cCurrentModuleObject,
    7505            0 :                                             state.dataSurface->Surface(Found).Name,
    7506              :                                             calculationMethod,
    7507            0 :                                             s_ipsc->cNumericFieldNames(numF)));
    7508              :                 }
    7509              :             } else {
    7510            0 :                 if (calculationMethod == CalculationMethod::TotalExposedPerimeter) {
    7511            0 :                     ShowSevereError(state,
    7512            0 :                                     format("{}: {}, {} set as calculation method, but no value has been set for {}",
    7513            0 :                                            s_ipsc->cCurrentModuleObject,
    7514            0 :                                            state.dataSurface->Surface(Found).Name,
    7515              :                                            calculationMethod,
    7516            0 :                                            s_ipsc->cNumericFieldNames(numF)));
    7517            0 :                     ErrorsFound = true;
    7518              :                 }
    7519              :             }
    7520            0 :             numF++;
    7521              : 
    7522            0 :             if (!s_ipsc->lNumericFieldBlanks(numF)) {
    7523            0 :                 if (calculationMethod == CalculationMethod::ExposedPerimeterFraction) {
    7524            0 :                     data.exposedFraction = s_ipsc->rNumericArgs(numF);
    7525            0 :                     data.useDetailedExposedPerimeter = false;
    7526              :                 } else {
    7527            0 :                     ShowWarningError(state,
    7528            0 :                                      format("{}: {}, {} set as calculation method, but a value has been set for {}. This value will be ignored.",
    7529            0 :                                             s_ipsc->cCurrentModuleObject,
    7530            0 :                                             state.dataSurface->Surface(Found).Name,
    7531              :                                             calculationMethod,
    7532            0 :                                             s_ipsc->cNumericFieldNames(numF)));
    7533              :                 }
    7534              :             } else {
    7535            0 :                 if (calculationMethod == CalculationMethod::ExposedPerimeterFraction) {
    7536            0 :                     ShowSevereError(state,
    7537            0 :                                     format("{}: {}, {} set as calculation method, but no value has been set for {}",
    7538            0 :                                            s_ipsc->cCurrentModuleObject,
    7539            0 :                                            state.dataSurface->Surface(Found).Name,
    7540              :                                            calculationMethod,
    7541            0 :                                            s_ipsc->cNumericFieldNames(numF)));
    7542            0 :                     ErrorsFound = true;
    7543              :                 }
    7544              :             }
    7545            0 :             numF++;
    7546              : 
    7547            0 :             int numRemainingFields = NumAlphas - (alpF - 1) + NumNumbers - (numF - 1);
    7548            0 :             if (numRemainingFields > 0) {
    7549            0 :                 if (calculationMethod == CalculationMethod::Bysegment) {
    7550            0 :                     if (numRemainingFields != (int)state.dataSurface->Surface(Found).Vertex.size()) {
    7551            0 :                         ShowSevereError(state,
    7552            0 :                                         format("{}: {}, must have equal number of segments as the floor has vertices.{}\" and \"{}\"",
    7553            0 :                                                s_ipsc->cCurrentModuleObject,
    7554            0 :                                                state.dataSurface->Surface(Found).Name,
    7555            0 :                                                s_ipsc->cAlphaFieldNames(alpF),
    7556            0 :                                                s_ipsc->cNumericFieldNames(numF - 1)));
    7557            0 :                         ShowContinueError(state,
    7558            0 :                                           format("{} number of vertices = {}, {} number of segments = {}",
    7559            0 :                                                  state.dataSurface->Surface(Found).Name,
    7560            0 :                                                  state.dataSurface->Surface(Found).Vertex.size(),
    7561            0 :                                                  s_ipsc->cCurrentModuleObject,
    7562              :                                                  numRemainingFields));
    7563            0 :                         ErrorsFound = true;
    7564              :                     }
    7565            0 :                     for (int segNum = 0; segNum < numRemainingFields; segNum++) {
    7566            0 :                         if (s_ipsc->lAlphaFieldBlanks(alpF)) {
    7567            0 :                             ShowSevereEmptyField(
    7568            0 :                                 state, eoh, s_ipsc->cAlphaFieldNames(alpF), "Calculation Method", CalculationMethodUC[(int)calculationMethod]);
    7569            0 :                             ErrorsFound = true;
    7570            0 :                         } else if (BooleanSwitch bs = getYesNoValue(s_ipsc->cAlphaArgs(alpF)); bs != BooleanSwitch::Invalid) {
    7571            0 :                             data.isExposedPerimeter.push_back(static_cast<bool>(bs));
    7572              :                         } else {
    7573            0 :                             ShowSevereInvalidBool(state, eoh, s_ipsc->cAlphaFieldNames(alpF), s_ipsc->cAlphaArgs(alpF));
    7574            0 :                             ErrorsFound = true;
    7575              :                         }
    7576            0 :                         alpF++;
    7577              :                     }
    7578              :                 }
    7579              :             } else {
    7580            0 :                 if (calculationMethod == CalculationMethod::Bysegment) {
    7581            0 :                     ShowSevereError(state,
    7582            0 :                                     format("{}: {}, {} set as calculation method, but no values have been set for Surface Segments Exposed",
    7583            0 :                                            s_ipsc->cCurrentModuleObject,
    7584            0 :                                            state.dataSurface->Surface(Found).Name,
    7585              :                                            calculationMethod));
    7586            0 :                     ErrorsFound = true;
    7587              :                 }
    7588              :             }
    7589            0 :             surfaceMap[Found] = data;
    7590            0 :         }
    7591          224 :     }
    7592              : 
    7593          224 :     void GetSurfaceLocalEnvData(EnergyPlusData &state, bool &ErrorsFound) // Error flag indicator (true if errors found)
    7594              :     {
    7595              :         // SUBROUTINE INFORMATION:
    7596              :         //       AUTHOR         X LUO
    7597              :         //       DATE WRITTEN   July 2017
    7598              : 
    7599              :         // PURPOSE OF THIS SUBROUTINE:
    7600              :         // load input data for Outdoor Air Node for exterior surfaces
    7601              : 
    7602              :         // SUBROUTINE PARAMETER DEFINITIONS:
    7603              :         static constexpr std::string_view RoutineName("GetSurfaceLocalEnvData: ");
    7604              :         static constexpr std::string_view routineName = "GetSurfaceLocalEnvData";
    7605              : 
    7606          224 :         auto &s_ipsc = state.dataIPShortCut;
    7607              : 
    7608          224 :         s_ipsc->cCurrentModuleObject = "SurfaceProperty:LocalEnvironment";
    7609          224 :         state.dataSurface->TotSurfLocalEnv = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
    7610              : 
    7611          224 :         if (state.dataSurface->TotSurfLocalEnv > 0) {
    7612              :             int NumAlpha;
    7613              :             int NumNumeric;
    7614              :             int IOStat;
    7615              : 
    7616           13 :             state.dataGlobal->AnyLocalEnvironmentsInModel = true;
    7617              : 
    7618           13 :             if (!allocated(state.dataSurface->SurfLocalEnvironment)) {
    7619           13 :                 state.dataSurface->SurfLocalEnvironment.allocate(state.dataSurface->TotSurfLocalEnv);
    7620              :             }
    7621              : 
    7622           36 :             for (int Loop = 1; Loop <= state.dataSurface->TotSurfLocalEnv; ++Loop) {
    7623              : 
    7624           23 :                 auto &SurfLocalEnv = state.dataSurface->SurfLocalEnvironment(Loop);
    7625              : 
    7626           46 :                 state.dataInputProcessing->inputProcessor->getObjectItem(state,
    7627           23 :                                                                          s_ipsc->cCurrentModuleObject,
    7628              :                                                                          Loop,
    7629           23 :                                                                          s_ipsc->cAlphaArgs,
    7630              :                                                                          NumAlpha,
    7631           23 :                                                                          s_ipsc->rNumericArgs,
    7632              :                                                                          NumNumeric,
    7633              :                                                                          IOStat,
    7634           23 :                                                                          s_ipsc->lNumericFieldBlanks,
    7635           23 :                                                                          s_ipsc->lAlphaFieldBlanks,
    7636           23 :                                                                          s_ipsc->cAlphaFieldNames,
    7637           23 :                                                                          s_ipsc->cNumericFieldNames);
    7638              : 
    7639           23 :                 ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
    7640              : 
    7641           23 :                 Util::IsNameEmpty(state, s_ipsc->cAlphaArgs(1), s_ipsc->cCurrentModuleObject, ErrorsFound);
    7642              : 
    7643           23 :                 SurfLocalEnv.Name = s_ipsc->cAlphaArgs(1);
    7644              : 
    7645              :                 // Assign surface number
    7646           23 :                 int SurfNum = Util::FindItemInList(s_ipsc->cAlphaArgs(2), state.dataSurface->Surface);
    7647           23 :                 if (SurfNum == 0) {
    7648            0 :                     ShowSevereError(state,
    7649            0 :                                     format("{} {} = \"{}\", object. Illegal value for \"{}\" has been found.",
    7650              :                                            RoutineName,
    7651            0 :                                            s_ipsc->cCurrentModuleObject,
    7652            0 :                                            SurfLocalEnv.Name,
    7653            0 :                                            s_ipsc->cAlphaFieldNames(2)));
    7654            0 :                     ShowContinueError(state,
    7655            0 :                                       format("{} entered value = \"{}\", no corresponding surface (ref BuildingSurface:Detailed) has been "
    7656              :                                              "found in the input file.",
    7657            0 :                                              s_ipsc->cAlphaFieldNames(2),
    7658            0 :                                              s_ipsc->cAlphaArgs(2)));
    7659            0 :                     ErrorsFound = true;
    7660              :                 } else {
    7661           23 :                     SurfLocalEnv.SurfPtr = SurfNum;
    7662              :                 }
    7663              : 
    7664              :                 // Assign Sunlit Fraction Schedule number
    7665           23 :                 if (s_ipsc->lAlphaFieldBlanks(3)) {
    7666            1 :                 } else if ((SurfLocalEnv.sunlitFracSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(3))) == nullptr) {
    7667            0 :                     ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3));
    7668            0 :                     ErrorsFound = true;
    7669              :                 }
    7670              : 
    7671              :                 // Assign surrounding surfaces object number;
    7672           23 :                 if (!s_ipsc->lAlphaFieldBlanks(4)) {
    7673           21 :                     int SurroundingSurfsNum = Util::FindItemInList(s_ipsc->cAlphaArgs(4), state.dataSurface->SurroundingSurfsProperty);
    7674           21 :                     if (SurroundingSurfsNum == 0) {
    7675            0 :                         ShowSevereError(state,
    7676            0 :                                         format("{} {} = \"{}\", object. Illegal value for \"{}\" has been found.",
    7677              :                                                RoutineName,
    7678            0 :                                                s_ipsc->cCurrentModuleObject,
    7679            0 :                                                SurfLocalEnv.Name,
    7680            0 :                                                s_ipsc->cAlphaFieldNames(4)));
    7681            0 :                         ShowContinueError(state,
    7682            0 :                                           format("{} entered value = \"{}\", no corresponding surrounding surfaces properties has been found "
    7683              :                                                  "in the input file.",
    7684            0 :                                                  s_ipsc->cAlphaFieldNames(4),
    7685            0 :                                                  s_ipsc->cAlphaArgs(4)));
    7686            0 :                         ErrorsFound = true;
    7687              :                     } else {
    7688           21 :                         SurfLocalEnv.SurroundingSurfsPtr = SurroundingSurfsNum;
    7689              :                     }
    7690              :                 }
    7691              : 
    7692              :                 // Assign outdoor air node number;
    7693           23 :                 if (!s_ipsc->lAlphaFieldBlanks(5)) {
    7694            1 :                     int NodeNum = GetOnlySingleNode(state,
    7695            1 :                                                     s_ipsc->cAlphaArgs(5),
    7696              :                                                     ErrorsFound,
    7697              :                                                     DataLoopNode::ConnectionObjectType::SurfacePropertyLocalEnvironment,
    7698            1 :                                                     SurfLocalEnv.Name,
    7699              :                                                     DataLoopNode::NodeFluidType::Air,
    7700              :                                                     DataLoopNode::ConnectionType::Inlet,
    7701              :                                                     NodeInputManager::CompFluidStream::Primary,
    7702              :                                                     DataLoopNode::ObjectIsParent);
    7703            1 :                     if (NodeNum == 0 && OutAirNodeManager::CheckOutAirNodeNumber(state, NodeNum)) {
    7704            0 :                         ShowSevereError(state,
    7705            0 :                                         format("{} {} = \"{}\", object. Illegal value for \"{}\" has been found.",
    7706              :                                                RoutineName,
    7707            0 :                                                s_ipsc->cCurrentModuleObject,
    7708            0 :                                                SurfLocalEnv.Name,
    7709            0 :                                                s_ipsc->cAlphaFieldNames(5)));
    7710            0 :                         ShowContinueError(state,
    7711            0 :                                           format("{} entered value = \"{}\", no corresponding outdoor air node has been found in the input file.",
    7712            0 :                                                  s_ipsc->cAlphaFieldNames(5),
    7713            0 :                                                  s_ipsc->cAlphaArgs(5)));
    7714            0 :                         ErrorsFound = true;
    7715              :                     } else {
    7716            1 :                         SurfLocalEnv.OutdoorAirNodePtr = NodeNum;
    7717              :                     }
    7718              :                 }
    7719              : 
    7720              :                 // get ground surfaces object number;
    7721           23 :                 if (!s_ipsc->lAlphaFieldBlanks(6)) {
    7722           12 :                     int GndSurfsNum = Util::FindItemInList(s_ipsc->cAlphaArgs(6), state.dataSurface->GroundSurfsProperty);
    7723           12 :                     if (GndSurfsNum == 0) {
    7724            0 :                         ShowSevereError(state,
    7725            0 :                                         format("{} {} = \"{}\", object. Illegal value for \"{}\" has been found.",
    7726              :                                                RoutineName,
    7727            0 :                                                s_ipsc->cCurrentModuleObject,
    7728            0 :                                                SurfLocalEnv.Name,
    7729            0 :                                                s_ipsc->cAlphaFieldNames(6)));
    7730            0 :                         ShowContinueError(
    7731              :                             state,
    7732            0 :                             format("{} entered value = \"{}\", no corresponding ground surfaces object has been found in the input file.",
    7733            0 :                                    s_ipsc->cAlphaFieldNames(6),
    7734            0 :                                    s_ipsc->cAlphaArgs(6)));
    7735            0 :                         ErrorsFound = true;
    7736              :                     } else {
    7737           12 :                         SurfLocalEnv.GroundSurfsPtr = GndSurfsNum;
    7738              :                     }
    7739              :                 }
    7740              :             }
    7741              :         }
    7742              :         // Link surface properties to surface object
    7743         2486 :         for (int SurfLoop = 1; SurfLoop <= state.dataSurface->TotSurfaces; ++SurfLoop) {
    7744         2376 :             for (int Loop = 1; Loop <= state.dataSurface->TotSurfLocalEnv; ++Loop) {
    7745          114 :                 auto const &SurfLocalEnv = state.dataSurface->SurfLocalEnvironment(Loop);
    7746          114 :                 if (SurfLocalEnv.SurfPtr == SurfLoop) {
    7747           23 :                     auto &surface = state.dataSurface->Surface(SurfLoop);
    7748           23 :                     if (SurfLocalEnv.OutdoorAirNodePtr != 0) {
    7749            1 :                         surface.SurfLinkedOutAirNode = SurfLocalEnv.OutdoorAirNodePtr;
    7750              :                     }
    7751           23 :                     if (SurfLocalEnv.sunlitFracSched != nullptr) {
    7752            1 :                         surface.SurfSchedExternalShadingFrac = true;
    7753            1 :                         surface.surfExternalShadingSched = SurfLocalEnv.sunlitFracSched;
    7754              :                     }
    7755           23 :                     if (SurfLocalEnv.SurroundingSurfsPtr != 0) {
    7756           21 :                         surface.SurfHasSurroundingSurfProperty = true;
    7757           21 :                         surface.SurfSurroundingSurfacesNum = SurfLocalEnv.SurroundingSurfsPtr;
    7758           21 :                         surface.ViewFactorSrdSurfs =
    7759           21 :                             state.dataSurface->SurroundingSurfsProperty(surface.SurfSurroundingSurfacesNum).SurfsViewFactorSum;
    7760           21 :                         if (surface.ViewFactorSrdSurfs == 0.0) {
    7761            0 :                             surface.SurfHasSurroundingSurfProperty = false;
    7762              :                         }
    7763              :                     }
    7764           23 :                     if (SurfLocalEnv.GroundSurfsPtr != 0) {
    7765           12 :                         surface.IsSurfPropertyGndSurfacesDefined = true;
    7766           12 :                         surface.UseSurfPropertyGndSurfTemp = true;
    7767           12 :                         surface.UseSurfPropertyGndSurfRefl = true;
    7768           12 :                         surface.SurfPropertyGndSurfIndex = SurfLocalEnv.GroundSurfsPtr;
    7769              :                     }
    7770              :                 }
    7771              :             }
    7772              :         }
    7773          224 :     }
    7774              : 
    7775          224 :     void GetSurfaceSrdSurfsData(EnergyPlusData &state, bool &ErrorsFound) // Error flag indicator (true if errors found)
    7776              :     {
    7777              :         // SUBROUTINE INFORMATION:
    7778              :         //       AUTHOR         X LUO
    7779              :         //       DATE WRITTEN   July 2017
    7780              : 
    7781              :         // PURPOSE OF THIS SUBROUTINE:
    7782              :         // load input data for surrounding surfaces properties for exterior surfaces
    7783          224 :         constexpr std::string_view routineName = "GetSurfaceSrdSurfsData";
    7784              : 
    7785          224 :         auto &s_ipsc = state.dataIPShortCut;
    7786              : 
    7787          224 :         s_ipsc->cCurrentModuleObject = "SurfaceProperty:SurroundingSurfaces";
    7788          224 :         int TotSrdSurfProperties = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
    7789              : 
    7790          224 :         if (TotSrdSurfProperties > 0) {
    7791              :             int NumAlpha;
    7792              :             int NumNumeric;
    7793              :             int IOStat;
    7794              : 
    7795           11 :             if (!allocated(state.dataSurface->SurroundingSurfsProperty)) {
    7796           11 :                 state.dataSurface->SurroundingSurfsProperty.allocate(TotSrdSurfProperties);
    7797              :             }
    7798              : 
    7799           32 :             for (int Loop = 1; Loop <= TotSrdSurfProperties; ++Loop) {
    7800              : 
    7801           21 :                 auto &SrdSurfsProp = state.dataSurface->SurroundingSurfsProperty(Loop);
    7802              : 
    7803           42 :                 state.dataInputProcessing->inputProcessor->getObjectItem(state,
    7804           21 :                                                                          s_ipsc->cCurrentModuleObject,
    7805              :                                                                          Loop,
    7806           21 :                                                                          s_ipsc->cAlphaArgs,
    7807              :                                                                          NumAlpha,
    7808           21 :                                                                          s_ipsc->rNumericArgs,
    7809              :                                                                          NumNumeric,
    7810              :                                                                          IOStat,
    7811           21 :                                                                          s_ipsc->lNumericFieldBlanks,
    7812           21 :                                                                          s_ipsc->lAlphaFieldBlanks,
    7813           21 :                                                                          s_ipsc->cAlphaFieldNames,
    7814           21 :                                                                          s_ipsc->cNumericFieldNames);
    7815              : 
    7816           21 :                 ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
    7817              : 
    7818           21 :                 Util::IsNameEmpty(state, s_ipsc->cAlphaArgs(1), s_ipsc->cCurrentModuleObject, ErrorsFound);
    7819              : 
    7820              :                 // A1: Name
    7821           21 :                 SrdSurfsProp.Name = s_ipsc->cAlphaArgs(1);
    7822              : 
    7823              :                 // N1: sky view factor
    7824           21 :                 if (!s_ipsc->lNumericFieldBlanks(1)) {
    7825           16 :                     SrdSurfsProp.SkyViewFactor = s_ipsc->rNumericArgs(1);
    7826           16 :                     SrdSurfsProp.IsSkyViewFactorSet = true;
    7827              :                 }
    7828              : 
    7829              :                 // A2: sky temp sch name
    7830           21 :                 if (s_ipsc->lAlphaFieldBlanks(2)) {
    7831           15 :                 } else if ((SrdSurfsProp.skyTempSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(2))) == nullptr) {
    7832            5 :                     ShowWarningItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2));
    7833              :                 }
    7834              : 
    7835              :                 // N2: ground view factor
    7836           21 :                 if (!s_ipsc->lNumericFieldBlanks(2)) {
    7837            4 :                     SrdSurfsProp.GroundViewFactor = s_ipsc->rNumericArgs(2);
    7838            4 :                     SrdSurfsProp.IsGroundViewFactorSet = true;
    7839              :                 }
    7840              : 
    7841              :                 // A3: ground temp sch name
    7842           21 :                 if (s_ipsc->lAlphaFieldBlanks(3)) {
    7843            2 :                 } else if ((SrdSurfsProp.groundTempSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(3))) == nullptr) {
    7844            1 :                     ShowWarningItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3));
    7845              :                 }
    7846              : 
    7847              :                 // The object requires at least one srd surface input, each surface requires a set of 3 fields (2 Alpha fields Name and Temp
    7848              :                 // Sch Name and 1 Num fields View Factor)
    7849           21 :                 if (NumAlpha < 5) {
    7850            0 :                     ShowSevereError(state, format("{} = \"{}\" is not defined correctly.", s_ipsc->cCurrentModuleObject, SrdSurfsProp.Name));
    7851            0 :                     ShowContinueError(state, "At lease one set of surrounding surface properties should be defined.");
    7852            0 :                     ErrorsFound = true;
    7853            0 :                     continue;
    7854              :                 }
    7855           21 :                 if ((NumAlpha - 3) / 2 != (NumNumeric - 2)) {
    7856            0 :                     ShowSevereError(state, format("{} = \"{}\" is not defined correctly.", s_ipsc->cCurrentModuleObject, SrdSurfsProp.Name));
    7857            0 :                     ShowContinueError(state, "Check number of input fields for each surrounding surface.");
    7858            0 :                     ErrorsFound = true;
    7859            0 :                     continue;
    7860              :                 }
    7861              :                 // Read surrounding surfaces properties
    7862           21 :                 SrdSurfsProp.TotSurroundingSurface = NumNumeric - 2;
    7863           21 :                 SrdSurfsProp.SurroundingSurfs.allocate(SrdSurfsProp.TotSurroundingSurface);
    7864           54 :                 for (int SurfLoop = 1; SurfLoop <= SrdSurfsProp.TotSurroundingSurface; ++SurfLoop) {
    7865           33 :                     auto &surroundSurf = SrdSurfsProp.SurroundingSurfs(SurfLoop);
    7866           33 :                     surroundSurf.Name = s_ipsc->cAlphaArgs(SurfLoop * 2 + 2);
    7867           33 :                     surroundSurf.ViewFactor = s_ipsc->rNumericArgs(SurfLoop + 2);
    7868              : 
    7869              :                     // Added checking
    7870           33 :                     if (s_ipsc->lAlphaFieldBlanks(SurfLoop * 2 + 3)) {
    7871            0 :                         ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(SurfLoop * 2 + 3));
    7872            0 :                         ErrorsFound = true;
    7873           33 :                     } else if ((surroundSurf.tempSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(SurfLoop * 2 + 3))) == nullptr) {
    7874            0 :                         ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(SurfLoop * 2 + 3), s_ipsc->cAlphaArgs(SurfLoop * 2 + 3));
    7875            0 :                         ErrorsFound = true;
    7876              :                     }
    7877           33 :                     SrdSurfsProp.SurfsViewFactorSum += SrdSurfsProp.SurroundingSurfs(SurfLoop).ViewFactor;
    7878              :                 }
    7879              :             }
    7880              :         }
    7881          224 :     }
    7882              : 
    7883          224 :     void GetSurfaceGroundSurfsData(EnergyPlusData &state, bool &ErrorsFound)
    7884              :     {
    7885              :         static constexpr std::string_view routineName = "GetSurfaceGroundSurfsData";
    7886              : 
    7887          224 :         auto &s_ipsc = state.dataIPShortCut;
    7888          224 :         s_ipsc->cCurrentModuleObject = "SurfaceProperty:GroundSurfaces";
    7889          224 :         state.dataSurface->TotSurfPropGndSurfs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
    7890          224 :         auto const instances = state.dataInputProcessing->inputProcessor->epJSON.find(s_ipsc->cCurrentModuleObject);
    7891          224 :         if (instances == state.dataInputProcessing->inputProcessor->epJSON.end()) {
    7892          218 :             if (state.dataSurface->TotSurfPropGndSurfs > 0) ErrorsFound = true;
    7893          218 :             return;
    7894              :         }
    7895              : 
    7896            6 :         auto &instancesValue = instances.value();
    7897           18 :         for (auto instance = instancesValue.begin(); instance != instancesValue.end(); ++instance) {
    7898           12 :             auto const &fields = instance.value();
    7899           12 :             std::string const &thisObjectName = instance.key();
    7900              : 
    7901           12 :             ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, thisObjectName};
    7902              : 
    7903           12 :             DataSurfaces::GroundSurfacesProperty thisGndSurfsObj;
    7904           12 :             thisGndSurfsObj.Name = Util::makeUPPER(thisObjectName);
    7905           12 :             state.dataInputProcessing->inputProcessor->markObjectAsUsed(s_ipsc->cCurrentModuleObject, thisObjectName);
    7906           12 :             auto groundSurfaces = fields.find("ground_surfaces");
    7907           12 :             if (groundSurfaces != fields.end()) {
    7908           12 :                 auto &groundSurfacesArray = groundSurfaces.value();
    7909           12 :                 thisGndSurfsObj.NumGndSurfs = groundSurfacesArray.size();
    7910           32 :                 for (auto &groundSurface : groundSurfacesArray) {
    7911           20 :                     DataSurfaces::GroundSurfacesData thisGndSurf;
    7912           20 :                     auto GndSurfName = groundSurface.find("ground_surface_name");
    7913           20 :                     if (GndSurfName != groundSurface.end()) {
    7914           20 :                         std::string ground_surf_name = GndSurfName.value().get<std::string>();
    7915           20 :                         if (!ground_surf_name.empty()) {
    7916           20 :                             thisGndSurf.Name = Util::makeUPPER(ground_surf_name);
    7917              :                         }
    7918           20 :                     }
    7919           20 :                     auto groundSurfViewFactor = groundSurface.find("ground_surface_view_factor");
    7920           20 :                     if (groundSurfViewFactor != groundSurface.end()) {
    7921           15 :                         thisGndSurf.ViewFactor = groundSurfViewFactor.value().get<Real64>();
    7922           15 :                         thisGndSurfsObj.IsGroundViewFactorSet = true;
    7923              :                     }
    7924           20 :                     auto TempSchName = groundSurface.find("ground_surface_temperature_schedule_name");
    7925           20 :                     if (TempSchName != groundSurface.end()) {
    7926           20 :                         std::string schedName = TempSchName.value().get<std::string>();
    7927           20 :                         if (schedName.empty()) {
    7928           20 :                         } else if ((thisGndSurf.tempSched = Sched::GetSchedule(state, Util::makeUPPER(schedName))) == nullptr) {
    7929            0 :                             ShowSevereItemNotFound(state, eoh, "Ground Surface Temperature Schedule Name", schedName);
    7930            0 :                             ErrorsFound = true;
    7931              :                         }
    7932           20 :                     }
    7933              : 
    7934           20 :                     auto ReflSchName = groundSurface.find("ground_surface_reflectance_schedule_name");
    7935           20 :                     if (ReflSchName != groundSurface.end()) {
    7936            3 :                         std::string schedName = ReflSchName.value().get<std::string>();
    7937            3 :                         if (schedName.empty()) {
    7938            3 :                         } else if ((thisGndSurf.reflSched = Sched::GetSchedule(state, Util::makeUPPER(schedName))) == nullptr) {
    7939            0 :                             ShowSevereItemNotFound(state, eoh, "Ground Surface Reflectance Schedule Name", schedName);
    7940            0 :                             ErrorsFound = true;
    7941              :                         }
    7942            3 :                     }
    7943           20 :                     thisGndSurfsObj.GndSurfs.push_back(thisGndSurf);
    7944           20 :                 }
    7945              :             }
    7946           32 :             for (int gSurfNum = 1; gSurfNum <= thisGndSurfsObj.NumGndSurfs; gSurfNum++) {
    7947           20 :                 thisGndSurfsObj.SurfsViewFactorSum += thisGndSurfsObj.GndSurfs(gSurfNum).ViewFactor;
    7948              :             }
    7949           12 :             state.dataSurface->GroundSurfsProperty.push_back(thisGndSurfsObj);
    7950           12 :         } // for (instance)
    7951              : 
    7952              :         // set report variables
    7953            6 :         if (state.dataSurface->TotSurfPropGndSurfs > 0) {
    7954           18 :             for (int Loop = 1; Loop <= state.dataSurface->TotSurfPropGndSurfs; Loop++) {
    7955           12 :                 bool SetTempSchReportVar = true;
    7956           12 :                 bool SetReflSchReportVar = true;
    7957           12 :                 auto &thisGndSurfsObj = state.dataSurface->GroundSurfsProperty(Loop);
    7958           32 :                 for (int gSurfNum = 1; gSurfNum <= thisGndSurfsObj.NumGndSurfs; gSurfNum++) {
    7959           20 :                     if (thisGndSurfsObj.GndSurfs(gSurfNum).tempSched != nullptr && SetTempSchReportVar) {
    7960           24 :                         SetupOutputVariable(state,
    7961              :                                             "Surfaces Property Ground Surfaces Average Temperature",
    7962              :                                             Constant::Units::C,
    7963           12 :                                             thisGndSurfsObj.SurfsTempAvg,
    7964              :                                             OutputProcessor::TimeStepType::Zone,
    7965              :                                             OutputProcessor::StoreType::Average,
    7966           12 :                                             thisGndSurfsObj.Name);
    7967           12 :                         SetTempSchReportVar = false;
    7968              :                     }
    7969           20 :                     if (thisGndSurfsObj.GndSurfs(gSurfNum).reflSched != nullptr && SetReflSchReportVar) {
    7970            2 :                         SetupOutputVariable(state,
    7971              :                                             "Surfaces Property Ground Surfaces Average Reflectance",
    7972              :                                             Constant::Units::None,
    7973            1 :                                             thisGndSurfsObj.SurfsReflAvg,
    7974              :                                             OutputProcessor::TimeStepType::Zone,
    7975              :                                             OutputProcessor::StoreType::Average,
    7976            1 :                                             thisGndSurfsObj.Name);
    7977            1 :                         SetReflSchReportVar = false;
    7978              :                     }
    7979              :                 }
    7980              :             }
    7981              :         }
    7982              :     }
    7983              : 
    7984          224 :     void GetSurfaceHeatTransferAlgorithmOverrides(EnergyPlusData &state, bool &ErrorsFound)
    7985              :     {
    7986              : 
    7987              :         // SUBROUTINE INFORMATION:
    7988              :         //       AUTHOR         B. Griffith, portions from ApplyConvectionValue by Linda Lawrie
    7989              :         //       DATE WRITTEN   July 2012
    7990              :         static constexpr std::string_view routineName = "GetSurfaceHeatTransferAlgorithmOverrides";
    7991              : 
    7992              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    7993              :         int CountHTAlgoObjectsSingleSurf;
    7994              :         int CountHTAlgoObjectsMultiSurf;
    7995              :         int CountHTAlgoObjectsSurfList;
    7996              :         int IOStatus; // Used in GetObjectItem
    7997              :         DataSurfaces::HeatTransferModel tmpAlgoInput;
    7998              :         int Item;
    7999              :         int Item1;
    8000              :         int NumAlphas;
    8001              :         int NumNumbers;
    8002              :         int Found;
    8003              :         bool SurfacesOfType;
    8004              :         int SurfNum;
    8005              :         //  INTEGER :: Index
    8006              :         int NumEMPDMat;
    8007              :         int NumPCMat;
    8008              :         int NumVTCMat;
    8009              :         int NumHAMTMat1;
    8010              :         int NumHAMTMat2;
    8011              :         int NumHAMTMat3;
    8012              :         int NumHAMTMat4;
    8013              :         int NumHAMTMat5;
    8014              :         int NumHAMTMat6;
    8015              :         int SumHAMTMat;
    8016              :         bool msgneeded;
    8017              : 
    8018          224 :         auto &s_ipsc = state.dataIPShortCut;
    8019          224 :         s_ipsc->cCurrentModuleObject = "SurfaceProperty:HeatBalanceSourceTerm";
    8020          224 :         int CountAddHeatSourceSurf = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
    8021              : 
    8022          226 :         for (Item = 1; Item <= CountAddHeatSourceSurf; ++Item) {
    8023            4 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    8024            2 :                                                                      s_ipsc->cCurrentModuleObject,
    8025              :                                                                      Item,
    8026            2 :                                                                      s_ipsc->cAlphaArgs,
    8027              :                                                                      NumAlphas,
    8028            2 :                                                                      s_ipsc->rNumericArgs,
    8029              :                                                                      NumNumbers,
    8030              :                                                                      IOStatus,
    8031            2 :                                                                      s_ipsc->lNumericFieldBlanks,
    8032            2 :                                                                      s_ipsc->lAlphaFieldBlanks,
    8033            2 :                                                                      s_ipsc->cAlphaFieldNames,
    8034            2 :                                                                      s_ipsc->cNumericFieldNames);
    8035              : 
    8036            2 :             ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
    8037            2 :             Found = Util::FindItemInList(s_ipsc->cAlphaArgs(1), state.dataSurface->Surface, state.dataSurface->TotSurfaces);
    8038              : 
    8039            2 :             if (Found == 0) {
    8040            0 :                 ShowSevereError(state, format("{}=\"{}\", did not find matching surface.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
    8041            0 :                 ErrorsFound = true;
    8042            4 :             } else if (state.dataSurface->Surface(Found).insideHeatSourceTermSched != nullptr ||
    8043            2 :                        state.dataSurface->Surface(Found).outsideHeatSourceTermSched != nullptr) {
    8044            0 :                 ShowSevereError(state,
    8045            0 :                                 format("{}=\"{}\", multiple SurfaceProperty:HeatBalanceSourceTerm objects applied to the same surface.",
    8046            0 :                                        s_ipsc->cCurrentModuleObject,
    8047            0 :                                        s_ipsc->cAlphaArgs(1)));
    8048            0 :                 ErrorsFound = true;
    8049              :             }
    8050              : 
    8051            2 :             if (s_ipsc->lAlphaFieldBlanks(2)) {
    8052            1 :             } else if ((state.dataSurface->Surface(Found).insideHeatSourceTermSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(2))) == nullptr) {
    8053            0 :                 ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2));
    8054            0 :                 ErrorsFound = true;
    8055              :             } else {
    8056            1 :                 state.dataSurface->allInsideSourceSurfaceList.emplace_back(Found);
    8057              :             }
    8058              : 
    8059            2 :             if (s_ipsc->lAlphaFieldBlanks(3)) {
    8060            1 :             } else if ((state.dataSurface->Surface(Found).outsideHeatSourceTermSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(3))) == nullptr) {
    8061            0 :                 ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3));
    8062            0 :                 ErrorsFound = true;
    8063            1 :             } else if (state.dataSurface->Surface(Found).OSCPtr > 0) {
    8064            0 :                 ShowSevereError(state,
    8065            0 :                                 format("{}=\"SurfaceProperty:HeatBalanceSourceTerm\", cannot be specified for OtherSideCoefficient Surface={}",
    8066            0 :                                        s_ipsc->cCurrentModuleObject,
    8067            0 :                                        s_ipsc->cAlphaArgs(1)));
    8068            0 :                 ErrorsFound = true;
    8069              :             } else {
    8070            1 :                 state.dataSurface->allOutsideSourceSurfaceList.emplace_back(Found);
    8071              :             }
    8072              : 
    8073            3 :             if (state.dataSurface->Surface(Found).outsideHeatSourceTermSched == nullptr &&
    8074            1 :                 state.dataSurface->Surface(Found).insideHeatSourceTermSched == nullptr) {
    8075            0 :                 ShowSevereError(
    8076            0 :                     state, format("{}=\"{}\", no schedule defined for additional heat source.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
    8077            0 :                 ErrorsFound = true;
    8078              :             }
    8079              :         }
    8080              : 
    8081              :         // first initialize each heat transfer surface with the overall model type, array assignment
    8082         2486 :         for (auto &e : state.dataSurface->Surface)
    8083         2262 :             e.HeatTransferAlgorithm = state.dataHeatBal->OverallHeatTransferSolutionAlgo;
    8084              : 
    8085          224 :         s_ipsc->cCurrentModuleObject = "SurfaceProperty:HeatTransferAlgorithm";
    8086          224 :         CountHTAlgoObjectsSingleSurf = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
    8087              : 
    8088          224 :         s_ipsc->cCurrentModuleObject = "SurfaceProperty:HeatTransferAlgorithm";
    8089          226 :         for (Item = 1; Item <= CountHTAlgoObjectsSingleSurf; ++Item) {
    8090            4 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    8091            2 :                                                                      s_ipsc->cCurrentModuleObject,
    8092              :                                                                      Item,
    8093            2 :                                                                      s_ipsc->cAlphaArgs,
    8094              :                                                                      NumAlphas,
    8095            2 :                                                                      s_ipsc->rNumericArgs,
    8096              :                                                                      NumNumbers,
    8097              :                                                                      IOStatus,
    8098            2 :                                                                      s_ipsc->lNumericFieldBlanks,
    8099            2 :                                                                      s_ipsc->lAlphaFieldBlanks,
    8100            2 :                                                                      s_ipsc->cAlphaFieldNames,
    8101            2 :                                                                      s_ipsc->cNumericFieldNames);
    8102            2 :             bool ErrorsFoundSingleSurf = false;
    8103            2 :             Found = Util::FindItemInList(s_ipsc->cAlphaArgs(1), state.dataSurface->Surface, state.dataSurface->TotSurfaces);
    8104              : 
    8105            2 :             if (Found == 0) {
    8106            0 :                 ShowSevereError(state, format("{}=\"{}\", did not find matching surface.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
    8107            0 :                 ErrorsFoundSingleSurf = true;
    8108              :             }
    8109              : 
    8110              :             {
    8111            2 :                 std::string const &SELECT_CASE_var = s_ipsc->cAlphaArgs(2);
    8112              : 
    8113            2 :                 if (SELECT_CASE_var == "CONDUCTIONTRANSFERFUNCTION") {
    8114            1 :                     tmpAlgoInput = DataSurfaces::HeatTransferModel::CTF;
    8115            1 :                     state.dataHeatBal->AnyCTF = true;
    8116            1 :                 } else if (SELECT_CASE_var == "MOISTUREPENETRATIONDEPTHCONDUCTIONTRANSFERFUNCTION") {
    8117            0 :                     tmpAlgoInput = DataSurfaces::HeatTransferModel::EMPD;
    8118            0 :                     state.dataHeatBal->AnyEMPD = true;
    8119            1 :                 } else if (SELECT_CASE_var == "COMBINEDHEATANDMOISTUREFINITEELEMENT") {
    8120            1 :                     tmpAlgoInput = DataSurfaces::HeatTransferModel::HAMT;
    8121            1 :                     state.dataHeatBal->AnyHAMT = true;
    8122            0 :                 } else if (SELECT_CASE_var == "CONDUCTIONFINITEDIFFERENCE") {
    8123            0 :                     tmpAlgoInput = DataSurfaces::HeatTransferModel::CondFD;
    8124            0 :                     state.dataHeatBal->AnyCondFD = true;
    8125              :                 } else {
    8126            0 :                     ShowSevereError(state,
    8127            0 :                                     format("{}=\"{}\", invalid {}=\"{}",
    8128            0 :                                            s_ipsc->cCurrentModuleObject,
    8129            0 :                                            s_ipsc->cAlphaArgs(1),
    8130            0 :                                            s_ipsc->cAlphaFieldNames(2),
    8131            0 :                                            s_ipsc->cAlphaArgs(2)));
    8132            0 :                     ErrorsFoundSingleSurf = true;
    8133              :                 }
    8134              :             }
    8135              : 
    8136            2 :             if (!ErrorsFoundSingleSurf) {
    8137            2 :                 state.dataSurface->Surface(Found).HeatTransferAlgorithm = tmpAlgoInput;
    8138              :             } else {
    8139            0 :                 ErrorsFound = true;
    8140              :             }
    8141              :         } // single surface heat transfer algorithm override
    8142              : 
    8143          224 :         s_ipsc->cCurrentModuleObject = "SurfaceProperty:HeatTransferAlgorithm:MultipleSurface";
    8144          224 :         CountHTAlgoObjectsMultiSurf = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
    8145              : 
    8146          224 :         for (Item = 1; Item <= CountHTAlgoObjectsMultiSurf; ++Item) {
    8147            0 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    8148            0 :                                                                      s_ipsc->cCurrentModuleObject,
    8149              :                                                                      Item,
    8150            0 :                                                                      s_ipsc->cAlphaArgs,
    8151              :                                                                      NumAlphas,
    8152            0 :                                                                      s_ipsc->rNumericArgs,
    8153              :                                                                      NumNumbers,
    8154              :                                                                      IOStatus,
    8155            0 :                                                                      s_ipsc->lNumericFieldBlanks,
    8156            0 :                                                                      s_ipsc->lAlphaFieldBlanks,
    8157            0 :                                                                      s_ipsc->cAlphaFieldNames,
    8158            0 :                                                                      s_ipsc->cNumericFieldNames);
    8159            0 :             bool ErrorsFoundMultiSurf = false;
    8160              :             {
    8161            0 :                 std::string const &SELECT_CASE_var = s_ipsc->cAlphaArgs(3);
    8162              : 
    8163            0 :                 if (SELECT_CASE_var == "CONDUCTIONTRANSFERFUNCTION") {
    8164            0 :                     tmpAlgoInput = DataSurfaces::HeatTransferModel::CTF;
    8165            0 :                     state.dataHeatBal->AnyCTF = true;
    8166            0 :                 } else if (SELECT_CASE_var == "MOISTUREPENETRATIONDEPTHCONDUCTIONTRANSFERFUNCTION") {
    8167            0 :                     tmpAlgoInput = DataSurfaces::HeatTransferModel::EMPD;
    8168            0 :                     state.dataHeatBal->AnyEMPD = true;
    8169            0 :                 } else if (SELECT_CASE_var == "COMBINEDHEATANDMOISTUREFINITEELEMENT") {
    8170            0 :                     tmpAlgoInput = DataSurfaces::HeatTransferModel::HAMT;
    8171            0 :                     state.dataHeatBal->AnyHAMT = true;
    8172            0 :                 } else if (SELECT_CASE_var == "CONDUCTIONFINITEDIFFERENCE") {
    8173            0 :                     tmpAlgoInput = DataSurfaces::HeatTransferModel::CondFD;
    8174            0 :                     state.dataHeatBal->AnyCondFD = true;
    8175              :                 } else {
    8176            0 :                     ShowSevereError(state,
    8177            0 :                                     format("{}=\"{}\", invalid {}=\"{}",
    8178            0 :                                            s_ipsc->cCurrentModuleObject,
    8179            0 :                                            s_ipsc->cAlphaArgs(1),
    8180            0 :                                            s_ipsc->cAlphaFieldNames(3),
    8181            0 :                                            s_ipsc->cAlphaArgs(3)));
    8182            0 :                     ErrorsFoundMultiSurf = true;
    8183              :                 }
    8184              :             }
    8185              : 
    8186              :             {
    8187            0 :                 std::string const &SELECT_CASE_var = s_ipsc->cAlphaArgs(2);
    8188              : 
    8189            0 :                 if (SELECT_CASE_var == "ALLEXTERIORSURFACES") {
    8190            0 :                     SurfacesOfType = false;
    8191            0 :                     for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    8192            0 :                         auto &surf = state.dataSurface->Surface(SurfNum);
    8193            0 :                         if (!surf.HeatTransSurf) continue;
    8194            0 :                         if (surf.ExtBoundCond > 0) continue; // Interior surfaces
    8195            0 :                         if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) continue;
    8196            0 :                         SurfacesOfType = true;
    8197            0 :                         surf.HeatTransferAlgorithm = tmpAlgoInput;
    8198              :                     }
    8199              : 
    8200            0 :                 } else if (SELECT_CASE_var == "ALLEXTERIORWALLS") {
    8201            0 :                     SurfacesOfType = false;
    8202            0 :                     for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    8203            0 :                         auto &surf = state.dataSurface->Surface(SurfNum);
    8204            0 :                         if (!surf.HeatTransSurf) continue;
    8205            0 :                         if (surf.ExtBoundCond > 0) continue; // Interior surfaces
    8206              : 
    8207            0 :                         if (surf.Class != SurfaceClass::Wall) continue;
    8208            0 :                         if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) continue;
    8209            0 :                         SurfacesOfType = true;
    8210            0 :                         surf.HeatTransferAlgorithm = tmpAlgoInput;
    8211              :                     }
    8212              : 
    8213            0 :                 } else if (SELECT_CASE_var == "ALLEXTERIORROOFS") {
    8214            0 :                     SurfacesOfType = false;
    8215            0 :                     for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    8216            0 :                         auto &surf = state.dataSurface->Surface(SurfNum);
    8217            0 :                         if (!surf.HeatTransSurf) continue;
    8218            0 :                         if (surf.ExtBoundCond > 0) continue; // Interior surfaces
    8219            0 :                         if (surf.Class != SurfaceClass::Roof) continue;
    8220            0 :                         if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) continue;
    8221            0 :                         SurfacesOfType = true;
    8222            0 :                         surf.HeatTransferAlgorithm = tmpAlgoInput;
    8223              :                     }
    8224              : 
    8225            0 :                 } else if (SELECT_CASE_var == "ALLEXTERIORFLOORS") {
    8226            0 :                     SurfacesOfType = false;
    8227            0 :                     for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    8228            0 :                         auto &surf = state.dataSurface->Surface(SurfNum);
    8229            0 :                         if (!surf.HeatTransSurf) continue;
    8230            0 :                         if (surf.ExtBoundCond > 0) continue; // Interior surfaces
    8231            0 :                         if (surf.Class != SurfaceClass::Floor) continue;
    8232            0 :                         if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) continue;
    8233            0 :                         SurfacesOfType = true;
    8234            0 :                         surf.HeatTransferAlgorithm = tmpAlgoInput;
    8235              :                     }
    8236              : 
    8237            0 :                 } else if (SELECT_CASE_var == "ALLGROUNDCONTACTSURFACES") {
    8238            0 :                     SurfacesOfType = false;
    8239            0 :                     for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    8240            0 :                         auto &surf = state.dataSurface->Surface(SurfNum);
    8241            0 :                         if (!surf.HeatTransSurf) continue;
    8242            0 :                         if (surf.ExtBoundCond != DataSurfaces::Ground) continue; // ground BC
    8243            0 :                         if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) continue;
    8244            0 :                         SurfacesOfType = true;
    8245            0 :                         surf.HeatTransferAlgorithm = tmpAlgoInput;
    8246              :                     }
    8247            0 :                 } else if (SELECT_CASE_var == "ALLINTERIORSURFACES") {
    8248            0 :                     SurfacesOfType = false;
    8249            0 :                     for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    8250            0 :                         auto &surf = state.dataSurface->Surface(SurfNum);
    8251            0 :                         if (!surf.HeatTransSurf) continue;
    8252            0 :                         if (surf.ExtBoundCond <= 0) continue; // Exterior surfaces
    8253            0 :                         if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) continue;
    8254            0 :                         SurfacesOfType = true;
    8255            0 :                         surf.HeatTransferAlgorithm = tmpAlgoInput;
    8256              :                     }
    8257              : 
    8258            0 :                 } else if (SELECT_CASE_var == "ALLINTERIORWALLS") {
    8259            0 :                     SurfacesOfType = false;
    8260            0 :                     for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    8261            0 :                         auto &surf = state.dataSurface->Surface(SurfNum);
    8262            0 :                         if (!surf.HeatTransSurf) continue;
    8263            0 :                         if (surf.ExtBoundCond <= 0) continue; // Exterior surfaces
    8264            0 :                         if (surf.Class != SurfaceClass::Wall) continue;
    8265            0 :                         if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) continue;
    8266            0 :                         SurfacesOfType = true;
    8267            0 :                         surf.HeatTransferAlgorithm = tmpAlgoInput;
    8268              :                     }
    8269              : 
    8270            0 :                 } else if ((SELECT_CASE_var == "ALLINTERIORROOFS") || (SELECT_CASE_var == "ALLINTERIORCEILINGS")) {
    8271            0 :                     SurfacesOfType = false;
    8272            0 :                     for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    8273            0 :                         auto &surf = state.dataSurface->Surface(SurfNum);
    8274            0 :                         if (!surf.HeatTransSurf) continue;
    8275            0 :                         if (surf.ExtBoundCond <= 0) continue; // Exterior surfaces
    8276            0 :                         if (surf.Class != SurfaceClass::Roof) continue;
    8277            0 :                         if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) continue;
    8278            0 :                         SurfacesOfType = true;
    8279            0 :                         surf.HeatTransferAlgorithm = tmpAlgoInput;
    8280              :                     }
    8281              : 
    8282            0 :                 } else if (SELECT_CASE_var == "ALLINTERIORFLOORS") {
    8283            0 :                     SurfacesOfType = false;
    8284            0 :                     for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
    8285            0 :                         auto &surf = state.dataSurface->Surface(SurfNum);
    8286            0 :                         if (!surf.HeatTransSurf) continue;
    8287            0 :                         if (surf.ExtBoundCond <= 0) continue; // Exterior surfaces
    8288            0 :                         if (surf.Class != SurfaceClass::Floor) continue;
    8289            0 :                         if (state.dataConstruction->Construct(surf.Construction).TypeIsWindow) continue;
    8290            0 :                         SurfacesOfType = true;
    8291            0 :                         surf.HeatTransferAlgorithm = tmpAlgoInput;
    8292              :                     }
    8293              :                 } else {
    8294            0 :                     SurfacesOfType = false;
    8295            0 :                     ShowSevereError(state,
    8296            0 :                                     format("{}=\"{}\", invalid {}=\"{}",
    8297            0 :                                            s_ipsc->cCurrentModuleObject,
    8298            0 :                                            s_ipsc->cAlphaArgs(1),
    8299            0 :                                            s_ipsc->cAlphaFieldNames(2),
    8300            0 :                                            s_ipsc->cAlphaArgs(2)));
    8301            0 :                     ErrorsFoundMultiSurf = true;
    8302              :                 }
    8303              :             }
    8304              : 
    8305            0 :             if (!SurfacesOfType) {
    8306            0 :                 ShowWarningError(
    8307              :                     state,
    8308            0 :                     format("In {}=\"{}\", for Multiple Surface Assignment=\"{}\", there were no surfaces of that type found for assignment.",
    8309            0 :                            s_ipsc->cCurrentModuleObject,
    8310            0 :                            s_ipsc->cAlphaArgs(1),
    8311            0 :                            s_ipsc->cAlphaArgs(2)));
    8312              :             }
    8313            0 :             if (ErrorsFoundMultiSurf) ErrorsFound = true;
    8314              : 
    8315              :         } // multi surface heat transfer algo override
    8316              : 
    8317          224 :         s_ipsc->cCurrentModuleObject = "SurfaceProperty:HeatTransferAlgorithm:SurfaceList";
    8318          224 :         CountHTAlgoObjectsSurfList = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
    8319          224 :         for (Item = 1; Item <= CountHTAlgoObjectsSurfList; ++Item) {
    8320            0 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    8321            0 :                                                                      s_ipsc->cCurrentModuleObject,
    8322              :                                                                      Item,
    8323            0 :                                                                      s_ipsc->cAlphaArgs,
    8324              :                                                                      NumAlphas,
    8325            0 :                                                                      s_ipsc->rNumericArgs,
    8326              :                                                                      NumNumbers,
    8327              :                                                                      IOStatus,
    8328            0 :                                                                      s_ipsc->lNumericFieldBlanks,
    8329            0 :                                                                      s_ipsc->lAlphaFieldBlanks,
    8330            0 :                                                                      s_ipsc->cAlphaFieldNames,
    8331            0 :                                                                      s_ipsc->cNumericFieldNames);
    8332            0 :             bool ErrorsFoundSurfList = false;
    8333              :             {
    8334            0 :                 std::string const &SELECT_CASE_var = s_ipsc->cAlphaArgs(2);
    8335              : 
    8336            0 :                 if (SELECT_CASE_var == "CONDUCTIONTRANSFERFUNCTION") {
    8337            0 :                     tmpAlgoInput = DataSurfaces::HeatTransferModel::CTF;
    8338            0 :                     state.dataHeatBal->AnyCTF = true;
    8339            0 :                 } else if (SELECT_CASE_var == "MOISTUREPENETRATIONDEPTHCONDUCTIONTRANSFERFUNCTION") {
    8340            0 :                     tmpAlgoInput = DataSurfaces::HeatTransferModel::EMPD;
    8341            0 :                     state.dataHeatBal->AnyEMPD = true;
    8342            0 :                 } else if (SELECT_CASE_var == "COMBINEDHEATANDMOISTUREFINITEELEMENT") {
    8343            0 :                     tmpAlgoInput = DataSurfaces::HeatTransferModel::HAMT;
    8344            0 :                     state.dataHeatBal->AnyHAMT = true;
    8345            0 :                 } else if (SELECT_CASE_var == "CONDUCTIONFINITEDIFFERENCE") {
    8346            0 :                     tmpAlgoInput = DataSurfaces::HeatTransferModel::CondFD;
    8347            0 :                     state.dataHeatBal->AnyCondFD = true;
    8348              :                 } else {
    8349            0 :                     ShowSevereError(state,
    8350            0 :                                     format("{}=\"{}\", invalid {}=\"{}",
    8351            0 :                                            s_ipsc->cCurrentModuleObject,
    8352            0 :                                            s_ipsc->cAlphaArgs(1),
    8353            0 :                                            s_ipsc->cAlphaFieldNames(2),
    8354            0 :                                            s_ipsc->cAlphaArgs(2)));
    8355            0 :                     ErrorsFoundSurfList = true;
    8356              :                 }
    8357              :             }
    8358              : 
    8359            0 :             for (Item1 = 3; Item1 <= NumAlphas; ++Item1) {
    8360              : 
    8361            0 :                 Found = Util::FindItemInList(s_ipsc->cAlphaArgs(Item1), state.dataSurface->Surface, state.dataSurface->TotSurfaces);
    8362              : 
    8363            0 :                 if (Found == 0) {
    8364            0 :                     ShowSevereError(state, format("{}=\"{}\", did not find matching surface.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
    8365            0 :                     ShowContinueError(state, format("Name of surface not found = \"{}\"", s_ipsc->cAlphaArgs(Item1)));
    8366            0 :                     ErrorsFoundSurfList = true;
    8367              :                 }
    8368              : 
    8369            0 :                 if (!ErrorsFoundSurfList) {
    8370            0 :                     state.dataSurface->Surface(Found).HeatTransferAlgorithm = tmpAlgoInput;
    8371              :                 } else {
    8372            0 :                     ErrorsFound = true;
    8373              :                 }
    8374              :             }
    8375              :         }
    8376              : 
    8377          224 :         s_ipsc->cCurrentModuleObject = "SurfaceProperty:HeatTransferAlgorithm:Construction";
    8378          224 :         CountHTAlgoObjectsSurfList = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
    8379          225 :         for (Item = 1; Item <= CountHTAlgoObjectsSurfList; ++Item) {
    8380            2 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    8381            1 :                                                                      s_ipsc->cCurrentModuleObject,
    8382              :                                                                      Item,
    8383            1 :                                                                      s_ipsc->cAlphaArgs,
    8384              :                                                                      NumAlphas,
    8385            1 :                                                                      s_ipsc->rNumericArgs,
    8386              :                                                                      NumNumbers,
    8387              :                                                                      IOStatus,
    8388            1 :                                                                      s_ipsc->lNumericFieldBlanks,
    8389            1 :                                                                      s_ipsc->lAlphaFieldBlanks,
    8390            1 :                                                                      s_ipsc->cAlphaFieldNames,
    8391            1 :                                                                      s_ipsc->cNumericFieldNames);
    8392            1 :             bool ErrorsFoundByConstruct = false;
    8393              :             {
    8394            1 :                 std::string const &SELECT_CASE_var = s_ipsc->cAlphaArgs(2);
    8395              : 
    8396            1 :                 if (SELECT_CASE_var == "CONDUCTIONTRANSFERFUNCTION") {
    8397            0 :                     tmpAlgoInput = DataSurfaces::HeatTransferModel::CTF;
    8398            0 :                     state.dataHeatBal->AnyCTF = true;
    8399            1 :                 } else if (SELECT_CASE_var == "MOISTUREPENETRATIONDEPTHCONDUCTIONTRANSFERFUNCTION") {
    8400            0 :                     tmpAlgoInput = DataSurfaces::HeatTransferModel::EMPD;
    8401            0 :                     state.dataHeatBal->AnyEMPD = true;
    8402            1 :                 } else if (SELECT_CASE_var == "COMBINEDHEATANDMOISTUREFINITEELEMENT") {
    8403            0 :                     tmpAlgoInput = DataSurfaces::HeatTransferModel::HAMT;
    8404            0 :                     state.dataHeatBal->AnyHAMT = true;
    8405            1 :                 } else if (SELECT_CASE_var == "CONDUCTIONFINITEDIFFERENCE") {
    8406            1 :                     tmpAlgoInput = DataSurfaces::HeatTransferModel::CondFD;
    8407            1 :                     state.dataHeatBal->AnyCondFD = true;
    8408              :                 } else {
    8409            0 :                     ShowSevereError(state,
    8410            0 :                                     format("{}=\"{}\", invalid {}=\"{}",
    8411            0 :                                            s_ipsc->cCurrentModuleObject,
    8412            0 :                                            s_ipsc->cAlphaArgs(1),
    8413            0 :                                            s_ipsc->cAlphaFieldNames(2),
    8414            0 :                                            s_ipsc->cAlphaArgs(2)));
    8415            0 :                     ErrorsFoundByConstruct = true;
    8416              :                 }
    8417              :             }
    8418              : 
    8419            1 :             Found = Util::FindItemInList(s_ipsc->cAlphaArgs(3), state.dataConstruction->Construct, state.dataHeatBal->TotConstructs);
    8420            1 :             if (Found == 0) {
    8421            0 :                 ShowSevereError(state,
    8422            0 :                                 format("{}=\"{}\", invalid {}=\"{}",
    8423            0 :                                        s_ipsc->cCurrentModuleObject,
    8424            0 :                                        s_ipsc->cAlphaArgs(1),
    8425            0 :                                        s_ipsc->cAlphaFieldNames(3),
    8426            0 :                                        s_ipsc->cAlphaArgs(3)));
    8427            0 :                 ErrorsFoundByConstruct = true;
    8428              :             }
    8429              : 
    8430            1 :             if (!ErrorsFoundByConstruct) {
    8431            5 :                 for (Item1 = 1; Item1 <= state.dataSurface->TotSurfaces; ++Item1) {
    8432            4 :                     if (state.dataSurface->Surface(Item1).Construction == Found) {
    8433            1 :                         state.dataSurface->Surface(Item1).HeatTransferAlgorithm = tmpAlgoInput;
    8434              :                     }
    8435              :                 }
    8436              :             }
    8437              :         }
    8438              : 
    8439              :         // Change algorithm for Kiva and air boundary foundation surfaces
    8440         2486 :         for (auto &surf : state.dataSurface->Surface) {
    8441         2262 :             if (surf.ExtBoundCond == DataSurfaces::KivaFoundation) {
    8442            0 :                 surf.HeatTransferAlgorithm = DataSurfaces::HeatTransferModel::Kiva;
    8443            0 :                 state.dataHeatBal->AnyKiva = true;
    8444              :             }
    8445              :         }
    8446              : 
    8447              :         // test for missing materials for algorithms selected
    8448          224 :         NumEMPDMat = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "MaterialProperty:MoisturePenetrationDepth:Settings");
    8449          224 :         NumPCMat = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "MaterialProperty:PhaseChange") +
    8450          224 :                    state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "MaterialProperty:PhaseChangeHysteresis");
    8451          224 :         NumVTCMat = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "MaterialProperty:VariableThermalConductivity");
    8452          224 :         NumHAMTMat1 = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "MaterialProperty:HeatAndMoistureTransfer:Settings");
    8453              :         NumHAMTMat2 =
    8454          224 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "MaterialProperty:HeatAndMoistureTransfer:SorptionIsotherm");
    8455          224 :         NumHAMTMat3 = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "MaterialProperty:HeatAndMoistureTransfer:Suction");
    8456          224 :         NumHAMTMat4 = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "MaterialProperty:HeatAndMoistureTransfer:Redistribution");
    8457          224 :         NumHAMTMat5 = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "MaterialProperty:HeatAndMoistureTransfer:Diffusion");
    8458              :         NumHAMTMat6 =
    8459          224 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "MaterialProperty:HeatAndMoistureTransfer:ThermalConductivity");
    8460          224 :         SumHAMTMat = NumHAMTMat1 + NumHAMTMat2 + NumHAMTMat3 + NumHAMTMat4 + NumHAMTMat5 + NumHAMTMat6;
    8461          224 :         msgneeded = false;
    8462              : 
    8463          224 :         if (NumEMPDMat > 0 && !state.dataHeatBal->AnyEMPD) {
    8464            0 :             ShowWarningError(state,
    8465            0 :                              format("The input file includes {} MaterialProperty:MoisturePenetrationDepth:Settings objects but the moisture "
    8466              :                                     "penetration depth algorithm is not used anywhere.",
    8467              :                                     NumEMPDMat));
    8468            0 :             msgneeded = true;
    8469              :         }
    8470          224 :         if (NumPCMat > 0 && !state.dataHeatBal->AnyCondFD) {
    8471            0 :             ShowWarningError(state,
    8472            0 :                              format("The input file includes {} MaterialProperty:PhaseChange objects but the conduction finite difference algorithm "
    8473              :                                     "is not used anywhere.",
    8474              :                                     NumPCMat));
    8475            0 :             msgneeded = true;
    8476              :         }
    8477          224 :         if (NumVTCMat > 0 && !state.dataHeatBal->AnyCondFD) {
    8478            0 :             ShowWarningError(state,
    8479            0 :                              format("The input file includes {} MaterialProperty:VariableThermalConductivity objects but the conduction finite "
    8480              :                                     "difference algorithm is not used anywhere.",
    8481              :                                     NumVTCMat));
    8482            0 :             msgneeded = true;
    8483              :         }
    8484          224 :         if (SumHAMTMat > 0 && !state.dataHeatBal->AnyHAMT) {
    8485            0 :             ShowWarningError(state,
    8486            0 :                              format("The input file includes {} MaterialProperty:HeatAndMoistureTransfer:* objects but the combined heat and "
    8487              :                                     "moisture finite difference algorithm is not used anywhere.",
    8488              :                                     SumHAMTMat));
    8489            0 :             msgneeded = true;
    8490              :         }
    8491          224 :         if (msgneeded) {
    8492            0 :             ShowContinueError(state, "Previous materials will be ignored due to HeatBalanceAlgorithm choice.");
    8493              :         }
    8494          224 :         msgneeded = false;
    8495          224 :         if (NumEMPDMat == 0 && state.dataHeatBal->AnyEMPD) {
    8496            2 :             ShowWarningError(state,
    8497              :                              "The moisture penetration depth conduction transfer function algorithm is used but the input file includes no "
    8498              :                              "MaterialProperty:MoisturePenetrationDepth:Settings objects.");
    8499            1 :             msgneeded = true;
    8500              :         }
    8501          224 :         if (SumHAMTMat == 0 && state.dataHeatBal->AnyHAMT) {
    8502            2 :             ShowWarningError(state,
    8503              :                              "The combined heat and moisture finite element algorithm is used but the input file includes no "
    8504              :                              "MaterialProperty:HeatAndMoistureTransfer:* objects.");
    8505            1 :             msgneeded = true;
    8506              :         }
    8507          224 :         if (msgneeded) {
    8508            3 :             ShowContinueError(state,
    8509              :                               "Certain materials objects are necessary to achieve proper results with the heat transfer algorithm(s) selected.");
    8510              :         }
    8511              : 
    8512              :         // Write Solution Algorithm to the initialization output file for User Verification
    8513          224 :         print(state.files.eio,
    8514              :               "{}\n",
    8515              :               "! <Surface Heat Transfer Algorithm>, Value {CTF - ConductionTransferFunction | EMPD - "
    8516              :               "MoisturePenetrationDepthConductionTransferFunction | CondFD - ConductionFiniteDifference | HAMT - "
    8517              :               "CombinedHeatAndMoistureFiniteElement} - Description,Inside Surface Max Temperature Limit{C}, Surface "
    8518              :               "Convection Coefficient Lower Limit {W/m2-K}, Surface Convection Coefficient Upper Limit {W/m2-K}");
    8519              : 
    8520          224 :         int numberOfHeatTransferAlgosUsed = 0;
    8521              :         // Formats
    8522              :         static constexpr std::string_view Format_725("Surface Heat Transfer Algorithm, {},{:.0R},{:.2R},{:.1R}\n");
    8523              : 
    8524          224 :         if (state.dataHeatBal->AnyCTF) {
    8525          183 :             constexpr std::string_view AlgoName = "CTF - ConductionTransferFunction";
    8526          183 :             ++numberOfHeatTransferAlgosUsed;
    8527          183 :             print(state.files.eio,
    8528              :                   Format_725,
    8529              :                   AlgoName,
    8530          183 :                   state.dataHeatBalSurf->MaxSurfaceTempLimit,
    8531          183 :                   state.dataHeatBal->LowHConvLimit,
    8532          183 :                   state.dataHeatBal->HighHConvLimit);
    8533              :         }
    8534          224 :         if (state.dataHeatBal->AnyEMPD) {
    8535            1 :             state.dataHeatBal->AllCTF = false;
    8536            1 :             constexpr std::string_view AlgoName = "EMPD - MoisturePenetrationDepthConductionTransferFunction";
    8537            1 :             ++numberOfHeatTransferAlgosUsed;
    8538            1 :             print(state.files.eio,
    8539              :                   Format_725,
    8540              :                   AlgoName,
    8541            1 :                   state.dataHeatBalSurf->MaxSurfaceTempLimit,
    8542            1 :                   state.dataHeatBal->LowHConvLimit,
    8543            1 :                   state.dataHeatBal->HighHConvLimit);
    8544            1 :             if (state.dataHeatBal->doSpaceHeatBalanceSimulation || state.dataHeatBal->doSpaceHeatBalanceSizing) {
    8545            0 :                 ShowSevereError(
    8546              :                     state,
    8547              :                     "MoisturePenetrationDepthConductionTransferFunction is not supported with ZoneAirHeatBalanceAlgorithm Space Heat Balance.");
    8548            0 :                 ErrorsFound = true;
    8549              :             }
    8550              :         }
    8551          224 :         if (state.dataHeatBal->AnyCondFD) {
    8552            3 :             state.dataHeatBal->AllCTF = false;
    8553            3 :             constexpr std::string_view AlgoName = "CondFD - ConductionFiniteDifference";
    8554            3 :             ++numberOfHeatTransferAlgosUsed;
    8555            3 :             print(state.files.eio,
    8556              :                   Format_725,
    8557              :                   AlgoName,
    8558            3 :                   state.dataHeatBalSurf->MaxSurfaceTempLimit,
    8559            3 :                   state.dataHeatBal->LowHConvLimit,
    8560            3 :                   state.dataHeatBal->HighHConvLimit);
    8561              :         }
    8562          224 :         if (state.dataHeatBal->AnyHAMT) {
    8563            1 :             state.dataHeatBal->AllCTF = false;
    8564            1 :             constexpr std::string_view AlgoName = "HAMT - CombinedHeatAndMoistureFiniteElement";
    8565            1 :             ++numberOfHeatTransferAlgosUsed;
    8566            1 :             print(state.files.eio,
    8567              :                   Format_725,
    8568              :                   AlgoName,
    8569            1 :                   state.dataHeatBalSurf->MaxSurfaceTempLimit,
    8570            1 :                   state.dataHeatBal->LowHConvLimit,
    8571            1 :                   state.dataHeatBal->HighHConvLimit);
    8572            1 :             if (state.dataHeatBal->doSpaceHeatBalanceSimulation || state.dataHeatBal->doSpaceHeatBalanceSizing) {
    8573            0 :                 ShowSevereError(state, "CombinedHeatAndMoistureFiniteElement is not supported with ZoneAirHeatBalanceAlgorithm Space Heat Balance.");
    8574            0 :                 ErrorsFound = true;
    8575              :             }
    8576              :         }
    8577          224 :         if (state.dataHeatBal->AnyKiva) {
    8578            0 :             state.dataHeatBal->AllCTF = false;
    8579            0 :             constexpr std::string_view AlgoName = "KivaFoundation - TwoDimensionalFiniteDifference";
    8580            0 :             ++numberOfHeatTransferAlgosUsed;
    8581            0 :             print(state.files.eio,
    8582              :                   Format_725,
    8583              :                   AlgoName,
    8584            0 :                   state.dataHeatBalSurf->MaxSurfaceTempLimit,
    8585            0 :                   state.dataHeatBal->LowHConvLimit,
    8586            0 :                   state.dataHeatBal->HighHConvLimit);
    8587              :         }
    8588              : 
    8589              :         // Check HeatTransferAlgorithm for interior surfaces
    8590          224 :         if (numberOfHeatTransferAlgosUsed > 1) {
    8591              :             int ExtSurfNum;
    8592            5 :             for (Item = 1; Item <= state.dataSurface->TotSurfaces; ++Item) {
    8593            4 :                 auto &surf = state.dataSurface->Surface(Item);
    8594            4 :                 if (surf.ExtBoundCond > 0) {
    8595            2 :                     if ((surf.HeatTransferAlgorithm == DataSurfaces::HeatTransferModel::Invalid) ||
    8596            2 :                         (surf.HeatTransferAlgorithm == DataSurfaces::HeatTransferModel::None))
    8597            0 :                         continue;
    8598            2 :                     ExtSurfNum = surf.ExtBoundCond;
    8599            2 :                     auto &extSurf = state.dataSurface->Surface(ExtSurfNum);
    8600            2 :                     if (surf.HeatTransferAlgorithm != extSurf.HeatTransferAlgorithm) {
    8601            2 :                         ShowWarningError(state,
    8602              :                                          "An interior surface is defined as two surfaces with reverse constructions. The HeatTransferAlgorithm in "
    8603              :                                          "both constructions should be same.");
    8604            2 :                         ShowContinueError(state,
    8605            2 :                                           format("The HeatTransferAlgorithm of Surface: {}, is {}",
    8606            1 :                                                  surf.Name,
    8607            1 :                                                  DataSurfaces::HeatTransAlgoStrs[static_cast<int>(surf.HeatTransferAlgorithm)]));
    8608            2 :                         ShowContinueError(state,
    8609            2 :                                           format("The HeatTransferAlgorithm of Surface: {}, is {}",
    8610            1 :                                                  extSurf.Name,
    8611            1 :                                                  DataSurfaces::HeatTransAlgoStrs[static_cast<int>(extSurf.HeatTransferAlgorithm)]));
    8612            1 :                         if (surf.HeatTransferAlgorithm > extSurf.HeatTransferAlgorithm) {
    8613            2 :                             ShowContinueError(state,
    8614            2 :                                               format("The HeatTransferAlgorithm of Surface: {}, is assigned to {}. Simulation continues.",
    8615            1 :                                                      extSurf.Name,
    8616            1 :                                                      DataSurfaces::HeatTransAlgoStrs[static_cast<int>(surf.HeatTransferAlgorithm)]));
    8617            1 :                             extSurf.HeatTransferAlgorithm = surf.HeatTransferAlgorithm;
    8618              :                         } else {
    8619            0 :                             ShowContinueError(state,
    8620            0 :                                               format("The HeatTransferAlgorithm of Surface: {}, is assigned to {}. Simulation continues.",
    8621            0 :                                                      surf.Name,
    8622            0 :                                                      DataSurfaces::HeatTransAlgoStrs[static_cast<int>(extSurf.HeatTransferAlgorithm)]));
    8623            0 :                             surf.HeatTransferAlgorithm = extSurf.HeatTransferAlgorithm;
    8624              :                         }
    8625              :                     }
    8626              :                 }
    8627              :             }
    8628              :         }
    8629              : 
    8630              :         // Assign model type to windows, shading surfaces, and TDDs
    8631         2486 :         for (Item = 1; Item <= state.dataSurface->TotSurfaces; ++Item) {
    8632         2262 :             if (state.dataSurface->Surface(Item).Class == SurfaceClass::Window || state.dataSurface->Surface(Item).Class == SurfaceClass::GlassDoor) {
    8633              :                 // todo, add complex fenestration switch  HeatTransferModel_ComplexFenestration
    8634          197 :                 if (state.dataSurface->SurfWinWindowModelType(Item) == DataSurfaces::WindowModel::BSDF) {
    8635            0 :                     state.dataSurface->Surface(Item).HeatTransferAlgorithm = DataSurfaces::HeatTransferModel::ComplexFenestration;
    8636              :                 } else {
    8637          197 :                     state.dataSurface->Surface(Item).HeatTransferAlgorithm = DataSurfaces::HeatTransferModel::Window5;
    8638              :                 }
    8639              :             }
    8640         2262 :             if (state.dataSurface->Surface(Item).Class == SurfaceClass::Detached_B ||
    8641         2242 :                 state.dataSurface->Surface(Item).Class == SurfaceClass::Detached_F ||
    8642         6682 :                 state.dataSurface->Surface(Item).Class == SurfaceClass::Shading || state.dataSurface->Surface(Item).Class == SurfaceClass::Overhang ||
    8643         2178 :                 state.dataSurface->Surface(Item).Class == SurfaceClass::Fin) {
    8644           84 :                 state.dataSurface->Surface(Item).HeatTransferAlgorithm = DataSurfaces::HeatTransferModel::None;
    8645              :             }
    8646         4524 :             if (state.dataSurface->Surface(Item).Class == SurfaceClass::TDD_Diffuser ||
    8647         2262 :                 state.dataSurface->Surface(Item).Class == SurfaceClass::TDD_Dome) {
    8648            7 :                 state.dataSurface->Surface(Item).HeatTransferAlgorithm = DataSurfaces::HeatTransferModel::TDD;
    8649              :             }
    8650              : 
    8651         2565 :             if (state.dataSurface->Surface(Item).HeatTransferAlgorithm == DataSurfaces::HeatTransferModel::CTF ||
    8652          303 :                 state.dataSurface->Surface(Item).HeatTransferAlgorithm == DataSurfaces::HeatTransferModel::EMPD) {
    8653         1959 :                 state.dataConstruction->Construct(state.dataSurface->Surface(Item).Construction).IsUsedCTF = true;
    8654              :             }
    8655              :         }
    8656          224 :     }
    8657              : 
    8658              :     struct PopCoincidentVertexReturn
    8659              :     {
    8660              :         double perimeter;
    8661              :         int poppedVertexPos = -1; // This is a STL vector position, 0-indexed
    8662              :         int keptVertexPos = -1;
    8663              :     };
    8664              : 
    8665         2201 :     PopCoincidentVertexReturn checkPopCoincidentVertex(const Array1D<Vector> &vertices)
    8666              :     {
    8667              : 
    8668         2201 :         size_t const nSides = vertices.size();
    8669              : 
    8670              :         // Pass one: Vector of distance from this vertex to the next one
    8671         2201 :         std::vector<Real64> distances(nSides);
    8672         2201 :         size_t index = 0;
    8673         2201 :         double min_distance = std::numeric_limits<Real64>::max();
    8674         2201 :         double perimeter = 0.0;
    8675        11009 :         for (auto it = vertices.begin(); it != vertices.end(); ++it) {
    8676         8808 :             auto itnext = std::next(it);
    8677         8808 :             if (itnext == std::end(vertices)) {
    8678         2201 :                 itnext = std::begin(vertices);
    8679              :             }
    8680         8808 :             const auto dist = distance(*it, *itnext);
    8681         8808 :             distances[index++] = dist;
    8682         8808 :             min_distance = std::min(min_distance, dist);
    8683         8808 :             perimeter += dist;
    8684              :         }
    8685              :         // Return early if nothing to be popped
    8686         2201 :         if (min_distance >= Constant::OneCentimeter) {
    8687         2193 :             return {perimeter};
    8688              :         }
    8689              : 
    8690              :         // Pass two: figure out the vertex that is coincident with its previous and/or next vertex and
    8691              :         // that minimizes the (distanceThisToNext + distanceThisToPrev).
    8692            8 :         Real64 min_weight = std::numeric_limits<Real64>::max();
    8693            8 :         int poppedVertexPos = -1;
    8694            8 :         int keptVertexPos = -1;
    8695              : 
    8696           49 :         for (index = 0; index < nSides; ++index) {
    8697           41 :             size_t const prevIndex = (index == 0) ? nSides - 1 : index - 1;
    8698           41 :             Real64 const &distanceThisToNext = distances[index];
    8699           41 :             Real64 const &distanceThisToPrev = distances[prevIndex];
    8700           41 :             if ((distanceThisToNext >= Constant::OneCentimeter) && (distanceThisToPrev >= Constant::OneCentimeter)) {
    8701           19 :                 continue;
    8702              :             }
    8703           22 :             Real64 const weight = distanceThisToNext + distanceThisToPrev;
    8704           22 :             if (weight < min_weight) {
    8705           13 :                 min_weight = weight;
    8706           13 :                 poppedVertexPos = static_cast<int>(index);
    8707           13 :                 if (distanceThisToPrev < distanceThisToNext) {
    8708            4 :                     keptVertexPos = prevIndex;
    8709              :                 } else {
    8710            9 :                     keptVertexPos = static_cast<int>((index == nSides - 1) ? 0 : index + 1);
    8711              :                 }
    8712              :             }
    8713              :         }
    8714              : 
    8715              :         // Return the keptVertexPos (which can be the previous or the next), so we can print the displayExtraWarning correctly
    8716            8 :         return {perimeter, poppedVertexPos, keptVertexPos};
    8717         2201 :     }
    8718              : 
    8719         2194 :     void GetVertices(EnergyPlusData &state,
    8720              :                      int const SurfNum,             // Current surface number
    8721              :                      int const NSides,              // Number of sides to figure
    8722              :                      Array1S<Real64> const Vertices // Vertices, in specified order
    8723              :     )
    8724              :     {
    8725              : 
    8726              :         // SUBROUTINE INFORMATION:
    8727              :         //       AUTHOR         Linda Lawrie
    8728              :         //       DATE WRITTEN   May 2000
    8729              : 
    8730              :         // PURPOSE OF THIS SUBROUTINE:
    8731              :         // This subroutine gets the surface vertices from the arrays
    8732              :         // passed by the calling routine.  These had previously been obtained
    8733              :         // from the InputProcessor (GetObjectItem).  This routine will provide
    8734              :         // a standard place for determining various properties of the surface
    8735              :         // from the vertices.
    8736              : 
    8737              :         // SUBROUTINE PARAMETER DEFINITIONS:
    8738              :         static constexpr std::string_view RoutineName("GetVertices: ");
    8739              : 
    8740              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    8741              :         int n;    // Loop counter
    8742              :         int NSrc; // Used for CW -> CCW transformation
    8743              :         int NTar; // Used for CW -> CCW transformation
    8744              :         Real64 SurfWorldAz;
    8745              :         Real64 SurfTilt;
    8746              :         Real64 Perimeter; // Perimeter length of the surface
    8747              :         Real64 Xb;        // Intermediate calculation
    8748              :         Real64 Yb;        // Intermediate calculation
    8749              :         int ZoneNum;
    8750              :         int ThisCorner;
    8751              :         Real64 ThisWidth;
    8752              :         Real64 ThisHeight;
    8753              :         // unused    REAL(r64) :: ccwtest
    8754              :         // unused    LOGICAL   :: SurfaceCCW
    8755              :         Real64 dotp;
    8756              : 
    8757              :         // Object Data
    8758         2194 :         Vector const TestVector(0.0, 0.0, 1.0);
    8759         2194 :         Vector temp;
    8760              : 
    8761         2194 :         auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    8762              : 
    8763         2194 :         if (NSides > state.dataSurface->MaxVerticesPerSurface) state.dataSurface->MaxVerticesPerSurface = NSides;
    8764         2194 :         int Ptr = 1;
    8765        10971 :         for (n = 1; n <= NSides; ++n) {
    8766         8777 :             surfTemp.Vertex(n).x = Vertices(Ptr);
    8767         8777 :             ++Ptr;
    8768         8777 :             surfTemp.Vertex(n).y = Vertices(Ptr);
    8769         8777 :             ++Ptr;
    8770         8777 :             surfTemp.Vertex(n).z = Vertices(Ptr);
    8771         8777 :             ++Ptr;
    8772              :         }
    8773              : 
    8774              :         // Address changing vertices if they were put in in CW order rather than CCW
    8775         2194 :         if (!state.dataSurface->CCW) {
    8776              :             // If even number of sides, this will transfer appropriately
    8777              :             // If odd number, will leave the "odd" one, which is what you want.
    8778            2 :             NSrc = NSides;
    8779            2 :             NTar = 2;
    8780            4 :             for (n = 1; n <= (NSides - 1) / 2; ++n) {
    8781            2 :                 temp = surfTemp.Vertex(NSrc);
    8782            2 :                 surfTemp.Vertex(NSrc) = surfTemp.Vertex(NTar);
    8783            2 :                 surfTemp.Vertex(NTar) = temp;
    8784            2 :                 --NSrc;
    8785            2 :                 ++NTar;
    8786              :             }
    8787              :         }
    8788              :         // Now address which "Corner" has been put in first.  Note: the azimuth and tilt and area
    8789              :         // calculations do not care which corner is put in first.
    8790              :         // 2/2011 - don't think the shading calculations have a corner preference.  Will keep this for
    8791              :         // consistency (for now)
    8792         2194 :         ThisCorner = state.dataSurface->Corner;
    8793         2648 :         while (ThisCorner != DataSurfaces::UpperLeftCorner) {
    8794          454 :             if (NSides < 4) {
    8795            4 :                 if (ThisCorner == DataSurfaces::UpperRightCorner) {
    8796            0 :                     break;
    8797              :                 }
    8798              :             }
    8799          454 :             NTar = ThisCorner;
    8800          454 :             NSrc = ThisCorner + 1;
    8801          454 :             if (NSrc > NSides) NSrc = 1;
    8802         1812 :             for (n = 1; n <= NSides - 1; ++n) {
    8803         1358 :                 temp = surfTemp.Vertex(NTar);
    8804         1358 :                 surfTemp.Vertex(NTar) = surfTemp.Vertex(NSrc);
    8805         1358 :                 surfTemp.Vertex(NSrc) = temp;
    8806         1358 :                 ++NTar;
    8807         1358 :                 ++NSrc;
    8808         1358 :                 if (NTar > NSides) NTar = 1;
    8809         1358 :                 if (NSrc > NSides) NSrc = 1;
    8810              :             }
    8811          454 :             ++ThisCorner;
    8812          454 :             if (ThisCorner > NSides) ThisCorner = 1;
    8813              :         } // Corners
    8814         2194 :         if (!state.dataSurface->WorldCoordSystem) {
    8815              :             // Input in "relative" coordinates, use Building and Zone North Axes and Origins
    8816              :             //                                  to translate each point (including rotation for Appendix G)
    8817         1225 :             ZoneNum = surfTemp.Zone;
    8818         1225 :             if (ZoneNum > 0) {
    8819         6077 :                 for (n = 1; n <= NSides; ++n) {
    8820         4865 :                     Xb = surfTemp.Vertex(n).x * state.dataSurfaceGeometry->CosZoneRelNorth(ZoneNum) -
    8821         4865 :                          surfTemp.Vertex(n).y * state.dataSurfaceGeometry->SinZoneRelNorth(ZoneNum) + state.dataHeatBal->Zone(ZoneNum).OriginX;
    8822         4865 :                     Yb = surfTemp.Vertex(n).x * state.dataSurfaceGeometry->SinZoneRelNorth(ZoneNum) +
    8823         4865 :                          surfTemp.Vertex(n).y * state.dataSurfaceGeometry->CosZoneRelNorth(ZoneNum) + state.dataHeatBal->Zone(ZoneNum).OriginY;
    8824         4865 :                     surfTemp.Vertex(n).x = Xb * state.dataSurfaceGeometry->CosBldgRelNorth - Yb * state.dataSurfaceGeometry->SinBldgRelNorth;
    8825         4865 :                     surfTemp.Vertex(n).y = Xb * state.dataSurfaceGeometry->SinBldgRelNorth + Yb * state.dataSurfaceGeometry->CosBldgRelNorth;
    8826         4865 :                     surfTemp.Vertex(n).z += state.dataHeatBal->Zone(ZoneNum).OriginZ;
    8827              :                 }
    8828           13 :             } else if (surfTemp.Class == SurfaceClass::Detached_B) {
    8829           50 :                 for (n = 1; n <= NSides; ++n) {
    8830           40 :                     Xb = surfTemp.Vertex(n).x;
    8831           40 :                     Yb = surfTemp.Vertex(n).y;
    8832           40 :                     surfTemp.Vertex(n).x = Xb * state.dataSurfaceGeometry->CosBldgRelNorth - Yb * state.dataSurfaceGeometry->SinBldgRelNorth;
    8833           40 :                     surfTemp.Vertex(n).y = Xb * state.dataSurfaceGeometry->SinBldgRelNorth + Yb * state.dataSurfaceGeometry->CosBldgRelNorth;
    8834              :                 }
    8835              :             }
    8836              :         } else {
    8837              :             // if world coordinate only need to rotate for Appendix G
    8838          969 :             ZoneNum = surfTemp.Zone;
    8839          969 :             if (ZoneNum > 0) {
    8840         4809 :                 for (n = 1; n <= NSides; ++n) {
    8841         3844 :                     Xb = surfTemp.Vertex(n).x;
    8842         3844 :                     Yb = surfTemp.Vertex(n).y;
    8843         3844 :                     surfTemp.Vertex(n).x = Xb * state.dataSurfaceGeometry->CosBldgRotAppGonly - Yb * state.dataSurfaceGeometry->SinBldgRotAppGonly;
    8844         3844 :                     surfTemp.Vertex(n).y = Xb * state.dataSurfaceGeometry->SinBldgRotAppGonly + Yb * state.dataSurfaceGeometry->CosBldgRotAppGonly;
    8845              :                 }
    8846            4 :             } else if (surfTemp.Class == SurfaceClass::Detached_B) {
    8847           10 :                 for (n = 1; n <= NSides; ++n) {
    8848            8 :                     Xb = surfTemp.Vertex(n).x;
    8849            8 :                     Yb = surfTemp.Vertex(n).y;
    8850            8 :                     surfTemp.Vertex(n).x = Xb * state.dataSurfaceGeometry->CosBldgRotAppGonly - Yb * state.dataSurfaceGeometry->SinBldgRotAppGonly;
    8851            8 :                     surfTemp.Vertex(n).y = Xb * state.dataSurfaceGeometry->SinBldgRotAppGonly + Yb * state.dataSurfaceGeometry->CosBldgRotAppGonly;
    8852              :                 }
    8853              :             }
    8854              :         }
    8855              : 
    8856         2194 :         if (NSides > 2) {
    8857         2194 :             auto &surface = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    8858         2194 :             auto &vertices = surface.Vertex;
    8859         2194 :             auto &nSides = surface.Sides;
    8860         2194 :             std::string TiltString;
    8861              : 
    8862              :             while (true) {
    8863         2201 :                 PopCoincidentVertexReturn const popResult = checkPopCoincidentVertex(vertices);
    8864         2201 :                 Perimeter = popResult.perimeter;
    8865         2201 :                 if (popResult.poppedVertexPos < 0) {
    8866              :                     // No pop needed, we're done
    8867         2193 :                     break;
    8868              :                 }
    8869              : 
    8870              :                 // Grab the popped one, and the kept one (regardless of whether it's previous or next)
    8871            8 :                 auto it = vertices.begin();
    8872            8 :                 std::advance(it, popResult.poppedVertexPos);
    8873            8 :                 int const poppedVertexIndex = popResult.poppedVertexPos + 1;
    8874              : 
    8875            8 :                 auto itKept = vertices.begin();
    8876            8 :                 std::advance(itKept, popResult.keptVertexPos);
    8877            8 :                 int const keptVertexIndex = popResult.keptVertexPos + 1;
    8878              : 
    8879            8 :                 if (state.dataGlobal->DisplayExtraWarnings) {
    8880           12 :                     ShowWarningError(state,
    8881           12 :                                      format("{}Distance between two vertices < .01, possibly coincident. for Surface={}, in Zone={}",
    8882              :                                             RoutineName,
    8883            6 :                                             surfTemp.Name,
    8884            6 :                                             surfTemp.ZoneName));
    8885              : 
    8886            9 :                     bool const printPoppedFirst = (poppedVertexIndex < keptVertexIndex) ? !(poppedVertexIndex == 1 && keptVertexIndex == nSides)
    8887            3 :                                                                                         : (poppedVertexIndex == nSides && keptVertexIndex == 1);
    8888              : 
    8889            6 :                     if (printPoppedFirst) {
    8890            5 :                         ShowContinueError(state, format("Vertex [{}]=({:.2R},{:.2R},{:.2R})", poppedVertexIndex, it->x, it->y, it->z));
    8891            5 :                         ShowContinueError(state, format("Vertex [{}]=({:.2R},{:.2R},{:.2R})", keptVertexIndex, itKept->x, itKept->y, itKept->z));
    8892              :                     } else {
    8893            1 :                         ShowContinueError(state, format("Vertex [{}]=({:.2R},{:.2R},{:.2R})", keptVertexIndex, itKept->x, itKept->y, itKept->z));
    8894            1 :                         ShowContinueError(state, format("Vertex [{}]=({:.2R},{:.2R},{:.2R})", poppedVertexIndex, it->x, it->y, it->z));
    8895              :                     }
    8896              :                 }
    8897            8 :                 ++state.dataErrTracking->TotalCoincidentVertices;
    8898            8 :                 if (nSides <= 3) {
    8899            1 :                     if (state.dataGlobal->DisplayExtraWarnings) {
    8900            0 :                         ShowContinueError(state,
    8901            0 :                                           format("Cannot Drop Vertex [{}]; Number of Surface Sides at minimum. This surface is now a "
    8902              :                                                  "degenerate surface.",
    8903              :                                                  poppedVertexIndex));
    8904              :                     }
    8905            1 :                     ++state.dataErrTracking->TotalDegenerateSurfaces;
    8906              :                     // If degenerate, we won't be able to pop now nor later, so exit
    8907              :                     // mark degenerate surface?
    8908            1 :                     break;
    8909              :                 }
    8910              : 
    8911            7 :                 if (state.dataGlobal->DisplayExtraWarnings) {
    8912            6 :                     ShowContinueError(state, format("Dropping Vertex [{}].", poppedVertexIndex));
    8913              :                 }
    8914            7 :                 --nSides;
    8915            7 :                 vertices.erase(it);
    8916              :                 // No need to recompute perimeter, because it'll be done in the next iteration, until no popping or degenerate happens
    8917            7 :             }
    8918              : 
    8919         2194 :             surfTemp.Perimeter = Perimeter;
    8920              : 
    8921         2194 :             Vectors::CreateNewellSurfaceNormalVector(surfTemp.Vertex, surfTemp.Sides, surfTemp.NewellSurfaceNormalVector);
    8922         2194 :             Vectors::CreateNewellAreaVector(surfTemp.Vertex, surfTemp.Sides, surfTemp.NewellAreaVector);
    8923              :             // For surfaces with subsurfaces, the following two areas are turned into net areas later by
    8924              :             // subtracting subsurface areas
    8925         2194 :             surfTemp.GrossArea = Vectors::VecLength(surfTemp.NewellAreaVector);
    8926         2194 :             surfTemp.Area = surfTemp.GrossArea;
    8927         2194 :             surfTemp.NetAreaShadowCalc = surfTemp.Area;
    8928         2194 :             Vectors::DetermineAzimuthAndTilt(
    8929         2194 :                 surfTemp.Vertex, SurfWorldAz, SurfTilt, surfTemp.lcsx, surfTemp.lcsy, surfTemp.lcsz, surfTemp.NewellSurfaceNormalVector);
    8930         2194 :             dotp = dot(surfTemp.NewellSurfaceNormalVector, TestVector);
    8931         2194 :             if (surfTemp.Class == SurfaceClass::Roof && dotp < -0.000001) {
    8932           16 :                 TiltString = format("{:.1R}", SurfTilt);
    8933           32 :                 ShowWarningError(state,
    8934           32 :                                  format("{}Roof/Ceiling is upside down! Tilt angle=[{}], should be near 0, Surface=\"{}\", in Zone=\"{}\".",
    8935              :                                         RoutineName,
    8936              :                                         TiltString,
    8937           16 :                                         surfTemp.Name,
    8938           16 :                                         surfTemp.ZoneName));
    8939           32 :                 ShowContinueError(state, "Automatic fix is attempted.");
    8940           16 :                 ReverseAndRecalculate(state, SurfNum, surfTemp.Sides, SurfWorldAz, SurfTilt);
    8941         2178 :             } else if (surfTemp.Class == SurfaceClass::Roof && SurfTilt > 80.0) {
    8942            8 :                 TiltString = format("{:.1R}", SurfTilt);
    8943           16 :                 ShowWarningError(
    8944              :                     state,
    8945           16 :                     format("{}Roof/Ceiling is not oriented correctly! Tilt angle=[{}], should be near 0, Surface=\"{}\", in Zone=\"{}\".",
    8946              :                            RoutineName,
    8947              :                            TiltString,
    8948            8 :                            surfTemp.Name,
    8949            8 :                            surfTemp.ZoneName));
    8950              :             }
    8951         2194 :             if (surfTemp.Class == SurfaceClass::Floor && dotp > 0.000001) {
    8952           41 :                 TiltString = format("{:.1R}", SurfTilt);
    8953           82 :                 ShowWarningError(state,
    8954           82 :                                  format("{}Floor is upside down! Tilt angle=[{}], should be near 180, Surface=\"{}\", in Zone=\"{}\".",
    8955              :                                         RoutineName,
    8956              :                                         TiltString,
    8957           41 :                                         surfTemp.Name,
    8958           41 :                                         surfTemp.ZoneName));
    8959           82 :                 ShowContinueError(state, "Automatic fix is attempted.");
    8960           41 :                 ReverseAndRecalculate(state, SurfNum, surfTemp.Sides, SurfWorldAz, SurfTilt);
    8961         2153 :             } else if (surfTemp.Class == SurfaceClass::Floor && SurfTilt < 158.2) { // slope/grade = 40%!
    8962           16 :                 TiltString = format("{:.1R}", SurfTilt);
    8963           32 :                 ShowWarningError(state,
    8964           32 :                                  format("{}Floor is not oriented correctly! Tilt angle=[{}], should be near 180, Surface=\"{}\", in Zone=\"{}\".",
    8965              :                                         RoutineName,
    8966              :                                         TiltString,
    8967           16 :                                         surfTemp.Name,
    8968           16 :                                         surfTemp.ZoneName));
    8969              :             }
    8970         2194 :             surfTemp.Azimuth = SurfWorldAz;
    8971         2194 :             surfTemp.Tilt = SurfTilt;
    8972         2194 :             surfTemp.convOrientation = Convect::GetSurfConvOrientation(surfTemp.Tilt);
    8973              : 
    8974              :             // Sine and cosine of azimuth and tilt
    8975         2194 :             surfTemp.SinAzim = std::sin(SurfWorldAz * Constant::DegToRad);
    8976         2194 :             surfTemp.CosAzim = std::cos(SurfWorldAz * Constant::DegToRad);
    8977         2194 :             surfTemp.SinTilt = std::sin(SurfTilt * Constant::DegToRad);
    8978         2194 :             surfTemp.CosTilt = std::cos(SurfTilt * Constant::DegToRad);
    8979         2194 :             if (surfTemp.ViewFactorGround == Constant::AutoCalculate) {
    8980          477 :                 surfTemp.ViewFactorGround = 0.5 * (1.0 - surfTemp.CosTilt);
    8981              :             }
    8982              :             // Outward normal unit vector (pointing away from room)
    8983         2194 :             surfTemp.OutNormVec = surfTemp.NewellSurfaceNormalVector;
    8984         8776 :             for (n = 1; n <= 3; ++n) {
    8985         6582 :                 if (std::abs(surfTemp.OutNormVec(n) - 1.0) < 1.e-06) surfTemp.OutNormVec(n) = +1.0;
    8986         6582 :                 if (std::abs(surfTemp.OutNormVec(n) + 1.0) < 1.e-06) surfTemp.OutNormVec(n) = -1.0;
    8987         6582 :                 if (std::abs(surfTemp.OutNormVec(n)) < 1.e-06) surfTemp.OutNormVec(n) = 0.0;
    8988              :             }
    8989              : 
    8990         2194 :             if (surfTemp.Class == SurfaceClass::Window || surfTemp.Class == SurfaceClass::GlassDoor || surfTemp.Class == SurfaceClass::Door)
    8991          201 :                 surfTemp.Area *= surfTemp.Multiplier;
    8992              :             // Can perform tests on this surface here
    8993         2194 :             surfTemp.ViewFactorSky = 0.5 * (1.0 + surfTemp.CosTilt);
    8994              :             // The following IR view factors are modified in subr. SkyDifSolarShading if there are shadowing
    8995              :             // surfaces
    8996         2194 :             surfTemp.ViewFactorSkyIR = surfTemp.ViewFactorSky;
    8997         2194 :             surfTemp.ViewFactorGroundIR = 0.5 * (1.0 - surfTemp.CosTilt);
    8998              : 
    8999              :             // Call to transform vertices
    9000              : 
    9001         2194 :             TransformVertsByAspect(state, SurfNum, surfTemp.Sides);
    9002              : 
    9003         2194 :         } else {
    9004            0 :             ShowFatalError(state, format("{}Called with less than 2 sides, Surface={}", RoutineName, surfTemp.Name));
    9005              :         }
    9006              : 
    9007              :         // Preliminary Height/Width
    9008         2194 :         temp = surfTemp.Vertex(3) - surfTemp.Vertex(2);
    9009         2194 :         ThisWidth = Vectors::VecLength(temp);
    9010         2194 :         temp = surfTemp.Vertex(2) - surfTemp.Vertex(1);
    9011         2194 :         ThisHeight = Vectors::VecLength(temp);
    9012         2194 :         surfTemp.Height = ThisHeight;
    9013         2194 :         surfTemp.Width = ThisWidth;
    9014         2194 :     }
    9015              : 
    9016           57 :     void ReverseAndRecalculate(EnergyPlusData &state,
    9017              :                                int const SurfNum,   // Surface number for the surface
    9018              :                                int const NSides,    // number of sides to surface
    9019              :                                Real64 &SurfAzimuth, // Surface Facing angle (will be 0 for roofs/floors)
    9020              :                                Real64 &SurfTilt     // Surface tilt (
    9021              :     )
    9022              :     {
    9023              : 
    9024              :         // SUBROUTINE INFORMATION:
    9025              :         //       AUTHOR         Linda Lawrie
    9026              :         //       DATE WRITTEN   February 2011
    9027              : 
    9028              :         // PURPOSE OF THIS SUBROUTINE:
    9029              :         // This routine reverses the vertices for a surface (needed when roof/floor is upside down)
    9030              :         // and recalculates the azimuth, etc for the surface.
    9031              : 
    9032              :         // SUBROUTINE PARAMETER DEFINITIONS:
    9033              :         static constexpr std::string_view RoutineName("ReverseAndRecalculate: ");
    9034              : 
    9035              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    9036              :         int n;      // Loop Control
    9037              :         int RevPtr; // pointer for reversing vertices
    9038           57 :         std::string TiltString;
    9039              : 
    9040              :         // Object Data
    9041           57 :         Array1D<Vector> Vertices(NSides); // Vertices, in specified order
    9042              : 
    9043           57 :         auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    9044              : 
    9045          284 :         for (n = 1; n <= NSides; ++n) {
    9046          227 :             Vertices(n) = surfTemp.Vertex(n);
    9047              :         }
    9048           57 :         RevPtr = NSides;
    9049          284 :         for (n = 1; n <= NSides; ++n) {
    9050          227 :             surfTemp.Vertex(n) = Vertices(RevPtr);
    9051          227 :             --RevPtr;
    9052              :         }
    9053              : 
    9054           57 :         print(state.files.debug, "Reversing Surface Name={}\n", surfTemp.Name);
    9055          284 :         for (n = 1; n <= NSides; ++n) {
    9056          227 :             print(state.files.debug,
    9057              :                   "side={:5} abs coord vertex= {:18.13F} {:18.13F} {:18.13F}\n",
    9058              :                   n,
    9059          227 :                   surfTemp.Vertex(n).x,
    9060          227 :                   surfTemp.Vertex(n).y,
    9061          227 :                   surfTemp.Vertex(n).z);
    9062              :         }
    9063              : 
    9064           57 :         Vectors::CreateNewellSurfaceNormalVector(surfTemp.Vertex, surfTemp.Sides, surfTemp.NewellSurfaceNormalVector);
    9065           57 :         Vectors::DetermineAzimuthAndTilt(
    9066           57 :             surfTemp.Vertex, SurfAzimuth, SurfTilt, surfTemp.lcsx, surfTemp.lcsy, surfTemp.lcsz, surfTemp.NewellSurfaceNormalVector);
    9067           57 :         if (surfTemp.Class == SurfaceClass::Roof && SurfTilt > 80.0) {
    9068            0 :             TiltString = format("{:.1R}", SurfTilt);
    9069            0 :             ShowWarningError(
    9070              :                 state,
    9071            0 :                 format("{}Roof/Ceiling is still upside down! Tilt angle=[{}], should be near 0, please fix manually.", RoutineName, TiltString));
    9072              :         }
    9073           57 :         if (surfTemp.Class == SurfaceClass::Floor && SurfTilt < 158.2) { // 40% grade!
    9074           16 :             ShowWarningError(
    9075           16 :                 state, format("{}Floor is still upside down! Tilt angle=[{}], should be near 180, please fix manually.", RoutineName, TiltString));
    9076              :         }
    9077           57 :     }
    9078              : 
    9079           49 :     void MakeMirrorSurface(EnergyPlusData &state, int &SurfNum) // In=>Surface to Mirror, Out=>new Surface index // This is not good
    9080              :     {
    9081              : 
    9082              :         // SUBROUTINE INFORMATION:
    9083              :         //       AUTHOR         Linda Lawrie
    9084              :         //       DATE WRITTEN   June 2002
    9085              : 
    9086              :         // PURPOSE OF THIS SUBROUTINE:
    9087              :         // This subroutine creates a "mirror" surface using the indicated surface.
    9088              :         // This is the simple approach for bi-directional shading devices.  If, perchance,
    9089              :         // the user has already taken care of this (e.g. fins in middle of wall), there will
    9090              :         // be extra shading devices shown.
    9091              : 
    9092           49 :         auto &origSurface = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    9093           49 :         auto &newSurface = state.dataSurfaceGeometry->SurfaceTmp(SurfNum + 1);
    9094           49 :         newSurface = origSurface;
    9095              : 
    9096           49 :         auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    9097              : 
    9098           49 :         int nVert = origSurface.Sides;
    9099              :         // Reverse the vertices in the original surface.  Add "MIR-" to name.
    9100          244 :         for (int Vert = 1; Vert <= surfTemp.Sides; ++Vert) {
    9101          195 :             newSurface.Vertex(Vert) = origSurface.Vertex(nVert);
    9102          195 :             --nVert;
    9103              :         }
    9104           49 :         newSurface.Name = "Mir-" + origSurface.Name;
    9105           49 :         newSurface.MirroredSurf = true;
    9106              : 
    9107           49 :         if (newSurface.Sides > 2) {
    9108           49 :             Vectors::CreateNewellAreaVector(newSurface.Vertex, newSurface.Sides, newSurface.NewellAreaVector);
    9109           49 :             newSurface.GrossArea = Vectors::VecLength(newSurface.NewellAreaVector);
    9110           49 :             newSurface.Area = newSurface.GrossArea;
    9111           49 :             newSurface.NetAreaShadowCalc = newSurface.Area;
    9112           49 :             Vectors::CreateNewellSurfaceNormalVector(newSurface.Vertex, newSurface.Sides, newSurface.NewellSurfaceNormalVector);
    9113           49 :             Real64 SurfWorldAz = 0.0;
    9114           49 :             Real64 SurfTilt = 0.0;
    9115           49 :             Vectors::DetermineAzimuthAndTilt(
    9116           49 :                 newSurface.Vertex, SurfWorldAz, SurfTilt, newSurface.lcsx, newSurface.lcsy, newSurface.lcsz, newSurface.NewellSurfaceNormalVector);
    9117           49 :             newSurface.Azimuth = SurfWorldAz;
    9118           49 :             newSurface.Tilt = SurfTilt;
    9119           49 :             newSurface.convOrientation = Convect::GetSurfConvOrientation(newSurface.Tilt);
    9120              : 
    9121              :             // Sine and cosine of azimuth and tilt
    9122           49 :             newSurface.SinAzim = std::sin(SurfWorldAz * Constant::DegToRad);
    9123           49 :             newSurface.CosAzim = std::cos(SurfWorldAz * Constant::DegToRad);
    9124           49 :             newSurface.SinTilt = std::sin(SurfTilt * Constant::DegToRad);
    9125           49 :             newSurface.CosTilt = std::cos(SurfTilt * Constant::DegToRad);
    9126              :             // Outward normal unit vector (pointing away from room)
    9127           49 :             newSurface.OutNormVec = newSurface.NewellSurfaceNormalVector;
    9128          196 :             for (int n = 1; n <= 3; ++n) {
    9129          147 :                 if (std::abs(newSurface.OutNormVec(n) - 1.0) < 1.e-06) newSurface.OutNormVec(n) = +1.0;
    9130          147 :                 if (std::abs(newSurface.OutNormVec(n) + 1.0) < 1.e-06) newSurface.OutNormVec(n) = -1.0;
    9131          147 :                 if (std::abs(newSurface.OutNormVec(n)) < 1.e-06) newSurface.OutNormVec(n) = 0.0;
    9132              :             }
    9133              : 
    9134              :             // Can perform tests on this surface here
    9135           49 :             newSurface.ViewFactorSky = 0.5 * (1.0 + newSurface.CosTilt);
    9136              :             // The following IR view factors are modified in subr. SkyDifSolarShading if there are shadowing surfaces
    9137           49 :             newSurface.ViewFactorSkyIR = newSurface.ViewFactorSky;
    9138           49 :             newSurface.ViewFactorGroundIR = 0.5 * (1.0 - newSurface.CosTilt);
    9139           49 :             ++SurfNum; // Calling function expects incremented argument on return
    9140              :         }
    9141           49 :     }
    9142              : 
    9143          226 :     void GetWindowShadingControlData(EnergyPlusData &state, bool &ErrorsFound) // If errors found in input
    9144              :     {
    9145              : 
    9146              :         // SUBROUTINE INFORMATION:
    9147              :         //       AUTHOR         Fred Winkelmann
    9148              :         //       DATE WRITTEN   November 1998
    9149              :         //       MODIFIED       Aug 2001 (FW): add handling of new ShadingControlIsScheduled
    9150              :         //                      and GlareControlIsActive fields
    9151              :         //                      Nov 2001 (FW): add ShadingDevice as alternative to ShadedConstruction
    9152              :         //                      Dec 2001 (FW): add slat angle controls for blinds
    9153              :         //                      Aug 2002 (FW): add Setpoint2; check that specified control type is legal
    9154              :         //                      Feb 2003 (FW): add error if Material Name of Shading Device is used with
    9155              :         //                        Shading Type = BetweenGlassShade or BetweenGlassBlind
    9156              :         //                      Dec 2003 (FW): improve BetweenGlassBlind error messages
    9157              :         //                      Feb 2009 (BG): improve error checking for OnIfScheduleAllows
    9158              : 
    9159              :         // PURPOSE OF THIS SUBROUTINE:
    9160              :         // Reads in the window shading control information
    9161              :         // from the input data file, interprets it and puts it in the derived type
    9162              : 
    9163              :         // SUBROUTINE PARAMETER DEFINITIONS:
    9164              :         static constexpr std::string_view routineName = "GetWindowShadingControlData";
    9165              : 
    9166          226 :         int constexpr NumValidShadingTypes(9);
    9167              :         static Array1D_string const cValidShadingTypes(NumValidShadingTypes,
    9168              :                                                        {
    9169              :                                                            "SHADEOFF",          // 1
    9170              :                                                            "INTERIORSHADE",     // 2
    9171              :                                                            "SWITCHABLEGLAZING", // 3
    9172              :                                                            "EXTERIORSHADE",     // 4
    9173              :                                                            "EXTERIORSCREEN",    // 5
    9174              :                                                            "INTERIORBLIND",     // 6
    9175              :                                                            "EXTERIORBLIND",     // 7
    9176              :                                                            "BETWEENGLASSSHADE", // 8
    9177              :                                                            "BETWEENGLASSBLIND"  // 9
    9178          226 :                                                        });
    9179              : 
    9180          226 :         constexpr std::array<std::string_view, static_cast<int>(DataSurfaces::WindowShadingControlType::Num)> WindowShadingControlTypeNamesUC{
    9181              :             "ALWAYSON",
    9182              :             "ALWAYSOFF",
    9183              :             "ONIFSCHEDULEALLOWS",
    9184              :             "ONIFHIGHSOLARONWINDOW",
    9185              :             "ONIFHIGHHORIZONTALSOLAR",
    9186              :             "ONIFHIGHOUTDOORAIRTEMPERATURE",
    9187              :             "ONIFHIGHZONEAIRTEMPERATURE",
    9188              :             "ONIFHIGHZONECOOLING",
    9189              :             "ONIFHIGHGLARE",
    9190              :             "MEETDAYLIGHTILLUMINANCESETPOINT",
    9191              :             "ONNIGHTIFLOWOUTDOORTEMPANDOFFDAY",
    9192              :             "ONNIGHTIFLOWINSIDETEMPANDOFFDAY",
    9193              :             "ONNIGHTIFHEATINGANDOFFDAY",
    9194              :             "ONNIGHTIFLOWOUTDOORTEMPANDONDAYIFCOOLING",
    9195              :             "ONNIGHTIFHEATINGANDONDAYIFCOOLING",
    9196              :             "OFFNIGHTANDONDAYIFCOOLINGANDHIGHSOLARONWINDOW",
    9197              :             "ONNIGHTANDONDAYIFCOOLINGANDHIGHSOLARONWINDOW",
    9198              :             "ONIFHIGHOUTDOORAIRTEMPANDHIGHSOLARONWINDOW",
    9199              :             "ONIFHIGHOUTDOORAIRTEMPANDHIGHHORIZONTALSOLAR",
    9200              :             "ONIFHIGHZONEAIRTEMPANDHIGHSOLARONWINDOW",
    9201              :             "ONIFHIGHZONEAIRTEMPANDHIGHHORIZONTALSOLAR",
    9202              :             "ONIFHIGHSOLARORHIGHLUMINANCETILLMIDNIGHT",
    9203              :             "ONIFHIGHSOLARORHIGHLUMINANCETILLSUNSET",
    9204              :             "ONIFHIGHSOLARORHIGHLUMINANCETILLNEXTMORNING"};
    9205              : 
    9206          226 :         constexpr std::array<std::string_view, static_cast<int>(DataSurfaces::SlatAngleControl::Num)> SlatAngleNamesUC{
    9207              :             "FIXEDSLATANGLE", "SCHEDULEDSLATANGLE", "BLOCKBEAMSOLAR"};
    9208              : 
    9209          226 :         constexpr std::array<std::string_view, static_cast<int>(DataSurfaces::MultiSurfaceControl::Num)> MultiSurfaceControlNamesUC = {"SEQUENTIAL",
    9210              :                                                                                                                                        "GROUP"};
    9211              : 
    9212              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    9213              :         int IOStat;          // IO Status when calling get input subroutine
    9214              :         int ControlNumAlpha; // Number of control alpha names being passed
    9215              :         int ControlNumProp;  // Number of control properties being passed
    9216              :         int ControlNum;      // DO loop counter/index for window shading control number
    9217              :         int IShadedConst;    // Construction number of shaded construction
    9218              :         int IShadingDevice;  // Material number of shading device
    9219              :         int NLayers;         // Layers in shaded construction
    9220              :         int Loop;
    9221              :         bool BGShadeBlindError; // True if problem with construction that is supposed to have between-glass
    9222              :         // shade or blind
    9223              :         int Found;
    9224              : 
    9225          226 :         auto &s_mat = state.dataMaterial;
    9226          226 :         auto &s_ipsc = state.dataIPShortCut;
    9227              :         // Get the total number of window shading control blocks
    9228          226 :         s_ipsc->cCurrentModuleObject = "WindowShadingControl";
    9229          226 :         state.dataSurface->TotWinShadingControl = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
    9230          226 :         if (state.dataSurface->TotWinShadingControl == 0) return;
    9231              : 
    9232            4 :         state.dataSurface->WindowShadingControl.allocate(state.dataSurface->TotWinShadingControl);
    9233              : 
    9234            4 :         ControlNum = 0;
    9235            8 :         for (Loop = 1; Loop <= state.dataSurface->TotWinShadingControl; ++Loop) {
    9236              : 
    9237            8 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    9238            4 :                                                                      s_ipsc->cCurrentModuleObject,
    9239              :                                                                      Loop,
    9240            4 :                                                                      s_ipsc->cAlphaArgs,
    9241              :                                                                      ControlNumAlpha,
    9242            4 :                                                                      s_ipsc->rNumericArgs,
    9243              :                                                                      ControlNumProp,
    9244              :                                                                      IOStat,
    9245            4 :                                                                      s_ipsc->lNumericFieldBlanks,
    9246            4 :                                                                      s_ipsc->lAlphaFieldBlanks,
    9247            4 :                                                                      s_ipsc->cAlphaFieldNames,
    9248            4 :                                                                      s_ipsc->cNumericFieldNames);
    9249              : 
    9250            4 :             ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
    9251              : 
    9252            4 :             bool ErrorInName = false;
    9253            4 :             bool IsBlank = false;
    9254              : 
    9255            4 :             Util::VerifyName(state,
    9256            4 :                              s_ipsc->cAlphaArgs(1),
    9257            4 :                              state.dataSurface->WindowShadingControl,
    9258              :                              ControlNum,
    9259              :                              ErrorInName,
    9260              :                              IsBlank,
    9261            8 :                              s_ipsc->cCurrentModuleObject + " Name");
    9262            4 :             if (ErrorInName) {
    9263            0 :                 ErrorsFound = true;
    9264            0 :                 continue;
    9265              :             }
    9266              : 
    9267            4 :             ++ControlNum;
    9268              : 
    9269            4 :             auto &windowShadingControl = state.dataSurface->WindowShadingControl(ControlNum);
    9270              : 
    9271            4 :             windowShadingControl.Name = s_ipsc->cAlphaArgs(1); // Set the Control Name in the Derived Type
    9272              : 
    9273            4 :             windowShadingControl.ZoneIndex = Util::FindItemInList(s_ipsc->cAlphaArgs(2), state.dataHeatBal->Zone);
    9274            4 :             if (windowShadingControl.ZoneIndex == 0) {
    9275            0 :                 ShowSevereError(state,
    9276            0 :                                 format("{}=\"{}\" invalid {}=\"{}\" not found.",
    9277            0 :                                        s_ipsc->cCurrentModuleObject,
    9278            0 :                                        s_ipsc->cAlphaArgs(1),
    9279            0 :                                        s_ipsc->cAlphaFieldNames(2),
    9280            0 :                                        s_ipsc->cAlphaArgs(2)));
    9281            0 :                 ErrorsFound = true;
    9282              :             }
    9283              : 
    9284            4 :             windowShadingControl.SequenceNumber = int(s_ipsc->rNumericArgs(1));
    9285              : 
    9286              :             // For upward compatibility change old "noninsulating" and "insulating" shade types to
    9287              :             // INTERIORSHADE or EXTERIORSHADE
    9288            4 :             if (s_ipsc->cAlphaArgs(3) == "INTERIORNONINSULATINGSHADE" || s_ipsc->cAlphaArgs(3) == "INTERIORINSULATINGSHADE") {
    9289            0 :                 ShowWarningError(state,
    9290            0 :                                  format("{}=\"{}\" is using obsolete {}=\"{}\", changing to \"InteriorShade\"",
    9291            0 :                                         s_ipsc->cCurrentModuleObject,
    9292            0 :                                         windowShadingControl.Name,
    9293            0 :                                         s_ipsc->cAlphaFieldNames(3),
    9294            0 :                                         s_ipsc->cAlphaArgs(3)));
    9295            0 :                 windowShadingControl.ShadingType = DataSurfaces::WinShadingType::IntShade;
    9296            0 :                 s_ipsc->cAlphaArgs(3) = "INTERIORSHADE";
    9297              :             }
    9298            4 :             if (s_ipsc->cAlphaArgs(3) == "EXTERIORNONINSULATINGSHADE" || s_ipsc->cAlphaArgs(3) == "EXTERIORINSULATINGSHADE") {
    9299            0 :                 ShowWarningError(state,
    9300            0 :                                  format("{}=\"{}\" is using obsolete {}=\"{}\", changing to \"ExteriorShade\"",
    9301            0 :                                         s_ipsc->cCurrentModuleObject,
    9302            0 :                                         windowShadingControl.Name,
    9303            0 :                                         s_ipsc->cAlphaFieldNames(3),
    9304            0 :                                         s_ipsc->cAlphaArgs(3)));
    9305            0 :                 windowShadingControl.ShadingType = DataSurfaces::WinShadingType::ExtShade;
    9306            0 :                 s_ipsc->cAlphaArgs(3) = "EXTERIORSHADE";
    9307              :             }
    9308              : 
    9309              :             // Check for illegal shading type name
    9310            4 :             Found = Util::FindItemInList(s_ipsc->cAlphaArgs(3), cValidShadingTypes, NumValidShadingTypes);
    9311            4 :             if (Found <= 1) {
    9312            0 :                 ErrorsFound = true;
    9313            0 :                 ShowSevereError(state,
    9314            0 :                                 format("{}=\"{}\" invalid {}=\"{}\".",
    9315            0 :                                        s_ipsc->cCurrentModuleObject,
    9316            0 :                                        windowShadingControl.Name,
    9317            0 :                                        s_ipsc->cAlphaFieldNames(3),
    9318            0 :                                        s_ipsc->cAlphaArgs(3)));
    9319              :             } else {
    9320            4 :                 windowShadingControl.ShadingType = DataSurfaces::WinShadingType(Found);
    9321              :             }
    9322              : 
    9323              :             // WindowShadingControl().getInputShadedConstruction is only used during GetInput process and is ultimately stored in
    9324              :             // Surface().shadedConstructionList
    9325            4 :             windowShadingControl.getInputShadedConstruction =
    9326            4 :                 Util::FindItemInList(s_ipsc->cAlphaArgs(4), state.dataConstruction->Construct, state.dataHeatBal->TotConstructs);
    9327            4 :             windowShadingControl.ShadingDevice = Material::GetMaterialNum(state, s_ipsc->cAlphaArgs(9));
    9328              : 
    9329            4 :             if (s_ipsc->lAlphaFieldBlanks(6)) {
    9330            3 :                 windowShadingControl.sched = Sched::GetScheduleAlwaysOn(state); // Not an availability schedule, but the default is constant-1.0
    9331            1 :             } else if ((windowShadingControl.sched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(6))) == nullptr) {
    9332            0 :                 ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(6), s_ipsc->cAlphaArgs(6));
    9333            0 :                 ErrorsFound = true;
    9334              :             }
    9335              : 
    9336            4 :             windowShadingControl.SetPoint = s_ipsc->rNumericArgs(2);
    9337            4 :             windowShadingControl.SetPoint2 = s_ipsc->rNumericArgs(3);
    9338            4 :             windowShadingControl.ShadingControlIsScheduled = getYesNoValue(s_ipsc->cAlphaArgs(7)) == BooleanSwitch::Yes;
    9339            4 :             windowShadingControl.GlareControlIsActive = getYesNoValue(s_ipsc->cAlphaArgs(8)) == BooleanSwitch::Yes;
    9340              : 
    9341            4 :             if (windowShadingControl.ShadingType != DataSurfaces::WinShadingType::IntBlind &&
    9342            3 :                 windowShadingControl.ShadingType != DataSurfaces::WinShadingType::ExtBlind &&
    9343            3 :                 windowShadingControl.ShadingType != DataSurfaces::WinShadingType::BGBlind) {
    9344            1 :             } else if (s_ipsc->cAlphaArgs(10).empty()) {
    9345            0 :                 ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(10), s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3));
    9346            0 :                 ErrorsFound = true;
    9347            1 :             } else if ((windowShadingControl.slatAngleControl = static_cast<DataSurfaces::SlatAngleControl>(
    9348            1 :                             getEnumValue(SlatAngleNamesUC, s_ipsc->cAlphaArgs(10)))) == DataSurfaces::SlatAngleControl::Invalid) {
    9349            0 :                 ShowSevereInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(10), s_ipsc->cAlphaArgs(10));
    9350            0 :                 ErrorsFound = true;
    9351            1 :             } else if (windowShadingControl.slatAngleControl != DataSurfaces::SlatAngleControl::Scheduled) {
    9352            0 :             } else if (s_ipsc->lAlphaFieldBlanks(11)) {
    9353            0 :                 ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(11), s_ipsc->cAlphaFieldNames(10), s_ipsc->cAlphaArgs(10));
    9354            0 :                 ErrorsFound = true;
    9355            0 :             } else if ((windowShadingControl.slatAngleSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(11))) == nullptr) {
    9356            0 :                 ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(11), s_ipsc->cAlphaArgs(11));
    9357            0 :                 ErrorsFound = true;
    9358              :             }
    9359              : 
    9360              :             // store the string for now and associate it after daylighting control objects are read
    9361            4 :             windowShadingControl.DaylightingControlName = s_ipsc->cAlphaArgs(12);
    9362              : 
    9363            4 :             windowShadingControl.multiSurfaceControl =
    9364            4 :                 static_cast<DataSurfaces::MultiSurfaceControl>(getEnumValue(MultiSurfaceControlNamesUC, s_ipsc->cAlphaArgs(13)));
    9365              : 
    9366            4 :             if (windowShadingControl.multiSurfaceControl == DataSurfaces::MultiSurfaceControl::Invalid) {
    9367            0 :                 windowShadingControl.multiSurfaceControl = DataSurfaces::MultiSurfaceControl::Sequential;
    9368            0 :                 ShowWarningError(state,
    9369            0 :                                  format("{}=\"{}\" should be either SEQUENTIAL or GROUP {}=\"{}\", defaulting to \"SEQUENTIAL\"",
    9370            0 :                                         s_ipsc->cCurrentModuleObject,
    9371            0 :                                         windowShadingControl.Name,
    9372            0 :                                         s_ipsc->cAlphaFieldNames(13),
    9373            0 :                                         s_ipsc->cAlphaArgs(13)));
    9374              :             }
    9375              : 
    9376            4 :             if (ControlNumAlpha >= 14) {
    9377            4 :                 windowShadingControl.FenestrationCount = ControlNumAlpha - 13;
    9378            4 :                 windowShadingControl.FenestrationName.allocate(windowShadingControl.FenestrationCount);
    9379            4 :                 windowShadingControl.FenestrationIndex.allocate(windowShadingControl.FenestrationCount);
    9380           15 :                 for (int i = 1; i <= windowShadingControl.FenestrationCount; i++) {
    9381           11 :                     windowShadingControl.FenestrationName(i) = s_ipsc->cAlphaArgs(i + 13);
    9382              :                 }
    9383              :             } else {
    9384            0 :                 ShowSevereError(state,
    9385            0 :                                 format("{}=\"{}\" invalid. Must reference at least one Fenestration Surface object name.",
    9386            0 :                                        s_ipsc->cCurrentModuleObject,
    9387            0 :                                        s_ipsc->cAlphaArgs(1)));
    9388              :             }
    9389              : 
    9390            4 :             windowShadingControl.shadingControlType = static_cast<DataSurfaces::WindowShadingControlType>(
    9391            4 :                 getEnumValue(WindowShadingControlTypeNamesUC, Util::makeUPPER(s_ipsc->cAlphaArgs(5))));
    9392              : 
    9393            4 :             if (windowShadingControl.ShadingDevice > 0) {
    9394            0 :                 if (s_mat->materials(windowShadingControl.ShadingDevice)->group == Material::Group::Screen &&
    9395            0 :                     !(windowShadingControl.shadingControlType == DataSurfaces::WindowShadingControlType::AlwaysOn ||
    9396            0 :                       windowShadingControl.shadingControlType == DataSurfaces::WindowShadingControlType::AlwaysOff ||
    9397            0 :                       windowShadingControl.shadingControlType == DataSurfaces::WindowShadingControlType::OnIfScheduled)) {
    9398            0 :                     ErrorsFound = true;
    9399            0 :                     ShowSevereError(state,
    9400            0 :                                     format("{}=\"{}\" invalid {}=\"{}\" for exterior screens.",
    9401            0 :                                            s_ipsc->cCurrentModuleObject,
    9402            0 :                                            windowShadingControl.Name,
    9403            0 :                                            s_ipsc->cAlphaFieldNames(5),
    9404            0 :                                            s_ipsc->cAlphaArgs(5)));
    9405            0 :                     ShowContinueError(state,
    9406              :                                       "Valid shading control types for exterior window screens are ALWAYSON, ALWAYSOFF, or ONIFSCHEDULEALLOWS.");
    9407              :                 }
    9408              :             } else {
    9409            4 :                 if (windowShadingControl.getInputShadedConstruction > 0) {
    9410            4 :                     state.dataConstruction->Construct(windowShadingControl.getInputShadedConstruction).IsUsed = true;
    9411            4 :                     if (s_mat->materials(state.dataConstruction->Construct(windowShadingControl.getInputShadedConstruction).LayerPoint(1))->group ==
    9412            4 :                             Material::Group::Screen &&
    9413            0 :                         !(windowShadingControl.shadingControlType == DataSurfaces::WindowShadingControlType::AlwaysOn ||
    9414            0 :                           windowShadingControl.shadingControlType == DataSurfaces::WindowShadingControlType::AlwaysOff ||
    9415            0 :                           windowShadingControl.shadingControlType == DataSurfaces::WindowShadingControlType::OnIfScheduled)) {
    9416            0 :                         ErrorsFound = true;
    9417            0 :                         ShowSevereError(state,
    9418            0 :                                         format("{}=\"{}\" invalid {}=\"{}\" for exterior screens.",
    9419            0 :                                                s_ipsc->cCurrentModuleObject,
    9420            0 :                                                windowShadingControl.Name,
    9421            0 :                                                s_ipsc->cAlphaFieldNames(5),
    9422            0 :                                                s_ipsc->cAlphaArgs(5)));
    9423            0 :                         ShowContinueError(state,
    9424              :                                           "Valid shading control types for exterior window screens are ALWAYSON, ALWAYSOFF, or ONIFSCHEDULEALLOWS.");
    9425              :                     }
    9426            0 :                 } else if (s_ipsc->lAlphaFieldBlanks(4)) {
    9427            0 :                     ShowSevereError(
    9428              :                         state,
    9429            0 :                         format("{}=\"{}\", {} is blank.", s_ipsc->cCurrentModuleObject, windowShadingControl.Name, s_ipsc->cAlphaFieldNames(4)));
    9430            0 :                     ShowContinueError(state, "A valid construction is required.");
    9431            0 :                     ErrorsFound = true;
    9432              :                 } else {
    9433            0 :                     ShowSevereError(
    9434              :                         state,
    9435            0 :                         format("{}=\"{}\", {} is invalid.", s_ipsc->cCurrentModuleObject, windowShadingControl.Name, s_ipsc->cAlphaFieldNames(4)));
    9436            0 :                     ShowContinueError(state, format("Construction=\"{}\" was used. A valid construction is required.", s_ipsc->cAlphaArgs(4)));
    9437            0 :                     ErrorsFound = true;
    9438              :                 }
    9439              :             }
    9440              : 
    9441              :             // Warning if setpoint is unintentionally zero
    9442            4 :             if (windowShadingControl.SetPoint == 0 && windowShadingControl.shadingControlType != DataSurfaces::WindowShadingControlType::AlwaysOn &&
    9443            2 :                 windowShadingControl.shadingControlType != DataSurfaces::WindowShadingControlType::AlwaysOff &&
    9444            2 :                 windowShadingControl.shadingControlType != DataSurfaces::WindowShadingControlType::OnIfScheduled &&
    9445            1 :                 windowShadingControl.shadingControlType != DataSurfaces::WindowShadingControlType::HiGlare) {
    9446            0 :                 ShowWarningError(state, format("{}=\"{}\", The first SetPoint is zero.", s_ipsc->cCurrentModuleObject, windowShadingControl.Name));
    9447            0 :                 ShowContinueError(state, "..You may have forgotten to specify that setpoint.");
    9448              :             }
    9449              : 
    9450              :             // Error checks
    9451            4 :             if (BooleanSwitch bs = getYesNoValue(s_ipsc->cAlphaArgs(7)); bs == BooleanSwitch::Invalid) { // Shading Control is Schedule field
    9452            0 :                 ShowSevereInvalidBool(state, eoh, s_ipsc->cAlphaFieldNames(7), s_ipsc->cAlphaArgs(7));
    9453            0 :                 ErrorsFound = true;
    9454              :             }
    9455              : 
    9456            4 :             if (BooleanSwitch bs = getYesNoValue(s_ipsc->cAlphaArgs(8)); bs == BooleanSwitch::Invalid) { // Shading Control is Schedule field
    9457            0 :                 ShowSevereInvalidBool(state, eoh, s_ipsc->cAlphaFieldNames(8), s_ipsc->cAlphaArgs(8));
    9458            0 :                 ErrorsFound = true;
    9459              :             }
    9460              : 
    9461            4 :             if ((windowShadingControl.shadingControlType == DataSurfaces::WindowShadingControlType::OnIfScheduled) &&
    9462            1 :                 (!windowShadingControl.ShadingControlIsScheduled)) { // CR 7709 BG
    9463            0 :                 ErrorsFound = true;
    9464            0 :                 ShowSevereError(state,
    9465            0 :                                 format("{} = \"{}\" invalid, {} must be set to \"Yes\" for {} = OnIfScheduleAllows",
    9466            0 :                                        s_ipsc->cCurrentModuleObject,
    9467            0 :                                        windowShadingControl.Name,
    9468            0 :                                        s_ipsc->cAlphaFieldNames(7),
    9469            0 :                                        s_ipsc->cAlphaFieldNames(5)));
    9470              :             }
    9471              : 
    9472            4 :             if (windowShadingControl.shadingControlType == DataSurfaces::WindowShadingControlType::MeetDaylIlumSetp &&
    9473            0 :                 windowShadingControl.ShadingType != DataSurfaces::WinShadingType::SwitchableGlazing) {
    9474            0 :                 ErrorsFound = true;
    9475            0 :                 ShowSevereError(state,
    9476            0 :                                 format("{}=\"{}\" invalid {}=\"{}\".",
    9477            0 :                                        s_ipsc->cCurrentModuleObject,
    9478            0 :                                        windowShadingControl.Name,
    9479            0 :                                        s_ipsc->cAlphaFieldNames(3),
    9480            0 :                                        s_ipsc->cAlphaArgs(3)));
    9481            0 :                 ShowContinueError(state,
    9482            0 :                                   format("...{} must be SwitchableGlazing for this control, but entered type=\"{}\".",
    9483            0 :                                          s_ipsc->cAlphaFieldNames(3),
    9484            0 :                                          s_ipsc->cAlphaArgs(3)));
    9485              :             }
    9486              : 
    9487            4 :             DataSurfaces::WinShadingType ShTyp = windowShadingControl.ShadingType;
    9488            4 :             IShadedConst = windowShadingControl.getInputShadedConstruction;
    9489            4 :             IShadingDevice = windowShadingControl.ShadingDevice;
    9490              : 
    9491            4 :             if (IShadedConst == 0 && IShadingDevice == 0) {
    9492            0 :                 ShowSevereError(state,
    9493            0 :                                 format("{}=\"{}\" has no matching shaded construction or shading device.",
    9494            0 :                                        s_ipsc->cCurrentModuleObject,
    9495            0 :                                        windowShadingControl.Name));
    9496            0 :                 ErrorsFound = true;
    9497            4 :             } else if (IShadedConst == 0 && IShadingDevice > 0) {
    9498            0 :                 if (ShTyp == DataSurfaces::WinShadingType::SwitchableGlazing) {
    9499            0 :                     ShowSevereError(state,
    9500            0 :                                     format("{}=\"{}\" has {}= SwitchableGlazing but no matching shaded construction",
    9501            0 :                                            s_ipsc->cCurrentModuleObject,
    9502            0 :                                            windowShadingControl.Name,
    9503            0 :                                            s_ipsc->cAlphaArgs(3)));
    9504            0 :                     ErrorsFound = true;
    9505              :                 }
    9506            0 :                 if ((ShTyp == DataSurfaces::WinShadingType::IntShade || ShTyp == DataSurfaces::WinShadingType::ExtShade) &&
    9507            0 :                     s_mat->materials(IShadingDevice)->group != Material::Group::Shade) {
    9508            0 :                     ShowSevereError(state,
    9509            0 :                                     format("{}=\"{}\" has {}= InteriorShade or ExteriorShade but matching shading device is not a window shade",
    9510            0 :                                            s_ipsc->cCurrentModuleObject,
    9511            0 :                                            windowShadingControl.Name,
    9512            0 :                                            s_ipsc->cAlphaArgs(3)));
    9513            0 :                     ShowContinueError(state, format("{} in error=\"{}\".", s_ipsc->cAlphaFieldNames(8), s_mat->materials(IShadingDevice)->Name));
    9514            0 :                     ErrorsFound = true;
    9515              :                 }
    9516            0 :                 if ((ShTyp == DataSurfaces::WinShadingType::ExtScreen) && s_mat->materials(IShadingDevice)->group != Material::Group::Screen) {
    9517            0 :                     ShowSevereError(state,
    9518            0 :                                     format("{}=\"{}\" has {}= ExteriorScreen but matching shading device is not a window screen",
    9519            0 :                                            s_ipsc->cCurrentModuleObject,
    9520            0 :                                            windowShadingControl.Name,
    9521            0 :                                            s_ipsc->cAlphaArgs(3)));
    9522            0 :                     ShowContinueError(state, format("{} in error=\"{}\".", s_ipsc->cAlphaFieldNames(8), s_mat->materials(IShadingDevice)->Name));
    9523            0 :                     ErrorsFound = true;
    9524              :                 }
    9525            0 :                 if ((ShTyp == DataSurfaces::WinShadingType::IntBlind || ShTyp == DataSurfaces::WinShadingType::ExtBlind) &&
    9526            0 :                     s_mat->materials(IShadingDevice)->group != Material::Group::Blind) {
    9527            0 :                     ShowSevereError(state,
    9528            0 :                                     format("{}=\"{}\" has {}= InteriorBlind or ExteriorBlind but matching shading device is not a window blind",
    9529            0 :                                            s_ipsc->cCurrentModuleObject,
    9530            0 :                                            windowShadingControl.Name,
    9531            0 :                                            s_ipsc->cAlphaArgs(3)));
    9532            0 :                     ShowContinueError(state, format("{} in error=\"{}\".", s_ipsc->cAlphaFieldNames(8), s_mat->materials(IShadingDevice)->Name));
    9533            0 :                     ErrorsFound = true;
    9534              :                 }
    9535            0 :                 if (ShTyp == DataSurfaces::WinShadingType::BGShade || ShTyp == DataSurfaces::WinShadingType::BGBlind) {
    9536            0 :                     ShowSevereError(state,
    9537            0 :                                     format("{}=\"{}\" has {}= BetweenGlassShade or BetweenGlassBlind and",
    9538            0 :                                            s_ipsc->cCurrentModuleObject,
    9539            0 :                                            windowShadingControl.Name,
    9540            0 :                                            s_ipsc->cAlphaArgs(3)));
    9541            0 :                     ShowContinueError(state,
    9542            0 :                                       format("{} is specified. This is illegal. Specify shaded construction instead.", s_ipsc->cAlphaFieldNames(8)));
    9543            0 :                     ErrorsFound = true;
    9544              :                 }
    9545            4 :             } else if (IShadedConst > 0 && IShadingDevice > 0) {
    9546            0 :                 IShadingDevice = 0;
    9547            0 :                 ShowWarningError(state,
    9548            0 :                                  format("{}=\"{}\" Both {} and {} are specified.",
    9549            0 :                                         s_ipsc->cCurrentModuleObject,
    9550            0 :                                         windowShadingControl.Name,
    9551            0 :                                         s_ipsc->cAlphaFieldNames(4),
    9552            0 :                                         s_ipsc->cAlphaFieldNames(9)));
    9553            0 :                 ShowContinueError(
    9554            0 :                     state, format("The {}=\"{}\" will be used.", s_ipsc->cAlphaFieldNames(4), state.dataConstruction->Construct(IShadedConst).Name));
    9555              :             }
    9556              : 
    9557              :             // If type = interior or exterior shade or blind require that the shaded construction
    9558              :             // have a shade layer in the correct position
    9559            4 :             if (IShadedConst != 0) {
    9560              : 
    9561            4 :                 NLayers = state.dataConstruction->Construct(IShadedConst).TotLayers;
    9562            4 :                 BGShadeBlindError = false;
    9563            4 :                 IShadingDevice = 0;
    9564            4 :                 if (state.dataConstruction->Construct(IShadedConst).LayerPoint(NLayers) != 0) {
    9565            4 :                     if (windowShadingControl.ShadingType == DataSurfaces::WinShadingType::IntShade) {
    9566            1 :                         IShadingDevice = state.dataConstruction->Construct(IShadedConst).LayerPoint(NLayers);
    9567            1 :                         if (s_mat->materials(state.dataConstruction->Construct(IShadedConst).LayerPoint(NLayers))->group != Material::Group::Shade) {
    9568            0 :                             ErrorsFound = true;
    9569            0 :                             ShowSevereError(state,
    9570            0 :                                             format("{}=\"{}\" the {}=\"{}\"",
    9571            0 :                                                    s_ipsc->cCurrentModuleObject,
    9572            0 :                                                    windowShadingControl.Name,
    9573            0 :                                                    s_ipsc->cAlphaFieldNames(4),
    9574            0 :                                                    s_ipsc->cAlphaArgs(4)));
    9575            0 :                             ShowContinueError(state,
    9576            0 :                                               format("of {}=\"{}\" should have a shade layer on the inside of the window.",
    9577            0 :                                                      s_ipsc->cAlphaFieldNames(3),
    9578            0 :                                                      s_ipsc->cAlphaArgs(3)));
    9579              :                         }
    9580            3 :                     } else if (windowShadingControl.ShadingType == DataSurfaces::WinShadingType::ExtShade) {
    9581            0 :                         IShadingDevice = state.dataConstruction->Construct(IShadedConst).LayerPoint(1);
    9582            0 :                         if (s_mat->materials(state.dataConstruction->Construct(IShadedConst).LayerPoint(1))->group != Material::Group::Shade) {
    9583            0 :                             ErrorsFound = true;
    9584            0 :                             ShowSevereError(state,
    9585            0 :                                             format("{}=\"{}\" the {}=\"{}\"",
    9586            0 :                                                    s_ipsc->cCurrentModuleObject,
    9587            0 :                                                    windowShadingControl.Name,
    9588            0 :                                                    s_ipsc->cAlphaFieldNames(43),
    9589            0 :                                                    s_ipsc->cAlphaArgs(4)));
    9590            0 :                             ShowContinueError(state,
    9591            0 :                                               format("of {}=\"{}\" should have a shade layer on the outside of the window.",
    9592            0 :                                                      s_ipsc->cAlphaFieldNames(3),
    9593            0 :                                                      s_ipsc->cAlphaArgs(3)));
    9594              :                         }
    9595            3 :                     } else if (windowShadingControl.ShadingType == DataSurfaces::WinShadingType::ExtScreen) {
    9596            0 :                         IShadingDevice = state.dataConstruction->Construct(IShadedConst).LayerPoint(1);
    9597            0 :                         if (s_mat->materials(state.dataConstruction->Construct(IShadedConst).LayerPoint(1))->group != Material::Group::Screen) {
    9598            0 :                             ErrorsFound = true;
    9599            0 :                             ShowSevereError(state,
    9600            0 :                                             format("{}=\"{}\" the {}=\"{}\"",
    9601            0 :                                                    s_ipsc->cCurrentModuleObject,
    9602            0 :                                                    windowShadingControl.Name,
    9603            0 :                                                    s_ipsc->cAlphaFieldNames(4),
    9604            0 :                                                    s_ipsc->cAlphaArgs(4)));
    9605            0 :                             ShowContinueError(state,
    9606            0 :                                               format("of {}=\"{}\" should have a screen layer on the outside of the window.",
    9607            0 :                                                      s_ipsc->cAlphaFieldNames(3),
    9608            0 :                                                      s_ipsc->cAlphaArgs(3)));
    9609              :                         }
    9610            3 :                     } else if (windowShadingControl.ShadingType == DataSurfaces::WinShadingType::IntBlind) {
    9611            1 :                         IShadingDevice = state.dataConstruction->Construct(IShadedConst).LayerPoint(NLayers);
    9612            1 :                         if (s_mat->materials(state.dataConstruction->Construct(IShadedConst).LayerPoint(NLayers))->group != Material::Group::Blind) {
    9613            0 :                             ErrorsFound = true;
    9614            0 :                             ShowSevereError(state,
    9615            0 :                                             format("{}=\"{}\" the {}=\"{}\"",
    9616            0 :                                                    s_ipsc->cCurrentModuleObject,
    9617            0 :                                                    windowShadingControl.Name,
    9618            0 :                                                    s_ipsc->cAlphaFieldNames(4),
    9619            0 :                                                    s_ipsc->cAlphaArgs(4)));
    9620            0 :                             ShowContinueError(state,
    9621            0 :                                               format("of {}=\"{}\" should have a blind layer on the inside of the window.",
    9622            0 :                                                      s_ipsc->cAlphaFieldNames(3),
    9623            0 :                                                      s_ipsc->cAlphaArgs(3)));
    9624              :                         }
    9625            2 :                     } else if (windowShadingControl.ShadingType == DataSurfaces::WinShadingType::ExtBlind) {
    9626            0 :                         IShadingDevice = state.dataConstruction->Construct(IShadedConst).LayerPoint(1);
    9627            0 :                         if (s_mat->materials(state.dataConstruction->Construct(IShadedConst).LayerPoint(1))->group != Material::Group::Blind) {
    9628            0 :                             ErrorsFound = true;
    9629            0 :                             ShowSevereError(state,
    9630            0 :                                             format("{}=\"{}\" the {}=\"{}\"",
    9631            0 :                                                    s_ipsc->cCurrentModuleObject,
    9632            0 :                                                    windowShadingControl.Name,
    9633            0 :                                                    s_ipsc->cAlphaFieldNames(4),
    9634            0 :                                                    s_ipsc->cAlphaArgs(4)));
    9635            0 :                             ShowContinueError(state,
    9636            0 :                                               format("of {}=\"{}\" should have a blind layer on the outside of the window.",
    9637            0 :                                                      s_ipsc->cAlphaFieldNames(3),
    9638            0 :                                                      s_ipsc->cAlphaArgs(3)));
    9639              :                         }
    9640            2 :                     } else if (windowShadingControl.ShadingType == DataSurfaces::WinShadingType::BGShade) {
    9641            0 :                         if (NLayers != 5 && NLayers != 7) BGShadeBlindError = true;
    9642            0 :                         if (NLayers == 5) {
    9643            0 :                             if (s_mat->materials(state.dataConstruction->Construct(IShadedConst).LayerPoint(3))->group != Material::Group::Shade)
    9644            0 :                                 BGShadeBlindError = true;
    9645              :                         }
    9646            0 :                         if (NLayers == 7) {
    9647            0 :                             if (s_mat->materials(state.dataConstruction->Construct(IShadedConst).LayerPoint(5))->group != Material::Group::Shade)
    9648            0 :                                 BGShadeBlindError = true;
    9649              :                         }
    9650            0 :                         if (BGShadeBlindError) {
    9651            0 :                             ErrorsFound = true;
    9652            0 :                             ShowSevereError(state,
    9653            0 :                                             format("{}=\"{}\" the {}=\"{}\"",
    9654            0 :                                                    s_ipsc->cCurrentModuleObject,
    9655            0 :                                                    windowShadingControl.Name,
    9656            0 :                                                    s_ipsc->cAlphaFieldNames(4),
    9657            0 :                                                    s_ipsc->cAlphaArgs(4)));
    9658            0 :                             ShowContinueError(state,
    9659            0 :                                               format("of {}=\"{}\" should have two or three glass layers and a",
    9660            0 :                                                      s_ipsc->cAlphaFieldNames(3),
    9661            0 :                                                      s_ipsc->cAlphaArgs(3)));
    9662            0 :                             ShowContinueError(state, "between-glass shade layer with a gas layer on each side.");
    9663              :                         }
    9664            2 :                     } else if (windowShadingControl.ShadingType == DataSurfaces::WinShadingType::BGBlind) {
    9665            0 :                         if (NLayers != 5 && NLayers != 7) BGShadeBlindError = true;
    9666            0 :                         if (NLayers == 5) {
    9667            0 :                             if (s_mat->materials(state.dataConstruction->Construct(IShadedConst).LayerPoint(3))->group != Material::Group::Blind)
    9668            0 :                                 BGShadeBlindError = true;
    9669              :                         }
    9670            0 :                         if (NLayers == 7) {
    9671            0 :                             if (s_mat->materials(state.dataConstruction->Construct(IShadedConst).LayerPoint(5))->group != Material::Group::Blind)
    9672            0 :                                 BGShadeBlindError = true;
    9673              :                         }
    9674            0 :                         if (BGShadeBlindError) {
    9675            0 :                             ErrorsFound = true;
    9676            0 :                             ShowSevereError(state,
    9677            0 :                                             format("{}=\"{}\" the {}=\"{}\"",
    9678            0 :                                                    s_ipsc->cCurrentModuleObject,
    9679            0 :                                                    windowShadingControl.Name,
    9680            0 :                                                    s_ipsc->cAlphaFieldNames(4),
    9681            0 :                                                    s_ipsc->cAlphaArgs(4)));
    9682            0 :                             ShowContinueError(state,
    9683            0 :                                               format("of {}=\"{}\" should have two or three glass layers and a",
    9684            0 :                                                      s_ipsc->cAlphaFieldNames(3),
    9685            0 :                                                      s_ipsc->cAlphaArgs(3)));
    9686            0 :                             ShowContinueError(state, "between-glass blind layer with a gas layer on each side.");
    9687              :                         }
    9688              :                     }
    9689              :                 }
    9690            4 :                 if (IShadingDevice > 0) {
    9691            3 :                     if ((ShTyp == DataSurfaces::WinShadingType::IntShade || ShTyp == DataSurfaces::WinShadingType::ExtShade) &&
    9692            1 :                         s_mat->materials(IShadingDevice)->group != Material::Group::Shade) {
    9693            0 :                         ShowSevereError(state,
    9694            0 :                                         format("{}=\"{}\" has {}= InteriorShade or ExteriorShade but matching shading device is not a window shade",
    9695            0 :                                                s_ipsc->cCurrentModuleObject,
    9696            0 :                                                windowShadingControl.Name,
    9697            0 :                                                s_ipsc->cAlphaFieldNames(3)));
    9698            0 :                         ShowContinueError(state, format("Shading Device in error=\"{}\".", s_mat->materials(IShadingDevice)->Name));
    9699            0 :                         ErrorsFound = true;
    9700              :                     }
    9701            2 :                     if ((ShTyp == DataSurfaces::WinShadingType::ExtScreen) && s_mat->materials(IShadingDevice)->group != Material::Group::Screen) {
    9702            0 :                         ShowSevereError(state,
    9703            0 :                                         format("{}=\"{}\" has {}= ExteriorScreen but matching shading device is not an exterior window screen.",
    9704            0 :                                                s_ipsc->cCurrentModuleObject,
    9705            0 :                                                windowShadingControl.Name,
    9706            0 :                                                s_ipsc->cAlphaFieldNames(3)));
    9707            0 :                         ShowContinueError(state, format("Shading Device in error=\"{}\".", s_mat->materials(IShadingDevice)->Name));
    9708            0 :                         ErrorsFound = true;
    9709              :                     }
    9710            3 :                     if ((ShTyp == DataSurfaces::WinShadingType::IntBlind || ShTyp == DataSurfaces::WinShadingType::ExtBlind) &&
    9711            1 :                         s_mat->materials(IShadingDevice)->group != Material::Group::Blind) {
    9712            0 :                         ShowSevereError(state,
    9713            0 :                                         format("{}=\"{}\" has {}= InteriorBlind or ExteriorBlind but matching shading device is not a window blind.",
    9714            0 :                                                s_ipsc->cCurrentModuleObject,
    9715            0 :                                                windowShadingControl.Name,
    9716            0 :                                                s_ipsc->cAlphaFieldNames(3)));
    9717            0 :                         ShowContinueError(state, format("Shading Device in error=\"{}\".", s_mat->materials(IShadingDevice)->Name));
    9718            0 :                         ErrorsFound = true;
    9719              :                     }
    9720              :                 }
    9721              :             }
    9722              :         } // End of loop over window shading controls
    9723              :     }
    9724              : 
    9725          218 :     void InitialAssociateWindowShadingControlFenestration(EnergyPlusData &state, bool &ErrorsFound, int SurfNum)
    9726              :     {
    9727          218 :         auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
    9728              :         // J.Glazer 2018 - operates on SurfaceTmp array before final indices are known for windows and sets the activeWindowShadingControl
    9729          273 :         for (int iShadeCtrl = 1; iShadeCtrl <= state.dataSurface->TotWinShadingControl; ++iShadeCtrl) {
    9730           55 :             int curShadedConstruction = state.dataSurface->WindowShadingControl(iShadeCtrl).getInputShadedConstruction;
    9731          257 :             for (int jFeneRef = 1; jFeneRef <= state.dataSurface->WindowShadingControl(iShadeCtrl).FenestrationCount; ++jFeneRef) {
    9732          202 :                 if (Util::SameString(state.dataSurface->WindowShadingControl(iShadeCtrl).FenestrationName(jFeneRef), surfTemp.Name)) {
    9733           29 :                     state.dataGlobal->AndShadingControlInModel = true;
    9734           29 :                     surfTemp.HasShadeControl = true;
    9735           29 :                     surfTemp.windowShadingControlList.push_back(iShadeCtrl);
    9736           29 :                     surfTemp.activeWindowShadingControl = iShadeCtrl;
    9737           29 :                     surfTemp.shadedConstructionList.push_back(curShadedConstruction);
    9738           29 :                     surfTemp.activeShadedConstruction = curShadedConstruction;
    9739              : 
    9740              :                     // check to make the window refenced is an exterior window
    9741           29 :                     if (surfTemp.ExtBoundCond != DataSurfaces::ExternalEnvironment) {
    9742            0 :                         ErrorsFound = true;
    9743            0 :                         ShowSevereError(
    9744              :                             state,
    9745            0 :                             format("InitialAssociateWindowShadingControlFenestration: \"{}\", invalid  because it is not an exterior window.",
    9746            0 :                                    surfTemp.Name));
    9747            0 :                         ShowContinueError(
    9748              :                             state,
    9749            0 :                             format(".. It appears on WindowShadingControl object: \"{}", state.dataSurface->WindowShadingControl(iShadeCtrl).Name));
    9750              :                     }
    9751              :                     // check to make sure the window is not using equivalent layer window construction
    9752           29 :                     if (state.dataConstruction->Construct(surfTemp.Construction).WindowTypeEQL) {
    9753            0 :                         ErrorsFound = true;
    9754            0 :                         ShowSevereError(state, format("InitialAssociateWindowShadingControlFenestration: =\"{}\", invalid \".", surfTemp.Name));
    9755            0 :                         ShowContinueError(state, ".. equivalent layer window model does not use shading control object.");
    9756            0 :                         ShowContinueError(state, ".. Shading control is set to none or zero, and simulation continues.");
    9757            0 :                         ShowContinueError(
    9758              :                             state,
    9759            0 :                             format(".. It appears on WindowShadingControl object: \"{}", state.dataSurface->WindowShadingControl(iShadeCtrl).Name));
    9760            0 :                         surfTemp.activeWindowShadingControl = 0;
    9761              :                     }
    9762              :                 }
    9763              :             }
    9764              :         }
    9765          218 :     }
    9766              : 
    9767          225 :     void FinalAssociateWindowShadingControlFenestration(EnergyPlusData &state, bool &ErrorsFound)
    9768              :     {
    9769              :         // J.Glazer 2018 - operates on Surface array after final indices are known for windows and checks to make sure it is correct
    9770          232 :         for (int iShadeCtrl = 1; iShadeCtrl <= state.dataSurface->TotWinShadingControl; ++iShadeCtrl) {
    9771           27 :             for (int jFeneRef = 1; jFeneRef <= state.dataSurface->WindowShadingControl(iShadeCtrl).FenestrationCount; ++jFeneRef) {
    9772           20 :                 int fenestrationIndex = Util::FindItemInList(state.dataSurface->WindowShadingControl(iShadeCtrl).FenestrationName(jFeneRef),
    9773           20 :                                                              state.dataSurface->Surface,
    9774           20 :                                                              state.dataSurface->TotSurfaces);
    9775           20 :                 if (std::find(state.dataSurface->Surface(fenestrationIndex).windowShadingControlList.begin(),
    9776           20 :                               state.dataSurface->Surface(fenestrationIndex).windowShadingControlList.end(),
    9777           40 :                               iShadeCtrl) != state.dataSurface->Surface(fenestrationIndex).windowShadingControlList.end()) {
    9778           20 :                     state.dataSurface->WindowShadingControl(iShadeCtrl).FenestrationIndex(jFeneRef) = fenestrationIndex;
    9779              :                 } else {
    9780              :                     // this error condition should not occur since the rearrangement of Surface() from SurfureTmp() is reliable.
    9781            0 :                     ErrorsFound = true;
    9782            0 :                     ShowSevereError(state,
    9783            0 :                                     format("FinalAssociateWindowShadingControlFenestration: Fenestration surface named \"{}\" has "
    9784              :                                            "WindowShadingContol index that does not match the initial index assigned.",
    9785            0 :                                            state.dataSurface->Surface(fenestrationIndex).Name));
    9786            0 :                     ShowContinueError(state,
    9787            0 :                                       format("This occurs while WindowShadingControl object: \"{}\" is being evaluated. ",
    9788            0 :                                              state.dataSurface->WindowShadingControl(iShadeCtrl).Name));
    9789              :                 }
    9790              :             }
    9791              :         }
    9792          225 :     }
    9793              : 
    9794          226 :     void CheckWindowShadingControlSimilarForWindow(EnergyPlusData &state, bool &ErrorsFound)
    9795              :     {
    9796              :         // For each window check if all window shading controls on list are the same except for name, schedule name, construction, and
    9797              :         // material
    9798         2490 :         for (auto &theSurf : state.dataSurface->Surface) {
    9799         2264 :             if (theSurf.HasShadeControl) {
    9800           13 :                 if (theSurf.windowShadingControlList.size() > 1) {
    9801            2 :                     int firstWindowShadingControl = theSurf.windowShadingControlList.front();
    9802            8 :                     for (auto wsc = std::next(theSurf.windowShadingControlList.begin()); wsc != theSurf.windowShadingControlList.end(); ++wsc) {
    9803            4 :                         if (!isWindowShadingControlSimilar(state, firstWindowShadingControl, *wsc)) {
    9804            1 :                             ErrorsFound = true;
    9805            2 :                             ShowSevereError(state,
    9806            2 :                                             format("CheckWindowShadingControlSimilarForWindow: Fenestration surface named \"{}\" has multiple "
    9807              :                                                    "WindowShadingContols that are not similar.",
    9808            1 :                                                    theSurf.Name));
    9809            2 :                             ShowContinueError(state,
    9810            2 :                                               format("for: \"{} and: {}",
    9811            1 :                                                      state.dataSurface->WindowShadingControl(firstWindowShadingControl).Name,
    9812            1 :                                                      state.dataSurface->WindowShadingControl(*wsc).Name));
    9813              :                         }
    9814              :                     }
    9815              :                 }
    9816              :             }
    9817              :         }
    9818          226 :     }
    9819              : 
    9820           24 :     bool isWindowShadingControlSimilar(EnergyPlusData &state, int a, int b)
    9821              :     {
    9822              :         // Compares two window shading controls are the same except for the name, schedule name, construction, and material
    9823           24 :         auto const &WindowShadingControlA = state.dataSurface->WindowShadingControl(a);
    9824           24 :         auto const &WindowShadingControlB = state.dataSurface->WindowShadingControl(b);
    9825           47 :         return (WindowShadingControlA.ZoneIndex == WindowShadingControlB.ZoneIndex &&
    9826           23 :                 WindowShadingControlA.ShadingType == WindowShadingControlB.ShadingType &&
    9827           22 :                 WindowShadingControlA.shadingControlType == WindowShadingControlB.shadingControlType &&
    9828           21 :                 WindowShadingControlA.SetPoint == WindowShadingControlB.SetPoint &&
    9829           19 :                 WindowShadingControlA.ShadingControlIsScheduled == WindowShadingControlB.ShadingControlIsScheduled &&
    9830           18 :                 WindowShadingControlA.GlareControlIsActive == WindowShadingControlB.GlareControlIsActive &&
    9831           17 :                 WindowShadingControlA.slatAngleControl == WindowShadingControlB.slatAngleControl &&
    9832           31 :                 WindowShadingControlA.SetPoint2 == WindowShadingControlB.SetPoint2 &&
    9833           15 :                 WindowShadingControlA.DaylightingControlName == WindowShadingControlB.DaylightingControlName &&
    9834           60 :                 WindowShadingControlA.DaylightControlIndex == WindowShadingControlB.DaylightControlIndex &&
    9835           37 :                 WindowShadingControlA.multiSurfaceControl == WindowShadingControlB.multiSurfaceControl);
    9836              :     }
    9837              : 
    9838          192 :     void GetStormWindowData(EnergyPlusData &state, bool &ErrorsFound) // If errors found in input
    9839              :     {
    9840              : 
    9841              :         // SUBROUTINE INFORMATION:
    9842              :         //       AUTHOR         Fred Winkelmann
    9843              :         //       DATE WRITTEN   December 2003
    9844              : 
    9845              :         // PURPOSE OF THIS SUBROUTINE:
    9846              :         // Reads in the storm window data from the input file, interprets it and puts it in the derived type
    9847              : 
    9848              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    9849              :         int IOStat;           // IO Status when calling get input subroutine
    9850              :         int StormWinNumAlpha; // Number of alpha names being passed
    9851              :         int StormWinNumProp;  // Number of properties being passed
    9852              :         int loop;             // Do loop counter
    9853              : 
    9854          192 :         auto &s_ipsc = state.dataIPShortCut;
    9855          192 :         auto &s_mat = state.dataMaterial;
    9856              : 
    9857              :         // Get the total number of storm window input objects
    9858          192 :         s_ipsc->cCurrentModuleObject = "WindowProperty:StormWindow";
    9859          192 :         state.dataSurface->TotStormWin = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
    9860          192 :         if (state.dataSurface->TotStormWin == 0) return;
    9861              : 
    9862            0 :         state.dataSurface->StormWindow.allocate(state.dataSurface->TotStormWin);
    9863              : 
    9864            0 :         int StormWinNum = 0;
    9865            0 :         for (loop = 1; loop <= state.dataSurface->TotStormWin; ++loop) {
    9866              : 
    9867            0 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    9868            0 :                                                                      s_ipsc->cCurrentModuleObject,
    9869              :                                                                      loop,
    9870            0 :                                                                      s_ipsc->cAlphaArgs,
    9871              :                                                                      StormWinNumAlpha,
    9872            0 :                                                                      s_ipsc->rNumericArgs,
    9873              :                                                                      StormWinNumProp,
    9874              :                                                                      IOStat,
    9875            0 :                                                                      s_ipsc->lNumericFieldBlanks,
    9876            0 :                                                                      s_ipsc->lAlphaFieldBlanks,
    9877            0 :                                                                      s_ipsc->cAlphaFieldNames,
    9878            0 :                                                                      s_ipsc->cNumericFieldNames);
    9879            0 :             ++StormWinNum;
    9880            0 :             state.dataSurface->StormWindow(StormWinNum).BaseWindowNum =
    9881            0 :                 Util::FindItemInList(s_ipsc->cAlphaArgs(1), state.dataSurface->Surface, state.dataSurface->TotSurfaces);
    9882            0 :             state.dataSurface->StormWindow(StormWinNum).StormWinMaterialNum = Material::GetMaterialNum(state, s_ipsc->cAlphaArgs(2));
    9883            0 :             state.dataSurface->StormWindow(StormWinNum).StormWinDistance = s_ipsc->rNumericArgs(1);
    9884            0 :             state.dataSurface->StormWindow(StormWinNum).MonthOn = s_ipsc->rNumericArgs(2);
    9885            0 :             state.dataSurface->StormWindow(StormWinNum).DayOfMonthOn = s_ipsc->rNumericArgs(3);
    9886            0 :             state.dataSurface->StormWindow(StormWinNum).DateOn =
    9887            0 :                 General::OrdinalDay(state.dataSurface->StormWindow(StormWinNum).MonthOn, state.dataSurface->StormWindow(StormWinNum).DayOfMonthOn, 1);
    9888            0 :             state.dataSurface->StormWindow(StormWinNum).MonthOff = s_ipsc->rNumericArgs(4);
    9889            0 :             state.dataSurface->StormWindow(StormWinNum).DayOfMonthOff = s_ipsc->rNumericArgs(5);
    9890            0 :             state.dataSurface->StormWindow(StormWinNum).DateOff = General::OrdinalDay(
    9891            0 :                 state.dataSurface->StormWindow(StormWinNum).MonthOff, state.dataSurface->StormWindow(StormWinNum).DayOfMonthOff, 1);
    9892              : 
    9893            0 :             if (state.dataSurface->StormWindow(StormWinNum).DateOn == state.dataSurface->StormWindow(StormWinNum).DateOff) {
    9894            0 :                 ShowSevereError(state,
    9895            0 :                                 format("{}: Date On = Date Off -- not allowed, occurred in WindowProperty:StormWindow Input #{}",
    9896            0 :                                        s_ipsc->cCurrentModuleObject,
    9897              :                                        StormWinNum));
    9898            0 :                 ErrorsFound = true;
    9899              :             }
    9900              : 
    9901              :             enum Month
    9902              :             {
    9903              :                 January = 1,
    9904              :                 February,
    9905              :                 March,
    9906              :                 April,
    9907              :                 May,
    9908              :                 June,
    9909              :                 July,
    9910              :                 August,
    9911              :                 September,
    9912              :                 October,
    9913              :                 November,
    9914              :                 December
    9915              :             };
    9916            0 :             constexpr std::array<int, 13> oneBasedDaysInMonth = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    9917              : 
    9918            0 :             int const monthOn = state.dataSurface->StormWindow(StormWinNum).MonthOn;
    9919            0 :             if (monthOn >= January && monthOn <= December) {
    9920            0 :                 if (state.dataSurface->StormWindow(StormWinNum).DayOfMonthOn >
    9921            0 :                     oneBasedDaysInMonth[state.dataSurface->StormWindow(StormWinNum).MonthOn]) {
    9922            0 :                     ShowSevereError(state,
    9923            0 :                                     format("{}: Date On (Day of Month) [{}], invalid for WindowProperty:StormWindow Input #{}",
    9924            0 :                                            s_ipsc->cCurrentModuleObject,
    9925            0 :                                            state.dataSurface->StormWindow(StormWinNum).DayOfMonthOn,
    9926              :                                            StormWinNum));
    9927            0 :                     ErrorsFound = true;
    9928              :                 }
    9929            0 :                 break;
    9930              :             } else {
    9931            0 :                 ShowSevereError(state,
    9932            0 :                                 format("{}: Date On Month [{}], invalid for WindowProperty:StormWindow Input #{}",
    9933            0 :                                        s_ipsc->cCurrentModuleObject,
    9934            0 :                                        state.dataSurface->StormWindow(StormWinNum).MonthOn,
    9935              :                                        StormWinNum));
    9936            0 :                 ErrorsFound = true;
    9937              :             }
    9938              : 
    9939            0 :             int const monthOff = state.dataSurface->StormWindow(StormWinNum).MonthOff;
    9940            0 :             if (monthOff >= January && monthOff <= December) {
    9941            0 :                 if (state.dataSurface->StormWindow(StormWinNum).DayOfMonthOff >
    9942            0 :                     oneBasedDaysInMonth[state.dataSurface->StormWindow(StormWinNum).MonthOff]) {
    9943            0 :                     ShowSevereError(state,
    9944            0 :                                     format("{}: Date Off (Day of Month) [{}], invalid for WindowProperty:StormWindow Input #{}",
    9945            0 :                                            s_ipsc->cCurrentModuleObject,
    9946            0 :                                            state.dataSurface->StormWindow(StormWinNum).DayOfMonthOff,
    9947              :                                            StormWinNum));
    9948            0 :                     ErrorsFound = true;
    9949              :                 }
    9950            0 :                 break;
    9951              :             } else {
    9952            0 :                 ShowSevereError(state,
    9953            0 :                                 format("{}: Date Off Month [{}], invalid for WindowProperty:StormWindow Input #{}",
    9954            0 :                                        s_ipsc->cCurrentModuleObject,
    9955            0 :                                        state.dataSurface->StormWindow(StormWinNum).MonthOff,
    9956              :                                        StormWinNum));
    9957            0 :                 ErrorsFound = true;
    9958              :             }
    9959              :         }
    9960              : 
    9961              :         // Error checks
    9962              : 
    9963            0 :         for (StormWinNum = 1; StormWinNum <= state.dataSurface->TotStormWin; ++StormWinNum) {
    9964              :             // Require BaseWindowNum be that of an exterior window
    9965            0 :             int SurfNum = state.dataSurface->StormWindow(StormWinNum).BaseWindowNum;
    9966            0 :             if (SurfNum == 0) {
    9967            0 :                 ShowSevereError(state, format("{}=\"{}\" invalid.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
    9968            0 :                 ErrorsFound = true;
    9969              :             } else {
    9970            0 :                 auto const &surf = state.dataSurface->Surface(SurfNum);
    9971            0 :                 if (surf.Class != SurfaceClass::Window || surf.ExtBoundCond != 0) {
    9972            0 :                     ShowSevereError(state, format("{}=\"{}\"", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
    9973            0 :                     ShowSevereError(state, format("cannot be used with surface={}", surf.Name));
    9974            0 :                     ShowContinueError(state, "because that surface is not an exterior window.");
    9975            0 :                     ErrorsFound = true;
    9976              :                 }
    9977              :             }
    9978              : 
    9979              :             // Require that storm window material be glass
    9980            0 :             int MatNum = state.dataSurface->StormWindow(StormWinNum).StormWinMaterialNum;
    9981            0 :             if (SurfNum > 0) {
    9982            0 :                 if (MatNum == 0) {
    9983            0 :                     ShowSevereError(state, format("{}=\"{}\"", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
    9984            0 :                     ShowContinueError(state,
    9985            0 :                                       format("{}=\"{}\" not found as storm window layer.", s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2)));
    9986            0 :                     ErrorsFound = true;
    9987              :                 } else {
    9988            0 :                     if (s_mat->materials(MatNum)->group != Material::Group::Glass) {
    9989            0 :                         ShowSevereError(state, format("{}=\"{}\"", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
    9990            0 :                         ShowContinueError(state,
    9991            0 :                                           format("{}=\"{}must be a WindowMaterial:Glazing or WindowMaterial:Glazing:RefractionExtinctionMethod",
    9992            0 :                                                  s_ipsc->cAlphaFieldNames(2),
    9993            0 :                                                  s_ipsc->cAlphaArgs(2)));
    9994            0 :                         ErrorsFound = true;
    9995              :                     }
    9996              :                 }
    9997              :                 // Error if base window has airflow control
    9998            0 :                 if (state.dataSurface->SurfWinAirflowControlType(SurfNum) != DataSurfaces::WindowAirFlowControlType::Invalid) {
    9999            0 :                     ShowSevereError(
   10000              :                         state,
   10001            0 :                         format("{}=\"{} cannot be used because it is an airflow window (i.e., has WindowProperty:AirflowControl specified)",
   10002            0 :                                s_ipsc->cCurrentModuleObject,
   10003            0 :                                s_ipsc->cAlphaArgs(1)));
   10004            0 :                     ErrorsFound = true;
   10005              :                 }
   10006              :             }
   10007              : 
   10008              :             // Check for reversal of on and off times
   10009            0 :             if (SurfNum > 0) {
   10010            0 :                 if ((state.dataEnvrn->Latitude > 0.0 &&
   10011            0 :                      (state.dataSurface->StormWindow(StormWinNum).MonthOn < state.dataSurface->StormWindow(StormWinNum).MonthOff)) ||
   10012            0 :                     (state.dataEnvrn->Latitude <= 0.0 &&
   10013            0 :                      (state.dataSurface->StormWindow(StormWinNum).MonthOn > state.dataSurface->StormWindow(StormWinNum).MonthOff))) {
   10014            0 :                     ShowWarningError(state, format("{}=\"{}\" check times that storm window", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
   10015            0 :                     ShowContinueError(state,
   10016            0 :                                       format("is put on (month={}, day={}) and taken off (month={}, day={});",
   10017            0 :                                              state.dataSurface->StormWindow(StormWinNum).MonthOn,
   10018            0 :                                              state.dataSurface->StormWindow(StormWinNum).DayOfMonthOn,
   10019            0 :                                              state.dataSurface->StormWindow(StormWinNum).MonthOff,
   10020            0 :                                              state.dataSurface->StormWindow(StormWinNum).DayOfMonthOff));
   10021            0 :                     ShowContinueError(state, format("these times may be reversed for your building latitude={:.2R} deg.", state.dataEnvrn->Latitude));
   10022              :                 }
   10023              :             }
   10024              :         }
   10025              :     }
   10026              : 
   10027          192 :     void GetWindowGapAirflowControlData(EnergyPlusData &state, bool &ErrorsFound) // If errors found in input
   10028              :     {
   10029              : 
   10030              :         // SUBROUTINE INFORMATION:
   10031              :         //       AUTHOR         Fred Winkelmann
   10032              :         //       DATE WRITTEN   Feb 2003
   10033              :         //       MODIFIED       June 2003, FCW: add destination = return air;
   10034              :         //                        more error messages
   10035              : 
   10036              :         // PURPOSE OF THIS SUBROUTINE:
   10037              :         // Reads in the window airflow control information from the input data file,
   10038              :         // interprets it and puts it in the SurfaceWindow derived type
   10039              : 
   10040              :         static constexpr std::string_view routineName = "GetWindowGapAirflowControlData";
   10041              : 
   10042              :         int IOStat;               // IO Status when calling get input subroutine
   10043              :         int ControlNumAlpha;      // Number of control alpha names being passed
   10044              :         int ControlNumProp;       // Number of control properties being passed
   10045              :         int TotWinAirflowControl; // Total window airflow control statements
   10046              :         int Loop;
   10047          192 :         int ConstrNum(0); // Construction number
   10048              :         int ConstrNumSh;  // Shaded Construction number
   10049              :         int MatGapFlow;   // Material number of gas in airflow gap of window's construction
   10050              :         int MatGapFlow1;  // Material number of gas on either side of a between-glass shade/blind
   10051              :         int MatGapFlow2;
   10052              : 
   10053          192 :         constexpr std::array<std::string_view, static_cast<int>(DataSurfaces::WindowAirFlowSource::Num)> WindowAirFlowSourceNamesUC{"INDOORAIR",
   10054              :                                                                                                                                     "OUTDOORAIR"};
   10055          192 :         constexpr std::array<std::string_view, static_cast<int>(DataSurfaces::WindowAirFlowDestination::Num)> WindowAirFlowDestinationNamesUC{
   10056              :             "INDOORAIR", "OUTDOORAIR", "RETURNAIR"};
   10057              : 
   10058              :         // of the shaded construction of airflow window
   10059          192 :         auto &s_ipsc = state.dataIPShortCut;
   10060          192 :         auto &s_mat = state.dataMaterial;
   10061              : 
   10062              :         // Get the total number of window airflow control statements
   10063          192 :         s_ipsc->cCurrentModuleObject = "WindowProperty:AirflowControl";
   10064          192 :         TotWinAirflowControl = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
   10065          192 :         if (TotWinAirflowControl == 0) return;
   10066              : 
   10067            0 :         for (Loop = 1; Loop <= TotWinAirflowControl; ++Loop) { // Loop through all surfaces in the input...
   10068              : 
   10069            0 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
   10070            0 :                                                                      s_ipsc->cCurrentModuleObject,
   10071              :                                                                      Loop,
   10072            0 :                                                                      s_ipsc->cAlphaArgs,
   10073              :                                                                      ControlNumAlpha,
   10074            0 :                                                                      s_ipsc->rNumericArgs,
   10075              :                                                                      ControlNumProp,
   10076              :                                                                      IOStat,
   10077            0 :                                                                      s_ipsc->lNumericFieldBlanks,
   10078            0 :                                                                      s_ipsc->lAlphaFieldBlanks,
   10079            0 :                                                                      s_ipsc->cAlphaFieldNames,
   10080            0 :                                                                      s_ipsc->cNumericFieldNames);
   10081              : 
   10082            0 :             ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
   10083              : 
   10084            0 :             int SurfNum = Util::FindItemInList(s_ipsc->cAlphaArgs(1), state.dataSurface->Surface, state.dataSurface->TotSurfaces);
   10085            0 :             if (SurfNum == 0) {
   10086            0 :                 ShowSevereError(state, format("{}=\"{}\" not found.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
   10087            0 :                 ErrorsFound = true;
   10088              :             }
   10089              :             // Check that associated surface is a 2- or 3-pane exterior window
   10090            0 :             if (SurfNum != 0) {
   10091            0 :                 bool WrongSurfaceType = false;
   10092            0 :                 auto const &surf = state.dataSurface->Surface(SurfNum);
   10093            0 :                 if (surf.Class != SurfaceClass::Window) WrongSurfaceType = true;
   10094            0 :                 if (surf.Class == SurfaceClass::Window) {
   10095            0 :                     ConstrNum = surf.Construction;
   10096            0 :                     if (state.dataConstruction->Construct(ConstrNum).TotGlassLayers != 2 &&
   10097            0 :                         state.dataConstruction->Construct(ConstrNum).TotGlassLayers != 3)
   10098            0 :                         WrongSurfaceType = true;
   10099            0 :                     if (surf.ExtBoundCond != DataSurfaces::ExternalEnvironment) WrongSurfaceType = true;
   10100              :                 }
   10101            0 :                 if (WrongSurfaceType) {
   10102            0 :                     ShowSevereError(
   10103              :                         state,
   10104            0 :                         format("{}=\"{}\" is not an exterior window with 2 or 3 glass layers.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
   10105            0 :                     ErrorsFound = true;
   10106              :                 }
   10107              :             }
   10108              : 
   10109              :             // Error if illegal airflow source
   10110            0 :             if (s_ipsc->cAlphaArgs(2) != "INDOORAIR" && s_ipsc->cAlphaArgs(2) != "OUTDOORAIR") {
   10111            0 :                 ErrorsFound = true;
   10112            0 :                 ShowSevereError(state,
   10113            0 :                                 format("{}=\"{}\" invalid {}=\"{}\"",
   10114            0 :                                        s_ipsc->cCurrentModuleObject,
   10115            0 :                                        s_ipsc->cAlphaArgs(1),
   10116            0 :                                        s_ipsc->cAlphaFieldNames(2),
   10117            0 :                                        s_ipsc->cAlphaArgs(2)));
   10118              :             }
   10119              : 
   10120              :             // Error if illegal airflow destination
   10121            0 :             if (s_ipsc->cAlphaArgs(3) != "INDOORAIR" && s_ipsc->cAlphaArgs(3) != "OUTDOORAIR" && s_ipsc->cAlphaArgs(3) != "RETURNAIR") {
   10122            0 :                 ErrorsFound = true;
   10123            0 :                 ShowSevereError(state,
   10124            0 :                                 format("{}=\"{}\" invalid {}=\"{}\"",
   10125            0 :                                        s_ipsc->cCurrentModuleObject,
   10126            0 :                                        s_ipsc->cAlphaArgs(1),
   10127            0 :                                        s_ipsc->cAlphaFieldNames(3),
   10128            0 :                                        s_ipsc->cAlphaArgs(3)));
   10129              :             }
   10130              : 
   10131              :             // Error if source = OutsideAir and destination = ReturnAir
   10132            0 :             if (s_ipsc->cAlphaArgs(2) == "OUTDOORAIR" && s_ipsc->cAlphaArgs(3) == "RETURNAIR") {
   10133            0 :                 ErrorsFound = true;
   10134            0 :                 ShowSevereError(state,
   10135            0 :                                 format("{}=\"{}\" invalid {}=\"{}\"",
   10136            0 :                                        s_ipsc->cCurrentModuleObject,
   10137            0 :                                        s_ipsc->cAlphaArgs(1),
   10138            0 :                                        s_ipsc->cAlphaFieldNames(2),
   10139            0 :                                        s_ipsc->cAlphaArgs(2)));
   10140            0 :                 ShowContinueError(state, format("..when {}=\"{}\"", s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3)));
   10141              :             }
   10142              : 
   10143              :             // Error if illegal airflow control type
   10144            0 :             if (s_ipsc->cAlphaArgs(4) != "ALWAYSONATMAXIMUMFLOW" && s_ipsc->cAlphaArgs(4) != "ALWAYSOFF" &&
   10145            0 :                 s_ipsc->cAlphaArgs(4) != "SCHEDULEDONLY") {
   10146            0 :                 ErrorsFound = true;
   10147            0 :                 ShowSevereError(state,
   10148            0 :                                 format("{}=\"{}\" invalid {}=\"{}\"",
   10149            0 :                                        s_ipsc->cCurrentModuleObject,
   10150            0 :                                        s_ipsc->cAlphaArgs(1),
   10151            0 :                                        s_ipsc->cAlphaFieldNames(4),
   10152            0 :                                        s_ipsc->cAlphaArgs(4)));
   10153              :             }
   10154              : 
   10155              :             // Error if illegal value for Airflow Has Multiplier Schedule
   10156            0 :             if (s_ipsc->cAlphaArgs(5) != "YES" && s_ipsc->cAlphaArgs(5) != "NO") {
   10157            0 :                 ErrorsFound = true;
   10158            0 :                 ShowSevereError(state,
   10159            0 :                                 format("{}=\"{}\" invalid {}=\"{}\"",
   10160            0 :                                        s_ipsc->cCurrentModuleObject,
   10161            0 :                                        s_ipsc->cAlphaArgs(1),
   10162            0 :                                        s_ipsc->cAlphaFieldNames(5),
   10163            0 :                                        s_ipsc->cAlphaArgs(5)));
   10164              :             }
   10165              : 
   10166              :             // Error if Airflow Control Type = ScheduledOnly and Airflow Has Multiplier Schedule = No
   10167            0 :             if (s_ipsc->cAlphaArgs(4) == "SCHEDULEDONLY" && s_ipsc->cAlphaArgs(5) == "NO") {
   10168            0 :                 ErrorsFound = true;
   10169            0 :                 ShowSevereError(state,
   10170            0 :                                 format("{}=\"{}\" invalid {}=\"{}\"",
   10171            0 :                                        s_ipsc->cCurrentModuleObject,
   10172            0 :                                        s_ipsc->cAlphaArgs(1),
   10173            0 :                                        s_ipsc->cAlphaFieldNames(4),
   10174            0 :                                        s_ipsc->cAlphaArgs(4)));
   10175            0 :                 ShowContinueError(state, format("..when {}=\"{}\"", s_ipsc->cAlphaFieldNames(5), s_ipsc->cAlphaArgs(5)));
   10176              :             }
   10177              : 
   10178              :             // Warning if Airflow Control Type = AlwaysOnAtMaxFlow and Airflow Has Multiplier Schedule = Yes
   10179            0 :             if (s_ipsc->cAlphaArgs(4) == "ALWAYSONATMAXIMUMFLOW" && s_ipsc->cAlphaArgs(5) == "YES") {
   10180            0 :                 ShowWarningError(state,
   10181            0 :                                  format("{}=\"{}has {}=\"{}\"",
   10182            0 :                                         s_ipsc->cCurrentModuleObject,
   10183            0 :                                         s_ipsc->cAlphaArgs(1),
   10184            0 :                                         s_ipsc->cAlphaFieldNames(4),
   10185            0 :                                         s_ipsc->cAlphaArgs(4)));
   10186            0 :                 ShowContinueError(state,
   10187            0 :                                   format("..but {}=\"{}If specified, the {} will be ignored.",
   10188            0 :                                          s_ipsc->cAlphaFieldNames(5),
   10189            0 :                                          s_ipsc->cAlphaArgs(5),
   10190            0 :                                          s_ipsc->cAlphaFieldNames(5)));
   10191              :             }
   10192              : 
   10193              :             // Warning if Airflow Control Type = AlwaysOff and Airflow Has Multiplier Schedule = Yes
   10194            0 :             if (s_ipsc->cAlphaArgs(4) == "ALWAYSOFF" && s_ipsc->cAlphaArgs(5) == "YES") {
   10195            0 :                 ShowWarningError(state,
   10196            0 :                                  format("{}=\"{}has {}=\"{}\"",
   10197            0 :                                         s_ipsc->cCurrentModuleObject,
   10198            0 :                                         s_ipsc->cAlphaArgs(1),
   10199            0 :                                         s_ipsc->cAlphaFieldNames(4),
   10200            0 :                                         s_ipsc->cAlphaArgs(4)));
   10201            0 :                 ShowContinueError(state,
   10202            0 :                                   format("..but {}=\"{}\". If specified, the {} will be ignored.",
   10203            0 :                                          s_ipsc->cAlphaFieldNames(5),
   10204            0 :                                          s_ipsc->cAlphaArgs(5),
   10205            0 :                                          s_ipsc->cAlphaFieldNames(5)));
   10206              :             }
   10207              : 
   10208            0 :             if (SurfNum > 0) {
   10209            0 :                 auto const &surf = state.dataSurface->Surface(SurfNum);
   10210            0 :                 state.dataSurface->AirflowWindows = true;
   10211            0 :                 state.dataSurface->SurfWinAirflowSource(SurfNum) =
   10212            0 :                     static_cast<DataSurfaces::WindowAirFlowSource>(getEnumValue(WindowAirFlowSourceNamesUC, s_ipsc->cAlphaArgs(2)));
   10213              : 
   10214            0 :                 state.dataSurface->SurfWinAirflowDestination(SurfNum) =
   10215            0 :                     static_cast<DataSurfaces::WindowAirFlowDestination>(getEnumValue(WindowAirFlowDestinationNamesUC, s_ipsc->cAlphaArgs(3)));
   10216              : 
   10217            0 :                 if (state.dataSurface->SurfWinAirflowDestination(SurfNum) == DataSurfaces::WindowAirFlowDestination::Return) {
   10218            0 :                     int controlledZoneNum = DataZoneEquipment::GetControlledZoneIndex(state, surf.ZoneName);
   10219            0 :                     if (controlledZoneNum > 0) {
   10220            0 :                         state.dataHeatBal->Zone(surf.Zone).HasAirFlowWindowReturn = true;
   10221              :                     }
   10222              : 
   10223              :                     // Set return air node number
   10224            0 :                     state.dataSurface->SurfWinAirflowReturnNodePtr(SurfNum) = 0;
   10225            0 :                     std::string retNodeName = "";
   10226            0 :                     if (!s_ipsc->lAlphaFieldBlanks(7)) {
   10227            0 :                         retNodeName = s_ipsc->cAlphaArgs(7);
   10228              :                     }
   10229            0 :                     std::string callDescription = s_ipsc->cCurrentModuleObject + "=" + surf.Name;
   10230            0 :                     state.dataSurface->SurfWinAirflowReturnNodePtr(SurfNum) =
   10231            0 :                         DataZoneEquipment::GetReturnAirNodeForZone(state, surf.Zone, retNodeName, callDescription);
   10232            0 :                     if (state.dataSurface->SurfWinAirflowReturnNodePtr(SurfNum) == 0) {
   10233            0 :                         ShowSevereError(state,
   10234            0 :                                         format("{}{}=\"{}\", airflow window return air node not found for {} = {}",
   10235              :                                                routineName,
   10236            0 :                                                s_ipsc->cCurrentModuleObject,
   10237            0 :                                                surf.Name,
   10238            0 :                                                s_ipsc->cAlphaFieldNames(3),
   10239            0 :                                                s_ipsc->cAlphaArgs(3)));
   10240            0 :                         if (!s_ipsc->lAlphaFieldBlanks(7))
   10241            0 :                             ShowContinueError(
   10242              :                                 state,
   10243            0 :                                 format("{}=\"{}\" did not find a matching return air node.", s_ipsc->cAlphaFieldNames(7), s_ipsc->cAlphaArgs(7)));
   10244            0 :                         ShowContinueError(state,
   10245              :                                           "..Airflow windows with Airflow Destination = ReturnAir must reference a controlled Zone (appear in a "
   10246              :                                           "ZoneHVAC:EquipmentConnections object) with at least one return air node.");
   10247            0 :                         ErrorsFound = true;
   10248              :                     }
   10249            0 :                 }
   10250            0 :                 if (Util::SameString(s_ipsc->cAlphaArgs(4), "AlwaysOnAtMaximumFlow")) {
   10251            0 :                     state.dataSurface->SurfWinAirflowControlType(SurfNum) = DataSurfaces::WindowAirFlowControlType::MaxFlow;
   10252            0 :                 } else if (Util::SameString(s_ipsc->cAlphaArgs(4), "AlwaysOff")) {
   10253            0 :                     state.dataSurface->SurfWinAirflowControlType(SurfNum) = DataSurfaces::WindowAirFlowControlType::AlwaysOff;
   10254            0 :                 } else if (Util::SameString(s_ipsc->cAlphaArgs(4), "ScheduledOnly")) {
   10255            0 :                     state.dataSurface->SurfWinAirflowControlType(SurfNum) = DataSurfaces::WindowAirFlowControlType::Schedule;
   10256              :                 }
   10257            0 :                 state.dataSurface->SurfWinMaxAirflow(SurfNum) = s_ipsc->rNumericArgs(1);
   10258            0 :                 if (s_ipsc->cAlphaArgs(4) == "SCHEDULEDONLY" && s_ipsc->cAlphaArgs(5) == "YES") {
   10259            0 :                     if (s_ipsc->lAlphaFieldBlanks(6)) {
   10260            0 :                         ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(6), s_ipsc->cAlphaFieldNames(4), s_ipsc->cAlphaArgs(4));
   10261            0 :                         ErrorsFound = true;
   10262            0 :                     } else if ((state.dataSurface->SurfWinAirflowScheds(SurfNum) = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(6))) == nullptr) {
   10263            0 :                         ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(6), s_ipsc->cAlphaArgs(6));
   10264            0 :                         ErrorsFound = true;
   10265            0 :                         ShowSevereError(state,
   10266            0 :                                         format("{}=\"{}\", has {}=\"{}\"",
   10267            0 :                                                s_ipsc->cCurrentModuleObject,
   10268            0 :                                                s_ipsc->cAlphaArgs(1),
   10269            0 :                                                s_ipsc->cAlphaFieldNames(4),
   10270            0 :                                                s_ipsc->cAlphaArgs(4)));
   10271            0 :                         ShowContinueError(state,
   10272            0 :                                           format("..and {}=\"{}\", but no {} specified.",
   10273            0 :                                                  s_ipsc->cAlphaFieldNames(5),
   10274            0 :                                                  s_ipsc->cAlphaArgs(5),
   10275            0 :                                                  s_ipsc->cAlphaFieldNames(6)));
   10276              :                     } else {
   10277            0 :                         state.dataSurface->SurfWinAirflowHasSchedule(SurfNum) = true;
   10278            0 :                         if ((state.dataSurface->SurfWinAirflowScheds(SurfNum) = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(6))) == nullptr) {
   10279            0 :                             ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(6), s_ipsc->cAlphaArgs(6));
   10280            0 :                             ErrorsFound = true;
   10281              :                         }
   10282              :                     }
   10283              :                 }
   10284              :                 // Warning if associated window is an interior window
   10285            0 :                 if (surf.ExtBoundCond != DataSurfaces::ExternalEnvironment && !ErrorsFound)
   10286            0 :                     ShowWarningError(state,
   10287            0 :                                      format("{}=\"{}\", is an Interior window; cannot be an airflow window.",
   10288            0 :                                             s_ipsc->cCurrentModuleObject,
   10289            0 :                                             s_ipsc->cAlphaArgs(1)));
   10290            0 :                 if (!ErrorsFound) {
   10291              :                     // Require that gas in airflow gap has type = air
   10292            0 :                     MatGapFlow = state.dataConstruction->Construct(ConstrNum).LayerPoint(2);
   10293            0 :                     if (state.dataConstruction->Construct(ConstrNum).TotGlassLayers == 3)
   10294            0 :                         MatGapFlow = state.dataConstruction->Construct(ConstrNum).LayerPoint(4);
   10295            0 :                     if (dynamic_cast<Material::MaterialGasMix const *>(s_mat->materials(MatGapFlow))->gases[0].type != Material::GasType::Air) {
   10296            0 :                         ErrorsFound = true;
   10297            0 :                         ShowSevereError(state,
   10298            0 :                                         format("{}=\"{}\", Gas type not air in airflow gap of construction {}",
   10299            0 :                                                s_ipsc->cCurrentModuleObject,
   10300            0 :                                                s_ipsc->cAlphaArgs(1),
   10301            0 :                                                state.dataConstruction->Construct(ConstrNum).Name));
   10302              :                     }
   10303              :                     // Require that gas be air in airflow gaps on either side of a between glass shade/blind
   10304            0 :                     if (surf.HasShadeControl) {
   10305            0 :                         for (std::size_t listIndex = 0; listIndex < surf.windowShadingControlList.size(); ++listIndex) {
   10306            0 :                             int WSCPtr = surf.windowShadingControlList[listIndex];
   10307            0 :                             if (ANY_BETWEENGLASS_SHADE_BLIND(state.dataSurface->WindowShadingControl(WSCPtr).ShadingType)) {
   10308            0 :                                 ConstrNumSh = surf.shadedConstructionList[listIndex];
   10309            0 :                                 if (state.dataConstruction->Construct(ConstrNum).TotGlassLayers == 2) {
   10310            0 :                                     MatGapFlow1 = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(2);
   10311            0 :                                     MatGapFlow2 = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(4);
   10312              :                                 } else {
   10313            0 :                                     MatGapFlow1 = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(4);
   10314            0 :                                     MatGapFlow2 = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(6);
   10315              :                                 }
   10316            0 :                                 if (dynamic_cast<Material::MaterialGasMix const *>(s_mat->materials(MatGapFlow1))->gases[0].type !=
   10317            0 :                                         Material::GasType::Air ||
   10318            0 :                                     dynamic_cast<Material::MaterialGasMix const *>(s_mat->materials(MatGapFlow2))->gases[0].type !=
   10319              :                                         Material::GasType::Air) {
   10320            0 :                                     ErrorsFound = true;
   10321            0 :                                     ShowSevereError(state,
   10322            0 :                                                     format("{}=\"{}\", gas type must be air on either side of the shade/blind",
   10323            0 :                                                            s_ipsc->cCurrentModuleObject,
   10324            0 :                                                            s_ipsc->cAlphaArgs(1)));
   10325              :                                 }
   10326            0 :                                 break; // only need the first window shading control since they should be the same
   10327              :                             }
   10328              :                         }
   10329              :                     }
   10330              :                 }
   10331              :             }
   10332              : 
   10333              :         } // End of loop over window airflow controls
   10334              :     }
   10335              : 
   10336          234 :     void GetFoundationData(EnergyPlusData &state, bool &ErrorsFound)
   10337              :     {
   10338              : 
   10339              :         int NumAlphas;
   10340              :         int NumProps;
   10341              :         int IOStat;
   10342              : 
   10343              :         static constexpr std::string_view routineName = "GetFoundationData";
   10344              : 
   10345          234 :         auto &s_ipsc = state.dataIPShortCut;
   10346              : 
   10347              :         // Read Kiva Settings
   10348          234 :         s_ipsc->cCurrentModuleObject = "Foundation:Kiva:Settings";
   10349          234 :         int TotKivaStgs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
   10350              : 
   10351          234 :         if (TotKivaStgs > 1) {
   10352            0 :             ErrorsFound = true;
   10353            0 :             ShowSevereError(state, format("Multiple {} objects found. Only one is allowed.", s_ipsc->cCurrentModuleObject));
   10354              :         }
   10355              : 
   10356          234 :         if (TotKivaStgs == 1) {
   10357            4 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
   10358            2 :                                                                      s_ipsc->cCurrentModuleObject,
   10359              :                                                                      1,
   10360            2 :                                                                      s_ipsc->cAlphaArgs,
   10361              :                                                                      NumAlphas,
   10362            2 :                                                                      s_ipsc->rNumericArgs,
   10363              :                                                                      NumProps,
   10364              :                                                                      IOStat,
   10365            2 :                                                                      s_ipsc->lNumericFieldBlanks,
   10366            2 :                                                                      s_ipsc->lAlphaFieldBlanks,
   10367            2 :                                                                      s_ipsc->cAlphaFieldNames,
   10368            2 :                                                                      s_ipsc->cNumericFieldNames);
   10369              : 
   10370            2 :             int numF = 1;
   10371            2 :             int alpF = 1;
   10372              : 
   10373            2 :             if (!s_ipsc->lNumericFieldBlanks(numF)) {
   10374            2 :                 state.dataSurfaceGeometry->kivaManager.settings.soilK = s_ipsc->rNumericArgs(numF);
   10375              :             }
   10376            2 :             numF++;
   10377            2 :             if (!s_ipsc->lNumericFieldBlanks(numF)) {
   10378            2 :                 state.dataSurfaceGeometry->kivaManager.settings.soilRho = s_ipsc->rNumericArgs(numF);
   10379              :             }
   10380            2 :             numF++;
   10381            2 :             if (!s_ipsc->lNumericFieldBlanks(numF)) {
   10382            2 :                 state.dataSurfaceGeometry->kivaManager.settings.soilCp = s_ipsc->rNumericArgs(numF);
   10383              :             }
   10384            2 :             numF++;
   10385            2 :             if (!s_ipsc->lNumericFieldBlanks(numF)) {
   10386            2 :                 state.dataSurfaceGeometry->kivaManager.settings.groundSolarAbs = s_ipsc->rNumericArgs(numF);
   10387              :             }
   10388            2 :             numF++;
   10389            2 :             if (!s_ipsc->lNumericFieldBlanks(numF)) {
   10390            2 :                 state.dataSurfaceGeometry->kivaManager.settings.groundThermalAbs = s_ipsc->rNumericArgs(numF);
   10391              :             }
   10392            2 :             numF++;
   10393            2 :             if (!s_ipsc->lNumericFieldBlanks(numF)) {
   10394            2 :                 state.dataSurfaceGeometry->kivaManager.settings.groundRoughness = s_ipsc->rNumericArgs(numF);
   10395              :             }
   10396            2 :             numF++;
   10397            2 :             if (!s_ipsc->lNumericFieldBlanks(numF)) {
   10398            2 :                 state.dataSurfaceGeometry->kivaManager.settings.farFieldWidth = s_ipsc->rNumericArgs(numF);
   10399              :             }
   10400            2 :             numF++;
   10401              : 
   10402            2 :             if (!s_ipsc->lAlphaFieldBlanks(alpF)) {
   10403            2 :                 if (Util::SameString(s_ipsc->cAlphaArgs(alpF), "ZeroFlux")) {
   10404            1 :                     state.dataSurfaceGeometry->kivaManager.settings.deepGroundBoundary = HeatBalanceKivaManager::KivaManager::Settings::ZERO_FLUX;
   10405            1 :                 } else if (Util::SameString(s_ipsc->cAlphaArgs(alpF), "GroundWater")) {
   10406            0 :                     state.dataSurfaceGeometry->kivaManager.settings.deepGroundBoundary = HeatBalanceKivaManager::KivaManager::Settings::GROUNDWATER;
   10407            1 :                 } else if (Util::SameString(s_ipsc->cAlphaArgs(alpF), "Autoselect")) {
   10408            1 :                     state.dataSurfaceGeometry->kivaManager.settings.deepGroundBoundary = HeatBalanceKivaManager::KivaManager::Settings::AUTO;
   10409              :                 } else {
   10410            0 :                     ErrorsFound = true;
   10411            0 :                     ShowSevereError(state,
   10412            0 :                                     format("{}, {} is not a valid choice for {}",
   10413            0 :                                            s_ipsc->cCurrentModuleObject,
   10414            0 :                                            s_ipsc->cAlphaArgs(alpF),
   10415            0 :                                            s_ipsc->cAlphaFieldNames(alpF)));
   10416              :                 }
   10417              :             }
   10418            2 :             alpF++;
   10419              : 
   10420            2 :             if (s_ipsc->lNumericFieldBlanks(numF) || s_ipsc->rNumericArgs(numF) == Constant::AutoCalculate) {
   10421              :                 // Autocalculate deep-ground depth (see KivaManager::defineDefaultFoundation() for actual calculation)
   10422            1 :                 state.dataSurfaceGeometry->kivaManager.settings.deepGroundDepth = 40.0;
   10423            1 :                 state.dataSurfaceGeometry->kivaManager.settings.autocalculateDeepGroundDepth = true;
   10424            1 :                 if (state.dataSurfaceGeometry->kivaManager.settings.deepGroundBoundary != HeatBalanceKivaManager::KivaManager::Settings::AUTO) {
   10425            1 :                     ErrorsFound = true;
   10426            2 :                     ShowSevereError(state,
   10427            4 :                                     format("{}, {} should not be set to Autocalculate unless {} is set to Autoselect",
   10428            1 :                                            s_ipsc->cCurrentModuleObject,
   10429            1 :                                            s_ipsc->cNumericFieldNames(numF),
   10430            1 :                                            s_ipsc->cAlphaFieldNames(alpF - 1)));
   10431              :                 }
   10432              :             } else {
   10433            1 :                 state.dataSurfaceGeometry->kivaManager.settings.deepGroundDepth = s_ipsc->rNumericArgs(numF);
   10434            1 :                 state.dataSurfaceGeometry->kivaManager.settings.autocalculateDeepGroundDepth = false;
   10435              :             }
   10436            2 :             numF++;
   10437            2 :             if (!s_ipsc->lNumericFieldBlanks(numF)) {
   10438            0 :                 state.dataSurfaceGeometry->kivaManager.settings.minCellDim = s_ipsc->rNumericArgs(numF);
   10439              :             }
   10440            2 :             numF++;
   10441            2 :             if (!s_ipsc->lNumericFieldBlanks(numF)) {
   10442            0 :                 state.dataSurfaceGeometry->kivaManager.settings.maxGrowthCoeff = s_ipsc->rNumericArgs(numF);
   10443              :             }
   10444            2 :             numF++;
   10445              : 
   10446            2 :             if (!s_ipsc->lAlphaFieldBlanks(alpF)) {
   10447            0 :                 if (Util::SameString(s_ipsc->cAlphaArgs(alpF), "Hourly")) {
   10448            0 :                     state.dataSurfaceGeometry->kivaManager.settings.timestepType = HeatBalanceKivaManager::KivaManager::Settings::HOURLY;
   10449            0 :                     state.dataSurfaceGeometry->kivaManager.timestep = 3600.; // seconds
   10450              :                 } else {                                                     // if (Util::SameString(s_ipsc->cAlphaArgs( alpF ), "Timestep"))
   10451            0 :                     state.dataSurfaceGeometry->kivaManager.settings.timestepType = HeatBalanceKivaManager::KivaManager::Settings::TIMESTEP;
   10452            0 :                     state.dataSurfaceGeometry->kivaManager.timestep = state.dataGlobal->MinutesInTimeStep * 60.;
   10453              :                 }
   10454              :             }
   10455            2 :             alpF++;
   10456              :         }
   10457              : 
   10458              :         // Set default foundation (probably doesn't need to be called if there are no Kiva
   10459              :         // surfaces, but we don't know that yet). We call this here so that the default
   10460              :         // foundation is available for 1) the starting copy for user-defined Foundation:Kiva
   10461              :         // object default inputs, and 2) the actual default Foundation object if a
   10462              :         // user-defined Foundation:Kiva name is not referenced by a surface.
   10463          234 :         state.dataSurfaceGeometry->kivaManager.defineDefaultFoundation(state);
   10464              : 
   10465              :         // Read Foundation objects
   10466          234 :         s_ipsc->cCurrentModuleObject = "Foundation:Kiva";
   10467          234 :         int TotKivaFnds = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
   10468              : 
   10469          234 :         if (TotKivaFnds > 0) {
   10470            1 :             auto &s_mat = state.dataMaterial;
   10471            2 :             for (int Loop = 1; Loop <= TotKivaFnds; ++Loop) {
   10472            2 :                 state.dataInputProcessing->inputProcessor->getObjectItem(state,
   10473            1 :                                                                          s_ipsc->cCurrentModuleObject,
   10474              :                                                                          Loop,
   10475            1 :                                                                          s_ipsc->cAlphaArgs,
   10476              :                                                                          NumAlphas,
   10477            1 :                                                                          s_ipsc->rNumericArgs,
   10478              :                                                                          NumProps,
   10479              :                                                                          IOStat,
   10480            1 :                                                                          s_ipsc->lNumericFieldBlanks,
   10481            1 :                                                                          s_ipsc->lAlphaFieldBlanks,
   10482            1 :                                                                          s_ipsc->cAlphaFieldNames,
   10483            1 :                                                                          s_ipsc->cNumericFieldNames);
   10484              : 
   10485            1 :                 ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
   10486              : 
   10487            1 :                 int numF = 1;
   10488            1 :                 int alpF = 1;
   10489              : 
   10490            1 :                 bool ErrorInName = false;
   10491              : 
   10492            1 :                 HeatBalanceKivaManager::FoundationKiva fndInput;
   10493              : 
   10494            1 :                 fndInput.name = s_ipsc->cAlphaArgs(alpF);
   10495            1 :                 alpF++;
   10496            1 :                 Util::IsNameEmpty(state, fndInput.name, s_ipsc->cCurrentModuleObject, ErrorInName);
   10497            1 :                 if (ErrorInName) {
   10498            0 :                     ErrorsFound = true;
   10499            0 :                     continue;
   10500              :                 }
   10501              : 
   10502              :                 // Start with copy of default
   10503            1 :                 auto &fnd = fndInput.foundation;
   10504            1 :                 fnd = state.dataSurfaceGeometry->kivaManager.defaultFoundation.foundation;
   10505              : 
   10506              :                 // Indoor temperature
   10507            1 :                 if (!s_ipsc->lNumericFieldBlanks(numF)) {
   10508            1 :                     fndInput.assumedIndoorTemperature = s_ipsc->rNumericArgs(numF);
   10509              :                 } else {
   10510            0 :                     fndInput.assumedIndoorTemperature = -9999;
   10511              :                 }
   10512            1 :                 numF++;
   10513              : 
   10514              :                 // Interior horizontal insulation
   10515            1 :                 if (!s_ipsc->lAlphaFieldBlanks(alpF)) {
   10516            0 :                     int index = Material::GetMaterialNum(state, s_ipsc->cAlphaArgs(alpF));
   10517            0 :                     if (index == 0) {
   10518            0 :                         ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(alpF), s_ipsc->cAlphaArgs(alpF));
   10519            0 :                         ErrorsFound = true;
   10520            0 :                         continue;
   10521              :                     }
   10522            0 :                     auto *m = s_mat->materials(index);
   10523            0 :                     if (m->group != Material::Group::Regular || m->ROnly) {
   10524            0 :                         ErrorsFound = true;
   10525            0 :                         ShowSevereError(state,
   10526            0 :                                         format("{}=\"{}\", invalid {}=\"{}",
   10527            0 :                                                s_ipsc->cCurrentModuleObject,
   10528              :                                                fndInput.name,
   10529            0 :                                                s_ipsc->cAlphaFieldNames(alpF),
   10530            0 :                                                s_ipsc->cAlphaArgs(alpF)));
   10531            0 :                         ShowContinueError(state, "Must be of type \"Material\"");
   10532            0 :                         continue;
   10533              :                     }
   10534            0 :                     fndInput.intHIns.x = 0.0;
   10535            0 :                     fndInput.intHIns.material = Kiva::Material(m->Conductivity, m->Density, m->SpecHeat);
   10536            0 :                     fndInput.intHIns.depth = m->Thickness;
   10537              :                 }
   10538            1 :                 alpF++;
   10539              : 
   10540            1 :                 if (!s_ipsc->lAlphaFieldBlanks(alpF - 1)) {
   10541            0 :                     if (s_ipsc->lNumericFieldBlanks(numF)) {
   10542            0 :                         fndInput.intHIns.z = 0.0;
   10543              :                     } else {
   10544            0 :                         fndInput.intHIns.z = s_ipsc->rNumericArgs(numF);
   10545              :                     }
   10546            0 :                     numF++;
   10547            0 :                     if (s_ipsc->lNumericFieldBlanks(numF)) {
   10548            0 :                         ErrorsFound = true;
   10549            0 :                         ShowSevereError(state,
   10550            0 :                                         format("{}=\"{}\", {} defined, but no {}provided",
   10551            0 :                                                s_ipsc->cCurrentModuleObject,
   10552              :                                                fndInput.name,
   10553            0 :                                                s_ipsc->cAlphaFieldNames(alpF - 1),
   10554            0 :                                                s_ipsc->cNumericFieldNames(numF)));
   10555            0 :                         continue;
   10556              :                     } else {
   10557            0 :                         fndInput.intHIns.width = -s_ipsc->rNumericArgs(numF);
   10558              :                     }
   10559            0 :                     numF++;
   10560              :                 } else {
   10561            1 :                     if (!s_ipsc->lNumericFieldBlanks(numF)) {
   10562            0 :                         ShowWarningError(
   10563              :                             state,
   10564            0 :                             format("{}=\"{}\", no {} defined", s_ipsc->cCurrentModuleObject, fndInput.name, s_ipsc->cAlphaFieldNames(alpF - 1)));
   10565            0 :                         ShowContinueError(state, format("{} will not be used.", s_ipsc->cNumericFieldNames(numF)));
   10566              :                     }
   10567            1 :                     numF++;
   10568            1 :                     if (!s_ipsc->lNumericFieldBlanks(numF)) {
   10569            0 :                         ShowWarningError(
   10570              :                             state,
   10571            0 :                             format("{}=\"{}\", no {} defined", s_ipsc->cCurrentModuleObject, fndInput.name, s_ipsc->cAlphaFieldNames(alpF - 1)));
   10572            0 :                         ShowContinueError(state, format("{} will not be used.", s_ipsc->cNumericFieldNames(numF)));
   10573              :                     }
   10574            1 :                     numF++;
   10575              :                 }
   10576              : 
   10577              :                 // Interior vertical insulation
   10578            1 :                 if (!s_ipsc->lAlphaFieldBlanks(alpF)) {
   10579            0 :                     int index = Material::GetMaterialNum(state, s_ipsc->cAlphaArgs(alpF));
   10580            0 :                     if (index == 0) {
   10581            0 :                         ErrorsFound = true;
   10582            0 :                         ShowSevereError(state,
   10583            0 :                                         format("Did not find matching material for {}=\"{}\", {}, missing material = {}",
   10584            0 :                                                s_ipsc->cCurrentModuleObject,
   10585              :                                                fndInput.name,
   10586            0 :                                                s_ipsc->cAlphaFieldNames(alpF),
   10587            0 :                                                s_ipsc->cAlphaArgs(alpF)));
   10588            0 :                         continue;
   10589              :                     }
   10590            0 :                     auto *m = s_mat->materials(index);
   10591            0 :                     if (m->group != Material::Group::Regular || m->ROnly) {
   10592            0 :                         ErrorsFound = true;
   10593            0 :                         ShowSevereError(state,
   10594            0 :                                         format("{}=\"{}\", invalid {}=\"{}",
   10595            0 :                                                s_ipsc->cCurrentModuleObject,
   10596              :                                                fndInput.name,
   10597            0 :                                                s_ipsc->cAlphaFieldNames(alpF),
   10598            0 :                                                s_ipsc->cAlphaArgs(alpF)));
   10599            0 :                         ShowContinueError(state, "Must be of type \"Material\"");
   10600            0 :                         continue;
   10601              :                     }
   10602            0 :                     fndInput.intVIns.material = Kiva::Material(m->Conductivity, m->Density, m->SpecHeat);
   10603            0 :                     fndInput.intVIns.width = -m->Thickness;
   10604            0 :                     fndInput.intVIns.x = 0.0;
   10605            0 :                     fndInput.intVIns.z = 0.0;
   10606              :                 }
   10607            1 :                 alpF++;
   10608              : 
   10609            1 :                 if (!s_ipsc->lAlphaFieldBlanks(alpF - 1)) {
   10610            0 :                     if (s_ipsc->lNumericFieldBlanks(numF)) {
   10611            0 :                         ErrorsFound = true;
   10612            0 :                         ShowSevereError(state,
   10613            0 :                                         format("{}=\"{}\", {} defined, but no {}provided",
   10614            0 :                                                s_ipsc->cCurrentModuleObject,
   10615              :                                                fndInput.name,
   10616            0 :                                                s_ipsc->cAlphaFieldNames(alpF - 1),
   10617            0 :                                                s_ipsc->cNumericFieldNames(numF)));
   10618            0 :                         continue;
   10619              :                     } else {
   10620            0 :                         fndInput.intVIns.depth = s_ipsc->rNumericArgs(numF);
   10621              :                     }
   10622            0 :                     numF++;
   10623              :                 } else {
   10624            1 :                     if (!s_ipsc->lNumericFieldBlanks(numF)) {
   10625            0 :                         ShowWarningError(
   10626              :                             state,
   10627            0 :                             format("{}=\"{}\", no {} defined", s_ipsc->cCurrentModuleObject, fndInput.name, s_ipsc->cAlphaFieldNames(alpF - 1)));
   10628            0 :                         ShowContinueError(state, format("{} will not be used.", s_ipsc->cNumericFieldNames(numF)));
   10629              :                     }
   10630            1 :                     numF++;
   10631              :                 }
   10632              : 
   10633              :                 // Exterior horizontal insulation
   10634            1 :                 if (!s_ipsc->lAlphaFieldBlanks(alpF)) {
   10635            0 :                     int index = Material::GetMaterialNum(state, s_ipsc->cAlphaArgs(alpF));
   10636            0 :                     if (index == 0) {
   10637            0 :                         ErrorsFound = true;
   10638            0 :                         ShowSevereError(state,
   10639            0 :                                         format("Did not find matching material for {}=\"{}\", {}, missing material = {}",
   10640            0 :                                                s_ipsc->cCurrentModuleObject,
   10641              :                                                fndInput.name,
   10642            0 :                                                s_ipsc->cAlphaFieldNames(alpF),
   10643            0 :                                                s_ipsc->cAlphaArgs(alpF)));
   10644            0 :                         continue;
   10645              :                     }
   10646            0 :                     auto *m = s_mat->materials(index);
   10647            0 :                     if (m->group != Material::Group::Regular || m->ROnly) {
   10648            0 :                         ErrorsFound = true;
   10649            0 :                         ShowSevereError(state,
   10650            0 :                                         format("{}=\"{}\", invalid {}=\"{}",
   10651            0 :                                                s_ipsc->cCurrentModuleObject,
   10652              :                                                fndInput.name,
   10653            0 :                                                s_ipsc->cAlphaFieldNames(alpF),
   10654            0 :                                                s_ipsc->cAlphaArgs(alpF)));
   10655            0 :                         ShowContinueError(state, "Must be of type \"Material\"");
   10656            0 :                         continue;
   10657              :                     }
   10658            0 :                     fndInput.extHIns.x = 0.0;
   10659            0 :                     fndInput.extHIns.material = Kiva::Material(m->Conductivity, m->Density, m->SpecHeat);
   10660            0 :                     fndInput.extHIns.depth = m->Thickness;
   10661              :                 }
   10662            1 :                 alpF++;
   10663              : 
   10664            1 :                 if (!s_ipsc->lAlphaFieldBlanks(alpF - 1)) {
   10665            0 :                     if (s_ipsc->lNumericFieldBlanks(numF)) {
   10666            0 :                         fndInput.extHIns.z = 0.0;
   10667              :                     } else {
   10668            0 :                         fndInput.extHIns.z = s_ipsc->rNumericArgs(numF);
   10669              :                     }
   10670            0 :                     numF++;
   10671            0 :                     if (s_ipsc->lNumericFieldBlanks(numF)) {
   10672            0 :                         ErrorsFound = true;
   10673            0 :                         ShowSevereError(state,
   10674            0 :                                         format("{}=\"{}\", {} defined, but no {}provided",
   10675            0 :                                                s_ipsc->cCurrentModuleObject,
   10676              :                                                fndInput.name,
   10677            0 :                                                s_ipsc->cAlphaFieldNames(alpF - 1),
   10678            0 :                                                s_ipsc->cNumericFieldNames(numF)));
   10679            0 :                         continue;
   10680              :                     } else {
   10681            0 :                         fndInput.extHIns.width = s_ipsc->rNumericArgs(numF);
   10682              :                     }
   10683            0 :                     numF++;
   10684              :                 } else {
   10685            1 :                     if (!s_ipsc->lNumericFieldBlanks(numF)) {
   10686            0 :                         ShowWarningError(
   10687              :                             state,
   10688            0 :                             format("{}=\"{}\", no {} defined", s_ipsc->cCurrentModuleObject, fndInput.name, s_ipsc->cAlphaFieldNames(alpF - 1)));
   10689            0 :                         ShowContinueError(state, format("{} will not be used.", s_ipsc->cNumericFieldNames(numF)));
   10690              :                     }
   10691            1 :                     numF++;
   10692            1 :                     if (!s_ipsc->lNumericFieldBlanks(numF)) {
   10693            0 :                         ShowWarningError(
   10694              :                             state,
   10695            0 :                             format("{}=\"{}\", no {} defined", s_ipsc->cCurrentModuleObject, fndInput.name, s_ipsc->cAlphaFieldNames(alpF - 1)));
   10696            0 :                         ShowContinueError(state, format("{} will not be used.", s_ipsc->cNumericFieldNames(numF)));
   10697              :                     }
   10698            1 :                     numF++;
   10699              :                 }
   10700              : 
   10701              :                 // Exterior vertical insulation
   10702            1 :                 if (!s_ipsc->lAlphaFieldBlanks(alpF)) {
   10703            0 :                     int index = Material::GetMaterialNum(state, s_ipsc->cAlphaArgs(alpF));
   10704            0 :                     if (index == 0) {
   10705            0 :                         ErrorsFound = true;
   10706            0 :                         ShowSevereError(state,
   10707            0 :                                         format("Did not find matching material for {}=\"{}\", {}, missing material = {}",
   10708            0 :                                                s_ipsc->cCurrentModuleObject,
   10709              :                                                fndInput.name,
   10710            0 :                                                s_ipsc->cAlphaFieldNames(alpF),
   10711            0 :                                                s_ipsc->cAlphaArgs(alpF)));
   10712            0 :                         continue;
   10713              :                     }
   10714            0 :                     auto *m = s_mat->materials(index);
   10715            0 :                     if (m->group != Material::Group::Regular || m->ROnly) {
   10716            0 :                         ErrorsFound = true;
   10717            0 :                         ShowSevereError(state,
   10718            0 :                                         format("{}=\"{}\", invalid {}=\"{}",
   10719            0 :                                                s_ipsc->cCurrentModuleObject,
   10720              :                                                fndInput.name,
   10721            0 :                                                s_ipsc->cAlphaFieldNames(alpF),
   10722            0 :                                                s_ipsc->cAlphaArgs(alpF)));
   10723            0 :                         ShowContinueError(state, "Must be of type \"Material\"");
   10724            0 :                         continue;
   10725              :                     }
   10726            0 :                     fndInput.extVIns.material = Kiva::Material(m->Conductivity, m->Density, m->SpecHeat);
   10727            0 :                     fndInput.extVIns.width = m->Thickness;
   10728            0 :                     fndInput.extVIns.x = 0.0;
   10729            0 :                     fndInput.extVIns.z = 0.0;
   10730              :                 }
   10731            1 :                 alpF++;
   10732              : 
   10733            1 :                 if (!s_ipsc->lAlphaFieldBlanks(alpF - 1)) {
   10734            0 :                     if (s_ipsc->lNumericFieldBlanks(numF)) {
   10735            0 :                         ErrorsFound = true;
   10736            0 :                         ShowSevereError(state,
   10737            0 :                                         format("{}=\"{}\", {} defined, but no {}provided",
   10738            0 :                                                s_ipsc->cCurrentModuleObject,
   10739              :                                                fndInput.name,
   10740            0 :                                                s_ipsc->cAlphaFieldNames(alpF - 1),
   10741            0 :                                                s_ipsc->cNumericFieldNames(numF)));
   10742            0 :                         continue;
   10743              :                     } else {
   10744            0 :                         fndInput.extVIns.depth = s_ipsc->rNumericArgs(numF);
   10745              :                     }
   10746            0 :                     numF++;
   10747              :                 } else {
   10748            1 :                     if (!s_ipsc->lNumericFieldBlanks(numF)) {
   10749            0 :                         ShowWarningError(
   10750              :                             state,
   10751            0 :                             format("{}=\"{}\", no {} defined", s_ipsc->cCurrentModuleObject, fndInput.name, s_ipsc->cAlphaFieldNames(alpF - 1)));
   10752            0 :                         ShowContinueError(state, format("{} will not be used.", s_ipsc->cNumericFieldNames(numF)));
   10753              :                     }
   10754            1 :                     numF++;
   10755              :                 }
   10756              : 
   10757              :                 // Foundation wall
   10758            1 :                 if (!s_ipsc->lNumericFieldBlanks(numF)) {
   10759            1 :                     fnd.wall.heightAboveGrade = s_ipsc->rNumericArgs(numF);
   10760              :                 }
   10761            1 :                 numF++;
   10762              : 
   10763            1 :                 if (!s_ipsc->lNumericFieldBlanks(numF)) {
   10764            1 :                     fnd.wall.depthBelowSlab = s_ipsc->rNumericArgs(numF);
   10765              :                 }
   10766            1 :                 numF++;
   10767              : 
   10768            1 :                 if (!s_ipsc->lAlphaFieldBlanks(alpF)) {
   10769            0 :                     fndInput.wallConstructionIndex = Util::FindItemInList(s_ipsc->cAlphaArgs(alpF), state.dataConstruction->Construct);
   10770            0 :                     if (fndInput.wallConstructionIndex == 0) {
   10771            0 :                         ErrorsFound = true;
   10772            0 :                         ShowSevereError(state,
   10773            0 :                                         format("Did not find matching construction for {}=\"{}\", {}, missing construction = {}",
   10774            0 :                                                s_ipsc->cCurrentModuleObject,
   10775              :                                                fndInput.name,
   10776            0 :                                                s_ipsc->cAlphaFieldNames(alpF),
   10777            0 :                                                s_ipsc->cAlphaArgs(alpF)));
   10778            0 :                         continue;
   10779              :                     }
   10780            0 :                     auto &c = state.dataConstruction->Construct(fndInput.wallConstructionIndex);
   10781            0 :                     c.IsUsed = true;
   10782            0 :                     if (c.TypeIsWindow) {
   10783            0 :                         ErrorsFound = true;
   10784            0 :                         ShowSevereError(state,
   10785            0 :                                         format("{}=\"{}\", invalid {}=\"{}",
   10786            0 :                                                s_ipsc->cCurrentModuleObject,
   10787              :                                                fndInput.name,
   10788            0 :                                                s_ipsc->cAlphaFieldNames(alpF),
   10789            0 :                                                s_ipsc->cAlphaArgs(alpF)));
   10790            0 :                         ShowContinueError(state, "Cannot be a window construction");
   10791            0 :                         continue;
   10792              :                     }
   10793              :                 } else {
   10794            1 :                     fndInput.wallConstructionIndex = 0; // Use default wall construction
   10795              :                 }
   10796            1 :                 alpF++;
   10797              : 
   10798              :                 // Footing
   10799            1 :                 if (!s_ipsc->lAlphaFieldBlanks(alpF)) {
   10800            0 :                     int index = Material::GetMaterialNum(state, s_ipsc->cAlphaArgs(alpF));
   10801            0 :                     if (index == 0) {
   10802            0 :                         ErrorsFound = true;
   10803            0 :                         ShowSevereError(state,
   10804            0 :                                         format("Did not find matching material for {}=\"{}\", {}, missing material = {}",
   10805            0 :                                                s_ipsc->cCurrentModuleObject,
   10806              :                                                fndInput.name,
   10807            0 :                                                s_ipsc->cAlphaFieldNames(alpF),
   10808            0 :                                                s_ipsc->cAlphaArgs(alpF)));
   10809            0 :                         continue;
   10810              :                     }
   10811            0 :                     auto *m = s_mat->materials(index);
   10812            0 :                     if (m->group != Material::Group::Regular || m->ROnly) {
   10813            0 :                         ErrorsFound = true;
   10814            0 :                         ShowSevereError(state,
   10815            0 :                                         format("{}=\"{}\", invalid {}=\"{}",
   10816            0 :                                                s_ipsc->cCurrentModuleObject,
   10817              :                                                fndInput.name,
   10818            0 :                                                s_ipsc->cAlphaFieldNames(alpF),
   10819            0 :                                                s_ipsc->cAlphaArgs(alpF)));
   10820            0 :                         ShowContinueError(state, "Must be of type \"Material\"");
   10821            0 :                         continue;
   10822              :                     }
   10823            0 :                     fndInput.footing.material = Kiva::Material(m->Conductivity, m->Density, m->SpecHeat);
   10824            0 :                     fndInput.footing.width = m->Thickness;
   10825            0 :                     fndInput.footing.x = 0.0;
   10826            0 :                     fndInput.footing.z = 0.0;
   10827              :                 }
   10828            1 :                 alpF++;
   10829              : 
   10830            1 :                 if (!s_ipsc->lAlphaFieldBlanks(alpF - 1)) {
   10831            0 :                     if (s_ipsc->lNumericFieldBlanks(numF)) {
   10832            0 :                         ErrorsFound = true;
   10833            0 :                         ShowSevereError(state,
   10834            0 :                                         format("{}=\"{}\", {} defined, but no {}provided",
   10835            0 :                                                s_ipsc->cCurrentModuleObject,
   10836              :                                                fndInput.name,
   10837            0 :                                                s_ipsc->cAlphaFieldNames(alpF - 1),
   10838            0 :                                                s_ipsc->cNumericFieldNames(numF)));
   10839            0 :                         continue;
   10840              :                     } else {
   10841            0 :                         fndInput.footing.depth = s_ipsc->rNumericArgs(numF);
   10842              :                     }
   10843            0 :                     numF++;
   10844              :                 } else {
   10845            1 :                     if (!s_ipsc->lNumericFieldBlanks(numF)) {
   10846            0 :                         ShowWarningError(
   10847              :                             state,
   10848            0 :                             format("{}=\"{}\", no {} defined", s_ipsc->cCurrentModuleObject, fndInput.name, s_ipsc->cAlphaFieldNames(alpF - 1)));
   10849            0 :                         ShowContinueError(state, format("{} will not be used.", s_ipsc->cNumericFieldNames(numF)));
   10850              :                     }
   10851            1 :                     numF++;
   10852              :                 }
   10853              : 
   10854              :                 // General Blocks
   10855            1 :                 int numRemainingFields = NumAlphas - (alpF - 1) + NumProps - (numF - 1);
   10856            1 :                 if (numRemainingFields > 0) {
   10857            1 :                     int numBlocks = numRemainingFields / 4;
   10858            1 :                     if (mod(numRemainingFields, 4) != 0) {
   10859            0 :                         ShowWarningError(state,
   10860            0 :                                          format("{}=\"{}\", number of Block fields not even multiple of 4. Will read in {}",
   10861            0 :                                                 s_ipsc->cCurrentModuleObject,
   10862              :                                                 fndInput.name,
   10863              :                                                 numBlocks));
   10864              :                     }
   10865            2 :                     for (int blockNum = 0; blockNum < numBlocks; blockNum++) {
   10866            1 :                         Kiva::InputBlock block;
   10867            1 :                         if (!s_ipsc->lAlphaFieldBlanks(alpF)) {
   10868            1 :                             int index = Material::GetMaterialNum(state, s_ipsc->cAlphaArgs(alpF));
   10869            1 :                             if (index == 0) {
   10870            0 :                                 ErrorsFound = true;
   10871            0 :                                 ShowSevereError(state,
   10872            0 :                                                 format("Did not find matching material for {}=\"{}\", {}, missing material = {}",
   10873            0 :                                                        s_ipsc->cCurrentModuleObject,
   10874              :                                                        fndInput.name,
   10875            0 :                                                        s_ipsc->cAlphaFieldNames(alpF),
   10876            0 :                                                        s_ipsc->cAlphaArgs(alpF)));
   10877            0 :                                 continue;
   10878              :                             }
   10879            1 :                             auto *m = s_mat->materials(index);
   10880            1 :                             if (m->group != Material::Group::Regular || m->ROnly) {
   10881            0 :                                 ErrorsFound = true;
   10882            0 :                                 ShowSevereError(state,
   10883            0 :                                                 format("{}=\"{}\", invalid {}=\"{}",
   10884            0 :                                                        s_ipsc->cCurrentModuleObject,
   10885              :                                                        fndInput.name,
   10886            0 :                                                        s_ipsc->cAlphaFieldNames(alpF),
   10887            0 :                                                        s_ipsc->cAlphaArgs(alpF)));
   10888            0 :                                 ShowContinueError(state, "Must be of type \"Material\"");
   10889            0 :                                 continue;
   10890              :                             }
   10891            1 :                             block.material = Kiva::Material(m->Conductivity, m->Density, m->SpecHeat);
   10892            1 :                             block.width = m->Thickness;
   10893              :                         } else {
   10894            0 :                             ErrorsFound = true;
   10895            0 :                             ShowSevereError(state,
   10896            0 :                                             format("{}=\"{}\", {} is required and not given.",
   10897            0 :                                                    s_ipsc->cCurrentModuleObject,
   10898              :                                                    fndInput.name,
   10899            0 :                                                    s_ipsc->cAlphaFieldNames(alpF)));
   10900            0 :                             continue;
   10901              :                         }
   10902            1 :                         alpF++;
   10903              : 
   10904            1 :                         if (s_ipsc->lNumericFieldBlanks(numF)) {
   10905            0 :                             block.depth = 0.0; // Temporary indicator to default to foundation depth
   10906              :                         } else {
   10907            1 :                             block.depth = s_ipsc->rNumericArgs(numF);
   10908              :                         }
   10909            1 :                         numF++;
   10910              : 
   10911            1 :                         if (s_ipsc->lNumericFieldBlanks(numF)) {
   10912            0 :                             ErrorsFound = true;
   10913            0 :                             ShowSevereError(state,
   10914            0 :                                             format("{}=\"{}\", {} defined, but no {}provided",
   10915            0 :                                                    s_ipsc->cCurrentModuleObject,
   10916              :                                                    fndInput.name,
   10917            0 :                                                    s_ipsc->cAlphaFieldNames(alpF - 1),
   10918            0 :                                                    s_ipsc->cNumericFieldNames(numF)));
   10919            0 :                             continue;
   10920              :                         } else {
   10921            1 :                             block.x = s_ipsc->rNumericArgs(numF);
   10922              :                         }
   10923            1 :                         numF++;
   10924              : 
   10925            1 :                         if (s_ipsc->lNumericFieldBlanks(numF)) {
   10926            0 :                             block.z = 0.0;
   10927              :                         } else {
   10928            1 :                             block.z = s_ipsc->rNumericArgs(numF);
   10929              :                         }
   10930            1 :                         numF++;
   10931              : 
   10932            1 :                         fnd.inputBlocks.push_back(block);
   10933              :                     }
   10934              :                 }
   10935              : 
   10936            1 :                 state.dataSurfaceGeometry->kivaManager.foundationInputs.push_back(fndInput);
   10937            1 :             }
   10938              :         }
   10939          234 :     }
   10940              : 
   10941          231 :     void GetOSCData(EnergyPlusData &state, bool &ErrorsFound)
   10942              :     {
   10943              : 
   10944              :         // SUBROUTINE INFORMATION:
   10945              :         //       AUTHOR         Linda Lawrie
   10946              :         //       DATE WRITTEN   May 2000
   10947              :         //       MODIFIED       Jul 2011, M.J. Witte and C.O. Pedersen, add new fields to OSC for last T, max and min
   10948              : 
   10949              :         // PURPOSE OF THIS SUBROUTINE:
   10950              :         // This subroutine gets the OtherSideCoefficient data.
   10951              : 
   10952              :         // REFERENCES:
   10953              :         // Other Side Coefficient Definition
   10954              :         // OtherSideCoefficients,
   10955              :         //       \memo This object sets the other side conditions for a surface in a variety of ways.
   10956              :         //   A1, \field OtherSideCoeff Name
   10957              :         //       \required-field
   10958              :         //       \reference OSCNames
   10959              :         //       \reference OutFaceEnvNames
   10960              :         //   N1, \field Combined convective/radiative film coefficient
   10961              :         //       \required-field
   10962              :         //       \type real
   10963              :         //       \note if>0, N1 becomes exterior convective/radiative film coefficient and other fields
   10964              :         //       \note are used to calc outside air temp then exterior surface temp based on outside air
   10965              :         //       \note and specified coefficient
   10966              :         //       \note if<=0, then remaining fields calculate the outside surface temperature(?)
   10967              :         //       \note following fields are used in the equation:
   10968              :         //       \note SurfTemp=N7*TempZone + N4*OutsideDryBulb + N2*N3 + GroundTemp*N5 + WindSpeed*N6*OutsideDryBulb
   10969              :         //   N2, \field User selected Constant Temperature
   10970              :         //       \units C
   10971              :         //       \type real
   10972              :         //       \note This parameter will be overwritten by the values from the schedule(A2 below) if one is present
   10973              :         //   N3, \field Coefficient modifying the user selected constant temperature
   10974              :         //       \note This coefficient is used even with a schedule.  It should normally be 1.0 in that case
   10975              :         //   N4, \field Coefficient modifying the external dry bulb temperature
   10976              :         //       \type real
   10977              :         //   N5, \field Coefficient modifying the ground temperature
   10978              :         //       \type real
   10979              :         //   N6, \field Coefficient modifying the wind speed term (s/m)
   10980              :         //       \type real
   10981              :         //   N7, \field Coefficient modifying the zone air temperature part of the equation
   10982              :         //       \type real
   10983              :         //   A2, \field ScheduleName for constant temperature
   10984              :         //       \note Name of Schedule for values of "const" temperature.
   10985              :         //       \note Schedule values replace N2 - User selected constant temperature.
   10986              :         //       \type object-list
   10987              :         //       \object-list ScheduleNames
   10988              :         //   A3, \field Sinusoidal Variation of Constant Temperature Coefficient
   10989              :         //       \note Optionally used to vary Constant Temperature Coefficient with unitary sine wave
   10990              :         //       \type choice
   10991              :         //       \key Yes
   10992              :         //       \key No
   10993              :         //       \default No
   10994              :         //   N8; \field Period of Sinusoidal Variation
   10995              :         //       \note Use with sinusoidal variation to define the time period
   10996              :         //       \type real
   10997              :         //       \units hr
   10998              :         //       \default 24
   10999              :         //  N9, \field Previous Other Side Temperature Coefficient
   11000              :         //      \note This coefficient multiplies the other side temperature result from the
   11001              :         //      \note previous zone timestep
   11002              :         //      \type real
   11003              :         //      \default 0
   11004              :         // N10, \field Minimum Other Side Temperature
   11005              :         //      \type real
   11006              :         //      \units C
   11007              :         //      \default -100
   11008              :         // N11; \field Maximum Other Side Temperature
   11009              :         //      \type real
   11010              :         //      \units C
   11011              :         //      \default 200
   11012              : 
   11013              :         static constexpr std::string_view routineName = "GetOSCData";
   11014              :         // Locals
   11015              :         // SUBROUTINE ARGUMENT DEFINITIONS:
   11016              : 
   11017              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
   11018              :         int NumAlphas;
   11019              :         int NumProps;
   11020              :         int Loop;
   11021              :         int IOStat;
   11022          231 :         std::string cOSCLimitsString;
   11023              : 
   11024          231 :         auto &s_ipsc = state.dataIPShortCut;
   11025              : 
   11026          231 :         s_ipsc->cCurrentModuleObject = "SurfaceProperty:OtherSideCoefficients";
   11027          231 :         state.dataSurface->TotOSC = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
   11028          231 :         state.dataSurface->OSC.allocate(state.dataSurface->TotOSC);
   11029              : 
   11030          231 :         int OSCNum = 0;
   11031          231 :         for (Loop = 1; Loop <= state.dataSurface->TotOSC; ++Loop) {
   11032            0 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
   11033            0 :                                                                      s_ipsc->cCurrentModuleObject,
   11034              :                                                                      Loop,
   11035            0 :                                                                      s_ipsc->cAlphaArgs,
   11036              :                                                                      NumAlphas,
   11037            0 :                                                                      s_ipsc->rNumericArgs,
   11038              :                                                                      NumProps,
   11039              :                                                                      IOStat,
   11040            0 :                                                                      s_ipsc->lNumericFieldBlanks,
   11041            0 :                                                                      s_ipsc->lAlphaFieldBlanks,
   11042            0 :                                                                      s_ipsc->cAlphaFieldNames,
   11043            0 :                                                                      s_ipsc->cNumericFieldNames);
   11044              : 
   11045            0 :             ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
   11046            0 :             bool ErrorInName = false;
   11047            0 :             bool IsBlank = false;
   11048            0 :             Util::VerifyName(
   11049            0 :                 state, s_ipsc->cAlphaArgs(1), state.dataSurface->OSC, OSCNum, ErrorInName, IsBlank, s_ipsc->cCurrentModuleObject + " Name");
   11050            0 :             if (ErrorInName) {
   11051            0 :                 ErrorsFound = true;
   11052            0 :                 continue;
   11053              :             }
   11054              : 
   11055            0 :             ++OSCNum;
   11056            0 :             state.dataSurface->OSC(OSCNum).Name = s_ipsc->cAlphaArgs(1);
   11057            0 :             state.dataSurface->OSC(OSCNum).SurfFilmCoef = s_ipsc->rNumericArgs(1);
   11058            0 :             state.dataSurface->OSC(OSCNum).ConstTemp = s_ipsc->rNumericArgs(2); //  This will be replaced if  schedule is used
   11059            0 :             state.dataSurface->OSC(OSCNum).ConstTempCoef =
   11060            0 :                 s_ipsc->rNumericArgs(3); //  This multiplier is used (even with schedule).  It should normally be 1.0
   11061            0 :             state.dataSurface->OSC(OSCNum).ExtDryBulbCoef = s_ipsc->rNumericArgs(4);
   11062            0 :             state.dataSurface->OSC(OSCNum).GroundTempCoef = s_ipsc->rNumericArgs(5);
   11063            0 :             state.dataSurface->OSC(OSCNum).WindSpeedCoef = s_ipsc->rNumericArgs(6);
   11064            0 :             state.dataSurface->OSC(OSCNum).ZoneAirTempCoef = s_ipsc->rNumericArgs(7);
   11065            0 :             state.dataSurface->OSC(OSCNum).SinusoidPeriod = s_ipsc->rNumericArgs(8);
   11066              : 
   11067            0 :             if ((NumAlphas == 1) || s_ipsc->lAlphaFieldBlanks(2)) { //  Const temp will come from schedule specified below.
   11068            0 :             } else if ((state.dataSurface->OSC(OSCNum).constTempSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(2))) == nullptr) {
   11069            0 :                 ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2));
   11070            0 :                 ErrorsFound = true;
   11071              :             }
   11072              : 
   11073            0 :             if (!s_ipsc->lAlphaFieldBlanks(3)) {
   11074            0 :                 if (BooleanSwitch bs = getYesNoValue(s_ipsc->cAlphaArgs(3)); bs != BooleanSwitch::Invalid) {
   11075            0 :                     state.dataSurface->OSC(OSCNum).SinusoidalConstTempCoef = static_cast<bool>(bs);
   11076              :                 } else {
   11077            0 :                     ShowSevereInvalidBool(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3));
   11078            0 :                     ErrorsFound = true;
   11079              :                 }
   11080              :             }
   11081              : 
   11082            0 :             if (s_ipsc->rNumericArgs(1) > 0.0 && !any_ne(s_ipsc->rNumericArgs({3, 7}), 0.0) &&
   11083            0 :                 (!state.dataSurface->OSC(OSCNum).SinusoidalConstTempCoef)) {
   11084            0 :                 ShowSevereError(state, format("{}=\"{}\" has zeros for all coefficients.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
   11085            0 :                 ShowContinueError(state, "...The outdoor air temperature for surfaces using this OtherSideCoefficients object will always be 0C.");
   11086              :             }
   11087              : 
   11088            0 :             if (s_ipsc->rNumericArgs(1) <= 0.0 && !any_ne(s_ipsc->rNumericArgs({3, 7}), 0.0) &&
   11089            0 :                 (!state.dataSurface->OSC(OSCNum).SinusoidalConstTempCoef)) {
   11090            0 :                 ShowSevereError(state, format("{}=\"{}\" has zeros for all coefficients.", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
   11091            0 :                 ShowContinueError(state,
   11092              :                                   "...The outside surface temperature for surfaces using this OtherSideCoefficients object will always be 0C.");
   11093              :             }
   11094              : 
   11095            0 :             state.dataSurface->OSC(OSCNum).TPreviousCoef = s_ipsc->rNumericArgs(9);
   11096              : 
   11097            0 :             if (!s_ipsc->lNumericFieldBlanks(10)) {
   11098            0 :                 state.dataSurface->OSC(OSCNum).MinLimitPresent = true;
   11099            0 :                 state.dataSurface->OSC(OSCNum).MinTempLimit = s_ipsc->rNumericArgs(10);
   11100            0 :                 cOSCLimitsString = format("{:.3R}", s_ipsc->rNumericArgs(10));
   11101              :             } else {
   11102            0 :                 cOSCLimitsString = "N/A";
   11103              :             }
   11104            0 :             if (!s_ipsc->lNumericFieldBlanks(11)) {
   11105            0 :                 state.dataSurface->OSC(OSCNum).MaxLimitPresent = true;
   11106            0 :                 state.dataSurface->OSC(OSCNum).MaxTempLimit = s_ipsc->rNumericArgs(11);
   11107            0 :                 cOSCLimitsString += format(",{:.3R}", s_ipsc->rNumericArgs(10));
   11108              :             } else {
   11109            0 :                 cOSCLimitsString += ",N/A";
   11110              :             }
   11111              :         }
   11112              : 
   11113          231 :         for (Loop = 1; Loop <= state.dataSurface->TotOSC; ++Loop) {
   11114            0 :             if (Loop == 1) {
   11115              :                 static constexpr std::string_view OSCFormat1(
   11116              :                     "! <Other Side Coefficients>,Name,Combined convective/radiative film coefficient {W/m2-K},User selected "
   11117              :                     "Constant Temperature {C},Coefficient modifying the constant temperature term,Coefficient modifying the external "
   11118              :                     "dry bulb temperature term,Coefficient modifying the ground temperature term,Coefficient modifying the wind speed "
   11119              :                     "term {s/m},Coefficient modifying the zone air temperature term,Constant Temperature Schedule Name,Sinusoidal "
   11120              :                     "Variation,Period of Sinusoidal Variation,Previous Other Side Temperature Coefficient,Minimum Other Side "
   11121              :                     "Temperature {C},Maximum Other Side Temperature {C}");
   11122            0 :                 print(state.files.eio, "{}\n", OSCFormat1);
   11123              :             }
   11124            0 :             if (state.dataSurface->OSC(Loop).SurfFilmCoef > 0.0) {
   11125            0 :                 s_ipsc->cAlphaArgs(1) = format("{:.3R}", state.dataSurface->OSC(Loop).SurfFilmCoef);
   11126            0 :                 SetupOutputVariable(state,
   11127              :                                     "Surface Other Side Coefficients Exterior Air Drybulb Temperature",
   11128              :                                     Constant::Units::C,
   11129            0 :                                     state.dataSurface->OSC(Loop).OSCTempCalc,
   11130              :                                     OutputProcessor::TimeStepType::System,
   11131              :                                     OutputProcessor::StoreType::Average,
   11132            0 :                                     state.dataSurface->OSC(Loop).Name);
   11133              :             } else {
   11134            0 :                 s_ipsc->cAlphaArgs(1) = "N/A";
   11135              :             }
   11136              : 
   11137            0 :             print(state.files.eio,
   11138              :                   "Other Side Coefficients,{},{},{},{:.3R},{:.3R},{:.3R},{:.3R},{:.3R},{},{},{:.3R},{:.3R},{}\n",
   11139            0 :                   state.dataSurface->OSC(Loop).Name,
   11140            0 :                   s_ipsc->cAlphaArgs(1),
   11141            0 :                   (state.dataSurface->OSC(Loop).constTempSched != nullptr) ? "N/A" : format("{:.2R}", state.dataSurface->OSC(Loop).ConstTemp),
   11142            0 :                   state.dataSurface->OSC(Loop).ConstTempCoef,
   11143            0 :                   state.dataSurface->OSC(Loop).ExtDryBulbCoef,
   11144            0 :                   state.dataSurface->OSC(Loop).GroundTempCoef,
   11145            0 :                   state.dataSurface->OSC(Loop).WindSpeedCoef,
   11146            0 :                   state.dataSurface->OSC(Loop).ZoneAirTempCoef,
   11147            0 :                   (state.dataSurface->OSC(Loop).constTempSched == nullptr) ? "N/A" : state.dataSurface->OSC(Loop).constTempSched->Name,
   11148            0 :                   s_ipsc->cAlphaArgs(3),
   11149            0 :                   state.dataSurface->OSC(Loop).SinusoidPeriod,
   11150            0 :                   state.dataSurface->OSC(Loop).TPreviousCoef,
   11151              :                   cOSCLimitsString);
   11152              :         }
   11153          231 :     }
   11154              : 
   11155          257 :     void GetOSCMData(EnergyPlusData &state, bool &ErrorsFound)
   11156              :     {
   11157              : 
   11158              :         // SUBROUTINE INFORMATION:
   11159              :         //       AUTHOR         Brent Griffith
   11160              :         //       DATE WRITTEN   November 2004
   11161              : 
   11162              :         // PURPOSE OF THIS SUBROUTINE:
   11163              :         // This subroutine gets the OtherSideConditionsModel data.
   11164              : 
   11165              :         // REFERENCES:
   11166              :         // derived from GetOSCData subroutine by Linda Lawrie
   11167              : 
   11168              :         //  OtherSideConditionsModel,
   11169              :         //      \memo This object sets up modifying the other side conditions for a surface from other model results.
   11170              :         //  A1, \field OtherSideConditionsModel Name
   11171              :         //      \required-field
   11172              :         //      \reference OSCMNames
   11173              :         //      \reference OutFaceEnvNames
   11174              :         //  A2; \field Type of Model to determine Boundary Conditions
   11175              :         //      \type choice
   11176              :         //      \key Transpired Collector
   11177              :         //      \key Vented PV Cavity
   11178              :         //      \key Hybrid PV Transpired Collector
   11179              : 
   11180              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
   11181              :         int NumAlphas;
   11182              :         int NumProps;
   11183              :         int IOStat;
   11184              : 
   11185          257 :         auto &s_ipsc = state.dataIPShortCut;
   11186          257 :         s_ipsc->cCurrentModuleObject = "SurfaceProperty:OtherSideConditionsModel";
   11187          257 :         state.dataSurface->TotOSCM = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
   11188          257 :         state.dataSurface->OSCM.allocate(state.dataSurface->TotOSCM);
   11189              :         // OSCM is already initialized in derived type defn.
   11190              : 
   11191          257 :         int OSCMNum = 0;
   11192          286 :         for (int Loop = 1; Loop <= state.dataSurface->TotOSCM; ++Loop) {
   11193           58 :             state.dataInputProcessing->inputProcessor->getObjectItem(
   11194           29 :                 state, s_ipsc->cCurrentModuleObject, Loop, s_ipsc->cAlphaArgs, NumAlphas, s_ipsc->rNumericArgs, NumProps, IOStat);
   11195           29 :             bool ErrorInName = false;
   11196           29 :             bool IsBlank = false;
   11197           29 :             Util::VerifyName(
   11198           29 :                 state, s_ipsc->cAlphaArgs(1), state.dataSurface->OSCM, OSCMNum, ErrorInName, IsBlank, s_ipsc->cCurrentModuleObject + " Name");
   11199           29 :             if (ErrorInName) {
   11200            0 :                 ErrorsFound = true;
   11201            0 :                 continue;
   11202              :             }
   11203              : 
   11204           29 :             ++OSCMNum;
   11205           29 :             state.dataSurface->OSCM(OSCMNum).Name = s_ipsc->cAlphaArgs(1);
   11206              :             // Note no validation of the below at this time:
   11207           29 :             state.dataSurface->OSCM(OSCMNum).Class = s_ipsc->cAlphaArgs(2);
   11208              :             // setup output vars for modeled coefficients
   11209           58 :             SetupOutputVariable(state,
   11210              :                                 "Surface Other Side Conditions Modeled Convection Air Temperature",
   11211              :                                 Constant::Units::C,
   11212           29 :                                 state.dataSurface->OSCM(OSCMNum).TConv,
   11213              :                                 OutputProcessor::TimeStepType::System,
   11214              :                                 OutputProcessor::StoreType::Average,
   11215           29 :                                 state.dataSurface->OSCM(OSCMNum).Name);
   11216           58 :             SetupOutputVariable(state,
   11217              :                                 "Surface Other Side Conditions Modeled Convection Heat Transfer Coefficient",
   11218              :                                 Constant::Units::W_m2K,
   11219           29 :                                 state.dataSurface->OSCM(OSCMNum).HConv,
   11220              :                                 OutputProcessor::TimeStepType::System,
   11221              :                                 OutputProcessor::StoreType::Average,
   11222           29 :                                 state.dataSurface->OSCM(OSCMNum).Name);
   11223           58 :             SetupOutputVariable(state,
   11224              :                                 "Surface Other Side Conditions Modeled Radiation Temperature",
   11225              :                                 Constant::Units::C,
   11226           29 :                                 state.dataSurface->OSCM(OSCMNum).TRad,
   11227              :                                 OutputProcessor::TimeStepType::System,
   11228              :                                 OutputProcessor::StoreType::Average,
   11229           29 :                                 state.dataSurface->OSCM(OSCMNum).Name);
   11230           58 :             SetupOutputVariable(state,
   11231              :                                 "Surface Other Side Conditions Modeled Radiation Heat Transfer Coefficient",
   11232              :                                 Constant::Units::W_m2K,
   11233           29 :                                 state.dataSurface->OSCM(OSCMNum).HRad,
   11234              :                                 OutputProcessor::TimeStepType::System,
   11235              :                                 OutputProcessor::StoreType::Average,
   11236           29 :                                 state.dataSurface->OSCM(OSCMNum).Name);
   11237              : 
   11238           29 :             if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
   11239            0 :                 SetupEMSActuator(state,
   11240              :                                  "Other Side Boundary Conditions",
   11241            0 :                                  state.dataSurface->OSCM(OSCMNum).Name,
   11242              :                                  "Convection Bulk Air Temperature",
   11243              :                                  "[C]",
   11244            0 :                                  state.dataSurface->OSCM(OSCMNum).EMSOverrideOnTConv,
   11245            0 :                                  state.dataSurface->OSCM(OSCMNum).EMSOverrideTConvValue);
   11246            0 :                 SetupEMSActuator(state,
   11247              :                                  "Other Side Boundary Conditions",
   11248            0 :                                  state.dataSurface->OSCM(OSCMNum).Name,
   11249              :                                  "Convection Heat Transfer Coefficient",
   11250              :                                  "[W/m2-K]",
   11251            0 :                                  state.dataSurface->OSCM(OSCMNum).EMSOverrideOnHConv,
   11252            0 :                                  state.dataSurface->OSCM(OSCMNum).EMSOverrideHConvValue);
   11253            0 :                 SetupEMSActuator(state,
   11254              :                                  "Other Side Boundary Conditions",
   11255            0 :                                  state.dataSurface->OSCM(OSCMNum).Name,
   11256              :                                  "Radiation Effective Temperature",
   11257              :                                  "[C]",
   11258            0 :                                  state.dataSurface->OSCM(OSCMNum).EMSOverrideOnTRad,
   11259            0 :                                  state.dataSurface->OSCM(OSCMNum).EMSOverrideTRadValue);
   11260            0 :                 SetupEMSActuator(state,
   11261              :                                  "Other Side Boundary Conditions",
   11262            0 :                                  state.dataSurface->OSCM(OSCMNum).Name,
   11263              :                                  "Radiation Linear Heat Transfer Coefficient",
   11264              :                                  "[W/m2-K]",
   11265            0 :                                  state.dataSurface->OSCM(OSCMNum).EMSOverrideOnHrad,
   11266            0 :                                  state.dataSurface->OSCM(OSCMNum).EMSOverrideHradValue);
   11267              :             }
   11268              :         }
   11269              : 
   11270          286 :         for (int Loop = 1; Loop <= state.dataSurface->TotOSCM; ++Loop) {
   11271           29 :             if (Loop == 1) {
   11272              :                 static constexpr std::string_view OSCMFormat1("! <Other Side Conditions Model>,Name,Class\n");
   11273           29 :                 print(state.files.eio, OSCMFormat1);
   11274              :             }
   11275           29 :             print(state.files.eio, "Other Side Conditions Model,{},{}\n", state.dataSurface->OSCM(Loop).Name, state.dataSurface->OSCM(Loop).Class);
   11276              :         }
   11277          257 :     }
   11278              : 
   11279          225 :     void GetMovableInsulationData(EnergyPlusData &state, bool &ErrorsFound) // If errors found in input
   11280              :     {
   11281              : 
   11282              :         // SUBROUTINE INFORMATION:
   11283              :         //       AUTHOR         Linda Lawrie
   11284              :         //       DATE WRITTEN   May 2000
   11285              : 
   11286              :         // PURPOSE OF THIS SUBROUTINE:
   11287              :         // This subroutine gets the movable insulation data that can be associated with a surface.
   11288              : 
   11289              :         // REFERENCES:
   11290              :         // Movable Insulation Definition
   11291              :         // SurfaceControl:MovableInsulation,
   11292              :         //       \memo Exterior or Interior Insulation on opaque surfaces
   11293              :         //   A1, \field Insulation Type
   11294              :         //       \required-field
   11295              :         //       \type choice
   11296              :         //       \key Outside
   11297              :         //       \key Inside
   11298              :         //   A2, \field Surface Name
   11299              :         //       \required-field
   11300              :         //       \type object-list
   11301              :         //       \object-list SurfaceNames
   11302              :         //   A3, \field Material Name
   11303              :         //       \required-field
   11304              :         //       \object-list MaterialName
   11305              :         //   A4; \field Schedule Name
   11306              :         //        \required-field
   11307              :         //        \type object-list
   11308              :         //        \object-list ScheduleNames
   11309              : 
   11310              :         static constexpr std::string_view routineName = "GetMovableInsulationInput";
   11311              : 
   11312              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
   11313              :         int NAlphas;
   11314              :         int NNums;
   11315              :         int IOStat;
   11316              : 
   11317              :         enum class InsulationType
   11318              :         {
   11319              :             Invalid = -1,
   11320              :             Outside,
   11321              :             Inside,
   11322              :             Num
   11323              :         };
   11324          225 :         constexpr std::array<std::string_view, static_cast<int>(InsulationType::Num)> insulationTypeNamesUC = {"OUTSIDE", "INSIDE"};
   11325              : 
   11326          225 :         auto &s_ipsc = state.dataIPShortCut;
   11327          225 :         auto &s_mat = state.dataMaterial;
   11328              : 
   11329          225 :         s_ipsc->cCurrentModuleObject = "SurfaceControl:MovableInsulation";
   11330          225 :         int NMatInsul = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
   11331          226 :         for (int Loop = 1; Loop <= NMatInsul; ++Loop) {
   11332            2 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
   11333            1 :                                                                      s_ipsc->cCurrentModuleObject,
   11334              :                                                                      Loop,
   11335            1 :                                                                      s_ipsc->cAlphaArgs,
   11336              :                                                                      NAlphas,
   11337            1 :                                                                      s_ipsc->rNumericArgs,
   11338              :                                                                      NNums,
   11339              :                                                                      IOStat,
   11340            1 :                                                                      s_ipsc->lNumericFieldBlanks,
   11341            1 :                                                                      s_ipsc->lAlphaFieldBlanks,
   11342            1 :                                                                      s_ipsc->cAlphaFieldNames,
   11343            1 :                                                                      s_ipsc->cNumericFieldNames);
   11344            1 :             ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
   11345              : 
   11346            1 :             InsulationType insulationType = static_cast<InsulationType>(getEnumValue(insulationTypeNamesUC, s_ipsc->cAlphaArgs(1)));
   11347            1 :             if (insulationType == InsulationType::Invalid) {
   11348            0 :                 ShowSevereInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(1), s_ipsc->cAlphaArgs(1));
   11349            0 :                 ErrorsFound = true;
   11350            0 :                 continue;
   11351              :             }
   11352              : 
   11353              :             int SurfNum;
   11354            1 :             if ((SurfNum = Util::FindItemInList(s_ipsc->cAlphaArgs(2), state.dataSurface->Surface, state.dataSurface->TotSurfaces)) == 0) {
   11355            0 :                 ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2));
   11356            0 :                 ErrorsFound = true;
   11357            0 :                 continue;
   11358              :             }
   11359              : 
   11360              :             int MaterNum;
   11361            1 :             if ((MaterNum = Material::GetMaterialNum(state, s_ipsc->cAlphaArgs(3))) == 0) {
   11362            0 :                 ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3));
   11363            0 :                 ErrorsFound = true;
   11364            0 :                 continue;
   11365              :             }
   11366              : 
   11367            1 :             Sched::Schedule *sched = nullptr;
   11368            1 :             if (s_ipsc->lAlphaFieldBlanks(4)) {
   11369            0 :                 ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(4));
   11370            0 :                 ErrorsFound = true;
   11371            0 :                 continue;
   11372            1 :             } else if ((sched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(4))) == nullptr) {
   11373            0 :                 ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(4), s_ipsc->cAlphaArgs(4));
   11374            0 :                 ErrorsFound = true;
   11375            0 :                 continue;
   11376              :             }
   11377              : 
   11378            1 :             auto *thisMaterial = s_mat->materials(MaterNum);
   11379              : 
   11380              :             Array1D_string const cMaterialGroupType({-1, 18},
   11381              :                                                     {"invalid",
   11382              :                                                      "Material/Material:NoMass",
   11383              :                                                      "Material:AirGap",
   11384              :                                                      "WindowMaterial:Shade",
   11385              :                                                      "WindowMaterial:Glazing*",
   11386              :                                                      "WindowMaterial:Gas",
   11387              :                                                      "WindowMaterial:Blind",
   11388              :                                                      "WindowMaterial:GasMixture",
   11389              :                                                      "WindowMaterial:Screen",
   11390              :                                                      "Material:RoofVegetation",
   11391              :                                                      "Material:InfraredTransparent",
   11392              :                                                      "WindowMaterial:SimpleGlazingSystem",
   11393              :                                                      "WindowMaterial:ComplexShade",
   11394              :                                                      "WindowMaterial:Gap",
   11395              :                                                      "WindowMaterial:Glazing:EquivalentLayer",
   11396              :                                                      "WindowMaterial:Shade:EquivalentLayer",
   11397              :                                                      "WindowMaterial:Drape:EquivalentLayer",
   11398              :                                                      "WindowMaterial:Blind:EquivalentLayer",
   11399              :                                                      "WindowMaterial:Screen:EquivalentLayer",
   11400            1 :                                                      "WindowMaterial:Gap:EquivalentLayer"});
   11401              : 
   11402            1 :             Material::Group const MaterialLayerGroup = thisMaterial->group;
   11403            1 :             if ((MaterialLayerGroup == Material::Group::GlassSimple) || (MaterialLayerGroup == Material::Group::ShadeEQL) ||
   11404            0 :                 (MaterialLayerGroup == Material::Group::DrapeEQL) || (MaterialLayerGroup == Material::Group::BlindEQL) ||
   11405            0 :                 (MaterialLayerGroup == Material::Group::ScreenEQL) || (MaterialLayerGroup == Material::Group::WindowGapEQL)) {
   11406            1 :                 ShowSevereError(state, format("Invalid movable insulation material for {}:", s_ipsc->cCurrentModuleObject));
   11407            2 :                 ShowSevereError(
   11408            2 :                     state, format("...Movable insulation material type specified = {}", cMaterialGroupType(static_cast<int>(MaterialLayerGroup))));
   11409            1 :                 ShowSevereError(state, format("...Movable insulation material name specified = {}", s_ipsc->cAlphaArgs(3)));
   11410            1 :                 ErrorsFound = true;
   11411              :             }
   11412              : 
   11413            1 :             switch (insulationType) {
   11414            1 :             case InsulationType::Outside: {
   11415            1 :                 auto &movInsul = state.dataSurface->extMovInsuls(SurfNum);
   11416            1 :                 if (movInsul.matNum > 0) {
   11417            0 :                     ShowSevereDuplicateAssignment(
   11418            0 :                         state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2), s_mat->materials(movInsul.matNum)->Name);
   11419            0 :                     ErrorsFound = true;
   11420              :                 }
   11421              : 
   11422            1 :                 movInsul.matNum = MaterNum;
   11423            1 :                 movInsul.sched = sched;
   11424            1 :                 state.dataSurface->AnyMovableInsulation = true;
   11425            1 :                 state.dataSurface->extMovInsulSurfNums.push_back(SurfNum);
   11426              : 
   11427            1 :                 if (thisMaterial->Resistance <= 0.0) {
   11428            0 :                     if (thisMaterial->Conductivity <= 0.0 || thisMaterial->Thickness <= 0.0) {
   11429            0 :                         ShowSevereError(state,
   11430            0 :                                         format("{}, {}=\"{}\", invalid material.",
   11431            0 :                                                s_ipsc->cCurrentModuleObject,
   11432            0 :                                                s_ipsc->cAlphaFieldNames(2),
   11433            0 :                                                s_ipsc->cAlphaArgs(2)));
   11434            0 :                         ShowContinueError(state, "\"Outside\", invalid material for movable insulation.");
   11435            0 :                         ShowContinueError(state,
   11436            0 :                                           format("Material=\"{}\",Resistance=[{:.3R}], must be > 0 for use in Movable Insulation.",
   11437            0 :                                                  thisMaterial->Name,
   11438            0 :                                                  thisMaterial->Resistance));
   11439            0 :                         ErrorsFound = true;
   11440            0 :                     } else if (thisMaterial->Conductivity > 0.0) {
   11441            0 :                         thisMaterial->Resistance = thisMaterial->Thickness / thisMaterial->Conductivity;
   11442              :                     }
   11443              :                 }
   11444              : 
   11445            1 :                 if (thisMaterial->Conductivity <= 0.0) {
   11446            0 :                     if (thisMaterial->Resistance <= 0.0) {
   11447            0 :                         ShowSevereError(state,
   11448            0 :                                         format("{}, {}=\"{}\", invalid material.",
   11449            0 :                                                s_ipsc->cCurrentModuleObject,
   11450            0 :                                                s_ipsc->cAlphaFieldNames(2),
   11451            0 :                                                s_ipsc->cAlphaArgs(2)));
   11452            0 :                         ShowContinueError(state, "\"Outside\", invalid material for movable insulation.");
   11453            0 :                         ShowContinueError(state,
   11454            0 :                                           format("Material=\"{}\",Conductivity=[{:.3R}], must be > 0 for use in Movable Insulation.",
   11455            0 :                                                  thisMaterial->Name,
   11456            0 :                                                  thisMaterial->Conductivity));
   11457            0 :                         ErrorsFound = true;
   11458              :                     }
   11459              :                 }
   11460            1 :             } break;
   11461              : 
   11462            0 :             case InsulationType::Inside: {
   11463            0 :                 auto &movInsul = state.dataSurface->intMovInsuls(SurfNum);
   11464            0 :                 if (movInsul.matNum > 0) {
   11465            0 :                     ShowSevereDuplicateAssignment(
   11466            0 :                         state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2), s_mat->materials(movInsul.matNum)->Name);
   11467            0 :                     ErrorsFound = true;
   11468              :                 }
   11469              : 
   11470            0 :                 movInsul.matNum = MaterNum;
   11471            0 :                 movInsul.sched = sched;
   11472            0 :                 state.dataSurface->AnyMovableInsulation = true;
   11473            0 :                 state.dataSurface->intMovInsulSurfNums.push_back(SurfNum);
   11474            0 :                 if (thisMaterial->Resistance <= 0.0) {
   11475            0 :                     if (thisMaterial->Conductivity <= 0.0 || thisMaterial->Thickness <= 0.0) {
   11476            0 :                         ShowSevereError(state,
   11477            0 :                                         format("{}, {}=\"{}\", invalid material.",
   11478            0 :                                                s_ipsc->cCurrentModuleObject,
   11479            0 :                                                s_ipsc->cAlphaFieldNames(2),
   11480            0 :                                                s_ipsc->cAlphaArgs(2)));
   11481            0 :                         ShowContinueError(state, "\"Inside\", invalid material for movable insulation.");
   11482            0 :                         ShowContinueError(state,
   11483            0 :                                           format("Material=\"{}\",Resistance=[{:.3R}], must be > 0 for use in Movable Insulation.",
   11484            0 :                                                  thisMaterial->Name,
   11485            0 :                                                  thisMaterial->Resistance));
   11486            0 :                         ErrorsFound = true;
   11487            0 :                     } else if (thisMaterial->Conductivity > 0.0) {
   11488            0 :                         thisMaterial->Resistance = thisMaterial->Thickness / thisMaterial->Conductivity;
   11489              :                     }
   11490              :                 }
   11491            0 :             } break;
   11492            0 :             default: {
   11493            0 :                 assert(false);
   11494              :             } break;
   11495              :             } // switch (inulationType)
   11496              : 
   11497            1 :             if (state.dataSurface->Surface(SurfNum).Class == SurfaceClass::Window) {
   11498            0 :                 ShowSevereError(state, format("{}, {}=\"{}\"", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2)));
   11499            0 :                 ShowContinueError(state, "invalid use on a Window. Use WindowShadingControl instead.");
   11500            0 :                 ErrorsFound = true;
   11501              :             }
   11502            1 :         } // for (Loop)
   11503          225 :     }     // GetMovableInsulationData()
   11504              : 
   11505              :     // Calculates the volume (m3) of a zone using the surfaces as possible.
   11506          197 :     void CalculateZoneVolume(EnergyPlusData &state)
   11507              :     {
   11508              :         // SUBROUTINE INFORMATION:
   11509              :         //       AUTHOR         Legacy Code
   11510              :         //       DATE WRITTEN   1992-1994
   11511              :         //       MODIFIED       Sep 2007, Mar 2017
   11512              : 
   11513              :         // METHODOLOGY EMPLOYED:
   11514              :         // Uses surface area information for calculations.  Modified to use the
   11515              :         // user-entered ceiling height (x floor area, if applicable) instead of using
   11516              :         // the calculated volume when the user enters the ceiling height.
   11517              : 
   11518              :         // REFERENCES:
   11519              :         // Legacy Code (IBLAST)
   11520              : 
   11521          197 :         Vectors::Polyhedron ZoneStruct;
   11522          197 :         bool initmsg = true;
   11523          394 :         bool ShowZoneSurfaces = (state.dataInputProcessing->inputProcessor->getNumSectionsFound("SHOWZONESURFACES_DEBUG") > 0);
   11524          197 :         EPVector<int> surfacenotused;
   11525              : 
   11526              :         enum class ZoneVolumeCalcMethod
   11527              :         {
   11528              :             Invalid = -1,
   11529              :             Enclosed,
   11530              :             FloorAreaTimesHeight1,
   11531              :             FloorAreaTimesHeight2,
   11532              :             CeilingAreaTimesHeight,
   11533              :             OpWallAreaTimesDistance,
   11534              :             UserProvided,
   11535              :             Num
   11536              :         };
   11537              : 
   11538          197 :         int countNotFullyEnclosedZones = 0;
   11539          477 :         for (auto &thisZone : state.dataHeatBal->Zone) {
   11540          280 :             if (!thisZone.HasFloor) {
   11541           32 :                 ShowWarningError(state,
   11542           32 :                                  format("No floor exists in Zone=\"{}\", zone floor area is zero. All values for this zone that are entered per "
   11543              :                                         "floor area will be zero.",
   11544           16 :                                         thisZone.Name));
   11545              :             }
   11546              : 
   11547          280 :             Real64 SumAreas = 0.0;
   11548          280 :             Real64 CalcVolume = 0.0;
   11549              :             // Use AllSurfaceFirst which includes air boundaries
   11550          280 :             int NFaces = thisZone.AllSurfaceLast - thisZone.AllSurfaceFirst + 1;
   11551          280 :             int notused = 0;
   11552          280 :             ZoneStruct.NumSurfaceFaces = NFaces;
   11553          280 :             ZoneStruct.SurfaceFace.allocate(NFaces);
   11554          280 :             int NActFaces = 0;
   11555          280 :             surfacenotused.dimension(NFaces, 0);
   11556              : 
   11557         1922 :             for (int SurfNum = thisZone.AllSurfaceFirst; SurfNum <= thisZone.AllSurfaceLast; ++SurfNum) {
   11558         1642 :                 assert(SurfNum > 0);
   11559         1642 :                 auto &thisSurface = state.dataSurface->Surface(SurfNum);
   11560              :                 // Only include Base Surfaces in Calc.
   11561              : 
   11562         1642 :                 if (thisSurface.Class != SurfaceClass::Wall && thisSurface.Class != SurfaceClass::Floor && thisSurface.Class != SurfaceClass::Roof) {
   11563          145 :                     ++notused;
   11564          145 :                     surfacenotused(notused) = SurfNum;
   11565          145 :                     continue;
   11566              :                 }
   11567              : 
   11568         1497 :                 ++NActFaces;
   11569         1497 :                 auto &thisFace = ZoneStruct.SurfaceFace(NActFaces);
   11570         1497 :                 thisFace.FacePoints.allocate(thisSurface.Sides);
   11571         1497 :                 thisFace.NSides = thisSurface.Sides;
   11572         1497 :                 thisFace.SurfNum = SurfNum;
   11573         1497 :                 thisFace.FacePoints({1, thisSurface.Sides}) = thisSurface.Vertex({1, thisSurface.Sides});
   11574         1497 :                 Vectors::CreateNewellAreaVector(thisFace.FacePoints, thisFace.NSides, thisFace.NewellAreaVector);
   11575         1497 :                 SumAreas += Vectors::VecLength(thisFace.NewellAreaVector);
   11576              :             }
   11577          280 :             ZoneStruct.NumSurfaceFaces = NActFaces;
   11578              : 
   11579          280 :             bool isFloorHorizontal = false;
   11580          280 :             bool isCeilingHorizontal = false;
   11581          280 :             bool areWallsVertical = false;
   11582          280 :             std::tie(isFloorHorizontal, isCeilingHorizontal, areWallsVertical) = areSurfaceHorizAndVert(state, ZoneStruct);
   11583          280 :             Real64 oppositeWallArea = 0.0;
   11584          280 :             Real64 distanceBetweenOppositeWalls = 0.0;
   11585              : 
   11586          280 :             bool areWallsSameHeight = areWallHeightSame(state, ZoneStruct);
   11587              : 
   11588          280 :             std::vector<EdgeOfSurf> listOfedgeNotUsedTwice;
   11589          280 :             bool isZoneEnclosed = isEnclosedVolume(ZoneStruct, listOfedgeNotUsedTwice);
   11590              :             ZoneVolumeCalcMethod volCalcMethod;
   11591              : 
   11592          280 :             Real64 floorAreaForVolume = (thisZone.FloorArea > 0.0) ? thisZone.FloorArea : thisZone.geometricFloorArea;
   11593          280 :             Real64 ceilingAreaForVolume = (thisZone.CeilingArea > 0.0) ? thisZone.CeilingArea : thisZone.geometricCeilingArea;
   11594              : 
   11595          280 :             if (isZoneEnclosed) {
   11596          185 :                 CalcVolume = Vectors::CalcPolyhedronVolume(state, ZoneStruct);
   11597          185 :                 volCalcMethod = ZoneVolumeCalcMethod::Enclosed;
   11598           95 :             } else if (floorAreaForVolume > 0.0 && thisZone.CeilingHeight > 0.0 && areFloorAndCeilingSame(state, ZoneStruct)) {
   11599           18 :                 CalcVolume = floorAreaForVolume * thisZone.CeilingHeight;
   11600           18 :                 volCalcMethod = ZoneVolumeCalcMethod::FloorAreaTimesHeight1;
   11601           77 :             } else if (isFloorHorizontal && areWallsVertical && areWallsSameHeight && floorAreaForVolume > 0.0 && thisZone.CeilingHeight > 0.0) {
   11602           54 :                 CalcVolume = floorAreaForVolume * thisZone.CeilingHeight;
   11603           54 :                 volCalcMethod = ZoneVolumeCalcMethod::FloorAreaTimesHeight2;
   11604           23 :             } else if (isCeilingHorizontal && areWallsVertical && areWallsSameHeight && ceilingAreaForVolume > 0.0 && thisZone.CeilingHeight > 0.0) {
   11605            4 :                 CalcVolume = ceilingAreaForVolume * thisZone.CeilingHeight;
   11606            4 :                 volCalcMethod = ZoneVolumeCalcMethod::CeilingAreaTimesHeight;
   11607           19 :             } else if (areOppositeWallsSame(state, ZoneStruct, oppositeWallArea, distanceBetweenOppositeWalls)) {
   11608            2 :                 CalcVolume = oppositeWallArea * distanceBetweenOppositeWalls;
   11609            2 :                 volCalcMethod = ZoneVolumeCalcMethod::OpWallAreaTimesDistance;
   11610           17 :             } else if (thisZone.Volume == Constant::AutoCalculate) { // no user entered zone volume
   11611           24 :                 ShowSevereError(state,
   11612           24 :                                 format("For zone: {} it is not possible to calculate the volume from the surrounding surfaces so either provide the "
   11613              :                                        "volume value or define all the surfaces to fully enclose the zone.",
   11614           12 :                                        thisZone.Name));
   11615           12 :                 CalcVolume = 0.;
   11616           12 :                 volCalcMethod = ZoneVolumeCalcMethod::Invalid;
   11617              :             } else {
   11618            5 :                 CalcVolume = 0.;
   11619            5 :                 volCalcMethod = ZoneVolumeCalcMethod::UserProvided;
   11620              :             }
   11621          280 :             if (!isZoneEnclosed) {
   11622           95 :                 ++countNotFullyEnclosedZones;
   11623           95 :                 if (state.dataGlobal->DisplayExtraWarnings) { // report missing
   11624            8 :                     ShowWarningError(state,
   11625            8 :                                      format("CalculateZoneVolume: The Zone=\"{}\" is not fully enclosed. To be fully enclosed, each edge of a "
   11626              :                                             "surface must also be an edge on one other surface.",
   11627            4 :                                             thisZone.Name));
   11628            4 :                     switch (volCalcMethod) {
   11629            1 :                     case ZoneVolumeCalcMethod::FloorAreaTimesHeight1:
   11630            2 :                         ShowContinueError(state,
   11631              :                                           "  The zone volume was calculated using the floor area times ceiling height method where the floor and "
   11632              :                                           "ceiling are the same except for the z-coordinates.");
   11633            1 :                         break;
   11634            0 :                     case ZoneVolumeCalcMethod::FloorAreaTimesHeight2:
   11635            0 :                         ShowContinueError(state,
   11636              :                                           "  The zone volume was calculated using the floor area times ceiling height method where the floor is "
   11637              :                                           "horizontal, the walls are vertical, and the wall heights are all the same.");
   11638            0 :                         break;
   11639            3 :                     case ZoneVolumeCalcMethod::CeilingAreaTimesHeight:
   11640            6 :                         ShowContinueError(state,
   11641              :                                           "  The zone volume was calculated using the ceiling area times ceiling height method where the ceiling is "
   11642              :                                           "horizontal, the walls are vertical, and the wall heights are all the same.");
   11643            3 :                         break;
   11644            0 :                     case ZoneVolumeCalcMethod::OpWallAreaTimesDistance:
   11645            0 :                         ShowContinueError(state,
   11646              :                                           "  The zone volume was calculated using the opposite wall area times the distance between them method ");
   11647            0 :                         break;
   11648            0 :                     case ZoneVolumeCalcMethod::UserProvided:
   11649            0 :                         ShowContinueError(state, "  The zone volume was provided as an input to the ZONE object ");
   11650            0 :                         break;
   11651            0 :                     case ZoneVolumeCalcMethod::Invalid:
   11652            0 :                         ShowContinueError(state, "  The zone volume was not calculated and an error exists. ");
   11653            0 :                         break;
   11654            0 :                     case ZoneVolumeCalcMethod::Enclosed: // should not be called but completes enumeration
   11655            0 :                         ShowContinueError(state, "  The zone volume was calculated using multiple pyramids and was fully enclosed. ");
   11656            0 :                         break;
   11657            0 :                     default:
   11658            0 :                         assert(false);
   11659              :                     }
   11660           28 :                     for (auto &edge : listOfedgeNotUsedTwice) {
   11661           24 :                         if (edge.count < 2) {
   11662           24 :                             ShowContinueError(
   11663              :                                 state,
   11664           24 :                                 fmt::format("  The surface \"{}\" has an edge that was used only once: it is not an edge on another surface",
   11665           24 :                                             state.dataSurface->Surface(edge.surfNum).Name));
   11666              : 
   11667              :                         } else {
   11668            0 :                             ShowContinueError(
   11669              :                                 state,
   11670            0 :                                 fmt::format("  The surface \"{}\" has an edge that was used {} times: it is an edge on three or more surfaces: ",
   11671            0 :                                             state.dataSurface->Surface(edge.surfNum).Name,
   11672            0 :                                             edge.count));
   11673            0 :                             std::string surfaceNames = "    It was found on the following Surfaces: ";
   11674            0 :                             for (int surfNum : edge.otherSurfNums) {
   11675            0 :                                 surfaceNames += fmt::format("'{}' ", state.dataSurface->Surface(surfNum).Name);
   11676              :                             }
   11677            0 :                             ShowContinueError(state, surfaceNames);
   11678            0 :                         }
   11679           24 :                         ShowContinueError(state, format("    Vertex start {{ {:.4R}, {:.4R}, {:.4R}}}", edge.start.x, edge.start.y, edge.start.z));
   11680           24 :                         ShowContinueError(state, format("    Vertex end   {{ {:.4R}, {:.4R}, {:.4R}}}", edge.end.x, edge.end.y, edge.end.z));
   11681              :                     }
   11682              :                 }
   11683              :             }
   11684          280 :             if (thisZone.Volume > 0.0) { // User entered zone volume, produce message if not near calculated
   11685           43 :                 if (CalcVolume > 0.0) {
   11686           36 :                     if (std::abs(CalcVolume - thisZone.Volume) / thisZone.Volume > 0.05) {
   11687            8 :                         ++state.dataSurfaceGeometry->ErrCount5;
   11688            8 :                         if (state.dataSurfaceGeometry->ErrCount5 == 1 && !state.dataGlobal->DisplayExtraWarnings) {
   11689            8 :                             if (initmsg) {
   11690           16 :                                 ShowMessage(state,
   11691              :                                             "Note that the following warning(s) may/will occur if you have not enclosed your zone completely.");
   11692            8 :                                 initmsg = false;
   11693              :                             }
   11694           16 :                             ShowWarningError(state, "Entered Zone Volumes differ from calculated zone volume(s).");
   11695           24 :                             ShowContinueError(state, "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on individual zones.");
   11696              :                         }
   11697            8 :                         if (state.dataGlobal->DisplayExtraWarnings) {
   11698            0 :                             if (initmsg) {
   11699            0 :                                 ShowMessage(state,
   11700              :                                             "Note that the following warning(s) may/will occur if you have not enclosed your zone completely.");
   11701            0 :                                 initmsg = false;
   11702              :                             }
   11703              :                             // Warn user of using specified Zone Volume
   11704            0 :                             ShowWarningError(
   11705              :                                 state,
   11706            0 :                                 format("Entered Volume entered for Zone=\"{}\" significantly different from calculated Volume", thisZone.Name));
   11707            0 :                             ShowContinueError(state,
   11708            0 :                                               format("Entered Zone Volume value={:.2R}, Calculated Zone Volume value={:.2R}, entered volume will be "
   11709              :                                                      "used in calculations.",
   11710            0 :                                                      thisZone.Volume,
   11711              :                                                      CalcVolume));
   11712              :                         }
   11713              :                     }
   11714              :                 }
   11715          237 :             } else if (thisZone.ceilingHeightEntered) { // User did not enter zone volume, but entered ceiling height
   11716           33 :                 if (floorAreaForVolume > 0.0) {
   11717           30 :                     thisZone.Volume = floorAreaForVolume * thisZone.CeilingHeight;
   11718              :                 } else { // ceiling height entered but floor area zero
   11719            3 :                     thisZone.Volume = CalcVolume;
   11720              :                 }
   11721              :             } else { // Neither ceiling height nor volume entered
   11722          204 :                 thisZone.Volume = CalcVolume;
   11723              :             }
   11724              : 
   11725          280 :             if (thisZone.Volume <= 0.0) {
   11726           16 :                 ShowWarningError(state, format("Indicated Zone Volume <= 0.0 for Zone={}", thisZone.Name));
   11727           16 :                 ShowContinueError(state, format("The calculated Zone Volume was={:.2R}", thisZone.Volume));
   11728           32 :                 ShowContinueError(state, "The simulation will continue with the Zone Volume set to 10.0 m3. ");
   11729           32 :                 ShowContinueError(state, "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on individual zones.");
   11730           16 :                 thisZone.Volume = 10.;
   11731              :             }
   11732              :             // For now - pro-rate space volumes by floor area, if not entered
   11733          581 :             for (int spaceNum : thisZone.spaceIndexes) {
   11734          301 :                 auto &thisSpace = state.dataHeatBal->space(spaceNum);
   11735              :                 // don't touch if already user-specified
   11736          301 :                 if (thisSpace.Volume > 0.0) continue;
   11737          300 :                 if (thisZone.numSpaces == 1) {
   11738          260 :                     thisSpace.Volume = thisZone.Volume;
   11739           40 :                 } else if (thisZone.geometricFloorArea > 0.0) {
   11740           36 :                     thisSpace.Volume = thisZone.Volume * thisSpace.FloorArea / thisZone.geometricFloorArea;
   11741              :                 }
   11742              :             }
   11743          280 :             Real64 totSpacesVolume = 0.0;
   11744          581 :             for (int spaceNum : thisZone.spaceIndexes) {
   11745          301 :                 totSpacesVolume += state.dataHeatBal->space(spaceNum).Volume;
   11746              :             }
   11747          280 :             if (totSpacesVolume > 0.0) {
   11748          572 :                 for (int spaceNum : thisZone.spaceIndexes) {
   11749          297 :                     state.dataHeatBal->space(spaceNum).fracZoneVolume = state.dataHeatBal->space(spaceNum).Volume / totSpacesVolume;
   11750              :                 }
   11751              :             } // else leave fractions at zero
   11752              : 
   11753          280 :             if (ShowZoneSurfaces) {
   11754            0 :                 if (state.dataSurfaceGeometry->ShowZoneSurfaceHeaders) {
   11755            0 :                     print(state.files.debug, "{}\n", "===================================");
   11756            0 :                     print(state.files.debug, "{}\n", "showing zone surfaces used and not used in volume calculation");
   11757            0 :                     print(state.files.debug, "{}\n", "for volume calculation, only floors, walls and roofs/ceilings are used");
   11758            0 :                     print(state.files.debug, "{}\n", "surface class, 1=wall, 2=floor, 3=roof/ceiling");
   11759            0 :                     print(state.files.debug, "{}\n", "unused surface class(es), 5=internal mass, 11=window, 12=glass door");
   11760            0 :                     print(state.files.debug, "{}\n", "                          13=door, 14=shading, 15=overhang, 16=fin");
   11761            0 :                     print(state.files.debug, "{}\n", "                          17=TDD Dome, 18=TDD Diffuser");
   11762            0 :                     state.dataSurfaceGeometry->ShowZoneSurfaceHeaders = false;
   11763              :                 }
   11764            0 :                 print(state.files.debug, "{}\n", "===================================");
   11765            0 :                 print(state.files.debug, "zone={} calc volume={}\n", thisZone.Name, CalcVolume);
   11766            0 :                 print(state.files.debug, " nsurfaces={} nactual={}\n", NFaces, NActFaces);
   11767              :             }
   11768         1777 :             for (int faceNum = 1; faceNum <= ZoneStruct.NumSurfaceFaces; ++faceNum) {
   11769         1497 :                 auto &thisFace = ZoneStruct.SurfaceFace(faceNum);
   11770         1497 :                 if (ShowZoneSurfaces) {
   11771            0 :                     if (faceNum <= NActFaces) {
   11772            0 :                         auto &thisSurface = state.dataSurface->Surface(thisFace.SurfNum);
   11773            0 :                         print(state.files.debug, "surface={} nsides={}\n", thisFace.SurfNum, thisFace.NSides);
   11774            0 :                         print(state.files.debug, "surface name={} class={}\n", thisSurface.Name, thisSurface.Class);
   11775            0 :                         print(state.files.debug, "area={}\n", thisSurface.GrossArea);
   11776            0 :                         for (int iside = 1; iside <= thisFace.NSides; ++iside) {
   11777            0 :                             auto const &FacePoint(thisFace.FacePoints(iside));
   11778            0 :                             print(state.files.debug, "{} {} {}\n", FacePoint.x, FacePoint.y, FacePoint.z);
   11779              :                         }
   11780              :                     }
   11781              :                 }
   11782         1497 :                 thisFace.FacePoints.deallocate();
   11783              :             }
   11784          280 :             if (ShowZoneSurfaces) {
   11785            0 :                 for (int SurfNum = 1; SurfNum <= notused; ++SurfNum) {
   11786            0 :                     print(state.files.debug,
   11787              :                           "notused:surface={} name={} class={}\n",
   11788              :                           surfacenotused(SurfNum),
   11789            0 :                           state.dataSurface->Surface(surfacenotused(SurfNum)).Name,
   11790            0 :                           state.dataSurface->Surface(surfacenotused(SurfNum)).Class);
   11791              :                 }
   11792              :             }
   11793              : 
   11794          280 :             ZoneStruct.SurfaceFace.deallocate();
   11795          280 :             surfacenotused.deallocate();
   11796              : 
   11797          280 :         } // zone loop
   11798          197 :         if (!state.dataGlobal->DisplayExtraWarnings) {
   11799          184 :             if (countNotFullyEnclosedZones == 1) {
   11800          138 :                 ShowWarningError(
   11801              :                     state, "CalculateZoneVolume: 1 zone is not fully enclosed. For more details use:  Output:Diagnostics,DisplayExtrawarnings; ");
   11802          138 :             } else if (countNotFullyEnclosedZones > 1) {
   11803           28 :                 ShowWarningError(state,
   11804           28 :                                  format("CalculateZoneVolume: {} zones are not fully enclosed. For more details use:  "
   11805              :                                         "Output:Diagnostics,DisplayExtrawarnings; ",
   11806              :                                         countNotFullyEnclosedZones));
   11807              :             }
   11808              :         }
   11809          197 :     }
   11810              : 
   11811              :     // test if the volume described by the polyhedron if full enclosed (would not leak)
   11812          285 :     bool isEnclosedVolume(DataVectorTypes::Polyhedron const &zonePoly, std::vector<EdgeOfSurf> &edgeNot2)
   11813              :     {
   11814              :         // J. Glazer - March 2017
   11815              : 
   11816          285 :         std::vector<Vector> uniqueVertices = makeListOfUniqueVertices(zonePoly);
   11817              : 
   11818          285 :         std::vector<EdgeOfSurf> edgeNot2orig = edgesNotTwoForEnclosedVolumeTest(zonePoly, uniqueVertices);
   11819              :         // if all edges had two counts then it is fully enclosed
   11820          285 :         if (edgeNot2orig.empty()) {
   11821          178 :             edgeNot2 = edgeNot2orig;
   11822          178 :             return true;
   11823              :         } else { // if the count is three or greater it is likely that a vertex that is colinear was counted on the faces on one edge and not
   11824              :                  // on the "other side" of the edge Go through all the points looking for the number that are colinear and see if that is
   11825              :                  // consistent with the number of edges found that didn't have a count of two
   11826              :             DataVectorTypes::Polyhedron updatedZonePoly = updateZonePolygonsForMissingColinearPoints(
   11827          107 :                 zonePoly, uniqueVertices); // this is done after initial test since it is computationally intensive.
   11828          107 :             std::vector<EdgeOfSurf> edgeNot2again = edgesNotTwoForEnclosedVolumeTest(updatedZonePoly, uniqueVertices);
   11829          107 :             if (edgeNot2again.empty()) {
   11830           10 :                 return true;
   11831              :             } else {
   11832          194 :                 edgeNot2 = edgesInBoth(edgeNot2orig,
   11833           97 :                                        edgeNot2again); // only return a list of those edges that appear in both the original edge and the
   11834              :                                                        // revised edges this eliminates added edges that will confuse users and edges that
   11835              :                                                        // were caught by the updateZonePoly routine
   11836           97 :                 return false;
   11837              :             }
   11838          107 :         }
   11839          285 :     }
   11840              : 
   11841              :     // returns a vector of edges that are in both vectors
   11842           97 :     std::vector<EdgeOfSurf> edgesInBoth(std::vector<EdgeOfSurf> const &edges1, std::vector<EdgeOfSurf> const &edges2)
   11843              :     {
   11844              :         // J. Glazer - June 2017
   11845              :         // this is not optimized but the number of edges for a typical polyhedron is 12 and is probably rarely bigger than 20.
   11846              : 
   11847           97 :         std::vector<EdgeOfSurf> inBoth;
   11848          697 :         for (const auto &e1 : edges1) {
   11849         2660 :             for (const auto &e2 : edges2) {
   11850         2586 :                 if (edgesEqualOnSameSurface(e1, e2)) {
   11851          526 :                     inBoth.push_back(e1);
   11852          526 :                     break;
   11853              :                 }
   11854              :             }
   11855              :         }
   11856           97 :         return inBoth;
   11857            0 :     }
   11858              : 
   11859              :     // returns true if the edges match - including the surface number
   11860         2586 :     bool edgesEqualOnSameSurface(EdgeOfSurf a, EdgeOfSurf b)
   11861              :     {
   11862         2586 :         if (a.surfNum != b.surfNum) {
   11863         1344 :             return false;
   11864              :         }
   11865              : 
   11866              :         // vertex comparison (we compare indices, so absolute equal)
   11867         1242 :         return ((a.start == b.start && a.end == b.end) || (a.start == b.end && a.end == b.start));
   11868              :     }
   11869              : 
   11870              :     // returns the number of times the edges of the polyhedron of the zone are not used twice by the sides
   11871          396 :     std::vector<EdgeOfSurf> edgesNotTwoForEnclosedVolumeTest(DataVectorTypes::Polyhedron const &zonePoly, std::vector<Vector> const &uniqueVertices)
   11872              :     {
   11873              :         // J. Glazer - March 2017
   11874              : 
   11875              :         struct EdgeByPts
   11876              :         {
   11877              :             int start;
   11878              :             int end;
   11879              :             int count;
   11880              :             int firstSurfNum;
   11881              :             std::vector<int> otherSurfNums;
   11882         4234 :             EdgeByPts() : start(0), end(0), count(0), firstSurfNum(0)
   11883              :             {
   11884         4234 :             }
   11885              :         };
   11886          396 :         std::vector<EdgeByPts> uniqueEdges;
   11887          396 :         uniqueEdges.reserve(zonePoly.NumSurfaceFaces * 6);
   11888              : 
   11889              :         // construct list of unique edges
   11890          396 :         Vector curVertex;
   11891              :         int curVertexIndex;
   11892         2419 :         for (int iFace = 1; iFace <= zonePoly.NumSurfaceFaces; ++iFace) {
   11893         2023 :             Vector prevVertex;
   11894              :             int prevVertexIndex;
   11895        10248 :             for (int jVertex = 1; jVertex <= zonePoly.SurfaceFace(iFace).NSides; ++jVertex) {
   11896         8225 :                 if (jVertex == 1) {
   11897         2023 :                     prevVertex = zonePoly.SurfaceFace(iFace).FacePoints(zonePoly.SurfaceFace(iFace).NSides); // the last point
   11898         2023 :                     prevVertexIndex = findIndexOfVertex(prevVertex, uniqueVertices);
   11899              :                 } else {
   11900         6202 :                     prevVertex = curVertex;
   11901         6202 :                     prevVertexIndex = curVertexIndex;
   11902              :                 }
   11903         8225 :                 curVertex = zonePoly.SurfaceFace(iFace).FacePoints(jVertex);
   11904         8225 :                 curVertexIndex = findIndexOfVertex(curVertex, uniqueVertices); // uses isAlmostEqual3dPt
   11905         8225 :                 auto it = std::find_if(uniqueEdges.begin(), uniqueEdges.end(), [&curVertexIndex, &prevVertexIndex](const auto &edge) {
   11906        99782 :                     return ((edge.start == curVertexIndex && edge.end == prevVertexIndex) ||
   11907        99782 :                             (edge.start == prevVertexIndex && edge.end == curVertexIndex));
   11908              :                 });
   11909         8225 :                 if (it == uniqueEdges.end()) {
   11910         4234 :                     EdgeByPts curEdge;
   11911         4234 :                     curEdge.start = prevVertexIndex;
   11912         4234 :                     curEdge.end = curVertexIndex;
   11913         4234 :                     curEdge.count = 1;
   11914         4234 :                     curEdge.firstSurfNum = zonePoly.SurfaceFace(iFace).SurfNum;
   11915         4234 :                     uniqueEdges.emplace_back(curEdge);
   11916         4234 :                 } else {
   11917         3991 :                     ++(it->count);
   11918         3991 :                     it->otherSurfNums.push_back(zonePoly.SurfaceFace(iFace).SurfNum);
   11919              :                 }
   11920              :             }
   11921         2023 :         }
   11922              :         // All edges for an enclosed polyhedron should be shared by two (and only two) sides.
   11923              :         // So if the count is not two for all edges, the polyhedron is not enclosed
   11924          396 :         std::vector<EdgeOfSurf> edgesNotTwoCount;
   11925         4630 :         for (const auto &anEdge : uniqueEdges) {
   11926         4234 :             if (anEdge.count != 2) {
   11927         1259 :                 EdgeOfSurf curEdgeOne;
   11928         1259 :                 curEdgeOne.surfNum = anEdge.firstSurfNum;
   11929         1259 :                 curEdgeOne.start = uniqueVertices[anEdge.start];
   11930         1259 :                 curEdgeOne.end = uniqueVertices[anEdge.end];
   11931         1259 :                 curEdgeOne.count = anEdge.count;
   11932         1259 :                 curEdgeOne.otherSurfNums = anEdge.otherSurfNums;
   11933         1259 :                 edgesNotTwoCount.push_back(curEdgeOne);
   11934         1259 :             }
   11935              :         }
   11936          792 :         return edgesNotTwoCount;
   11937          396 :     }
   11938              : 
   11939              :     // create a list of unique vertices given the polyhedron describing the zone
   11940          289 :     std::vector<Vector> makeListOfUniqueVertices(DataVectorTypes::Polyhedron const &zonePoly)
   11941              :     {
   11942              :         // J. Glazer - March 2017
   11943              : 
   11944          289 :         std::vector<Vector> uniqVertices;
   11945          289 :         uniqVertices.reserve(zonePoly.NumSurfaceFaces * 6);
   11946              : 
   11947         1844 :         for (int iFace = 1; iFace <= zonePoly.NumSurfaceFaces; ++iFace) {
   11948         7781 :             for (int jVertex = 1; jVertex <= zonePoly.SurfaceFace(iFace).NSides; ++jVertex) {
   11949         6226 :                 Vector curVertex = zonePoly.SurfaceFace(iFace).FacePoints(jVertex);
   11950         6226 :                 if (uniqVertices.size() == 0) {
   11951          286 :                     uniqVertices.emplace_back(curVertex);
   11952              :                 } else {
   11953         5940 :                     bool found = false;
   11954        28502 :                     for (const auto &unqV : uniqVertices) {
   11955        26568 :                         if (isAlmostEqual3dPt(curVertex, unqV)) {
   11956         4006 :                             found = true;
   11957         4006 :                             break;
   11958              :                         }
   11959              :                     }
   11960         5940 :                     if (!found) {
   11961         1934 :                         uniqVertices.emplace_back(curVertex);
   11962              :                     }
   11963              :                 }
   11964         6226 :             }
   11965              :         }
   11966          289 :         return uniqVertices;
   11967            0 :     }
   11968              : 
   11969              :     // updates the polyhedron used to describe a zone to include points on an edge that are between and collinear to points already describing
   11970              :     // the edge
   11971          108 :     DataVectorTypes::Polyhedron updateZonePolygonsForMissingColinearPoints(DataVectorTypes::Polyhedron const &zonePoly,
   11972              :                                                                            std::vector<Vector> const &uniqVertices)
   11973              :     {
   11974              :         // J. Glazer - March 2017
   11975              : 
   11976          108 :         DataVectorTypes::Polyhedron updZonePoly = zonePoly; // set the return value to the original polyhedron describing the zone
   11977              : 
   11978          639 :         for (auto &updFace : updZonePoly.SurfaceFace) {
   11979          531 :             bool insertedVertext = true;
   11980         1732 :             while (insertedVertext) {
   11981          670 :                 insertedVertext = false;
   11982          670 :                 auto &vertices = updFace.FacePoints;
   11983         2948 :                 for (auto it = vertices.begin(); it != vertices.end(); ++it) {
   11984              : 
   11985         2417 :                     auto itnext = std::next(it);
   11986         2417 :                     if (itnext == std::end(vertices)) {
   11987          514 :                         itnext = std::begin(vertices);
   11988              :                     }
   11989              : 
   11990         2417 :                     auto curVertex = *it;      // (AUTO_OK_OBJ) can't tell if a copy is the intended behavior here
   11991         2417 :                     auto nextVertex = *itnext; // (AUTO_OK_OBJ)
   11992              : 
   11993              :                     // now go through all the vertices and see if they are colinear with start and end vertices
   11994        24055 :                     for (const auto &testVertex : uniqVertices) {
   11995        21777 :                         if (!isAlmostEqual3dPt(curVertex, testVertex) && !isAlmostEqual3dPt(nextVertex, testVertex)) {
   11996        17059 :                             if (isPointOnLineBetweenPoints(curVertex, nextVertex, testVertex)) {
   11997          139 :                                 vertices.insert(itnext, testVertex);
   11998          139 :                                 ++updFace.NSides;
   11999          139 :                                 insertedVertext = true;
   12000          139 :                                 break;
   12001              :                             }
   12002              :                         }
   12003              :                     }
   12004              :                     // Break out of the loop on vertices of the surface too, and start again at the while
   12005         2417 :                     if (insertedVertext) {
   12006          139 :                         break;
   12007              :                     }
   12008         2556 :                 }
   12009              :             }
   12010              :         }
   12011          108 :         return updZonePoly;
   12012            0 :     }
   12013              : 
   12014              :     // test if the ceiling and floor are the same except for their height difference by looking at the corners
   12015           77 :     bool areFloorAndCeilingSame(EnergyPlusData &state, DataVectorTypes::Polyhedron const &zonePoly)
   12016              :     {
   12017              :         // J. Glazer - March 2017
   12018              : 
   12019              :         // check if the floor and ceiling are the same
   12020              :         // this is almost equivalent to saying, if you ignore the z-coordinate, are the vertices the same
   12021              :         // so if you could all the unique vertices of the floor and ceiling, ignoring the z-coordinate, they
   12022              :         // should always be even (they would be two but you might define multiple surfaces that meet in a corner)
   12023              : 
   12024           77 :         std::vector<DataVectorTypes::Vector2dCount> floorCeilingXY;
   12025           77 :         floorCeilingXY.reserve(zonePoly.NumSurfaceFaces * 6);
   12026              : 
   12027              :         // make list of x and y coordinates for all faces that are on the floor or ceiling
   12028          428 :         for (int iFace = 1; iFace <= zonePoly.NumSurfaceFaces; ++iFace) {
   12029          351 :             int curSurfNum = zonePoly.SurfaceFace(iFace).SurfNum;
   12030          579 :             if (state.dataSurface->Surface(curSurfNum).Class == SurfaceClass::Floor ||
   12031          228 :                 state.dataSurface->Surface(curSurfNum).Class == SurfaceClass::Roof) {
   12032          928 :                 for (int jVertex = 1; jVertex <= zonePoly.SurfaceFace(iFace).NSides; ++jVertex) {
   12033          742 :                     Vector curVertex = zonePoly.SurfaceFace(iFace).FacePoints(jVertex);
   12034          742 :                     DataVectorTypes::Vector2dCount curXYc;
   12035          742 :                     curXYc.x = curVertex.x;
   12036          742 :                     curXYc.y = curVertex.y;
   12037          742 :                     curXYc.count = 1;
   12038          742 :                     bool found = false;
   12039         2376 :                     for (DataVectorTypes::Vector2dCount &curFloorCeiling : floorCeilingXY) { // can't use just "auto" because updating floorCeilingXY
   12040         2019 :                         if (isAlmostEqual2dPt(curXYc, curFloorCeiling)) {                    // count ignored in comparison
   12041          385 :                             ++curFloorCeiling.count;
   12042          385 :                             found = true;
   12043          385 :                             break;
   12044              :                         }
   12045              :                     }
   12046          742 :                     if (!found) {
   12047          357 :                         floorCeilingXY.emplace_back(curXYc);
   12048              :                     }
   12049          742 :                 }
   12050              :             }
   12051              :         }
   12052              :         // now make sure every point has been counted and even number of times (usually twice)
   12053              :         // if they are then the ceiling and floor are (almost certainly) the same x and y coordinates.
   12054           77 :         bool areFlrAndClgSame = true;
   12055           77 :         if (floorCeilingXY.size() > 0) {
   12056          188 :             for (auto const &curFloorCeiling : floorCeilingXY) {
   12057          169 :                 if (curFloorCeiling.count % 2 != 0) {
   12058           57 :                     areFlrAndClgSame = false;
   12059           57 :                     break;
   12060              :                 }
   12061              :             }
   12062              :         } else {
   12063            1 :             areFlrAndClgSame = false;
   12064              :         }
   12065           77 :         return areFlrAndClgSame;
   12066           77 :     }
   12067              : 
   12068              :     // test if the walls of a zone are all the same height using the polyhedron describing the zone geometry
   12069          288 :     bool areWallHeightSame(EnergyPlusData &state, DataVectorTypes::Polyhedron const &zonePoly)
   12070              :     {
   12071              :         // J. Glazer - March 2017
   12072              : 
   12073              :         // test if all the wall heights are the same (all walls have the same maximum z-coordinate
   12074              : 
   12075          288 :         bool areWlHgtSame = true;
   12076          288 :         Real64 wallHeightZ = -Constant::BigNumber;
   12077          288 :         bool foundWallHeight = false;
   12078         1717 :         for (int iFace = 1; iFace <= zonePoly.NumSurfaceFaces; ++iFace) {
   12079         1445 :             int curSurfNum = zonePoly.SurfaceFace(iFace).SurfNum;
   12080         1445 :             if (state.dataSurface->Surface(curSurfNum).Class == SurfaceClass::Wall) {
   12081          908 :                 Real64 maxZ = -Constant::BigNumber;
   12082         4543 :                 for (int jVertex = 1; jVertex <= zonePoly.SurfaceFace(iFace).NSides; ++jVertex) {
   12083         3635 :                     Vector curVertex = zonePoly.SurfaceFace(iFace).FacePoints(jVertex);
   12084         3635 :                     if (maxZ < curVertex.z) {
   12085          992 :                         maxZ = curVertex.z;
   12086              :                     }
   12087         3635 :                 }
   12088          908 :                 if (foundWallHeight) {
   12089          637 :                     if (std::abs(maxZ - wallHeightZ) > Constant::TwoCentimeters) {
   12090           16 :                         areWlHgtSame = false;
   12091           16 :                         break;
   12092              :                     }
   12093              :                 } else {
   12094          271 :                     wallHeightZ = maxZ;
   12095          271 :                     foundWallHeight = true;
   12096              :                 }
   12097              :             }
   12098              :         }
   12099          288 :         return areWlHgtSame;
   12100              :     }
   12101              : 
   12102              :     // tests if the floor is horizontal, ceiling is horizontal, and walls are vertical and returns all three as a tuple of booleans
   12103          292 :     std::tuple<bool, bool, bool> areSurfaceHorizAndVert(EnergyPlusData &state, DataVectorTypes::Polyhedron const &zonePoly)
   12104              :     {
   12105              :         // J. Glazer - March 2017
   12106              : 
   12107              :         // check if floors and ceilings are horizontal and walls are vertical
   12108          292 :         bool isFlrHoriz = true;
   12109          292 :         bool isClgHoriz = true;
   12110          292 :         bool areWlVert = true;
   12111         1897 :         for (int iFace = 1; iFace <= zonePoly.NumSurfaceFaces; ++iFace) {
   12112         1605 :             int curSurfNum = zonePoly.SurfaceFace(iFace).SurfNum;
   12113         1605 :             if (state.dataSurface->Surface(curSurfNum).Class == SurfaceClass::Floor) {
   12114          355 :                 if (std::abs(state.dataSurface->Surface(curSurfNum).Tilt - 180.) > 1.) { // with 1 degree angle
   12115           25 :                     isFlrHoriz = false;
   12116              :                 }
   12117         1250 :             } else if (state.dataSurface->Surface(curSurfNum).Class == SurfaceClass::Roof) { // includes ceilings
   12118          296 :                 if (std::abs(state.dataSurface->Surface(curSurfNum).Tilt) > 1.) {            // with 1 degree angle of
   12119           58 :                     isClgHoriz = false;
   12120              :                 }
   12121          954 :             } else if (state.dataSurface->Surface(curSurfNum).Class == SurfaceClass::Wall) {
   12122          954 :                 if (std::abs(state.dataSurface->Surface(curSurfNum).Tilt - 90) > 1.) { // with 1 degree angle
   12123           32 :                     areWlVert = false;
   12124              :                 }
   12125              :             }
   12126              :         }
   12127          584 :         return std::make_tuple(isFlrHoriz, isClgHoriz, areWlVert);
   12128              :     }
   12129              : 
   12130              :     // tests whether a pair of walls in the zone are the same except offset from one another and facing the opposite direction and also
   12131              :     // returns the wall area and distance between
   12132           25 :     bool areOppositeWallsSame(EnergyPlusData &state,
   12133              :                               DataVectorTypes::Polyhedron const &zonePoly,
   12134              :                               Real64 &oppositeWallArea,            // return the area of the wall that has an opposite wall
   12135              :                               Real64 &distanceBetweenOppositeWalls // returns distance
   12136              :     )
   12137              :     {
   12138              :         // J. Glazer - March 2017
   12139              : 
   12140              :         // approach: if opposite surfaces have opposite azimuth and same area, then check the distance between the
   12141              :         // vertices( one counting backwards ) and if it is the same distance than assume that it is the same.
   12142           25 :         bool foundOppEqual = false;
   12143           76 :         for (int iFace = 1; iFace <= zonePoly.NumSurfaceFaces; ++iFace) {
   12144           57 :             int curSurfNum = zonePoly.SurfaceFace(iFace).SurfNum;
   12145           57 :             if (state.dataSurface->Surface(curSurfNum).Class == SurfaceClass::Wall) {
   12146           31 :                 std::vector<int> facesAtAz = listOfFacesFacingAzimuth(state, zonePoly, state.dataSurface->Surface(curSurfNum).Azimuth);
   12147           31 :                 bool allFacesEquidistant = true;
   12148           31 :                 oppositeWallArea = 0.;
   12149           42 :                 for (int curFace : facesAtAz) {
   12150           36 :                     int possOppFace = findPossibleOppositeFace(state, zonePoly, curFace);
   12151           36 :                     if (possOppFace > 0) { // an opposite fact was found
   12152           20 :                         oppositeWallArea += state.dataSurface->Surface(zonePoly.SurfaceFace(curFace).SurfNum).Area;
   12153           20 :                         if (!areCornersEquidistant(zonePoly, curFace, possOppFace, distanceBetweenOppositeWalls)) {
   12154            9 :                             allFacesEquidistant = false;
   12155            9 :                             break;
   12156              :                         }
   12157              :                     } else {
   12158           16 :                         allFacesEquidistant = false;
   12159           16 :                         break;
   12160              :                     }
   12161              :                 }
   12162           31 :                 if (allFacesEquidistant) {
   12163            6 :                     foundOppEqual = true;
   12164            6 :                     break; // only need to find the first case where opposite walls are the same
   12165              :                 }
   12166           31 :             }
   12167              :         }
   12168           25 :         return foundOppEqual;
   12169              :     }
   12170              : 
   12171              :     // provides a list of indices of polyhedron faces that are facing a specific azimuth
   12172           39 :     std::vector<int> listOfFacesFacingAzimuth(EnergyPlusData &state, DataVectorTypes::Polyhedron const &zonePoly, Real64 const azimuth)
   12173              :     {
   12174              :         // J. Glazer - March 2017
   12175              : 
   12176           39 :         std::vector<int> facingAzimuth;
   12177           39 :         facingAzimuth.reserve(zonePoly.NumSurfaceFaces);
   12178              : 
   12179          287 :         for (int iFace = 1; iFace <= zonePoly.NumSurfaceFaces; ++iFace) {
   12180          248 :             int curSurfNum = zonePoly.SurfaceFace(iFace).SurfNum;
   12181          248 :             if (General::rotAzmDiffDeg(state.dataSurface->Surface(curSurfNum).Azimuth, azimuth) < 1.) {
   12182           65 :                 facingAzimuth.emplace_back(iFace);
   12183              :             }
   12184              :         }
   12185           39 :         return facingAzimuth;
   12186            0 :     }
   12187              : 
   12188              :     // returns the index of the face of a polyhedron that is probably opposite of the face index provided
   12189           52 :     int findPossibleOppositeFace(EnergyPlusData &state, DataVectorTypes::Polyhedron const &zonePoly, int const faceIndex)
   12190              :     {
   12191              :         // J. Glazer - March 2017
   12192              : 
   12193           52 :         int selectedSurNum = zonePoly.SurfaceFace(faceIndex).SurfNum;
   12194           52 :         Real64 selectedAzimuth = state.dataSurface->Surface(selectedSurNum).Azimuth;
   12195           52 :         Real64 oppositeAzimuth = fmod(selectedAzimuth + 180., 360.);
   12196           52 :         Real64 selectedArea = state.dataSurface->Surface(selectedSurNum).Area;
   12197           52 :         int selectedNumCorners = zonePoly.SurfaceFace(faceIndex).NSides;
   12198           52 :         int found = -1;
   12199              : 
   12200          215 :         for (int iFace = 1; iFace <= zonePoly.NumSurfaceFaces; ++iFace) {
   12201          193 :             int curSurfNum = zonePoly.SurfaceFace(iFace).SurfNum;
   12202          368 :             if ((zonePoly.SurfaceFace(iFace).NSides == selectedNumCorners) &&
   12203          368 :                 (std::abs(state.dataSurface->Surface(curSurfNum).Area - selectedArea) < 0.01) &&
   12204           98 :                 (std::abs(state.dataSurface->Surface(curSurfNum).Azimuth - oppositeAzimuth) < 1.)) {
   12205           30 :                 found = iFace;
   12206           30 :                 break;
   12207              :             }
   12208              :         }
   12209           52 :         return found;
   12210              :     }
   12211              : 
   12212              :     // tests if the corners of one face of the polyhedron are the same distance from corners of another face
   12213           22 :     bool areCornersEquidistant(DataVectorTypes::Polyhedron const &zonePoly, int const faceIndex, int const opFaceIndex, Real64 &distanceBetween)
   12214              :     {
   12215              :         // J. Glazer - March 2017
   12216              : 
   12217           22 :         bool allAreEquidistant = true;
   12218           22 :         Real64 firstDistance = -99.;
   12219           22 :         if (zonePoly.SurfaceFace(faceIndex).NSides == zonePoly.SurfaceFace(opFaceIndex).NSides) { // double check that the number of sides match
   12220           82 :             for (int iVertex = 1; iVertex <= zonePoly.SurfaceFace(faceIndex).NSides; ++iVertex) {
   12221           70 :                 int iVertexOpp = 1 + zonePoly.SurfaceFace(faceIndex).NSides - iVertex; // count backwards for opposite face
   12222              :                 Real64 curDistBetwCorners =
   12223           70 :                     distance(zonePoly.SurfaceFace(faceIndex).FacePoints(iVertex), zonePoly.SurfaceFace(opFaceIndex).FacePoints(iVertexOpp));
   12224           70 :                 if (iVertex == 1) {
   12225           22 :                     firstDistance = curDistBetwCorners;
   12226              :                 } else {
   12227           48 :                     if (std::abs(curDistBetwCorners - firstDistance) > Constant::OneCentimeter) {
   12228           10 :                         allAreEquidistant = false;
   12229           10 :                         break;
   12230              :                     }
   12231              :                 }
   12232              :             }
   12233              :         } else {
   12234            0 :             allAreEquidistant = false;
   12235              :         }
   12236           22 :         if (allAreEquidistant) distanceBetween = firstDistance;
   12237           22 :         return allAreEquidistant;
   12238              :     }
   12239              : 
   12240              :     // test if two points in space are in the same position based on a small tolerance
   12241       128523 :     bool isAlmostEqual3dPt(DataVectorTypes::Vector v1, DataVectorTypes::Vector v2)
   12242              :     {
   12243              :         // J. Glazer - March 2017
   12244              : 
   12245       160262 :         return ((std::abs(v1.x - v2.x) < Constant::OneCentimeter) && (std::abs(v1.y - v2.y) < Constant::OneCentimeter) &&
   12246       160262 :                 (std::abs(v1.z - v2.z) < Constant::OneCentimeter));
   12247              :     }
   12248              : 
   12249              :     // test if two points on a plane are in the same position based on a small tolerance
   12250         2025 :     bool isAlmostEqual2dPt(DataVectorTypes::Vector_2d v1, DataVectorTypes::Vector_2d v2)
   12251              :     {
   12252              :         // J. Glazer - March 2017
   12253              : 
   12254         2025 :         return ((std::abs(v1.x - v2.x) < Constant::OneCentimeter) && (std::abs(v1.y - v2.y) < Constant::OneCentimeter));
   12255              :     }
   12256              : 
   12257              :     // test if two points on a plane are in the same position based on a small tolerance (based on Vector2dCount comparison)
   12258            0 :     bool isAlmostEqual2dPt(DataVectorTypes::Vector2dCount v1, DataVectorTypes::Vector2dCount v2)
   12259              :     {
   12260              :         // J. Glazer - March 2017
   12261              : 
   12262            0 :         return ((std::abs(v1.x - v2.x) < Constant::OneCentimeter) && (std::abs(v1.y - v2.y) < Constant::OneCentimeter));
   12263              :     }
   12264              : 
   12265              :     // returns the index of vertex in a list that is in the same position in space as the given vertex
   12266        10254 :     int findIndexOfVertex(DataVectorTypes::Vector vertexToFind, std::vector<DataVectorTypes::Vector> const &listOfVertices)
   12267              :     {
   12268              :         // J. Glazer - March 2017
   12269              : 
   12270        49165 :         for (std::size_t i = 0; i < listOfVertices.size(); i++) {
   12271        49163 :             if (isAlmostEqual3dPt(listOfVertices[i], vertexToFind)) {
   12272        10252 :                 return i;
   12273              :             }
   12274              :         }
   12275            2 :         return -1;
   12276              :     }
   12277              : 
   12278              :     // returns the distance between two points in space
   12279        12591 :     Real64 distance(DataVectorTypes::Vector v1, DataVectorTypes::Vector v2)
   12280              :     {
   12281              :         // J. Glazer - March 2017
   12282              : 
   12283        12591 :         return sqrt(pow(v1.x - v2.x, 2) + pow(v1.y - v2.y, 2) + pow(v1.z - v2.z, 2));
   12284              :     }
   12285              : 
   12286        18396 :     Real64 distanceFromPointToLine(DataVectorTypes::Vector start, DataVectorTypes::Vector end, DataVectorTypes::Vector test)
   12287              :     {
   12288              :         // np.linalg.norm(np.cross(e-s,p-s)/np.linalg.norm(e-s))
   12289        18396 :         DataVectorTypes::Vector t = end - start;
   12290        18396 :         t.normalize(); // Unit vector of start to end
   12291              : 
   12292        18396 :         DataVectorTypes::Vector other = test - start;
   12293              : 
   12294        18396 :         DataVectorTypes::Vector projection = DataVectorTypes::cross(t, other); // normal unit vector, that's the distance component
   12295        36792 :         return projection.length();
   12296        18396 :     }
   12297              : 
   12298              :     // tests if a point in space lies on the line segment defined by two other points
   12299        18395 :     bool isPointOnLineBetweenPoints(DataVectorTypes::Vector start, DataVectorTypes::Vector end, DataVectorTypes::Vector test)
   12300              :     {
   12301              :         // J. Glazer - March 2017
   12302              :         // The tolerance has to be low enough. Take for eg a plenum that has an edge that's 30meters long, you risk adding point from the
   12303              :         // floor to the roof, cf #7383 compute the shortest distance from the point to the line first to avoid false positive
   12304        18395 :         if (distanceFromPointToLine(start, end, test) <
   12305              :             Constant::OneCentimeter) { // distanceFromPointToLine always positive, it's calculated as norml_L2
   12306         1080 :             return (std::abs((distance(start, end) - (distance(start, test) + distance(test, end)))) < Constant::OneCentimeter);
   12307              :         }
   12308        17315 :         return false;
   12309              :     }
   12310              : 
   12311         3059 :     bool EdgeOfSurf::operator==(const EdgeOfSurf &other) const
   12312              :     {
   12313         9264 :         return ((isAlmostEqual3dPt(this->start, other.start) && isAlmostEqual3dPt(this->end, other.end)) ||
   12314         6205 :                 (isAlmostEqual3dPt(this->start, other.end) && isAlmostEqual3dPt(this->end, other.start)));
   12315              :     }
   12316              : 
   12317            0 :     bool EdgeOfSurf::operator!=(const EdgeOfSurf &other) const
   12318              :     {
   12319            0 :         return !(*this == other);
   12320              :     }
   12321              : 
   12322         2155 :     bool EdgeOfSurf::containsPoints(const Vector &vertex) const
   12323              :     {
   12324         5640 :         return (!isAlmostEqual3dPt(this->start, vertex) && !isAlmostEqual3dPt(this->end, vertex) &&
   12325         5640 :                 isPointOnLineBetweenPoints(this->start, this->end, vertex));
   12326              :     }
   12327              : 
   12328          380 :     double EdgeOfSurf::length() const
   12329              :     {
   12330          380 :         return distance(this->start, this->end);
   12331              :     }
   12332              : 
   12333         1704 :     void ProcessSurfaceVertices(EnergyPlusData &state, int const ThisSurf, bool &ErrorsFound)
   12334              :     {
   12335              :         // SUBROUTINE INFORMATION:
   12336              :         //       AUTHOR         Legacy Code (Walton)
   12337              :         //       DATE WRITTEN   1976
   12338              :         //       MODIFIED        FW, Mar 2002: Add triangular windows
   12339              :         //                       FW, May 2002: modify test for 4-sided but non-rectangular subsurfaces
   12340              :         //                       FW, Sep 2002: add shape for base surfaces (walls and detached shading surfaces)
   12341              : 
   12342              :         // PURPOSE OF THIS SUBROUTINE:
   12343              :         // This subroutine processes each surface into the vertex representation used
   12344              :         // by the shading procedures.
   12345              : 
   12346              :         // METHODOLOGY EMPLOYED:
   12347              :         // Detached Shading, Base Surfaces, Attached Shading surfaces are represented in the
   12348              :         // same manner as original.  Subsurfaces (windows, doors) are a "relative coordinate".
   12349              : 
   12350              :         static constexpr std::string_view RoutineName("ProcessSurfaceVertices: ");
   12351              : 
   12352              :         Real64 X1;           // Intermediate Result
   12353              :         Real64 Y1;           // Intermediate Result
   12354              :         Real64 Z1;           // Intermediate Result
   12355              :         Real64 XLLC;         // X-coordinate of lower left corner
   12356              :         Real64 YLLC;         // Y-coordinate of lower left corner
   12357              :         Real64 ZLLC;         // Z-coordinate of lower left corner
   12358              :         int n;               // Vertex Number in Loop
   12359              :         int ThisBaseSurface; // Current base surface
   12360              :         Real64 Xp;
   12361              :         Real64 Yp;
   12362              :         Real64 Zp;
   12363              :         Real64 SurfWorldAz; // Surface Azimuth (facing)
   12364              :         Real64 SurfTilt;    // Surface Tilt
   12365         1704 :         DataSurfaces::SurfaceShape ThisShape(DataSurfaces::SurfaceShape::None);
   12366              :         bool BaseSurface; // True if a base surface or a detached shading surface
   12367              :         Real64 ThisSurfAz;
   12368              :         Real64 ThisSurfTilt;
   12369              :         Real64 ThisReveal;
   12370              :         Real64 ThisWidth;
   12371              :         Real64 ThisHeight;
   12372              :         Real64 FrWidth;      // Frame width for exterior windows (m)
   12373              :         Real64 FrArea;       // Frame area for exterior windows(m2)
   12374              :         Real64 DivWidth;     // Divider width for exterior windows (m)
   12375              :         Real64 DivArea;      // Divider area for exterior windows (m2)
   12376              :         Real64 DivFrac;      // Fraction of divider area without overlaps
   12377              :         bool ErrorInSurface; // false/true, depending on pass through routine
   12378              :         bool HeatTransSurf;
   12379              :         Real64 OutOfLine;
   12380              : 
   12381              :         // Object Data
   12382         1704 :         Vectors::PlaneEq BasePlane;
   12383         1704 :         Vector TVect;
   12384         1704 :         Vector CoordinateTransVector;
   12385              : 
   12386         1704 :         if (state.dataSurface->Surface(ThisSurf).VerticesProcessed) {
   12387           10 :             return;
   12388              :         }
   12389              : 
   12390         1694 :         ErrorInSurface = false;
   12391              : 
   12392         1694 :         if (state.dataSurfaceGeometry->ProcessSurfaceVerticesOneTimeFlag) {
   12393          180 :             state.dataSurfaceGeometry->Xpsv.allocate(state.dataSurface->MaxVerticesPerSurface);
   12394          180 :             state.dataSurfaceGeometry->Ypsv.allocate(state.dataSurface->MaxVerticesPerSurface);
   12395          180 :             state.dataSurfaceGeometry->Zpsv.allocate(state.dataSurface->MaxVerticesPerSurface);
   12396          180 :             state.dataSurfaceGeometry->Xpsv = 0.0;
   12397          180 :             state.dataSurfaceGeometry->Ypsv = 0.0;
   12398          180 :             state.dataSurfaceGeometry->Zpsv = 0.0;
   12399          180 :             state.dataSurfaceGeometry->ProcessSurfaceVerticesOneTimeFlag = false;
   12400              :         }
   12401              : 
   12402              :         // Categorize this surface
   12403         1694 :         auto &surf = state.dataSurface->Surface(ThisSurf);
   12404         1694 :         BaseSurface = (surf.BaseSurf == 0 || surf.BaseSurf == ThisSurf);
   12405              : 
   12406         1694 :         ThisBaseSurface = surf.BaseSurf; // Dont know if this is still needed or not
   12407         1694 :         HeatTransSurf = surf.HeatTransSurf;
   12408              : 
   12409              :         // Kludge for daylighting shelves
   12410         1694 :         if (surf.IsShadowing) {
   12411           74 :             ThisBaseSurface = ThisSurf;
   12412           74 :             HeatTransSurf = true;
   12413              :         }
   12414              : 
   12415              :         // IF (Surface(ThisSurf)%Name(1:3) /= 'Mir') THEN
   12416         1694 :         if (!surf.MirroredSurf) {
   12417              :             bool IsCoPlanar;
   12418              :             int LastVertexInError;
   12419         1657 :             Vectors::CalcCoPlanarNess(surf.Vertex, surf.Sides, IsCoPlanar, OutOfLine, LastVertexInError);
   12420         1657 :             if (!IsCoPlanar) {
   12421            0 :                 if (OutOfLine > 0.01) {
   12422            0 :                     ShowSevereError(state,
   12423            0 :                                     format("{}Suspected non-planar surface:\"{}\", Max \"out of line\"={:.5T} at Vertex # {}",
   12424              :                                            RoutineName,
   12425            0 :                                            surf.Name,
   12426              :                                            OutOfLine,
   12427              :                                            LastVertexInError));
   12428              :                 } else {
   12429            0 :                     ShowWarningError(state,
   12430            0 :                                      format("{}Possible non-planar surface:\"{}\", Max \"out of line\"={:.5T} at Vertex # {}",
   12431              :                                             RoutineName,
   12432            0 :                                             surf.Name,
   12433              :                                             OutOfLine,
   12434              :                                             LastVertexInError));
   12435              :                 }
   12436              :                 //       ErrorInSurface=.TRUE.
   12437              :             }
   12438              :         }
   12439              : 
   12440         1694 :         if (BaseSurface) {
   12441         1559 :             SurfWorldAz = surf.Azimuth;
   12442         1559 :             SurfTilt = surf.Tilt;
   12443         7801 :             for (n = 1; n <= surf.Sides; ++n) {
   12444         6242 :                 state.dataSurfaceGeometry->Xpsv(n) = surf.Vertex(n).x;
   12445         6242 :                 state.dataSurfaceGeometry->Ypsv(n) = surf.Vertex(n).y;
   12446         6242 :                 state.dataSurfaceGeometry->Zpsv(n) = surf.Vertex(n).z;
   12447              :             }
   12448         1559 :             TVect = surf.Vertex(3) - surf.Vertex(2);
   12449         1559 :             ThisWidth = Vectors::VecLength(TVect);
   12450         1559 :             TVect = surf.Vertex(2) - surf.Vertex(1);
   12451         1559 :             ThisHeight = Vectors::VecLength(TVect);
   12452         1559 :             surf.Width = ThisWidth;
   12453         1559 :             surf.Height = ThisHeight; // For a horizontal surface this is actually length!
   12454         1559 :             if (surf.Sides == 3) {
   12455           16 :                 surf.Shape = DataSurfaces::SurfaceShape::Triangle;
   12456         1543 :             } else if (surf.Sides == 4) {
   12457              :                 // Test for rectangularity
   12458         1529 :                 if (isRectangle(state, ThisSurf)) {
   12459         1404 :                     surf.Shape = DataSurfaces::SurfaceShape::Rectangle;
   12460              :                 } else {
   12461          125 :                     surf.Shape = DataSurfaces::SurfaceShape::Quadrilateral;
   12462              :                 }
   12463              :             } else { // Surface( ThisSurf ).Sides > 4
   12464           14 :                 surf.Shape = DataSurfaces::SurfaceShape::Polygonal;
   12465           14 :                 if (std::abs(ThisHeight * ThisWidth - surf.GrossArea) > 0.001) {
   12466           14 :                     surf.Width = std::sqrt(surf.GrossArea);
   12467           14 :                     surf.Height = surf.Width;
   12468           14 :                     ThisWidth = surf.Width;
   12469           14 :                     ThisHeight = surf.Height;
   12470              :                 }
   12471              :             }
   12472              : 
   12473              :         } else { // It's a subsurface to previous basesurface in this set of calls
   12474              : 
   12475          135 :             ThisSurfAz = surf.Azimuth;
   12476          135 :             ThisSurfTilt = surf.Tilt;
   12477              : 
   12478              :             // Retrieve base surface info
   12479          135 :             Real64 const baseSurfWorldAz = state.dataSurface->Surface(ThisBaseSurface).Azimuth;
   12480          135 :             Real64 const baseSurfTilt = state.dataSurface->Surface(ThisBaseSurface).Tilt;
   12481          135 :             Real64 const BaseCosAzimuth = std::cos(baseSurfWorldAz * Constant::DegToRad);
   12482          135 :             Real64 const BaseSinAzimuth = std::sin(baseSurfWorldAz * Constant::DegToRad);
   12483          135 :             Real64 const BaseCosTilt = std::cos(baseSurfTilt * Constant::DegToRad);
   12484          135 :             Real64 const BaseSinTilt = std::sin(baseSurfTilt * Constant::DegToRad);
   12485          135 :             Real64 const BaseXLLC = state.dataSurface->Surface(ThisBaseSurface).Vertex(2).x;
   12486          135 :             Real64 const BaseYLLC = state.dataSurface->Surface(ThisBaseSurface).Vertex(2).y;
   12487          135 :             Real64 const BaseZLLC = state.dataSurface->Surface(ThisBaseSurface).Vertex(2).z;
   12488              : 
   12489          135 :             if (HeatTransSurf) {
   12490              : 
   12491          131 :                 if (surf.Sides == 4) {
   12492          129 :                     ThisShape = DataSurfaces::SurfaceShape::RectangularDoorWindow;
   12493            2 :                 } else if (surf.Sides == 3 && surf.Class == SurfaceClass::Window) {
   12494            1 :                     ThisShape = DataSurfaces::SurfaceShape::TriangularWindow;
   12495            1 :                 } else if (surf.Sides == 3 && surf.Class == SurfaceClass::Door) {
   12496            1 :                     ThisShape = DataSurfaces::SurfaceShape::TriangularDoor;
   12497              :                 } else {
   12498            0 :                     assert(false);
   12499              :                 }
   12500              : 
   12501              :             } else { //  this is a shadowing subsurface
   12502              : 
   12503            4 :                 if (std::abs(state.dataSurface->Surface(surf.BaseSurf).Tilt - ThisSurfTilt) <= 0.01) {
   12504              :                     // left or right fin
   12505            4 :                     if (ThisSurfAz < 0.0) ThisSurfAz += 360.0;
   12506            4 :                     if (ThisSurfAz > state.dataSurface->Surface(surf.BaseSurf).Azimuth) {
   12507            0 :                         ThisShape = DataSurfaces::SurfaceShape::RectangularLeftFin;
   12508              :                     } else {
   12509            4 :                         ThisShape = DataSurfaces::SurfaceShape::RectangularRightFin;
   12510              :                     }
   12511              :                 } else {
   12512            0 :                     ThisShape = DataSurfaces::SurfaceShape::RectangularOverhang;
   12513              :                 }
   12514              :             }
   12515              : 
   12516              :             // Setting relative coordinates for shadowing calculations for subsurfaces
   12517              :             bool SError; // Bool used for return value of calls to PlaneEquation
   12518          135 :             switch (ThisShape) {
   12519          129 :             case DataSurfaces::SurfaceShape::RectangularDoorWindow: { // Rectangular heat transfer subsurface
   12520          258 :                 Vectors::PlaneEquation(
   12521          129 :                     state.dataSurface->Surface(surf.BaseSurf).Vertex, state.dataSurface->Surface(surf.BaseSurf).Sides, BasePlane, SError);
   12522          129 :                 if (SError) {
   12523            0 :                     ShowSevereError(state, format("{}Degenerate surface (likely two vertices equal):\"{}\".", RoutineName, surf.Name));
   12524            0 :                     ErrorInSurface = true;
   12525              :                 }
   12526          129 :                 ThisReveal = -Vectors::Pt2Plane(surf.Vertex(2), BasePlane);
   12527          129 :                 if (std::abs(ThisReveal) < 0.0002) ThisReveal = 0.0;
   12528          129 :                 surf.Reveal = ThisReveal;
   12529          129 :                 Xp = surf.Vertex(2).x - BaseXLLC;
   12530          129 :                 Yp = surf.Vertex(2).y - BaseYLLC;
   12531          129 :                 Zp = surf.Vertex(2).z - BaseZLLC;
   12532          129 :                 XLLC = -Xp * BaseCosAzimuth + Yp * BaseSinAzimuth;
   12533          129 :                 YLLC = -Xp * BaseSinAzimuth * BaseCosTilt - Yp * BaseCosAzimuth * BaseCosTilt + Zp * BaseSinTilt;
   12534          129 :                 ZLLC = Xp * BaseSinAzimuth * BaseSinTilt + Yp * BaseCosAzimuth * BaseSinTilt + Zp * BaseCosTilt;
   12535          129 :                 TVect = surf.Vertex(3) - surf.Vertex(2);
   12536          129 :                 ThisWidth = Vectors::VecLength(TVect);
   12537          129 :                 TVect = surf.Vertex(2) - surf.Vertex(1);
   12538          129 :                 ThisHeight = Vectors::VecLength(TVect);
   12539          129 :                 surf.Width = ThisWidth;
   12540          129 :                 surf.Height = ThisHeight;
   12541              : 
   12542              :                 // Processing of 4-sided but non-rectangular Window, Door or GlassDoor, for use in calc of convective air flow.
   12543          129 :                 if (!isRectangle(state, ThisSurf)) {
   12544              : 
   12545              :                     // Transform the surface into an equivalent rectangular surface with the same area and aspect ratio.
   12546            3 :                     MakeEquivalentRectangle(state, ThisSurf, ErrorsFound);
   12547              : 
   12548            3 :                     if (state.dataGlobal->DisplayExtraWarnings) {
   12549            0 :                         ShowWarningError(state, format("{}Suspected 4-sided but non-rectangular Window, Door or GlassDoor:", RoutineName));
   12550            0 :                         ShowContinueError(
   12551              :                             state,
   12552            0 :                             format("Surface={} is transformed into an equivalent rectangular surface with the same area and aspect ratio. ",
   12553            0 :                                    surf.Name));
   12554              :                     }
   12555              :                 }
   12556              : 
   12557          129 :                 state.dataSurfaceGeometry->Xpsv(1) = XLLC;
   12558          129 :                 state.dataSurfaceGeometry->Xpsv(2) = XLLC;
   12559          129 :                 state.dataSurfaceGeometry->Xpsv(3) = XLLC + surf.Width;
   12560          129 :                 state.dataSurfaceGeometry->Xpsv(4) = XLLC + surf.Width;
   12561          129 :                 state.dataSurfaceGeometry->Ypsv(1) = YLLC + surf.Height;
   12562          129 :                 state.dataSurfaceGeometry->Ypsv(4) = YLLC + surf.Height;
   12563          129 :                 state.dataSurfaceGeometry->Ypsv(2) = YLLC;
   12564          129 :                 state.dataSurfaceGeometry->Ypsv(3) = YLLC;
   12565          129 :                 state.dataSurfaceGeometry->Zpsv(1) = ZLLC;
   12566          129 :                 state.dataSurfaceGeometry->Zpsv(2) = ZLLC;
   12567          129 :                 state.dataSurfaceGeometry->Zpsv(3) = ZLLC;
   12568          129 :                 state.dataSurfaceGeometry->Zpsv(4) = ZLLC;
   12569              : 
   12570          129 :                 if (surf.Class == SurfaceClass::Window && surf.ExtBoundCond == DataSurfaces::ExternalEnvironment && surf.FrameDivider > 0) {
   12571           19 :                     int FrDivNum = surf.FrameDivider;
   12572              :                     // Set flag for calculating beam solar reflection from outside and/or inside window reveal
   12573            0 :                     if ((surf.Reveal > 0.0 && state.dataSurface->FrameDivider(FrDivNum).OutsideRevealSolAbs > 0.0) ||
   12574           19 :                         (state.dataSurface->FrameDivider(FrDivNum).InsideSillDepth > 0.0 &&
   12575           38 :                          state.dataSurface->FrameDivider(FrDivNum).InsideSillSolAbs > 0.0) ||
   12576           19 :                         (state.dataSurface->FrameDivider(FrDivNum).InsideReveal > 0.0 &&
   12577            0 :                          state.dataSurface->FrameDivider(FrDivNum).InsideRevealSolAbs > 0.0))
   12578            0 :                         state.dataHeatBal->CalcWindowRevealReflection = true;
   12579              : 
   12580              :                     // For exterior window with frame, subtract frame area from base surface
   12581              :                     // (only rectangular windows are allowed to have a frame and/or divider;
   12582              :                     // Surface(ThisSurf)%FrameDivider will be 0 for triangular windows)
   12583           19 :                     FrWidth = state.dataSurface->FrameDivider(FrDivNum).FrameWidth;
   12584           19 :                     if (FrWidth > 0.0) {
   12585           19 :                         FrArea = (surf.Height + 2.0 * FrWidth) * (surf.Width + 2.0 * FrWidth) - surf.Area / surf.Multiplier;
   12586           19 :                         state.dataSurface->SurfWinFrameArea(ThisSurf) = FrArea * surf.Multiplier;
   12587           19 :                         if ((state.dataSurface->Surface(surf.BaseSurf).Area - state.dataSurface->SurfWinFrameArea(ThisSurf)) <= 0.0) {
   12588            0 :                             ShowSevereError(state, format("{}Base Surface=\"{}\", ", RoutineName, state.dataSurface->Surface(surf.BaseSurf).Name));
   12589            0 :                             ShowContinueError(state,
   12590            0 :                                               format("Window Surface=\"{}\" area (with frame) is too large to fit on the surface.", surf.Name));
   12591            0 :                             ShowContinueError(state,
   12592            0 :                                               format("Base surface area (-windows and doors)=[{:.2T}] m2, frame area=[{:.2T}] m2.",
   12593            0 :                                                      state.dataSurface->Surface(surf.BaseSurf).Area,
   12594            0 :                                                      state.dataSurface->SurfWinFrameArea(ThisSurf)));
   12595            0 :                             ErrorInSurface = true;
   12596              :                         }
   12597           19 :                         state.dataSurface->Surface(surf.BaseSurf).Area -= state.dataSurface->SurfWinFrameArea(ThisSurf);
   12598              :                     }
   12599              :                     // If exterior window has divider, subtract divider area to get glazed area
   12600           19 :                     DivWidth = state.dataSurface->FrameDivider(surf.FrameDivider).DividerWidth;
   12601           19 :                     if (DivWidth > 0.0 && !ErrorInSurface) {
   12602           19 :                         DivArea = DivWidth * (state.dataSurface->FrameDivider(FrDivNum).HorDividers * surf.Width +
   12603           19 :                                               state.dataSurface->FrameDivider(FrDivNum).VertDividers * surf.Height -
   12604           19 :                                               state.dataSurface->FrameDivider(FrDivNum).HorDividers *
   12605           19 :                                                   state.dataSurface->FrameDivider(FrDivNum).VertDividers * DivWidth);
   12606           19 :                         state.dataSurface->SurfWinDividerArea(ThisSurf) = DivArea * surf.Multiplier;
   12607           19 :                         if ((surf.Area - state.dataSurface->SurfWinDividerArea(ThisSurf)) <= 0.0) {
   12608            0 :                             ShowSevereError(state, format("{}Divider area exceeds glazed opening for window {}", RoutineName, surf.Name));
   12609            0 :                             ShowContinueError(state,
   12610            0 :                                               format("Window surface area=[{:.2T}] m2, divider area=[{:.2T}] m2.",
   12611            0 :                                                      surf.Area,
   12612            0 :                                                      state.dataSurface->SurfWinDividerArea(ThisSurf)));
   12613            0 :                             ErrorInSurface = true;
   12614              :                         }
   12615           19 :                         surf.Area -= state.dataSurface->SurfWinDividerArea(ThisSurf); // Glazed area
   12616           19 :                         if (DivArea <= 0.0) {
   12617            0 :                             ShowWarningError(state, format("{}Calculated Divider Area <= 0.0 for Window={}", RoutineName, surf.Name));
   12618            0 :                             if (state.dataSurface->FrameDivider(FrDivNum).HorDividers == 0) {
   12619            0 :                                 ShowContinueError(state, "..Number of Horizontal Dividers = 0.");
   12620              :                             }
   12621            0 :                             if (state.dataSurface->FrameDivider(FrDivNum).VertDividers == 0) {
   12622            0 :                                 ShowContinueError(state, "..Number of Vertical Dividers = 0.");
   12623              :                             }
   12624              :                         } else {
   12625           19 :                             auto &surfWin = state.dataSurface->SurfaceWindow(ThisSurf);
   12626           19 :                             surfWin.glazedFrac = surf.Area / (surf.Area + state.dataSurface->SurfWinDividerArea(ThisSurf));
   12627              :                             // Correction factor for portion of divider subject to divider projection correction
   12628           19 :                             DivFrac = (1.0 - state.dataSurface->FrameDivider(FrDivNum).HorDividers *
   12629           19 :                                                  state.dataSurface->FrameDivider(FrDivNum).VertDividers * pow_2(DivWidth) / DivArea);
   12630           19 :                             state.dataSurface->SurfWinProjCorrDivOut(ThisSurf) =
   12631           19 :                                 DivFrac * state.dataSurface->FrameDivider(FrDivNum).DividerProjectionOut / DivWidth;
   12632           19 :                             state.dataSurface->SurfWinProjCorrDivIn(ThisSurf) =
   12633           19 :                                 DivFrac * state.dataSurface->FrameDivider(FrDivNum).DividerProjectionIn / DivWidth;
   12634              :                             // Correction factor for portion of frame subject to frame projection correction
   12635           19 :                             if (FrWidth > 0.0) {
   12636           19 :                                 state.dataSurface->SurfWinProjCorrFrOut(ThisSurf) =
   12637           19 :                                     (state.dataSurface->FrameDivider(FrDivNum).FrameProjectionOut / FrWidth) *
   12638           38 :                                     (ThisHeight + ThisWidth -
   12639           19 :                                      (state.dataSurface->FrameDivider(FrDivNum).HorDividers +
   12640           19 :                                       state.dataSurface->FrameDivider(FrDivNum).VertDividers) *
   12641           19 :                                          DivWidth) /
   12642           19 :                                     (ThisHeight + ThisWidth + 2 * FrWidth);
   12643           19 :                                 state.dataSurface->SurfWinProjCorrFrIn(ThisSurf) =
   12644           19 :                                     (state.dataSurface->FrameDivider(FrDivNum).FrameProjectionIn / FrWidth) *
   12645           38 :                                     (ThisHeight + ThisWidth -
   12646           19 :                                      (state.dataSurface->FrameDivider(FrDivNum).HorDividers +
   12647           19 :                                       state.dataSurface->FrameDivider(FrDivNum).VertDividers) *
   12648           19 :                                          DivWidth) /
   12649           19 :                                     (ThisHeight + ThisWidth + 2 * FrWidth);
   12650              :                             }
   12651              :                         }
   12652              :                     }
   12653              :                 }
   12654          129 :             } break;
   12655            2 :             case DataSurfaces::SurfaceShape::TriangularWindow:
   12656              :             case DataSurfaces::SurfaceShape::TriangularDoor: {
   12657            4 :                 Vectors::PlaneEquation(
   12658            2 :                     state.dataSurface->Surface(surf.BaseSurf).Vertex, state.dataSurface->Surface(surf.BaseSurf).Sides, BasePlane, SError);
   12659            2 :                 if (SError) {
   12660            0 :                     ShowSevereError(state, format("{}Degenerate surface (likely two vertices equal):\"{}\".", RoutineName, surf.Name));
   12661            0 :                     ErrorInSurface = true;
   12662              :                 }
   12663            2 :                 ThisReveal = -Vectors::Pt2Plane(surf.Vertex(2), BasePlane);
   12664            2 :                 if (std::abs(ThisReveal) < 0.0002) ThisReveal = 0.0;
   12665            2 :                 surf.Reveal = ThisReveal;
   12666            2 :                 Xp = surf.Vertex(2).x - BaseXLLC;
   12667            2 :                 Yp = surf.Vertex(2).y - BaseYLLC;
   12668            2 :                 Zp = surf.Vertex(2).z - BaseZLLC;
   12669            2 :                 state.dataSurfaceGeometry->Xpsv(2) = -Xp * BaseCosAzimuth + Yp * BaseSinAzimuth;
   12670            2 :                 state.dataSurfaceGeometry->Ypsv(2) = -Xp * BaseSinAzimuth * BaseCosTilt - Yp * BaseCosAzimuth * BaseCosTilt + Zp * BaseSinTilt;
   12671            2 :                 state.dataSurfaceGeometry->Zpsv(2) = Xp * BaseSinAzimuth * BaseSinTilt + Yp * BaseCosAzimuth * BaseSinTilt + Zp * BaseCosTilt;
   12672            2 :                 TVect = surf.Vertex(3) - surf.Vertex(2);
   12673            2 :                 ThisWidth = Vectors::VecLength(TVect);
   12674            2 :                 TVect = surf.Vertex(2) - surf.Vertex(1);
   12675            2 :                 ThisHeight = Vectors::VecLength(TVect);
   12676            2 :                 surf.Width = ThisWidth;
   12677              :                 // Effective height and width of a triangular window for use in calc of convective air flow
   12678              :                 // in gap between glass and shading device when shading device is present
   12679            2 :                 surf.Height = 4.0 * surf.Area / (3.0 * surf.Width);
   12680            2 :                 surf.Width *= 0.75;
   12681              : 
   12682            2 :                 Xp = surf.Vertex(1).x - BaseXLLC;
   12683            2 :                 Yp = surf.Vertex(1).y - BaseYLLC;
   12684            2 :                 Zp = surf.Vertex(1).z - BaseZLLC;
   12685            2 :                 state.dataSurfaceGeometry->Xpsv(1) = -Xp * BaseCosAzimuth + Yp * BaseSinAzimuth;
   12686            2 :                 state.dataSurfaceGeometry->Ypsv(1) = -Xp * BaseSinAzimuth * BaseCosTilt - Yp * BaseCosAzimuth * BaseCosTilt + Zp * BaseSinTilt;
   12687            2 :                 state.dataSurfaceGeometry->Zpsv(1) = Xp * BaseSinAzimuth * BaseSinTilt + Yp * BaseCosAzimuth * BaseSinTilt + Zp * BaseCosTilt;
   12688              : 
   12689            2 :                 Xp = surf.Vertex(3).x - BaseXLLC;
   12690            2 :                 Yp = surf.Vertex(3).y - BaseYLLC;
   12691            2 :                 Zp = surf.Vertex(3).z - BaseZLLC;
   12692            2 :                 state.dataSurfaceGeometry->Xpsv(3) = -Xp * BaseCosAzimuth + Yp * BaseSinAzimuth;
   12693            2 :                 state.dataSurfaceGeometry->Ypsv(3) = -Xp * BaseSinAzimuth * BaseCosTilt - Yp * BaseCosAzimuth * BaseCosTilt + Zp * BaseSinTilt;
   12694            2 :                 state.dataSurfaceGeometry->Zpsv(3) = Xp * BaseSinAzimuth * BaseSinTilt + Yp * BaseCosAzimuth * BaseSinTilt + Zp * BaseCosTilt;
   12695            2 :             } break;
   12696            0 :             case DataSurfaces::SurfaceShape::RectangularOverhang: {
   12697            0 :                 Xp = surf.Vertex(2).x - BaseXLLC;
   12698            0 :                 Yp = surf.Vertex(2).y - BaseYLLC;
   12699            0 :                 Zp = surf.Vertex(2).z - BaseZLLC;
   12700            0 :                 XLLC = -Xp * BaseCosAzimuth + Yp * BaseSinAzimuth;
   12701            0 :                 YLLC = -Xp * BaseSinAzimuth * BaseCosTilt - Yp * BaseCosAzimuth * BaseCosTilt + Zp * BaseSinTilt;
   12702            0 :                 ZLLC = Xp * BaseSinAzimuth * BaseSinTilt + Yp * BaseCosAzimuth * BaseSinTilt + Zp * BaseCosTilt;
   12703            0 :                 TVect = surf.Vertex(3) - surf.Vertex(2);
   12704            0 :                 ThisWidth = Vectors::VecLength(TVect);
   12705            0 :                 TVect = surf.Vertex(2) - surf.Vertex(1);
   12706            0 :                 ThisHeight = Vectors::VecLength(TVect);
   12707            0 :                 surf.Width = ThisWidth;
   12708            0 :                 surf.Height = ThisHeight;
   12709            0 :                 state.dataSurfaceGeometry->Xpsv(1) = XLLC;
   12710            0 :                 state.dataSurfaceGeometry->Xpsv(2) = XLLC;
   12711            0 :                 state.dataSurfaceGeometry->Xpsv(3) = XLLC + surf.Width;
   12712            0 :                 state.dataSurfaceGeometry->Xpsv(4) = XLLC + surf.Width;
   12713            0 :                 state.dataSurfaceGeometry->Ypsv(1) = YLLC;
   12714            0 :                 state.dataSurfaceGeometry->Ypsv(2) = YLLC;
   12715            0 :                 state.dataSurfaceGeometry->Ypsv(3) = YLLC;
   12716            0 :                 state.dataSurfaceGeometry->Ypsv(4) = YLLC;
   12717            0 :                 state.dataSurfaceGeometry->Zpsv(1) = surf.Height;
   12718            0 :                 state.dataSurfaceGeometry->Zpsv(4) = surf.Height;
   12719            0 :                 state.dataSurfaceGeometry->Zpsv(2) = 0.0;
   12720            0 :                 state.dataSurfaceGeometry->Zpsv(3) = 0.0;
   12721            0 :             } break;
   12722            0 :             case DataSurfaces::SurfaceShape::RectangularLeftFin: {
   12723            0 :                 Xp = surf.Vertex(2).x - BaseXLLC;
   12724            0 :                 Yp = surf.Vertex(2).y - BaseYLLC;
   12725            0 :                 Zp = surf.Vertex(2).z - BaseZLLC;
   12726            0 :                 XLLC = -Xp * BaseCosAzimuth + Yp * BaseSinAzimuth;
   12727            0 :                 YLLC = -Xp * BaseSinAzimuth * BaseCosTilt - Yp * BaseCosAzimuth * BaseCosTilt + Zp * BaseSinTilt;
   12728            0 :                 ZLLC = Xp * BaseSinAzimuth * BaseSinTilt + Yp * BaseCosAzimuth * BaseSinTilt + Zp * BaseCosTilt;
   12729            0 :                 TVect = surf.Vertex(3) - surf.Vertex(2);
   12730            0 :                 ThisWidth = Vectors::VecLength(TVect);
   12731            0 :                 TVect = surf.Vertex(2) - surf.Vertex(1);
   12732            0 :                 ThisHeight = Vectors::VecLength(TVect);
   12733            0 :                 surf.Width = ThisWidth;
   12734            0 :                 surf.Height = ThisHeight;
   12735            0 :                 state.dataSurfaceGeometry->Xpsv(1) = XLLC;
   12736            0 :                 state.dataSurfaceGeometry->Xpsv(2) = XLLC;
   12737            0 :                 state.dataSurfaceGeometry->Xpsv(3) = XLLC;
   12738            0 :                 state.dataSurfaceGeometry->Xpsv(4) = XLLC;
   12739            0 :                 state.dataSurfaceGeometry->Ypsv(1) = YLLC;
   12740            0 :                 state.dataSurfaceGeometry->Ypsv(2) = YLLC;
   12741            0 :                 state.dataSurfaceGeometry->Ypsv(3) = YLLC + surf.Width;
   12742            0 :                 state.dataSurfaceGeometry->Ypsv(4) = YLLC + surf.Width;
   12743            0 :                 state.dataSurfaceGeometry->Zpsv(1) = surf.Height;
   12744            0 :                 state.dataSurfaceGeometry->Zpsv(4) = surf.Height;
   12745            0 :                 state.dataSurfaceGeometry->Zpsv(2) = 0.0;
   12746            0 :                 state.dataSurfaceGeometry->Zpsv(3) = 0.0;
   12747            0 :             } break;
   12748            4 :             case DataSurfaces::SurfaceShape::RectangularRightFin: {
   12749            4 :                 Xp = surf.Vertex(2).x - BaseXLLC;
   12750            4 :                 Yp = surf.Vertex(2).y - BaseYLLC;
   12751            4 :                 Zp = surf.Vertex(2).z - BaseZLLC;
   12752            4 :                 XLLC = -Xp * BaseCosAzimuth + Yp * BaseSinAzimuth;
   12753            4 :                 YLLC = -Xp * BaseSinAzimuth * BaseCosTilt - Yp * BaseCosAzimuth * BaseCosTilt + Zp * BaseSinTilt;
   12754            4 :                 ZLLC = Xp * BaseSinAzimuth * BaseSinTilt + Yp * BaseCosAzimuth * BaseSinTilt + Zp * BaseCosTilt;
   12755            4 :                 TVect = surf.Vertex(3) - surf.Vertex(2);
   12756            4 :                 ThisWidth = Vectors::VecLength(TVect);
   12757            4 :                 TVect = surf.Vertex(2) - surf.Vertex(1);
   12758            4 :                 ThisHeight = Vectors::VecLength(TVect);
   12759            4 :                 surf.Width = ThisWidth;
   12760            4 :                 surf.Height = ThisHeight;
   12761            4 :                 state.dataSurfaceGeometry->Xpsv(1) = XLLC;
   12762            4 :                 state.dataSurfaceGeometry->Xpsv(2) = XLLC;
   12763            4 :                 state.dataSurfaceGeometry->Xpsv(3) = XLLC;
   12764            4 :                 state.dataSurfaceGeometry->Xpsv(4) = XLLC;
   12765            4 :                 state.dataSurfaceGeometry->Ypsv(1) = YLLC + surf.Width;
   12766            4 :                 state.dataSurfaceGeometry->Ypsv(2) = YLLC + surf.Width;
   12767            4 :                 state.dataSurfaceGeometry->Ypsv(3) = YLLC;
   12768            4 :                 state.dataSurfaceGeometry->Ypsv(4) = YLLC;
   12769            4 :                 state.dataSurfaceGeometry->Zpsv(1) = surf.Height;
   12770            4 :                 state.dataSurfaceGeometry->Zpsv(4) = surf.Height;
   12771            4 :                 state.dataSurfaceGeometry->Zpsv(2) = 0.0;
   12772            4 :                 state.dataSurfaceGeometry->Zpsv(3) = 0.0;
   12773            4 :             } break;
   12774            0 :             default: {
   12775              :                 // Error Condition
   12776            0 :                 ShowSevereError(state, format("{}Incorrect surface shape number.", RoutineName), OptionalOutputFileRef{state.files.eso});
   12777            0 :                 ShowContinueError(state, "Please notify EnergyPlus support of this error and send input file.");
   12778            0 :                 ErrorInSurface = true;
   12779            0 :             } break;
   12780              :             }
   12781              : 
   12782          673 :             for (n = 1; n <= surf.Sides; ++n) {
   12783              :                 // if less than 1/10 inch
   12784          538 :                 state.dataSurfaceGeometry->Xpsv(n) = nint64(10000.0 * state.dataSurfaceGeometry->Xpsv(n)) / 10000.0;
   12785          538 :                 if (std::abs(state.dataSurfaceGeometry->Xpsv(n)) < 0.0025) state.dataSurfaceGeometry->Xpsv(n) = 0.0;
   12786          538 :                 state.dataSurfaceGeometry->Ypsv(n) = nint64(10000.0 * state.dataSurfaceGeometry->Ypsv(n)) / 10000.0;
   12787          538 :                 if (std::abs(state.dataSurfaceGeometry->Ypsv(n)) < 0.0025) state.dataSurfaceGeometry->Ypsv(n) = 0.0;
   12788          538 :                 state.dataSurfaceGeometry->Zpsv(n) = nint64(10000.0 * state.dataSurfaceGeometry->Zpsv(n)) / 10000.0;
   12789          538 :                 if (std::abs(state.dataSurfaceGeometry->Zpsv(n)) < 0.0025) state.dataSurfaceGeometry->Zpsv(n) = 0.0;
   12790              :             }
   12791              : 
   12792          135 :             surf.Shape = ThisShape;
   12793              : 
   12794              :         } // End of check if ThisSurf is a base surface
   12795              : 
   12796         1694 :         if (ErrorInSurface) {
   12797            0 :             ErrorsFound = true;
   12798            0 :             return;
   12799              :         }
   12800              : 
   12801              :         // Transfer to XV,YV,ZV arrays
   12802              : 
   12803         1694 :         state.dataSurface->ShadeV(ThisSurf).NVert = surf.Sides;
   12804         1694 :         state.dataSurface->ShadeV(ThisSurf).XV.allocate(surf.Sides);
   12805         1694 :         state.dataSurface->ShadeV(ThisSurf).YV.allocate(surf.Sides);
   12806         1694 :         state.dataSurface->ShadeV(ThisSurf).ZV.allocate(surf.Sides);
   12807              : 
   12808         8474 :         for (n = 1; n <= surf.Sides; ++n) {
   12809              :             // if less than 1/10 inch
   12810         6780 :             state.dataSurface->ShadeV(ThisSurf).XV(n) = state.dataSurfaceGeometry->Xpsv(n);
   12811         6780 :             state.dataSurface->ShadeV(ThisSurf).YV(n) = state.dataSurfaceGeometry->Ypsv(n);
   12812         6780 :             state.dataSurface->ShadeV(ThisSurf).ZV(n) = state.dataSurfaceGeometry->Zpsv(n);
   12813              :         }
   12814              : 
   12815              :         // Process Surfaces According to Type of Coordinate Origin.
   12816         1694 :         if (BaseSurface) {
   12817              : 
   12818              :             // General Surfaces:
   12819         1559 :             CalcCoordinateTransformation(state, ThisSurf, CoordinateTransVector); // X00,Y00,Z00,X,Y,Z,A)    ! Compute Coordinate Transformation
   12820              : 
   12821              :             // RECORD DIRECTION COSINES.
   12822         1559 :             if (HeatTransSurf) { // This is a general surface but not detached shading surface
   12823              : 
   12824              :                 // RECORD COORDINATE TRANSFORMATION FOR BASE SURFACES.
   12825         1513 :                 state.dataSurface->X0(ThisBaseSurface) = CoordinateTransVector.x;
   12826         1513 :                 state.dataSurface->Y0(ThisBaseSurface) = CoordinateTransVector.y;
   12827         1513 :                 state.dataSurface->Z0(ThisBaseSurface) = CoordinateTransVector.z;
   12828              : 
   12829              :                 // COMPUTE INVERSE TRANSFORMATION.
   12830         1513 :                 X1 = state.dataSurfaceGeometry->Xpsv(2) - CoordinateTransVector.x;
   12831         1513 :                 Y1 = state.dataSurfaceGeometry->Ypsv(2) - CoordinateTransVector.y;
   12832         1513 :                 Z1 = state.dataSurfaceGeometry->Zpsv(2) - CoordinateTransVector.z;
   12833              :                 // Store the relative coordinate shift values for later use by any subsurfaces
   12834         3026 :                 state.dataSurface->Surface(ThisBaseSurface).XShift = state.dataSurface->Surface(ThisBaseSurface).lcsx.x * X1 +
   12835         1513 :                                                                      state.dataSurface->Surface(ThisBaseSurface).lcsx.y * Y1 +
   12836         1513 :                                                                      state.dataSurface->Surface(ThisBaseSurface).lcsx.z * Z1;
   12837         3026 :                 state.dataSurface->Surface(ThisBaseSurface).YShift = state.dataSurface->Surface(ThisBaseSurface).lcsy.x * X1 +
   12838         1513 :                                                                      state.dataSurface->Surface(ThisBaseSurface).lcsy.y * Y1 +
   12839         1513 :                                                                      state.dataSurface->Surface(ThisBaseSurface).lcsy.z * Z1;
   12840         1513 :                 state.dataSurface->Surface(ThisBaseSurface).VerticesProcessed = true;
   12841              :             }
   12842              : 
   12843              :             // SUBSURFACES: (Surface(ThisSurf)%BaseSurf /= ThisSurf)
   12844              :         } else {
   12845              :             // WINDOWS OR DOORS:
   12846              : 
   12847              :             // SHIFT RELATIVE COORDINATES FROM LOWER LEFT CORNER TO ORIGIN DEFINED
   12848              :             // BY CTRAN AND SET DIRECTION COSINES SAME AS BASE SURFACE.
   12849          135 :             if (!state.dataSurface->Surface(ThisBaseSurface).VerticesProcessed) {
   12850              : 
   12851            4 :                 if (surf.IsAirBoundarySurf) {
   12852            4 :                     ProcessSurfaceVertices(state, ThisBaseSurface, ErrorsFound);
   12853              :                 } else {
   12854              : 
   12855            0 :                     ShowSevereError(state, format("{}Developer error for Subsurface={}", RoutineName, surf.Name));
   12856            0 :                     ShowContinueError(state,
   12857            0 :                                       format("Base surface={} vertices must be processed before any subsurfaces.",
   12858            0 :                                              state.dataSurface->Surface(ThisBaseSurface).Name));
   12859            0 :                     ShowFatalError(state, std::string{RoutineName});
   12860              :                 }
   12861              :             }
   12862              : 
   12863          673 :             for (n = 1; n <= surf.Sides; ++n) {
   12864          538 :                 state.dataSurface->ShadeV(ThisSurf).XV(n) += state.dataSurface->Surface(ThisBaseSurface).XShift;
   12865          538 :                 state.dataSurface->ShadeV(ThisSurf).YV(n) += state.dataSurface->Surface(ThisBaseSurface).YShift;
   12866              :             }
   12867              :         }
   12868         1714 :     }
   12869              : 
   12870         1559 :     void CalcCoordinateTransformation(EnergyPlusData &state,
   12871              :                                       int const SurfNum,            // Surface Number
   12872              :                                       Vector &CompCoordTranslVector // Coordinate Translation Vector
   12873              :     )
   12874              :     {
   12875              :         // SUBROUTINE INFORMATION:
   12876              :         //       AUTHOR         George Walton, BLAST
   12877              :         //       DATE WRITTEN   August 1976
   12878              :         //       MODIFIED       LKL, May 2004 -- >4 sided polygons
   12879              :         //       RE-ENGINEERED  Yes
   12880              : 
   12881              :         // PURPOSE OF THIS SUBROUTINE:
   12882              :         // This subroutine develops a coordinate transformation such that the X-axis goes
   12883              :         // through points 2 and 3 and the Y-axis goes through point 1
   12884              :         // of a plane figure in 3-d space.
   12885              : 
   12886              :         // REFERENCES:
   12887              :         // 'NECAP' - NASA'S Energy-Cost Analysis Program
   12888              : 
   12889              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
   12890              :         Real64 Gamma; // Intermediate Result
   12891              :         Real64 DotSelfX23;
   12892              : 
   12893              :         // Object Data
   12894         1559 :         Vector x21;
   12895         1559 :         Vector x23;
   12896              : 
   12897              :         // Determine Components of the Coordinate Translation Vector.
   12898         1559 :         auto const &surf = state.dataSurface->Surface(SurfNum);
   12899              : 
   12900         1559 :         x21 = surf.Vertex(2) - surf.Vertex(1);
   12901         1559 :         x23 = surf.Vertex(2) - surf.Vertex(3);
   12902              : 
   12903         1559 :         DotSelfX23 = magnitude_squared(x23);
   12904              : 
   12905         1559 :         if (DotSelfX23 <= Constant::OneMillionth) {
   12906            0 :             ShowSevereError(state, format("CalcCoordinateTransformation: Invalid dot product, surface=\"{}\":", surf.Name));
   12907            0 :             for (int I = 1; I <= surf.Sides; ++I) {
   12908            0 :                 auto const &point = surf.Vertex(I);
   12909            0 :                 ShowContinueError(state, format(" ({:8.3F},{:8.3F},{:8.3F})", point.x, point.y, point.z));
   12910              :             }
   12911            0 :             ShowFatalError(
   12912            0 :                 state, "CalcCoordinateTransformation: Program terminates due to preceding condition.", OptionalOutputFileRef{state.files.eso});
   12913            0 :             return;
   12914              :         }
   12915              : 
   12916         1559 :         Gamma = dot(x21, x23) / magnitude_squared(x23);
   12917              : 
   12918         1559 :         CompCoordTranslVector = surf.Vertex(2) + Gamma * (surf.Vertex(3) - surf.Vertex(2));
   12919         1559 :     }
   12920              : 
   12921            0 :     void CreateShadedWindowConstruction(EnergyPlusData &state,
   12922              :                                         int const SurfNum,          // Surface number
   12923              :                                         int const WSCPtr,           // Pointer to WindowShadingControl for SurfNum
   12924              :                                         int const ShDevNum,         // Shading device material number for WSCptr
   12925              :                                         int const shadeControlIndex // index to the Surface().windowShadingControlList,
   12926              :                                                                     // Surface().shadedConstructionList, and Surface().shadedStormWinConstructionList
   12927              :     )
   12928              :     {
   12929              :         // SUBROUTINE INFORMATION:
   12930              :         //       AUTHOR         Fred Winkelmann
   12931              :         //       DATE WRITTEN   Nov 2001
   12932              : 
   12933              :         // PURPOSE OF THIS SUBROUTINE:
   12934              :         // Creates a shaded window construction for windows whose WindowShadingControl
   12935              :         // has a shading device specified instead of a shaded construction
   12936              : 
   12937              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
   12938              :         int ConstrNewSh;          // Number of shaded construction that is created
   12939            0 :         std::string ConstrNameSh; // Shaded construction name
   12940              : 
   12941            0 :         auto &s_mat = state.dataMaterial;
   12942            0 :         auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
   12943              : 
   12944            0 :         std::string const &ShDevName = s_mat->materials(ShDevNum)->Name;
   12945            0 :         int ConstrNum = surfTemp.Construction;
   12946            0 :         std::string const &ConstrName = state.dataConstruction->Construct(ConstrNum).Name;
   12947              : 
   12948            0 :         if (ANY_INTERIOR_SHADE_BLIND(state.dataSurface->WindowShadingControl(WSCPtr).ShadingType)) {
   12949            0 :             ConstrNameSh = ConstrName + ':' + ShDevName + ":INT";
   12950              :         } else {
   12951            0 :             ConstrNameSh = ConstrName + ':' + ShDevName + ":EXT";
   12952              :         }
   12953              : 
   12954              :         // If this construction name already exists, set the surface's shaded construction number to it
   12955              : 
   12956            0 :         ConstrNewSh = Util::FindItemInList(ConstrNameSh, state.dataConstruction->Construct);
   12957              : 
   12958            0 :         if (ConstrNewSh > 0) {
   12959            0 :             surfTemp.shadedConstructionList[shadeControlIndex] = ConstrNewSh;
   12960            0 :             surfTemp.activeShadedConstruction = ConstrNewSh; // set the active to the current for now
   12961              :         } else {
   12962              : 
   12963              :             // Create new construction
   12964              : 
   12965            0 :             ConstrNewSh = state.dataHeatBal->TotConstructs + 1;
   12966            0 :             surfTemp.shadedConstructionList[shadeControlIndex] = ConstrNewSh;
   12967            0 :             surfTemp.activeShadedConstruction = ConstrNewSh; // set the active to the current for now
   12968            0 :             state.dataHeatBal->TotConstructs = ConstrNewSh;
   12969            0 :             state.dataConstruction->Construct.redimension(state.dataHeatBal->TotConstructs);
   12970            0 :             state.dataHeatBal->NominalRforNominalUCalculation.redimension(state.dataHeatBal->TotConstructs);
   12971            0 :             state.dataHeatBal->NominalRforNominalUCalculation(state.dataHeatBal->TotConstructs) = 0.0;
   12972            0 :             state.dataHeatBal->NominalU.redimension(state.dataHeatBal->TotConstructs);
   12973            0 :             state.dataHeatBal->NominalU(state.dataHeatBal->TotConstructs) = 0.0;
   12974            0 :             state.dataHeatBal->NominalUBeforeAdjusted.redimension(state.dataHeatBal->TotConstructs);
   12975            0 :             state.dataHeatBal->CoeffAdjRatio.redimension(state.dataHeatBal->TotConstructs) = 1.0;
   12976              : 
   12977            0 :             state.dataConstruction->Construct(state.dataHeatBal->TotConstructs).setArraysBasedOnMaxSolidWinLayers(state);
   12978              : 
   12979            0 :             int TotLayersOld = state.dataConstruction->Construct(ConstrNum).TotLayers;
   12980            0 :             int TotLayersNew = TotLayersOld + 1;
   12981              : 
   12982            0 :             state.dataConstruction->Construct(ConstrNewSh).LayerPoint = 0;
   12983              : 
   12984            0 :             auto const *thisMaterialSh = s_mat->materials(ShDevNum);
   12985            0 :             auto &thisConstructNewSh = state.dataConstruction->Construct(ConstrNewSh);
   12986            0 :             if (state.dataSurface->WindowShadingControl(WSCPtr).ShadingType == DataSurfaces::WinShadingType::IntShade ||
   12987            0 :                 state.dataSurface->WindowShadingControl(WSCPtr).ShadingType == DataSurfaces::WinShadingType::IntBlind) {
   12988              :                 // Interior shading device
   12989            0 :                 thisConstructNewSh.LayerPoint({1, TotLayersOld}) = state.dataConstruction->Construct(ConstrNum).LayerPoint({1, TotLayersOld});
   12990            0 :                 thisConstructNewSh.LayerPoint(TotLayersNew) = ShDevNum;
   12991            0 :                 thisConstructNewSh.InsideAbsorpSolar = thisMaterialSh->AbsorpSolar;
   12992            0 :                 auto const *thisMaterialShLayer1 = s_mat->materials(state.dataConstruction->Construct(ConstrNewSh).LayerPoint(1));
   12993            0 :                 thisConstructNewSh.OutsideAbsorpSolar = thisMaterialShLayer1->AbsorpSolar;
   12994            0 :                 thisConstructNewSh.OutsideAbsorpThermal = thisMaterialShLayer1->AbsorpThermalFront;
   12995              :             } else {
   12996              :                 // Exterior shading device
   12997            0 :                 thisConstructNewSh.LayerPoint(1) = ShDevNum;
   12998            0 :                 thisConstructNewSh.LayerPoint({2, TotLayersNew}) = state.dataConstruction->Construct(ConstrNum).LayerPoint({1, TotLayersOld});
   12999            0 :                 auto const *thisMaterialShInside = s_mat->materials(state.dataConstruction->Construct(ConstrNewSh).LayerPoint(TotLayersNew));
   13000            0 :                 thisConstructNewSh.InsideAbsorpSolar = thisMaterialShInside->AbsorpSolar;
   13001            0 :                 thisConstructNewSh.OutsideAbsorpSolar = thisMaterialSh->AbsorpSolar;
   13002            0 :                 thisConstructNewSh.OutsideAbsorpThermal = thisMaterialSh->AbsorpThermalFront;
   13003              :             }
   13004              :             // The following InsideAbsorpThermal applies only to inside glass; it is corrected
   13005              :             //  later in InitGlassOpticalCalculations if construction has inside shade or blind.
   13006            0 :             thisConstructNewSh.InsideAbsorpThermal =
   13007            0 :                 s_mat->materials(state.dataConstruction->Construct(ConstrNum).LayerPoint(TotLayersOld))->AbsorpThermalBack;
   13008            0 :             thisConstructNewSh.OutsideRoughness = Material::SurfaceRoughness::VerySmooth;
   13009            0 :             thisConstructNewSh.DayltPropPtr = 0;
   13010            0 :             thisConstructNewSh.CTFCross.fill(0.0);
   13011            0 :             thisConstructNewSh.CTFFlux.fill(0.0);
   13012            0 :             thisConstructNewSh.CTFInside.fill(0.0);
   13013            0 :             thisConstructNewSh.CTFOutside.fill(0.0);
   13014            0 :             thisConstructNewSh.CTFSourceIn.fill(0.0);
   13015            0 :             thisConstructNewSh.CTFSourceOut.fill(0.0);
   13016            0 :             thisConstructNewSh.CTFTimeStep = 0.0;
   13017            0 :             thisConstructNewSh.CTFTSourceOut.fill(0.0);
   13018            0 :             thisConstructNewSh.CTFTSourceIn.fill(0.0);
   13019            0 :             thisConstructNewSh.CTFTSourceQ.fill(0.0);
   13020            0 :             thisConstructNewSh.CTFTUserOut.fill(0.0);
   13021            0 :             thisConstructNewSh.CTFTUserIn.fill(0.0);
   13022            0 :             thisConstructNewSh.CTFTUserSource.fill(0.0);
   13023            0 :             thisConstructNewSh.NumHistories = 0;
   13024            0 :             thisConstructNewSh.NumCTFTerms = 0;
   13025            0 :             thisConstructNewSh.UValue = 0.0;
   13026            0 :             thisConstructNewSh.SourceSinkPresent = false;
   13027            0 :             thisConstructNewSh.SolutionDimensions = 0;
   13028            0 :             thisConstructNewSh.SourceAfterLayer = 0;
   13029            0 :             thisConstructNewSh.TempAfterLayer = 0;
   13030            0 :             thisConstructNewSh.ThicknessPerpend = 0.0;
   13031            0 :             thisConstructNewSh.AbsDiff = 0.0;
   13032            0 :             thisConstructNewSh.AbsDiffBack = 0.0;
   13033            0 :             thisConstructNewSh.AbsDiffShade = 0.0;
   13034            0 :             thisConstructNewSh.AbsDiffBackShade = 0.0;
   13035            0 :             thisConstructNewSh.ShadeAbsorpThermal = 0.0;
   13036            0 :             std::fill(thisConstructNewSh.AbsBeamShadeCoef.begin(), thisConstructNewSh.AbsBeamShadeCoef.end(), 0.0);
   13037            0 :             thisConstructNewSh.TransDiff = 0.0;
   13038            0 :             thisConstructNewSh.TransDiffVis = 0.0;
   13039            0 :             thisConstructNewSh.ReflectSolDiffBack = 0.0;
   13040            0 :             thisConstructNewSh.ReflectSolDiffFront = 0.0;
   13041            0 :             thisConstructNewSh.ReflectVisDiffBack = 0.0;
   13042            0 :             thisConstructNewSh.ReflectVisDiffFront = 0.0;
   13043            0 :             std::fill(thisConstructNewSh.TransSolBeamCoef.begin(), thisConstructNewSh.TransSolBeamCoef.end(), 0.0);
   13044            0 :             std::fill(thisConstructNewSh.TransVisBeamCoef.begin(), thisConstructNewSh.TransVisBeamCoef.end(), 0.0);
   13045            0 :             std::fill(thisConstructNewSh.ReflSolBeamFrontCoef.begin(), thisConstructNewSh.ReflSolBeamFrontCoef.end(), 0.0);
   13046            0 :             std::fill(thisConstructNewSh.ReflSolBeamBackCoef.begin(), thisConstructNewSh.ReflSolBeamBackCoef.end(), 0.0);
   13047            0 :             thisConstructNewSh.W5FrameDivider = 0;
   13048            0 :             thisConstructNewSh.FromWindow5DataFile = false;
   13049              : 
   13050            0 :             thisConstructNewSh.Name = ConstrNameSh;
   13051            0 :             thisConstructNewSh.TotLayers = TotLayersNew;
   13052            0 :             thisConstructNewSh.TotSolidLayers = state.dataConstruction->Construct(ConstrNum).TotSolidLayers + 1;
   13053            0 :             thisConstructNewSh.TotGlassLayers = state.dataConstruction->Construct(ConstrNum).TotGlassLayers;
   13054            0 :             thisConstructNewSh.TypeIsWindow = true;
   13055            0 :             thisConstructNewSh.IsUsed = true;
   13056              : 
   13057            0 :             for (int Layer = 1; Layer <= state.dataHeatBal->MaxSolidWinLayers; ++Layer) {
   13058            0 :                 std::fill(thisConstructNewSh.AbsBeamCoef(Layer).begin(), thisConstructNewSh.AbsBeamCoef(Layer).end(), 0.0);
   13059            0 :                 std::fill(thisConstructNewSh.AbsBeamBackCoef(Layer).begin(), thisConstructNewSh.AbsBeamBackCoef(Layer).end(), 0.0);
   13060              :             }
   13061              :         }
   13062            0 :     }
   13063              : 
   13064            0 :     void CreateStormWindowConstructions(EnergyPlusData &state)
   13065              :     {
   13066              :         // For windows with an associated StormWindow object, creates a construction
   13067              :         // consisting of the base construction plus a storm window and air gap on the outside.
   13068              :         // If the window has an interior or between-glass shade/blind, also creates a
   13069              :         // construction consisting of the storm window added to the shaded construction.
   13070            0 :         DisplayString(state, "Creating Storm Window Constructions");
   13071              : 
   13072            0 :         auto &s_mat = state.dataMaterial;
   13073              : 
   13074            0 :         for (int StormWinNum = 1; StormWinNum <= state.dataSurface->TotStormWin; ++StormWinNum) {
   13075            0 :             int SurfNum = state.dataSurface->StormWindow(StormWinNum).BaseWindowNum; // Surface number
   13076            0 :             auto &surf = state.dataSurface->Surface(SurfNum);
   13077            0 :             int ConstrNum = surf.Construction; // Number of unshaded construction
   13078              :             // Fatal error if base construction has more than three glass layers
   13079            0 :             if (state.dataConstruction->Construct(ConstrNum).TotGlassLayers > 3) {
   13080            0 :                 ShowFatalError(state, format("Window={} has more than 3 glass layers; a storm window cannot be applied.", surf.Name));
   13081              :             }
   13082              : 
   13083              :             // create unshaded construction with storm window
   13084            0 :             const std::string ChrNum = fmt::to_string(StormWinNum);
   13085            0 :             std::string ConstrNameSt = "BARECONSTRUCTIONWITHSTORMWIN:" + ChrNum; // Name of unshaded construction with storm window
   13086              :             // If this construction name already exists, set the surface's storm window construction number to it
   13087            0 :             int ConstrNewSt = Util::FindItemInList(ConstrNameSt,
   13088            0 :                                                    state.dataConstruction->Construct,
   13089            0 :                                                    state.dataHeatBal->TotConstructs); // Number of unshaded storm window construction that is created
   13090              :             // If necessary, create new material corresponding to the air layer between the storm window and the rest of the window
   13091            0 :             int MatNewStAir = createAirMaterialFromDistance(state, state.dataSurface->StormWindow(StormWinNum).StormWinDistance, "AIR:STORMWIN:");
   13092            0 :             if (ConstrNewSt == 0) {
   13093            0 :                 ConstrNewSt = createConstructionWithStorm(
   13094            0 :                     state, ConstrNum, ConstrNameSt, state.dataSurface->StormWindow(StormWinNum).StormWinMaterialNum, MatNewStAir);
   13095              :             }
   13096            0 :             state.dataSurface->SurfWinStormWinConstr(SurfNum) = ConstrNewSt;
   13097              : 
   13098              :             // create shaded constructions with storm window
   13099            0 :             surf.shadedStormWinConstructionList.resize(surf.shadedConstructionList.size(),
   13100            0 :                                                        0); // make the shaded storm window size the same size as the number of shaded constructions
   13101            0 :             for (std::size_t iConstruction = 0; iConstruction < surf.shadedConstructionList.size(); ++iConstruction) {
   13102            0 :                 int curConstruction = surf.shadedConstructionList[iConstruction];
   13103              :                 // Set ShAndSt, which is true if the window has a shaded construction to which a storm window
   13104              :                 // can be added. (A storm window can be added if there is an interior shade or blind and up to three
   13105              :                 // glass layers, or there is a between-glass shade or blind and two glass layers.)
   13106            0 :                 bool ShAndSt = false; // True if unshaded and shaded window can have a storm window
   13107            0 :                 int TotLayers = state.dataConstruction->Construct(curConstruction).TotLayers;            // Total layers in a construction
   13108            0 :                 int MatIntSh = state.dataConstruction->Construct(curConstruction).LayerPoint(TotLayers); // Material number of interior shade or blind
   13109            0 :                 int MatBetweenGlassSh = 0; // Material number of between-glass shade or blind
   13110            0 :                 if (TotLayers == 5) MatBetweenGlassSh = state.dataConstruction->Construct(curConstruction).LayerPoint(3);
   13111            0 :                 if (state.dataConstruction->Construct(curConstruction).TotGlassLayers <= 3 &&
   13112            0 :                     (s_mat->materials(MatIntSh)->group == Material::Group::Shade || s_mat->materials(MatIntSh)->group == Material::Group::Blind))
   13113            0 :                     ShAndSt = true;
   13114            0 :                 if (MatBetweenGlassSh > 0) {
   13115            0 :                     if (s_mat->materials(MatBetweenGlassSh)->group == Material::Group::Shade ||
   13116            0 :                         s_mat->materials(MatBetweenGlassSh)->group == Material::Group::Blind) {
   13117            0 :                         ShAndSt = true;
   13118              :                     } else {
   13119            0 :                         ShowContinueError(state, format("Window={} has a shaded construction to which a storm window cannot be applied.", surf.Name));
   13120            0 :                         ShowContinueError(state, "Storm windows can only be applied to shaded constructions that:");
   13121            0 :                         ShowContinueError(state, "have an interior shade or blind and up to three glass layers, or");
   13122            0 :                         ShowContinueError(state, "have a between-glass shade or blind and two glass layers.");
   13123            0 :                         ShowFatalError(state, "EnergyPlus is exiting due to reason stated above.");
   13124              :                     }
   13125              :                 }
   13126            0 :                 if (ShAndSt) {
   13127            0 :                     std::string ConstrNameStSh = "SHADEDCONSTRUCTIONWITHSTORMWIN:" + state.dataConstruction->Construct(iConstruction).Name + ":" +
   13128            0 :                                                  ChrNum; // Name of shaded construction with storm window
   13129            0 :                     int ConstrNewStSh = createConstructionWithStorm(
   13130            0 :                         state, ConstrNum, ConstrNameStSh, state.dataSurface->StormWindow(StormWinNum).StormWinMaterialNum, MatNewStAir);
   13131            0 :                     surf.shadedStormWinConstructionList[iConstruction] = ConstrNewStSh; // put in same index as the shaded construction
   13132            0 :                 }
   13133              :             } // end of loop for shaded constructions
   13134            0 :         }     // end of loop over storm window objects
   13135            0 :     }
   13136              : 
   13137            3 :     int createAirMaterialFromDistance(EnergyPlusData &state, Real64 distance, std::string_view namePrefix)
   13138              :     {
   13139            3 :         auto const &s_mat = state.dataMaterial;
   13140              : 
   13141            3 :         int mmDistance = int(1000 * distance); // Thickness of air gap in mm (usually between storm window and rest of window)
   13142            3 :         std::string MatNameStAir = format("{}{}MM", namePrefix, mmDistance); // Name of created air layer material
   13143            3 :         int matNum = Material::GetMaterialNum(state, MatNameStAir);
   13144            3 :         if (matNum != 0) return matNum;
   13145              : 
   13146              :         // Create new material
   13147            2 :         auto *mat = new Material::MaterialGasMix;
   13148            2 :         mat->Name = MatNameStAir;
   13149            2 :         mat->group = Material::Group::Gas;
   13150              : 
   13151            2 :         s_mat->materials.push_back(mat);
   13152            2 :         mat->Num = s_mat->materials.isize();
   13153            2 :         s_mat->materialMap.insert_or_assign(Util::makeUPPER(mat->Name), mat->Num);
   13154              : 
   13155            2 :         mat->Roughness = Material::SurfaceRoughness::MediumRough;
   13156            2 :         mat->Conductivity = 0.0;
   13157            2 :         mat->Density = 0.0;
   13158            2 :         mat->Resistance = 0.0;
   13159            2 :         mat->SpecHeat = 0.0;
   13160            2 :         mat->Thickness = distance;
   13161            2 :         mat->numGases = 1;
   13162            2 :         mat->gases[0] = Material::gases[(int)Material::GasType::Air];
   13163            2 :         mat->gasFracts[0] = 1.0;
   13164            2 :         mat->AbsorpSolar = 0.0;
   13165            2 :         mat->AbsorpThermal = 0.0;
   13166            2 :         mat->AbsorpVisible = 0.0;
   13167            2 :         return mat->Num;
   13168            3 :     }
   13169              : 
   13170              :     // create a new construction with storm based on an old construction and storm and gap materials
   13171            1 :     int createConstructionWithStorm(EnergyPlusData &state, int oldConstruction, std::string name, int stormMaterial, int gapMaterial)
   13172              :     {
   13173            1 :         int newConstruct = Util::FindItemInList(name,
   13174            1 :                                                 state.dataConstruction->Construct,
   13175            1 :                                                 state.dataHeatBal->TotConstructs); // Number of shaded storm window construction that is created
   13176            1 :         if (newConstruct == 0) {
   13177            1 :             auto &s_mat = state.dataMaterial;
   13178            1 :             state.dataHeatBal->TotConstructs = state.dataHeatBal->TotConstructs + 1;
   13179            1 :             newConstruct = state.dataHeatBal->TotConstructs;
   13180            1 :             state.dataConstruction->Construct.redimension(state.dataHeatBal->TotConstructs);
   13181            1 :             state.dataHeatBal->NominalRforNominalUCalculation.redimension(state.dataHeatBal->TotConstructs);
   13182            1 :             state.dataHeatBal->NominalU.redimension(state.dataHeatBal->TotConstructs);
   13183            1 :             state.dataHeatBal->NominalUBeforeAdjusted.redimension(state.dataHeatBal->TotConstructs);
   13184            1 :             state.dataHeatBal->CoeffAdjRatio.redimension(state.dataHeatBal->TotConstructs) = 1.0;
   13185              : 
   13186            1 :             auto &thisConstruct = state.dataConstruction->Construct(state.dataHeatBal->TotConstructs);
   13187              :             // these Construct arrays dimensioned based on MaxSolidWinLayers
   13188            1 :             thisConstruct.setArraysBasedOnMaxSolidWinLayers(state);
   13189              : 
   13190            1 :             int TotLayersOld = state.dataConstruction->Construct(oldConstruction).TotLayers;
   13191            1 :             thisConstruct.LayerPoint({1, Construction::MaxLayersInConstruct}) = 0;
   13192            1 :             thisConstruct.LayerPoint(1) = stormMaterial;
   13193            1 :             thisConstruct.LayerPoint(2) = gapMaterial;
   13194            1 :             thisConstruct.LayerPoint({3, TotLayersOld + 2}) = state.dataConstruction->Construct(oldConstruction).LayerPoint({1, TotLayersOld});
   13195            1 :             thisConstruct.Name = name;
   13196            1 :             thisConstruct.TotLayers = TotLayersOld + 2;
   13197            1 :             thisConstruct.TotSolidLayers = state.dataConstruction->Construct(oldConstruction).TotSolidLayers + 1;
   13198            1 :             thisConstruct.TotGlassLayers = state.dataConstruction->Construct(oldConstruction).TotGlassLayers + 1;
   13199            1 :             thisConstruct.TypeIsWindow = true;
   13200            1 :             thisConstruct.InsideAbsorpVis = 0.0;
   13201            1 :             thisConstruct.OutsideAbsorpVis = 0.0;
   13202            1 :             thisConstruct.InsideAbsorpSolar = 0.0;
   13203            1 :             thisConstruct.OutsideAbsorpSolar = 0.0;
   13204            1 :             thisConstruct.InsideAbsorpThermal = state.dataConstruction->Construct(oldConstruction).InsideAbsorpThermal;
   13205            1 :             thisConstruct.OutsideAbsorpThermal = s_mat->materials(stormMaterial)->AbsorpThermalFront;
   13206            1 :             thisConstruct.OutsideRoughness = Material::SurfaceRoughness::VerySmooth;
   13207            1 :             thisConstruct.DayltPropPtr = 0;
   13208            1 :             thisConstruct.CTFCross.fill(0.0);
   13209            1 :             thisConstruct.CTFFlux.fill(0.0);
   13210            1 :             thisConstruct.CTFInside.fill(0.0);
   13211            1 :             thisConstruct.CTFOutside.fill(0.0);
   13212            1 :             thisConstruct.CTFSourceIn.fill(0.0);
   13213            1 :             thisConstruct.CTFSourceOut.fill(0.0);
   13214            1 :             thisConstruct.CTFTimeStep = 0.0;
   13215            1 :             thisConstruct.CTFTSourceOut.fill(0.0);
   13216            1 :             thisConstruct.CTFTSourceIn.fill(0.0);
   13217            1 :             thisConstruct.CTFTSourceQ.fill(0.0);
   13218            1 :             thisConstruct.CTFTUserOut.fill(0.0);
   13219            1 :             thisConstruct.CTFTUserIn.fill(0.0);
   13220            1 :             thisConstruct.CTFTUserSource.fill(0.0);
   13221            1 :             thisConstruct.NumHistories = 0;
   13222            1 :             thisConstruct.NumCTFTerms = 0;
   13223            1 :             thisConstruct.UValue = 0.0;
   13224            1 :             thisConstruct.SourceSinkPresent = false;
   13225            1 :             thisConstruct.SolutionDimensions = 0;
   13226            1 :             thisConstruct.SourceAfterLayer = 0;
   13227            1 :             thisConstruct.TempAfterLayer = 0;
   13228            1 :             thisConstruct.ThicknessPerpend = 0.0;
   13229            1 :             thisConstruct.AbsDiffIn = 0.0;
   13230            1 :             thisConstruct.AbsDiffOut = 0.0;
   13231            1 :             thisConstruct.AbsDiff = 0.0;
   13232            1 :             thisConstruct.AbsDiffBack = 0.0;
   13233            1 :             thisConstruct.AbsDiffShade = 0.0;
   13234            1 :             thisConstruct.AbsDiffBackShade = 0.0;
   13235            1 :             thisConstruct.ShadeAbsorpThermal = 0.0;
   13236            1 :             std::fill(thisConstruct.AbsBeamShadeCoef.begin(), thisConstruct.AbsBeamShadeCoef.end(), 0.0);
   13237            1 :             thisConstruct.TransDiff = 0.0;
   13238            1 :             thisConstruct.TransDiffVis = 0.0;
   13239            1 :             thisConstruct.ReflectSolDiffBack = 0.0;
   13240            1 :             thisConstruct.ReflectSolDiffFront = 0.0;
   13241            1 :             thisConstruct.ReflectVisDiffBack = 0.0;
   13242            1 :             thisConstruct.ReflectVisDiffFront = 0.0;
   13243            1 :             std::fill(thisConstruct.TransSolBeamCoef.begin(), thisConstruct.TransSolBeamCoef.end(), 0.0);
   13244            1 :             std::fill(thisConstruct.TransVisBeamCoef.begin(), thisConstruct.TransVisBeamCoef.end(), 0.0);
   13245            1 :             std::fill(thisConstruct.ReflSolBeamFrontCoef.begin(), thisConstruct.ReflSolBeamFrontCoef.end(), 0.0);
   13246            1 :             std::fill(thisConstruct.ReflSolBeamBackCoef.begin(), thisConstruct.ReflSolBeamBackCoef.end(), 0.0);
   13247            1 :             thisConstruct.W5FrameDivider = 0;
   13248            1 :             thisConstruct.FromWindow5DataFile = false;
   13249            1 :             thisConstruct.W5FileMullionWidth = 0.0;
   13250            1 :             thisConstruct.W5FileMullionOrientation = DataWindowEquivalentLayer::Orientation::Invalid;
   13251            1 :             thisConstruct.W5FileGlazingSysWidth = 0.0;
   13252            1 :             thisConstruct.W5FileGlazingSysHeight = 0.0;
   13253            1 :             for (int Layer = 1; Layer <= state.dataHeatBal->MaxSolidWinLayers; ++Layer) {
   13254            0 :                 std::fill(thisConstruct.AbsBeamCoef(Layer).begin(), thisConstruct.AbsBeamCoef(Layer).end(), 0.0);
   13255            0 :                 std::fill(thisConstruct.AbsBeamBackCoef(Layer).begin(), thisConstruct.AbsBeamBackCoef(Layer).end(), 0.0);
   13256              :             }
   13257              :         }
   13258            1 :         return (newConstruct);
   13259              :     }
   13260              : 
   13261            0 :     void ModifyWindow(EnergyPlusData &state,
   13262              :                       int const SurfNum,    // SurfNum has construction of glazing system from Window5 Data File;
   13263              :                       bool &ErrorsFound,    // Set to true if errors found
   13264              :                       int &AddedSubSurfaces // Subsurfaces added when window references a
   13265              :     )
   13266              :     {
   13267              :         // SUBROUTINE INFORMATION:
   13268              :         //       AUTHOR         Fred Winkelmann
   13269              :         //       DATE WRITTEN   Feb 2002
   13270              :         //       MODIFIED       June 2004, FCW: SinAzim, CosAzim, SinTilt, CosTilt, OutNormVec, GrossArea
   13271              :         //                       and Perimeter weren't being set for created window for case when
   13272              :         //                       window from Window5DataFile had two different glazing systems. Also,
   13273              :         //                       GrossArea and Perimeter of original window were not being recalculated.
   13274              :         //                      October 2007, LKL: Net area for shading calculations was not being
   13275              :         //                       recalculated.
   13276              : 
   13277              :         // PURPOSE OF THIS SUBROUTINE:
   13278              :         // If a window from the Window5DataFile has one glazing system, modify the
   13279              :         // vertex coordinates of the original window to correspond to the dimensions
   13280              :         // of the glazing system on the Data File.
   13281              :         // If a window from the Window5DataFile has two different glazing systems, split
   13282              :         // the window into two separate windows with different properties and adjust the
   13283              :         // vertices of these windows taking into account the dimensions of the glazing systems
   13284              :         // on the Data File and the width and orientation of the mullion that separates
   13285              :         // the glazing systems.
   13286              : 
   13287              :         // SUBROUTINE ARGUMENT DEFINITIONS:
   13288              :         // If there is a second glazing system on the Data File, SurfNum+1
   13289              :         // has the construction of the second glazing system.
   13290              : 
   13291              :         // 2-glazing system Window5 data file entry
   13292              : 
   13293              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
   13294              :         Real64 H; // Height and width of original window (m)
   13295              :         Real64 W;
   13296              :         // unused1208  REAL(r64)    :: MulWidth                        ! Mullion width (m)
   13297              :         Real64 h1; // height and width of first glazing system (m)
   13298              :         Real64 w1;
   13299              :         // unused1208  REAL(r64)    :: h2,w2                           ! height and width of second glazing system (m)
   13300              :         // unused1208  type (rectangularwindow) :: NewCoord
   13301              :         int IConst;             // Construction number of first glazing system
   13302              :         int IConst2;            // Construction number of second glazing system
   13303            0 :         std::string Const2Name; // Name of construction of second glazing system
   13304              :         // unused1208  REAL(r64)    :: AreaNew                         ! Sum of areas of the two glazing systems (m2)
   13305              : 
   13306            0 :         auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
   13307              : 
   13308              :         struct rectangularwindow
   13309              :         {
   13310              :             // Members
   13311              :             Array1D<Vector> Vertex;
   13312              : 
   13313              :             // Default Constructor
   13314            0 :             rectangularwindow() : Vertex(4)
   13315              :             {
   13316            0 :             }
   13317              :         };
   13318              : 
   13319              :         // Object Data
   13320            0 :         Vector TVect;
   13321            0 :         rectangularwindow OriginalCoord;
   13322              : 
   13323            0 :         IConst = surfTemp.Construction;
   13324              : 
   13325              :         // Height and width of original window
   13326            0 :         TVect = surfTemp.Vertex(3) - surfTemp.Vertex(2);
   13327            0 :         W = Vectors::VecLength(TVect); // SQRT((X(3)-X(2))**2 + (Y(3)-Y(2))**2 + (Z(3)-Z(2))**2)
   13328            0 :         TVect = surfTemp.Vertex(2) - surfTemp.Vertex(1);
   13329            0 :         H = Vectors::VecLength(TVect); // SQRT((X(1)-X(2))**2 + (Y(1)-Y(2))**2 + (Z(1)-Z(2))**2)
   13330              : 
   13331              :         // Save coordinates of original window in case Window 5 data overwrites.
   13332            0 :         OriginalCoord.Vertex({1, surfTemp.Sides}) = surfTemp.Vertex({1, surfTemp.Sides});
   13333              : 
   13334              :         // Height and width of first glazing system
   13335            0 :         h1 = state.dataConstruction->Construct(IConst).W5FileGlazingSysHeight;
   13336            0 :         w1 = state.dataConstruction->Construct(IConst).W5FileGlazingSysWidth;
   13337              : 
   13338            0 :         Const2Name = state.dataConstruction->Construct(IConst).Name + ":2";
   13339            0 :         IConst2 = Util::FindItemInList(Const2Name, state.dataConstruction->Construct);
   13340              : 
   13341            0 :         if (IConst2 == 0) { // Only one glazing system on Window5 Data File for this window.
   13342              : 
   13343              :             // So... original dimensions and area of window are used (entered in IDF)
   13344              :             // Warning if dimensions of original window differ from those on Data File by more than 10%
   13345              : 
   13346            0 :             if (std::abs((H - h1) / H) > 0.10 || std::abs((W - w1) / W) > 0.10) {
   13347              : 
   13348            0 :                 if (state.dataGlobal->DisplayExtraWarnings) {
   13349            0 :                     ShowWarningError(state,
   13350            0 :                                      format("SurfaceGeometry: ModifyWindow: Window {} uses the Window5 Data File Construction {}",
   13351            0 :                                             surfTemp.Name,
   13352            0 :                                             state.dataConstruction->Construct(IConst).Name));
   13353            0 :                     ShowContinueError(state, format("The height {:.3R}(m) or width  (m) of this window differs by more than 10%{:.3R}", H, W));
   13354            0 :                     ShowContinueError(state,
   13355            0 :                                       format("from the corresponding height {:.3R} (m) or width  (m) on the Window5 Data file.{:.3R}", h1, w1));
   13356            0 :                     ShowContinueError(state, "This will affect the frame heat transfer calculation if the frame in the Data File entry");
   13357            0 :                     ShowContinueError(state, "is not uniform, i.e., has sections with different geometry and/or thermal properties.");
   13358              :                 } else {
   13359            0 :                     ++state.dataSurfaceGeometry->Warning1Count;
   13360              :                 }
   13361              :             }
   13362              : 
   13363              :             // Calculate net area for base surface
   13364            0 :             state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).Area -= surfTemp.Area;
   13365            0 :             if (state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).Area <= 0.0) {
   13366            0 :                 ShowSevereError(
   13367              :                     state,
   13368            0 :                     format("Subsurfaces have too much area for base surface={}", state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).Name));
   13369            0 :                 ShowContinueError(state, format("Subsurface creating error={}", surfTemp.Name));
   13370            0 :                 ErrorsFound = true;
   13371              :             }
   13372              : 
   13373              :             // Net area of base surface with unity window multipliers (used in shadowing checks)
   13374            0 :             state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).NetAreaShadowCalc -= surfTemp.Area / surfTemp.Multiplier;
   13375              : 
   13376              :         } else { // Two glazing systems on Window5 data file for this window
   13377              : 
   13378              :             // if exterior window, okay.
   13379              : 
   13380            0 :             if (surfTemp.ExtBoundCond == DataSurfaces::ExternalEnvironment) {
   13381              :                 // There are two glazing systems (separated by a vertical or horizontal mullion) on the Window5 Data File.
   13382              :                 // Fill in geometry data for the second window (corresponding to the second glazing system on the data file.
   13383              :                 // The first glazing system is assumed to be at left for vertical mullion, at bottom for horizontal mullion.
   13384              :                 // The second glazing system is assumed to be at right for vertical mullion, at top for horizontal mullion.
   13385              :                 // The lower left-hand corner of the original window (its vertex #2) is assumed to coincide with
   13386              :                 // vertex #2 of the first glazing system.
   13387              : 
   13388            0 :                 if (state.dataGlobal->DisplayExtraWarnings) {
   13389            0 :                     ShowMessage(state,
   13390            0 :                                 format("SurfaceGeometry: ModifyWindow: Window {} has been replaced with the Window 5/6 two glazing system=\"{}\".",
   13391            0 :                                        surfTemp.Name,
   13392            0 :                                        state.dataConstruction->Construct(IConst).Name));
   13393            0 :                     ShowContinueError(state, "Note that originally entered dimensions are overridden.");
   13394              :                 } else {
   13395            0 :                     ++state.dataSurfaceGeometry->Warning2Count;
   13396              :                 }
   13397              : 
   13398              :                 // Allocate another window
   13399            0 :                 AddWindow(state, SurfNum, ErrorsFound, AddedSubSurfaces);
   13400              : 
   13401            0 :             } else if (surfTemp.ExtBoundCond > 0) { // Interior window, specified  ! not external environment
   13402              : 
   13403            0 :                 if (state.dataGlobal->DisplayExtraWarnings) {
   13404            0 :                     ShowWarningError(
   13405              :                         state,
   13406            0 :                         format("SurfaceGeometry: ModifyWindow: Interior Window {} has been replaced with the Window 5/6 two glazing system=\"{}\".",
   13407            0 :                                surfTemp.Name,
   13408            0 :                                state.dataConstruction->Construct(IConst).Name));
   13409            0 :                     ShowContinueError(
   13410              :                         state, "Please check to make sure interior window is correct. Note that originally entered dimensions are overridden.");
   13411              :                 } else {
   13412            0 :                     ++state.dataSurfaceGeometry->Warning3Count;
   13413              :                 }
   13414              : 
   13415            0 :                 AddWindow(state, SurfNum, ErrorsFound, AddedSubSurfaces);
   13416              : 
   13417              :             } else { // Interior window, specified not entered
   13418              : 
   13419            0 :                 ShowSevereError(state, format("SurfaceGeometry: ModifyWindow: Interior Window {} is a window in an adjacent zone.", surfTemp.Name));
   13420            0 :                 ShowContinueError(
   13421              :                     state,
   13422            0 :                     format("Attempted to add/reverse Window 5/6 multiple glazing system=\"{}\".", state.dataConstruction->Construct(IConst).Name));
   13423            0 :                 ShowContinueError(state, "Cannot use these Window 5/6 constructs for these Interior Windows. Program will terminate.");
   13424            0 :                 ErrorsFound = true;
   13425              :             }
   13426              : 
   13427              :         } // End of check if one or two glazing systems are on the Window5 Data File
   13428            0 :     }
   13429              : 
   13430            0 :     void AddWindow(EnergyPlusData &state,
   13431              :                    int const SurfNum,    // SurfNum has construction of glazing system from Window5 Data File;
   13432              :                    bool &ErrorsFound,    // Set to true if errors found
   13433              :                    int &AddedSubSurfaces // Subsurfaces added when window references a
   13434              :     )
   13435              :     {
   13436              :         // SUBROUTINE INFORMATION:
   13437              :         //       AUTHOR         Linda Lawrie
   13438              :         //       DATE WRITTEN   Nov 2008
   13439              : 
   13440              :         // PURPOSE OF THIS SUBROUTINE:
   13441              :         // This routine is called from ModifyWindow to add a window.  Allows it to be
   13442              :         // called in more than one place in the calling routine so as to be able to have
   13443              :         // specific warnings or errors issued.
   13444              : 
   13445              :         // SUBROUTINE ARGUMENT DEFINITIONS:
   13446              :         // If there is a second glazing system on the Data File, SurfNum+1
   13447              :         // has the construction of the second glazing system.
   13448              : 
   13449              :         // 2-glazing system Window5 data file entry
   13450              : 
   13451              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
   13452              :         int loop; // DO loop index
   13453              :         Real64 H; // Height and width of original window (m)
   13454              :         Real64 W;
   13455              :         Real64 MulWidth; // Mullion width (m)
   13456              :         Real64 h1;       // height and width of first glazing system (m)
   13457              :         Real64 w1;
   13458              :         Real64 h2; // height and width of second glazing system (m)
   13459              :         Real64 w2;
   13460              :         Real64 xa; // Vertex intermediate variables (m)
   13461              :         Real64 ya;
   13462              :         Real64 za;
   13463              :         Real64 xb;
   13464              :         Real64 yb;
   13465              :         Real64 zb;
   13466              :         Real64 dx; // Vertex displacements from original window (m)
   13467              :         Real64 dy;
   13468              :         int IConst;             // Construction number of first glazing system
   13469              :         int IConst2;            // Construction number of second glazing system
   13470            0 :         std::string Const2Name; // Name of construction of second glazing system
   13471              :         Real64 AreaNew;         // Sum of areas of the two glazing systems (m2)
   13472              : 
   13473              :         struct rectangularwindow
   13474              :         {
   13475              :             // Members
   13476              :             Array1D<Vector> Vertex;
   13477              : 
   13478              :             // Default Constructor
   13479            0 :             rectangularwindow() : Vertex(4)
   13480              :             {
   13481            0 :             }
   13482              :         };
   13483              : 
   13484              :         // Object Data
   13485            0 :         Vector TVect;
   13486            0 :         rectangularwindow NewCoord;
   13487            0 :         rectangularwindow OriginalCoord;
   13488              : 
   13489            0 :         auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
   13490              : 
   13491            0 :         IConst = surfTemp.Construction;
   13492              : 
   13493              :         // Height and width of original window
   13494            0 :         TVect = surfTemp.Vertex(3) - surfTemp.Vertex(2);
   13495            0 :         W = Vectors::VecLength(TVect); // SQRT((X(3)-X(2))**2 + (Y(3)-Y(2))**2 + (Z(3)-Z(2))**2)
   13496            0 :         TVect = surfTemp.Vertex(2) - surfTemp.Vertex(1);
   13497            0 :         H = Vectors::VecLength(TVect); // SQRT((X(1)-X(2))**2 + (Y(1)-Y(2))**2 + (Z(1)-Z(2))**2)
   13498              : 
   13499              :         // Save coordinates of original window in case Window 5 data overwrites.
   13500            0 :         OriginalCoord.Vertex({1, surfTemp.Sides}) = surfTemp.Vertex({1, surfTemp.Sides});
   13501              : 
   13502              :         // Height and width of first glazing system
   13503            0 :         h1 = state.dataConstruction->Construct(IConst).W5FileGlazingSysHeight;
   13504            0 :         w1 = state.dataConstruction->Construct(IConst).W5FileGlazingSysWidth;
   13505              : 
   13506            0 :         Const2Name = state.dataConstruction->Construct(IConst).Name + ":2";
   13507            0 :         IConst2 = Util::FindItemInList(Const2Name, state.dataConstruction->Construct);
   13508              : 
   13509            0 :         ++AddedSubSurfaces;
   13510            0 :         state.dataSurfaceGeometry->SurfaceTmp.redimension(++state.dataSurface->TotSurfaces);
   13511              : 
   13512            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Vertex.allocate(4);
   13513              : 
   13514            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Name = surfTemp.Name + ":2";
   13515            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Construction = IConst2;
   13516            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).ConstructionStoredInputValue = IConst2;
   13517            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Class = surfTemp.Class;
   13518            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Azimuth = surfTemp.Azimuth;
   13519              :         // Sine and cosine of azimuth and tilt
   13520            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).SinAzim = surfTemp.SinAzim;
   13521            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).CosAzim = surfTemp.CosAzim;
   13522            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).SinTilt = surfTemp.SinTilt;
   13523            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).CosTilt = surfTemp.CosTilt;
   13524              :         // Outward normal unit vector (pointing away from room)
   13525            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Centroid = surfTemp.Centroid;
   13526            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).lcsx = surfTemp.lcsx;
   13527            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).lcsy = surfTemp.lcsy;
   13528            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).lcsz = surfTemp.lcsz;
   13529            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).NewellAreaVector = surfTemp.NewellAreaVector;
   13530            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).OutNormVec = surfTemp.OutNormVec;
   13531            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Reveal = surfTemp.Reveal;
   13532            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Shape = surfTemp.Shape;
   13533            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Sides = surfTemp.Sides;
   13534            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Tilt = surfTemp.Tilt;
   13535            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).convOrientation = Convect::GetSurfConvOrientation(surfTemp.Tilt);
   13536            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).HeatTransSurf = surfTemp.HeatTransSurf;
   13537            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).BaseSurfName = surfTemp.BaseSurfName;
   13538            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).BaseSurf = surfTemp.BaseSurf;
   13539            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).ZoneName = surfTemp.ZoneName;
   13540            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Zone = surfTemp.Zone;
   13541            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).ExtBoundCondName = surfTemp.ExtBoundCondName;
   13542            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).ExtBoundCond = surfTemp.ExtBoundCond;
   13543            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).ExtSolar = surfTemp.ExtSolar;
   13544            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).ExtWind = surfTemp.ExtWind;
   13545            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).ViewFactorGround = surfTemp.ViewFactorGround;
   13546            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).ViewFactorSky = surfTemp.ViewFactorSky;
   13547            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).ViewFactorGroundIR = surfTemp.ViewFactorGroundIR;
   13548            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).ViewFactorSkyIR = surfTemp.ViewFactorSkyIR;
   13549            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).OSCPtr = surfTemp.OSCPtr;
   13550            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).shadowSurfSched = surfTemp.shadowSurfSched;
   13551            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).activeWindowShadingControl = surfTemp.activeWindowShadingControl;
   13552            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).windowShadingControlList = surfTemp.windowShadingControlList;
   13553            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).HasShadeControl = surfTemp.HasShadeControl;
   13554            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).activeShadedConstruction = surfTemp.activeShadedConstruction;
   13555            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).windowShadingControlList = surfTemp.windowShadingControlList;
   13556            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).shadedStormWinConstructionList =
   13557            0 :             surfTemp.shadedStormWinConstructionList;
   13558            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).FrameDivider = surfTemp.FrameDivider;
   13559            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Multiplier = surfTemp.Multiplier;
   13560            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).NetAreaShadowCalc = surfTemp.NetAreaShadowCalc;
   13561              : 
   13562            0 :         MulWidth = state.dataConstruction->Construct(IConst).W5FileMullionWidth;
   13563            0 :         w2 = state.dataConstruction->Construct(IConst2).W5FileGlazingSysWidth;
   13564            0 :         h2 = state.dataConstruction->Construct(IConst2).W5FileGlazingSysHeight;
   13565              : 
   13566              :         // Correction to net area of base surface. Add back in the original glazing area and subtract the
   13567              :         // area of the two glazing systems. Note that for Surface(SurfNum)%Class = 'Window' the effect
   13568              :         // of a window multiplier is included in the glazing area. Note that frame areas are subtracted later.
   13569              : 
   13570            0 :         AreaNew = surfTemp.Multiplier * (h1 * w1 + h2 * w2); // both glazing systems
   13571              :         // Adjust net area for base surface
   13572            0 :         state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).Area -= AreaNew;
   13573              : 
   13574              :         // Net area of base surface with unity window multipliers (used in shadowing checks)
   13575            0 :         state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).NetAreaShadowCalc -= AreaNew / surfTemp.Multiplier;
   13576              : 
   13577              :         // Reset area, etc. of original window
   13578            0 :         surfTemp.Area = surfTemp.Multiplier * (h1 * w1);
   13579            0 :         surfTemp.GrossArea = surfTemp.Area;
   13580            0 :         surfTemp.NetAreaShadowCalc = h1 * w1;
   13581            0 :         surfTemp.Perimeter = 2 * (h1 + w1);
   13582            0 :         surfTemp.Height = h1;
   13583            0 :         surfTemp.Width = w1;
   13584              :         // Set area, etc. of new window
   13585            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Area =
   13586            0 :             state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Multiplier * (h2 * w2);
   13587            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).GrossArea =
   13588            0 :             state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Area;
   13589            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).NetAreaShadowCalc = h2 * w2;
   13590            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Perimeter = 2 * (h2 + w2);
   13591            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Height = h2;
   13592            0 :         state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Width = w2;
   13593              : 
   13594            0 :         if (state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).Area <= 0.0) {
   13595            0 :             ShowSevereError(state,
   13596            0 :                             format("SurfaceGeometry: ModifyWindow: Subsurfaces have too much area for base surface={}",
   13597            0 :                                    state.dataSurfaceGeometry->SurfaceTmp(surfTemp.BaseSurf).Name));
   13598            0 :             ShowContinueError(state, format("Subsurface (window) creating error={}", surfTemp.Name));
   13599            0 :             ShowContinueError(state,
   13600            0 :                               format("This window has been replaced by two windows from the Window5 Data File of total area {:.2R} m2", AreaNew));
   13601            0 :             ErrorsFound = true;
   13602              :         }
   13603              : 
   13604              :         // Assign vertices to the new window; modify vertices of original window.
   13605              :         // In the following, vertices are numbered counter-clockwise with vertex #1 at the upper left.
   13606              : 
   13607            0 :         if (state.dataConstruction->Construct(IConst).W5FileMullionOrientation == DataWindowEquivalentLayer::Orientation::Vertical) {
   13608              : 
   13609              :             // VERTICAL MULLION: original window is modified to become left-hand glazing (system #1);
   13610              :             // new window is created to become right-hand glazing (system #2)
   13611              : 
   13612              :             // Left-hand glazing
   13613              : 
   13614              :             // Vertex 1
   13615            0 :             dx = 0.0;
   13616            0 :             dy = H - h1;
   13617            0 :             xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
   13618            0 :             ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
   13619            0 :             za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
   13620            0 :             xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
   13621            0 :             yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
   13622            0 :             zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
   13623            0 :             NewCoord.Vertex(1).x = xa + (dx / W) * (xb - xa);
   13624            0 :             NewCoord.Vertex(1).y = ya + (dx / W) * (yb - ya);
   13625            0 :             NewCoord.Vertex(1).z = za + (dx / W) * (zb - za);
   13626              : 
   13627              :             // Vertex 2
   13628            0 :             dx = 0.0;
   13629            0 :             dy = H;
   13630            0 :             xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
   13631            0 :             ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
   13632            0 :             za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
   13633            0 :             xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
   13634            0 :             yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
   13635            0 :             zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
   13636            0 :             NewCoord.Vertex(2).x = xa + (dx / W) * (xb - xa);
   13637            0 :             NewCoord.Vertex(2).y = ya + (dx / W) * (yb - ya);
   13638            0 :             NewCoord.Vertex(2).z = za + (dx / W) * (zb - za);
   13639              : 
   13640              :             // Vertex 3
   13641            0 :             dx = w1;
   13642            0 :             dy = H;
   13643            0 :             xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
   13644            0 :             ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
   13645            0 :             za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
   13646            0 :             xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
   13647            0 :             yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
   13648            0 :             zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
   13649            0 :             NewCoord.Vertex(3).x = xa + (dx / W) * (xb - xa);
   13650            0 :             NewCoord.Vertex(3).y = ya + (dx / W) * (yb - ya);
   13651            0 :             NewCoord.Vertex(3).z = za + (dx / W) * (zb - za);
   13652              : 
   13653              :             // Vertex 4
   13654            0 :             dx = w1;
   13655            0 :             dy = H - h1;
   13656            0 :             xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
   13657            0 :             ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
   13658            0 :             za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
   13659            0 :             xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
   13660            0 :             yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
   13661            0 :             zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
   13662            0 :             NewCoord.Vertex(4).x = xa + (dx / W) * (xb - xa);
   13663            0 :             NewCoord.Vertex(4).y = ya + (dx / W) * (yb - ya);
   13664            0 :             NewCoord.Vertex(4).z = za + (dx / W) * (zb - za);
   13665              : 
   13666            0 :             for (loop = 1; loop <= surfTemp.Sides; ++loop) {
   13667            0 :                 surfTemp.Vertex(loop) = NewCoord.Vertex(loop);
   13668              :             }
   13669              : 
   13670              :             // Right-hand glazing
   13671              : 
   13672              :             // Vertex 1
   13673            0 :             dx = w1 + MulWidth;
   13674            0 :             dy = H - (h1 + h2) / 2.0;
   13675            0 :             xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
   13676            0 :             ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
   13677            0 :             za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
   13678            0 :             xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
   13679            0 :             yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
   13680            0 :             zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
   13681            0 :             NewCoord.Vertex(1).x = xa + (dx / W) * (xb - xa);
   13682            0 :             NewCoord.Vertex(1).y = ya + (dx / W) * (yb - ya);
   13683            0 :             NewCoord.Vertex(1).z = za + (dx / W) * (zb - za);
   13684              : 
   13685              :             // Vertex 2
   13686            0 :             dx = w1 + MulWidth;
   13687            0 :             dy = H + (h2 - h1) / 2.0;
   13688            0 :             xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
   13689            0 :             ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
   13690            0 :             za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
   13691            0 :             xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
   13692            0 :             yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
   13693            0 :             zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
   13694            0 :             NewCoord.Vertex(2).x = xa + (dx / W) * (xb - xa);
   13695            0 :             NewCoord.Vertex(2).y = ya + (dx / W) * (yb - ya);
   13696            0 :             NewCoord.Vertex(2).z = za + (dx / W) * (zb - za);
   13697              : 
   13698              :             // Vertex 3
   13699            0 :             dx = w1 + MulWidth + w2;
   13700            0 :             dy = H + (h2 - h1) / 2.0;
   13701            0 :             xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
   13702            0 :             ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
   13703            0 :             za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
   13704            0 :             xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
   13705            0 :             yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
   13706            0 :             zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
   13707            0 :             NewCoord.Vertex(3).x = xa + (dx / W) * (xb - xa);
   13708            0 :             NewCoord.Vertex(3).y = ya + (dx / W) * (yb - ya);
   13709            0 :             NewCoord.Vertex(3).z = za + (dx / W) * (zb - za);
   13710              : 
   13711              :             // Vertex 4
   13712            0 :             dx = w1 + MulWidth + w2;
   13713            0 :             dy = H - (h1 + h2) / 2.0;
   13714            0 :             xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
   13715            0 :             ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
   13716            0 :             za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
   13717            0 :             xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
   13718            0 :             yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
   13719            0 :             zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
   13720            0 :             NewCoord.Vertex(4).x = xa + (dx / W) * (xb - xa);
   13721            0 :             NewCoord.Vertex(4).y = ya + (dx / W) * (yb - ya);
   13722            0 :             NewCoord.Vertex(4).z = za + (dx / W) * (zb - za);
   13723              : 
   13724            0 :             for (loop = 1; loop <= state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Sides; ++loop) {
   13725            0 :                 state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Vertex(loop) = NewCoord.Vertex(loop);
   13726              :             }
   13727              : 
   13728              :         } else { // Horizontal mullion
   13729              : 
   13730              :             // HORIZONTAL MULLION: original window is modified to become bottom glazing (system #1);
   13731              :             // new window is created to become top glazing (system #2)
   13732              : 
   13733              :             // Bottom glazing
   13734              : 
   13735              :             // Vertex 1
   13736            0 :             dx = 0.0;
   13737            0 :             dy = H - h1;
   13738            0 :             xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
   13739            0 :             ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
   13740            0 :             za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
   13741            0 :             xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
   13742            0 :             yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
   13743            0 :             zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
   13744            0 :             NewCoord.Vertex(1).x = xa + (dx / W) * (xb - xa);
   13745            0 :             NewCoord.Vertex(1).y = ya + (dx / W) * (yb - ya);
   13746            0 :             NewCoord.Vertex(1).z = za + (dx / W) * (zb - za);
   13747              : 
   13748              :             // Vertex 2
   13749            0 :             dx = 0.0;
   13750            0 :             dy = H;
   13751            0 :             xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
   13752            0 :             ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
   13753            0 :             za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
   13754            0 :             xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
   13755            0 :             yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
   13756            0 :             zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
   13757            0 :             NewCoord.Vertex(2).x = xa + (dx / W) * (xb - xa);
   13758            0 :             NewCoord.Vertex(2).y = ya + (dx / W) * (yb - ya);
   13759            0 :             NewCoord.Vertex(2).z = za + (dx / W) * (zb - za);
   13760              : 
   13761              :             // Vertex 3
   13762            0 :             dx = w1;
   13763            0 :             dy = H;
   13764            0 :             xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
   13765            0 :             ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
   13766            0 :             za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
   13767            0 :             xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
   13768            0 :             yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
   13769            0 :             zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
   13770            0 :             NewCoord.Vertex(3).x = xa + (dx / W) * (xb - xa);
   13771            0 :             NewCoord.Vertex(3).y = ya + (dx / W) * (yb - ya);
   13772            0 :             NewCoord.Vertex(3).z = za + (dx / W) * (zb - za);
   13773              : 
   13774              :             // Vertex 4
   13775            0 :             dx = w1;
   13776            0 :             dy = H - h1;
   13777            0 :             xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
   13778            0 :             ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
   13779            0 :             za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
   13780            0 :             xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
   13781            0 :             yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
   13782            0 :             zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
   13783            0 :             NewCoord.Vertex(4).x = xa + (dx / W) * (xb - xa);
   13784            0 :             NewCoord.Vertex(4).y = ya + (dx / W) * (yb - ya);
   13785            0 :             NewCoord.Vertex(4).z = za + (dx / W) * (zb - za);
   13786              : 
   13787            0 :             for (loop = 1; loop <= surfTemp.Sides; ++loop) {
   13788            0 :                 surfTemp.Vertex(loop) = NewCoord.Vertex(loop);
   13789              :             }
   13790              : 
   13791              :             // Top glazing
   13792              : 
   13793              :             // Vertex 1
   13794            0 :             dx = (w1 - w2) / 2.0;
   13795            0 :             dy = H - (h1 + h2 + MulWidth);
   13796            0 :             xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
   13797            0 :             ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
   13798            0 :             za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
   13799            0 :             xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
   13800            0 :             yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
   13801            0 :             zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
   13802            0 :             NewCoord.Vertex(1).x = xa + (dx / W) * (xb - xa);
   13803            0 :             NewCoord.Vertex(1).y = ya + (dx / W) * (yb - ya);
   13804            0 :             NewCoord.Vertex(1).z = za + (dx / W) * (zb - za);
   13805              : 
   13806              :             // Vertex 2
   13807            0 :             dx = (w1 - w2) / 2.0;
   13808            0 :             dy = H - (h1 + MulWidth);
   13809            0 :             xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
   13810            0 :             ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
   13811            0 :             za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
   13812            0 :             xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
   13813            0 :             yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
   13814            0 :             zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
   13815            0 :             NewCoord.Vertex(2).x = xa + (dx / W) * (xb - xa);
   13816            0 :             NewCoord.Vertex(2).y = ya + (dx / W) * (yb - ya);
   13817            0 :             NewCoord.Vertex(2).z = za + (dx / W) * (zb - za);
   13818              : 
   13819              :             // Vertex 3
   13820            0 :             dx = (w1 + w2) / 2.0;
   13821            0 :             dy = H - (h1 + MulWidth);
   13822            0 :             xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
   13823            0 :             ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
   13824            0 :             za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
   13825            0 :             xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
   13826            0 :             yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
   13827            0 :             zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
   13828            0 :             NewCoord.Vertex(3).x = xa + (dx / W) * (xb - xa);
   13829            0 :             NewCoord.Vertex(3).y = ya + (dx / W) * (yb - ya);
   13830            0 :             NewCoord.Vertex(3).z = za + (dx / W) * (zb - za);
   13831              : 
   13832              :             // Vertex 4
   13833            0 :             dx = (w1 + w2) / 2.0;
   13834            0 :             dy = H - (h1 + h2 + MulWidth);
   13835            0 :             xa = OriginalCoord.Vertex(1).x + (dy / H) * (OriginalCoord.Vertex(2).x - OriginalCoord.Vertex(1).x);
   13836            0 :             ya = OriginalCoord.Vertex(1).y + (dy / H) * (OriginalCoord.Vertex(2).y - OriginalCoord.Vertex(1).y);
   13837            0 :             za = OriginalCoord.Vertex(1).z + (dy / H) * (OriginalCoord.Vertex(2).z - OriginalCoord.Vertex(1).z);
   13838            0 :             xb = OriginalCoord.Vertex(4).x + (dy / H) * (OriginalCoord.Vertex(3).x - OriginalCoord.Vertex(4).x);
   13839            0 :             yb = OriginalCoord.Vertex(4).y + (dy / H) * (OriginalCoord.Vertex(3).y - OriginalCoord.Vertex(4).y);
   13840            0 :             zb = OriginalCoord.Vertex(4).z + (dy / H) * (OriginalCoord.Vertex(3).z - OriginalCoord.Vertex(4).z);
   13841            0 :             NewCoord.Vertex(4).x = xa + (dx / W) * (xb - xa);
   13842            0 :             NewCoord.Vertex(4).y = ya + (dx / W) * (yb - ya);
   13843            0 :             NewCoord.Vertex(4).z = za + (dx / W) * (zb - za);
   13844              : 
   13845            0 :             for (loop = 1; loop <= state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Sides; ++loop) {
   13846            0 :                 state.dataSurfaceGeometry->SurfaceTmp(state.dataSurface->TotSurfaces).Vertex(loop) = NewCoord.Vertex(loop);
   13847              :             }
   13848              : 
   13849              :         } // End of check if vertical or horizontal mullion
   13850            0 :     }
   13851              : 
   13852         2215 :     void TransformVertsByAspect(EnergyPlusData &state,
   13853              :                                 int const SurfNum, // Current surface number
   13854              :                                 int const NSides   // Number of sides to figure
   13855              :     )
   13856              :     {
   13857              :         // SUBROUTINE INFORMATION:
   13858              :         //       AUTHOR         Brent T Griffith
   13859              :         //       DATE WRITTEN   April 2003
   13860              : 
   13861              :         // PURPOSE OF THIS SUBROUTINE:
   13862              :         // Alter input for surface geometry
   13863              :         // Optimizing building design for energy can involve
   13864              :         //  altering building geometry.  Rather than assemble routines to transform
   13865              :         //  geometry through pre-processing on input, it may be simpler to change
   13866              :         //  vertices within EnergyPlus since it already reads the data from the input
   13867              :         //  file and there would no longer be a need to rewrite the text data.
   13868              :         //  This is essentially a crude hack to allow adjusting geometry with
   13869              :         //  a single parameter...
   13870              : 
   13871              :         // METHODOLOGY EMPLOYED:
   13872              :         // once vertices have been converted to WCS, change them to reflect a different aspect
   13873              :         // ratio for the entire building based on user input.
   13874              :         // This routine is called once for each surface by subroutine GetVertices
   13875              : 
   13876         2637 :         static std::string const CurrentModuleObject("GeometryTransform");
   13877              : 
   13878         2215 :         Array1D_string cAlphas(1);
   13879         2215 :         Array1D<Real64> rNumerics(2);
   13880         2215 :         auto &OldAspectRatio = state.dataSurfaceGeometry->OldAspectRatio;
   13881         2215 :         auto &NewAspectRatio = state.dataSurfaceGeometry->NewAspectRatio;
   13882              :         int n;
   13883              :         Real64 Xo;
   13884              :         Real64 XnoRot;
   13885              :         Real64 Xtrans;
   13886              :         Real64 Yo;
   13887              :         Real64 YnoRot;
   13888              :         Real64 Ytrans;
   13889              :         // begin execution
   13890              :         // get user input...
   13891              : 
   13892         2215 :         auto &s_ipsc = state.dataIPShortCut;
   13893         2215 :         auto &surfTemp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
   13894              : 
   13895         2215 :         if (state.dataSurfaceGeometry->firstTime) {
   13896          220 :             if (state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject) == 1) {
   13897              :                 int NAlphas;
   13898              :                 int NNum;
   13899              :                 int IOStat;
   13900            0 :                 auto &s_ipsc = state.dataIPShortCut;
   13901            0 :                 auto &transformPlane = state.dataSurfaceGeometry->transformPlane;
   13902            0 :                 state.dataInputProcessing->inputProcessor->getObjectItem(state,
   13903              :                                                                          CurrentModuleObject,
   13904              :                                                                          1,
   13905              :                                                                          cAlphas,
   13906              :                                                                          NAlphas,
   13907              :                                                                          rNumerics,
   13908              :                                                                          NNum,
   13909              :                                                                          IOStat,
   13910            0 :                                                                          s_ipsc->lNumericFieldBlanks,
   13911            0 :                                                                          s_ipsc->lAlphaFieldBlanks,
   13912            0 :                                                                          s_ipsc->cAlphaFieldNames,
   13913            0 :                                                                          s_ipsc->cNumericFieldNames);
   13914            0 :                 OldAspectRatio = rNumerics(1);
   13915            0 :                 NewAspectRatio = rNumerics(2);
   13916            0 :                 transformPlane = cAlphas(1);
   13917            0 :                 if (transformPlane != "XY") {
   13918            0 :                     ShowWarningError(state, format("{}: invalid {}=\"{}...ignored.", CurrentModuleObject, s_ipsc->cAlphaFieldNames(1), cAlphas(1)));
   13919              :                 }
   13920            0 :                 state.dataSurfaceGeometry->firstTime = false;
   13921            0 :                 state.dataSurfaceGeometry->noTransform = false;
   13922            0 :                 state.dataSurface->AspectTransform = true;
   13923            0 :                 if (state.dataSurface->WorldCoordSystem) {
   13924            0 :                     ShowWarningError(state, format("{}: must use Relative Coordinate System.  Transform request ignored.", CurrentModuleObject));
   13925            0 :                     state.dataSurfaceGeometry->noTransform = true;
   13926            0 :                     state.dataSurface->AspectTransform = false;
   13927              :                 }
   13928              :             } else {
   13929          220 :                 state.dataSurfaceGeometry->firstTime = false;
   13930              :             }
   13931              :         }
   13932         2215 :         if (state.dataSurfaceGeometry->noTransform) return;
   13933              : 
   13934              :         // check surface type.
   13935            0 :         if (!surfTemp.HeatTransSurf) {
   13936              :             // Site Shading do not get transformed.
   13937            0 :             if (surfTemp.Class == SurfaceClass::Detached_F) return;
   13938              :         }
   13939              : 
   13940              :         // testing method of transforming  x and y coordinates as follows
   13941              : 
   13942              :         // this works if not rotated wrt north axis ... but if it is, then trouble
   13943              :         // try to first derotate it , transform by aspect and then rotate back.
   13944              : 
   13945            0 :         for (n = 1; n <= NSides; ++n) {
   13946            0 :             Xo = surfTemp.Vertex(n).x; // world coordinates.... shifted by relative north angle...
   13947            0 :             Yo = surfTemp.Vertex(n).y;
   13948              :             // next derotate the building
   13949            0 :             XnoRot = Xo * state.dataSurfaceGeometry->CosBldgRelNorth + Yo * state.dataSurfaceGeometry->SinBldgRelNorth;
   13950            0 :             YnoRot = Yo * state.dataSurfaceGeometry->CosBldgRelNorth - Xo * state.dataSurfaceGeometry->SinBldgRelNorth;
   13951              :             // translate
   13952            0 :             Xtrans = XnoRot * std::sqrt(NewAspectRatio / OldAspectRatio);
   13953            0 :             Ytrans = YnoRot * std::sqrt(OldAspectRatio / NewAspectRatio);
   13954              :             // rerotate
   13955            0 :             surfTemp.Vertex(n).x = Xtrans * state.dataSurfaceGeometry->CosBldgRelNorth - Ytrans * state.dataSurfaceGeometry->SinBldgRelNorth;
   13956              : 
   13957            0 :             surfTemp.Vertex(n).y = Xtrans * state.dataSurfaceGeometry->SinBldgRelNorth + Ytrans * state.dataSurfaceGeometry->CosBldgRelNorth;
   13958              :         }
   13959         4430 :     }
   13960              : 
   13961          225 :     void CalcSurfaceCentroid(EnergyPlusData &state)
   13962              :     {
   13963              :         // SUBROUTINE INFORMATION:
   13964              :         //       AUTHOR         B. Griffith
   13965              :         //       DATE WRITTEN   Feb. 2004
   13966              : 
   13967              :         // PURPOSE OF THIS SUBROUTINE:
   13968              :         // compute centroid of all the surfaces in the main
   13969              :         // surface structure. Store the vertex coordinates of
   13970              :         // the centroid in the 'SURFACE' derived type.
   13971              : 
   13972              :         // METHODOLOGY EMPLOYED:
   13973              :         // The centroid of triangle is easily computed by averaging the vertices
   13974              :         // The centroid of a quadrilateral is computed by area weighting the centroids
   13975              :         // of two triangles.
   13976              :         // (Algorithm would need to be changed for higher order
   13977              :         // polygons with more than four sides).
   13978              : 
   13979          225 :         auto &Triangle1 = state.dataSurfaceGeometry->Triangle1;
   13980          225 :         auto &Triangle2 = state.dataSurfaceGeometry->Triangle2;
   13981          225 :         static Vector const zero_vector(0.0);
   13982          225 :         Vector centroid;
   13983              : 
   13984          225 :         int negZcount(0); // for warning error in surface centroids
   13985              : 
   13986              :         // loop through all the surfaces
   13987         2497 :         for (int ThisSurf = 1; ThisSurf <= state.dataSurface->TotSurfaces; ++ThisSurf) {
   13988         2272 :             auto &surface = state.dataSurface->Surface(ThisSurf);
   13989              : 
   13990         2272 :             if (surface.Class == SurfaceClass::IntMass) continue;
   13991              : 
   13992         2256 :             auto const &vertex = surface.Vertex;
   13993              : 
   13994         2256 :             if (surface.Sides == 3) { // 3-sided polygon
   13995              : 
   13996           30 :                 centroid = cen(vertex(1), vertex(2), vertex(3));
   13997              : 
   13998         2226 :             } else if (surface.Sides == 4) { // 4-sided polygon
   13999              : 
   14000              :                 // split into 2 3-sided polygons (Triangle 1 and Triangle 2)
   14001         2204 :                 Triangle1(1) = vertex(1);
   14002         2204 :                 Triangle1(2) = vertex(2);
   14003         2204 :                 Triangle1(3) = vertex(3);
   14004         2204 :                 Triangle2(1) = vertex(1);
   14005         2204 :                 Triangle2(2) = vertex(3);
   14006         2204 :                 Triangle2(3) = vertex(4);
   14007              : 
   14008              :                 // get total Area of quad.
   14009         2204 :                 Real64 TotalArea(surface.GrossArea);
   14010         2204 :                 if (TotalArea <= 0.0) {
   14011              :                     // catch a problem....
   14012            0 :                     ShowWarningError(state, format("CalcSurfaceCentroid: zero area surface, for surface={}", surface.Name));
   14013            0 :                     continue;
   14014              :                 }
   14015              : 
   14016              :                 // get area fraction of triangles.
   14017         2204 :                 Real64 Tri1Area(Vectors::AreaPolygon(3, Triangle1) / TotalArea);
   14018         2204 :                 Real64 Tri2Area(Vectors::AreaPolygon(3, Triangle2) / TotalArea);
   14019              : 
   14020              :                 // check if sum of fractions are slightly greater than 1.0 which is a symptom of the triangles for a non-convex
   14021              :                 // quadrilateral using the wrong two triangles
   14022         2204 :                 if ((Tri1Area + Tri2Area) > 1.05) {
   14023              : 
   14024              :                     // if so repeat the process with the other two possible triangles (notice the vertices are in a different order this
   14025              :                     // time) split into 2 3-sided polygons (Triangle 1 and Triangle 2)
   14026            3 :                     Triangle1(1) = vertex(1);
   14027            3 :                     Triangle1(2) = vertex(2);
   14028            3 :                     Triangle1(3) = vertex(4);
   14029            3 :                     Triangle2(1) = vertex(2);
   14030            3 :                     Triangle2(2) = vertex(3);
   14031            3 :                     Triangle2(3) = vertex(4);
   14032              : 
   14033              :                     // get area fraction of triangles.
   14034            3 :                     Real64 AreaTriangle1 = Vectors::AreaPolygon(3, Triangle1);
   14035            3 :                     Real64 AreaTriangle2 = Vectors::AreaPolygon(3, Triangle2);
   14036            3 :                     TotalArea = AreaTriangle1 + AreaTriangle2;
   14037            3 :                     Tri1Area = AreaTriangle1 / TotalArea;
   14038            3 :                     Tri2Area = AreaTriangle2 / TotalArea;
   14039              :                 }
   14040              : 
   14041              :                 // get centroid of Triangle 1
   14042         2204 :                 Vector cen1(cen(Triangle1(1), Triangle1(2), Triangle1(3)));
   14043              : 
   14044              :                 // get centroid of Triangle 2
   14045         2204 :                 Vector cen2(cen(Triangle2(1), Triangle2(2), Triangle2(3)));
   14046              : 
   14047              :                 // find area weighted combination of the two centroids (coded to avoid temporary Vectors)
   14048         2204 :                 cen1 *= Tri1Area;
   14049         2204 :                 cen2 *= Tri2Area;
   14050         2204 :                 centroid = cen1;
   14051         2204 :                 centroid += cen2;
   14052              : 
   14053         2226 :             } else if (surface.Sides >= 5) { // multi-sided polygon
   14054              :                 // (Maybe triangulate?  For now, use old "z" average method")
   14055              :                 // and X and Y -- straight average
   14056              : 
   14057              :                 //        X1=MINVAL(Surface(ThisSurf)%Vertex(1:Surface(ThisSurf)%Sides)%x)
   14058              :                 //        X2=MAXVAL(Surface(ThisSurf)%Vertex(1:Surface(ThisSurf)%Sides)%x)
   14059              :                 //        Y1=MINVAL(Surface(ThisSurf)%Vertex(1:Surface(ThisSurf)%Sides)%y)
   14060              :                 //        Y2=MAXVAL(Surface(ThisSurf)%Vertex(1:Surface(ThisSurf)%Sides)%y)
   14061              :                 //        Z1=MINVAL(Surface(ThisSurf)%Vertex(1:Surface(ThisSurf)%Sides)%z)
   14062              :                 //        Z2=MAXVAL(Surface(ThisSurf)%Vertex(1:Surface(ThisSurf)%Sides)%z)
   14063              :                 //        Xcm=(X1+X2)/2.0d0
   14064              :                 //        Ycm=(Y1+Y2)/2.0d0
   14065              :                 //        Zcm=(Z1+Z2)/2.0d0
   14066              : 
   14067              :                 // Calc centroid as average of surfaces
   14068           13 :                 centroid = 0.0;
   14069           86 :                 for (int vert = 1; vert <= surface.Sides; ++vert) {
   14070           73 :                     centroid += vertex(vert);
   14071              :                 }
   14072           13 :                 centroid /= double(surface.Sides);
   14073              : 
   14074              :             } else {
   14075              : 
   14076            9 :                 if (!surface.Name.empty()) {
   14077            0 :                     ShowWarningError(state, format("CalcSurfaceCentroid: caught problem with # of sides, for surface={}", surface.Name));
   14078            0 :                     ShowContinueError(state, format("... number of sides must be >= 3, this surface # sides={}", surface.Sides));
   14079              :                 } else {
   14080            9 :                     ShowWarningError(state, format("CalcSurfaceCentroid: caught problem with # of sides, for surface=#{}", ThisSurf));
   14081           18 :                     ShowContinueError(state,
   14082              :                                       "...surface name is blank. Examine surfaces -- this may be a problem with ill-formed interzone surfaces.");
   14083            9 :                     ShowContinueError(state, format("... number of sides must be >= 3, this surface # sides={}", surface.Sides));
   14084              :                 }
   14085            9 :                 centroid = 0.0;
   14086              :             }
   14087              : 
   14088              :             // store result in the surface structure in DataSurfaces
   14089         2256 :             surface.Centroid = centroid;
   14090              : 
   14091         2256 :             if (centroid.z < 0.0) {
   14092            5 :                 if (surface.ExtWind || surface.ExtBoundCond == DataSurfaces::ExternalEnvironment) ++negZcount;
   14093              :             }
   14094              : 
   14095              :         } // loop through surfaces
   14096              : 
   14097          225 :         if (negZcount > 0) {
   14098            1 :             ShowWarningError(state, format("CalcSurfaceCentroid: {} Surfaces have the Z coordinate < 0.", negZcount));
   14099            2 :             ShowContinueError(state, "...in any calculations, Wind Speed will be 0.0 for these surfaces.");
   14100            2 :             ShowContinueError(state,
   14101            2 :                               format("...in any calculations, Outside temperatures will be the outside temperature + {:.3R} for these surfaces.",
   14102            1 :                                      state.dataEnvrn->WeatherFileTempModCoeff));
   14103            3 :             ShowContinueError(state, "...that is, these surfaces will have conditions as though at ground level.");
   14104              :         }
   14105          225 :     }
   14106              : 
   14107          224 :     void SetupShadeSurfacesForSolarCalcs(EnergyPlusData &state)
   14108              :     {
   14109              :         // SUBROUTINE INFORMATION:
   14110              :         //       AUTHOR         B. Griffith
   14111              :         //       DATE WRITTEN   Dec. 2008
   14112              : 
   14113              :         // PURPOSE OF THIS SUBROUTINE:
   14114              :         // determine if Shading surfaces need full solar calcs because they
   14115              :         // are also used to define geometry of an active solar component.
   14116              :         // Normally, a shading surface is not included in calculations of incident solar, only shading
   14117              : 
   14118              :         // METHODOLOGY EMPLOYED:
   14119              :         // Mine solar renewables input and collect surface names.
   14120              :         // find shading surfaces with names that match those in solar objects.
   14121              :         // setup flags for shading surfaces so that the solar renewables can reuse incident solar calcs
   14122              :         // new solar component models that use shading surfaces will have to extend the code here.
   14123              : 
   14124              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
   14125          224 :         Array1D_string TmpCandidateSurfaceNames;
   14126          224 :         Array1D_string TmpCandidateICSSurfaceNames;
   14127          224 :         Array1D_string TmpCandidateICSBCTypeNames;
   14128              :         int NumAlphas;  // Number of alpha names being passed
   14129              :         int NumNumbers; // Number of numeric parameters being passed
   14130              :         int IOStatus;
   14131              : 
   14132          224 :         auto &s_ipsc = state.dataIPShortCut;
   14133              :         // First collect names of surfaces referenced by active solar components
   14134          224 :         s_ipsc->cCurrentModuleObject = "SolarCollector:FlatPlate:Water";
   14135          224 :         int NumOfFlatPlateUnits = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
   14136          224 :         s_ipsc->cCurrentModuleObject = "SolarCollector:FlatPlate:PhotovoltaicThermal";
   14137          224 :         int NumPVTs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
   14138          224 :         s_ipsc->cCurrentModuleObject = "Generator:Photovoltaic";
   14139          224 :         int NumPVs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
   14140          224 :         s_ipsc->cCurrentModuleObject = "SolarCollector:IntegralCollectorStorage";
   14141          224 :         int NumOfICSUnits = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
   14142              : 
   14143          224 :         int NumCandidateNames = NumOfFlatPlateUnits + NumPVTs + NumPVs + NumOfICSUnits;
   14144          224 :         int NumOfCollectors = NumOfFlatPlateUnits + NumOfICSUnits;
   14145              : 
   14146          224 :         TmpCandidateSurfaceNames.allocate(NumCandidateNames);
   14147          224 :         TmpCandidateICSSurfaceNames.allocate(NumOfCollectors);
   14148          224 :         TmpCandidateICSBCTypeNames.allocate(NumOfCollectors);
   14149              : 
   14150          224 :         if (NumOfCollectors > 0) {
   14151            0 :             s_ipsc->cCurrentModuleObject = "SolarCollector:FlatPlate:Water";
   14152            0 :             for (int CollectorNum = 1; CollectorNum <= NumOfFlatPlateUnits; ++CollectorNum) {
   14153              : 
   14154            0 :                 state.dataInputProcessing->inputProcessor->getObjectItem(
   14155            0 :                     state, s_ipsc->cCurrentModuleObject, CollectorNum, s_ipsc->cAlphaArgs, NumAlphas, s_ipsc->rNumericArgs, NumNumbers, IOStatus);
   14156              : 
   14157            0 :                 TmpCandidateSurfaceNames(CollectorNum) = s_ipsc->cAlphaArgs(3);
   14158            0 :                 TmpCandidateICSBCTypeNames(CollectorNum) = "";
   14159              :             }
   14160              :         }
   14161              : 
   14162          224 :         if (NumPVTs > 0) {
   14163            2 :             s_ipsc->cCurrentModuleObject = "SolarCollector:FlatPlate:PhotovoltaicThermal";
   14164            4 :             for (int PVTnum = 1; PVTnum <= NumPVTs; ++PVTnum) {
   14165              : 
   14166            4 :                 state.dataInputProcessing->inputProcessor->getObjectItem(
   14167            2 :                     state, s_ipsc->cCurrentModuleObject, PVTnum, s_ipsc->cAlphaArgs, NumAlphas, s_ipsc->rNumericArgs, NumNumbers, IOStatus);
   14168              : 
   14169            2 :                 TmpCandidateSurfaceNames(NumOfFlatPlateUnits + PVTnum) = s_ipsc->cAlphaArgs(2);
   14170              :             }
   14171              :         }
   14172              : 
   14173          224 :         if (NumPVs > 0) {
   14174            2 :             s_ipsc->cCurrentModuleObject = "Generator:Photovoltaic";
   14175            4 :             for (int PVnum = 1; PVnum <= NumPVs; ++PVnum) {
   14176            4 :                 state.dataInputProcessing->inputProcessor->getObjectItem(
   14177            2 :                     state, s_ipsc->cCurrentModuleObject, PVnum, s_ipsc->cAlphaArgs, NumAlphas, s_ipsc->rNumericArgs, NumNumbers, IOStatus);
   14178            2 :                 TmpCandidateSurfaceNames(NumOfFlatPlateUnits + NumPVTs + PVnum) = s_ipsc->cAlphaArgs(2);
   14179              :             }
   14180              :         }
   14181              : 
   14182          224 :         if (NumOfICSUnits > 0) {
   14183            0 :             s_ipsc->cCurrentModuleObject = "SolarCollector:IntegralCollectorStorage";
   14184            0 :             for (int CollectorNum = 1; CollectorNum <= NumOfICSUnits; ++CollectorNum) {
   14185            0 :                 state.dataInputProcessing->inputProcessor->getObjectItem(
   14186            0 :                     state, s_ipsc->cCurrentModuleObject, CollectorNum, s_ipsc->cAlphaArgs, NumAlphas, s_ipsc->rNumericArgs, NumNumbers, IOStatus);
   14187            0 :                 TmpCandidateSurfaceNames(NumOfFlatPlateUnits + NumPVTs + NumPVs + CollectorNum) = s_ipsc->cAlphaArgs(3);
   14188            0 :                 TmpCandidateICSSurfaceNames(NumOfFlatPlateUnits + CollectorNum) = s_ipsc->cAlphaArgs(3);
   14189            0 :                 TmpCandidateICSBCTypeNames(NumOfFlatPlateUnits + CollectorNum) = s_ipsc->cAlphaArgs(4);
   14190              :             }
   14191              :         }
   14192              : 
   14193              :         // loop through all the surfaces
   14194         2486 :         for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
   14195         2262 :             auto &surf = state.dataSurface->Surface(SurfNum);
   14196         2262 :             int Found = Util::FindItemInList(surf.Name, TmpCandidateSurfaceNames, NumCandidateNames);
   14197         2262 :             if (Found > 0) {
   14198            2 :                 if (!surf.HeatTransSurf) { // not BIPV, must be a shading surf with solar device
   14199              :                     // Setup missing values to allow shading surfaces to model incident solar and wind
   14200            1 :                     surf.ExtSolar = true;
   14201            1 :                     surf.ExtWind = true;
   14202            1 :                     surf.ViewFactorGround = 0.5 * (1.0 - surf.CosTilt);
   14203              :                 }
   14204              :                 // check if this surface is used for ICS collector mounting and has OthersideCondictionsModel as its
   14205              :                 // boundary condition
   14206            2 :                 if (NumOfICSUnits > 0) {
   14207            0 :                     for (int CollectorNum = 1; CollectorNum <= NumOfCollectors; ++CollectorNum) {
   14208            0 :                         if (Util::SameString(surf.Name, TmpCandidateICSSurfaceNames(CollectorNum)) &&
   14209            0 :                             Util::SameString(TmpCandidateICSBCTypeNames(CollectorNum), "OTHERSIDECONDITIONSMODEL")) {
   14210            0 :                             state.dataSurface->SurfIsICS(SurfNum) = true;
   14211            0 :                             state.dataSurface->SurfICSPtr(SurfNum) = CollectorNum;
   14212              :                         }
   14213              :                     }
   14214              :                 }
   14215              : 
   14216              :             } // end of IF (Found > 0) Then
   14217              :         }
   14218          224 :     }
   14219              : 
   14220              :     void
   14221          416 :     SetupEnclosuresAndAirBoundaries(EnergyPlusData &state,
   14222              :                                     EPVector<DataViewFactorInformation::EnclosureViewFactorInformation> &Enclosures, // Radiant or Solar Enclosures
   14223              :                                     SurfaceGeometry::enclosureType const EnclosureType,                              // Radiant or Solar
   14224              :                                     bool &ErrorsFound)                                                               // Set to true if errors found
   14225              :     {
   14226              :         static constexpr std::string_view RoutineName = "SetupEnclosuresAndAirBoundaries";
   14227          416 :         bool anyGroupedSpaces = false;
   14228          416 :         bool radiantSetup = false;
   14229          416 :         bool solarSetup = false;
   14230          416 :         std::string RadiantOrSolar = "";
   14231          416 :         int enclosureNum = 0;
   14232          416 :         if (EnclosureType == RadiantEnclosures) {
   14233          224 :             radiantSetup = true;
   14234          224 :             RadiantOrSolar = "Radiant";
   14235          224 :             state.dataViewFactor->EnclRadInfo.allocate(state.dataGlobal->numSpaces);
   14236          192 :         } else if (EnclosureType == SolarEnclosures) {
   14237          192 :             solarSetup = true;
   14238          192 :             RadiantOrSolar = "Solar";
   14239          192 :             state.dataViewFactor->EnclSolInfo.allocate(state.dataGlobal->numSpaces);
   14240              :         } else {
   14241            0 :             ShowFatalError(
   14242            0 :                 state, format("{}: Illegal call to this function. Second argument must be 'RadiantEnclosures' or 'SolarEnclosures'", RoutineName));
   14243              :         }
   14244          416 :         if (std::any_of(state.dataConstruction->Construct.begin(),
   14245          416 :                         state.dataConstruction->Construct.end(),
   14246         1390 :                         [](Construction::ConstructionProps const &e) { return e.TypeIsAirBoundary; })) {
   14247           18 :             int errorCount = 0;
   14248          222 :             for (int surfNum = 1; surfNum <= state.dataSurface->TotSurfaces; ++surfNum) {
   14249          204 :                 auto &surf = state.dataSurface->Surface(surfNum);
   14250          204 :                 if (surf.Construction == 0) continue;
   14251          204 :                 auto &constr = state.dataConstruction->Construct(surf.Construction);
   14252          204 :                 if (!constr.TypeIsAirBoundary) continue;
   14253           84 :                 surf.IsAirBoundarySurf = true;
   14254              : 
   14255              :                 // Check for invalid air boundary surfaces - valid only on non-adiabatic interzone surfaces
   14256              :                 // Only check this once during radiant setup, skip for solar setup
   14257           84 :                 if (radiantSetup && (surf.ExtBoundCond <= 0 || surf.ExtBoundCond == surfNum)) {
   14258            0 :                     ErrorsFound = true;
   14259            0 :                     if (!state.dataGlobal->DisplayExtraWarnings) {
   14260            0 :                         ++errorCount;
   14261              :                     } else {
   14262            0 :                         ShowSevereError(
   14263            0 :                             state, format("{}: Surface=\"{}\" uses Construction:AirBoundary in a non-interzone surface.", RoutineName, surf.Name));
   14264              :                     }
   14265              :                 } else {
   14266              :                     // Process air boundary - set surface properties and set up enclosures Radiant exchange, Boundary is grouped - assign enclosure
   14267           84 :                     state.dataHeatBal->AnyAirBoundary = true;
   14268           84 :                     int thisSideEnclosureNum = 0;
   14269           84 :                     int otherSideEnclosureNum = 0;
   14270           84 :                     if (radiantSetup) {
   14271              :                         // Radiant enclosure setup
   14272           42 :                         constr.IsUsedCTF = false;
   14273           42 :                         surf.HeatTransSurf = false;
   14274           42 :                         surf.HeatTransferAlgorithm = DataSurfaces::HeatTransferModel::AirBoundaryNoHT;
   14275           42 :                         thisSideEnclosureNum = state.dataHeatBal->space(surf.spaceNum).radiantEnclosureNum;
   14276           42 :                         otherSideEnclosureNum = state.dataHeatBal->space(state.dataSurface->Surface(surf.ExtBoundCond).spaceNum).radiantEnclosureNum;
   14277              :                     } else {
   14278              :                         // Solar enclosure setup
   14279           42 :                         thisSideEnclosureNum = state.dataHeatBal->space(surf.spaceNum).solarEnclosureNum;
   14280           42 :                         otherSideEnclosureNum = state.dataHeatBal->space(state.dataSurface->Surface(surf.ExtBoundCond).spaceNum).solarEnclosureNum;
   14281              :                     }
   14282           84 :                     anyGroupedSpaces = true;
   14283           84 :                     if ((thisSideEnclosureNum == 0) && (otherSideEnclosureNum == 0)) {
   14284              :                         // Neither zone is assigned to an enclosure, so increment the counter and assign to both
   14285           22 :                         ++enclosureNum;
   14286           22 :                         auto &thisEnclosure = Enclosures(enclosureNum);
   14287           22 :                         thisSideEnclosureNum = enclosureNum;
   14288           22 :                         thisEnclosure.Name = format("{} Enclosure {}", RadiantOrSolar, enclosureNum);
   14289           22 :                         thisEnclosure.spaceNames.push_back(state.dataHeatBal->space(surf.spaceNum).Name);
   14290           22 :                         thisEnclosure.spaceNums.push_back(surf.spaceNum);
   14291           22 :                         thisEnclosure.FloorArea += state.dataHeatBal->space(surf.spaceNum).FloorArea;
   14292           22 :                         otherSideEnclosureNum = enclosureNum;
   14293           22 :                         int otherSideSpaceNum = state.dataSurface->Surface(surf.ExtBoundCond).spaceNum;
   14294           22 :                         if (otherSideSpaceNum != surf.spaceNum) {
   14295           20 :                             thisEnclosure.spaceNames.push_back(state.dataHeatBal->space(otherSideSpaceNum).Name);
   14296           20 :                             thisEnclosure.spaceNums.push_back(otherSideSpaceNum);
   14297           20 :                             thisEnclosure.FloorArea += state.dataHeatBal->space(otherSideSpaceNum).FloorArea;
   14298              :                         }
   14299           22 :                         if (radiantSetup) {
   14300           11 :                             state.dataHeatBal->space(surf.spaceNum).radiantEnclosureNum = thisSideEnclosureNum;
   14301           11 :                             state.dataHeatBal->space(state.dataSurface->Surface(surf.ExtBoundCond).spaceNum).radiantEnclosureNum =
   14302              :                                 otherSideEnclosureNum;
   14303              :                         } else {
   14304           11 :                             thisEnclosure.ExtWindowArea += state.dataHeatBal->space(surf.spaceNum).extWindowArea;
   14305           11 :                             thisEnclosure.TotalSurfArea += state.dataHeatBal->space(surf.spaceNum).totalSurfArea;
   14306           11 :                             if (otherSideSpaceNum != surf.spaceNum) {
   14307           10 :                                 thisEnclosure.ExtWindowArea += state.dataHeatBal->space(otherSideSpaceNum).extWindowArea;
   14308           10 :                                 thisEnclosure.TotalSurfArea += state.dataHeatBal->space(otherSideSpaceNum).totalSurfArea;
   14309              :                             }
   14310           11 :                             state.dataHeatBal->space(surf.spaceNum).solarEnclosureNum = thisSideEnclosureNum;
   14311           11 :                             state.dataHeatBal->space(state.dataSurface->Surface(surf.ExtBoundCond).spaceNum).solarEnclosureNum =
   14312              :                                 otherSideEnclosureNum;
   14313              :                         }
   14314           84 :                     } else if (thisSideEnclosureNum == 0) {
   14315              :                         // Other side is assigned, so use that one for both
   14316            0 :                         thisSideEnclosureNum = otherSideEnclosureNum;
   14317            0 :                         auto &thisEnclosure = Enclosures(thisSideEnclosureNum);
   14318            0 :                         thisEnclosure.spaceNames.push_back(state.dataHeatBal->space(surf.spaceNum).Name);
   14319            0 :                         thisEnclosure.spaceNums.push_back(surf.spaceNum);
   14320            0 :                         thisEnclosure.FloorArea += state.dataHeatBal->space(surf.spaceNum).FloorArea;
   14321            0 :                         if (radiantSetup) {
   14322            0 :                             state.dataHeatBal->space(surf.spaceNum).radiantEnclosureNum = thisSideEnclosureNum;
   14323              :                         } else {
   14324            0 :                             thisEnclosure.ExtWindowArea += state.dataHeatBal->space(surf.spaceNum).extWindowArea;
   14325            0 :                             thisEnclosure.TotalSurfArea += state.dataHeatBal->space(surf.spaceNum).totalSurfArea;
   14326            0 :                             state.dataHeatBal->space(surf.spaceNum).solarEnclosureNum = thisSideEnclosureNum;
   14327              :                         }
   14328           62 :                     } else if (otherSideEnclosureNum == 0) {
   14329              :                         // This side is assigned, so use that one for both
   14330           14 :                         otherSideEnclosureNum = thisSideEnclosureNum;
   14331           14 :                         auto &thisEnclosure = Enclosures(thisSideEnclosureNum);
   14332           14 :                         thisEnclosure.spaceNames.push_back(state.dataHeatBal->space(state.dataSurface->Surface(surf.ExtBoundCond).spaceNum).Name);
   14333           14 :                         thisEnclosure.spaceNums.push_back(state.dataSurface->Surface(surf.ExtBoundCond).spaceNum);
   14334           14 :                         thisEnclosure.FloorArea += state.dataHeatBal->space(state.dataSurface->Surface(surf.ExtBoundCond).spaceNum).FloorArea;
   14335           14 :                         if (radiantSetup) {
   14336            7 :                             state.dataHeatBal->space(state.dataSurface->Surface(surf.ExtBoundCond).spaceNum).radiantEnclosureNum =
   14337              :                                 otherSideEnclosureNum;
   14338              :                         } else {
   14339            7 :                             thisEnclosure.ExtWindowArea +=
   14340            7 :                                 state.dataHeatBal->space(state.dataSurface->Surface(surf.ExtBoundCond).spaceNum).extWindowArea;
   14341            7 :                             thisEnclosure.TotalSurfArea +=
   14342            7 :                                 state.dataHeatBal->space(state.dataSurface->Surface(surf.ExtBoundCond).spaceNum).totalSurfArea;
   14343            7 :                             state.dataHeatBal->space(state.dataSurface->Surface(surf.ExtBoundCond).spaceNum).solarEnclosureNum =
   14344              :                                 otherSideEnclosureNum;
   14345              :                         }
   14346           48 :                     } else if (thisSideEnclosureNum != otherSideEnclosureNum) {
   14347              :                         // If both sides are already assigned to an enclosure, then merge the two enclosures
   14348            4 :                         auto const &thisEnclosure = Enclosures(thisSideEnclosureNum);
   14349            4 :                         auto &otherEnclosure = Enclosures(otherSideEnclosureNum);
   14350           16 :                         for (const auto &zName : thisEnclosure.spaceNames) {
   14351           12 :                             otherEnclosure.spaceNames.push_back(zName);
   14352              :                         }
   14353           16 :                         for (int zNum : thisEnclosure.spaceNums) {
   14354           12 :                             otherEnclosure.spaceNums.push_back(zNum);
   14355           12 :                             if (radiantSetup) {
   14356            6 :                                 state.dataHeatBal->space(zNum).radiantEnclosureNum = otherSideEnclosureNum;
   14357              :                             } else {
   14358            6 :                                 state.dataHeatBal->space(zNum).solarEnclosureNum = otherSideEnclosureNum;
   14359              :                             }
   14360              :                         }
   14361            4 :                         otherEnclosure.FloorArea += thisEnclosure.FloorArea;
   14362            4 :                         otherEnclosure.ExtWindowArea += thisEnclosure.ExtWindowArea;
   14363            4 :                         otherEnclosure.TotalSurfArea += thisEnclosure.TotalSurfArea;
   14364              :                         // Move any enclosures beyond thisEnclosure down one slot - at this point all enclosures are named "Radiant
   14365              :                         // Enclosure N"
   14366            8 :                         for (int enclNum = thisSideEnclosureNum; enclNum < enclosureNum; ++enclNum) {
   14367            4 :                             std::string saveName = Enclosures(enclNum).Name;
   14368            4 :                             Enclosures(enclNum) = Enclosures(enclNum + 1);
   14369            4 :                             Enclosures(enclNum).Name = saveName;
   14370           22 :                             for (int sNum : Enclosures(enclNum).spaceNums) {
   14371           18 :                                 if (radiantSetup) {
   14372            9 :                                     state.dataHeatBal->space(sNum).radiantEnclosureNum = enclNum;
   14373              :                                 } else {
   14374            9 :                                     state.dataHeatBal->space(sNum).solarEnclosureNum = enclNum;
   14375              :                                 }
   14376              :                             }
   14377            4 :                         }
   14378              :                         // Clear the last rad enclosure and reduce the total number of enclosures by 1
   14379            4 :                         Enclosures(enclosureNum).Name.clear();
   14380            4 :                         Enclosures(enclosureNum).spaceNames.clear();
   14381            4 :                         Enclosures(enclosureNum).spaceNums.clear();
   14382            4 :                         Enclosures(enclosureNum).FloorArea = 0;
   14383            4 :                         Enclosures(enclosureNum).ExtWindowArea = 0;
   14384            4 :                         Enclosures(enclosureNum).TotalSurfArea = 0;
   14385            4 :                         enclosureNum -= 1;
   14386              :                     }
   14387           84 :                     if (solarSetup && constr.TypeIsAirBoundaryMixing) {
   14388              :                         // Set up mixing air boundaries only once, during solar setup
   14389            4 :                         int spaceNum1 = min(surf.spaceNum, state.dataSurface->Surface(surf.ExtBoundCond).spaceNum);
   14390            4 :                         int spaceNum2 = max(surf.spaceNum, state.dataSurface->Surface(surf.ExtBoundCond).spaceNum);
   14391              :                         // This pair already saved?
   14392            4 :                         bool found = false;
   14393            4 :                         for (auto const &thisAirBoundaryMixing : state.dataHeatBal->airBoundaryMixing) {
   14394            2 :                             if ((spaceNum1 == thisAirBoundaryMixing.space1) && (spaceNum2 == thisAirBoundaryMixing.space2)) {
   14395            2 :                                 found = true;
   14396            2 :                                 break;
   14397              :                             }
   14398              :                         }
   14399            4 :                         if (!found) {
   14400              :                             // Store the space pairs, schedule, and flow rate to use later to create cross mixing objects
   14401            2 :                             DataHeatBalance::AirBoundaryMixingSpecs newAirBoundaryMixing;
   14402            2 :                             newAirBoundaryMixing.space1 = spaceNum1;
   14403            2 :                             newAirBoundaryMixing.space2 = spaceNum2;
   14404            2 :                             newAirBoundaryMixing.sched = state.dataConstruction->Construct(surf.Construction).airBoundaryMixingSched;
   14405            2 :                             Real64 mixingVolume = state.dataConstruction->Construct(surf.Construction).AirBoundaryACH *
   14406            2 :                                                   min(state.dataHeatBal->space(spaceNum1).Volume, state.dataHeatBal->space(spaceNum2).Volume) /
   14407            2 :                                                   Constant::rSecsInHour;
   14408            2 :                             newAirBoundaryMixing.mixingVolumeFlowRate = mixingVolume;
   14409            2 :                             state.dataHeatBal->airBoundaryMixing.push_back(newAirBoundaryMixing);
   14410              :                         }
   14411              :                     }
   14412              :                 }
   14413              :             }
   14414           18 :             if (errorCount > 0) {
   14415            0 :                 ShowSevereError(state, format("{}: {} surfaces use Construction:AirBoundary in non-interzone surfaces.", RoutineName, errorCount));
   14416            0 :                 ShowContinueError(state, "For explicit details on each use, use Output:Diagnostics,DisplayExtraWarnings;");
   14417              :             }
   14418              :         }
   14419              :         // Check for any spaces defined only by floor surface(s) and group them
   14420         1045 :         for (auto const &zone : state.dataHeatBal->Zone) {
   14421          629 :             int newEnclosureNum = 0;
   14422         1302 :             for (int const spaceNum : zone.spaceIndexes) {
   14423          673 :                 int spaceEnclosureNum = 0;
   14424          673 :                 bool spaceHasOnlyFloors = false;
   14425          673 :                 if (radiantSetup) {
   14426          376 :                     spaceEnclosureNum = state.dataHeatBal->space(spaceNum).radiantEnclosureNum;
   14427              :                 } else {
   14428          297 :                     spaceEnclosureNum = state.dataHeatBal->space(spaceNum).solarEnclosureNum;
   14429              :                 }
   14430          673 :                 if (spaceEnclosureNum == 0) {
   14431          616 :                     spaceHasOnlyFloors = true;
   14432          699 :                     for (int const surfNum : state.dataHeatBal->space(spaceNum).surfaces) {
   14433          630 :                         if (state.dataSurface->Surface(surfNum).Class == SurfaceClass::IntMass) continue;
   14434          630 :                         if (state.dataSurface->Surface(surfNum).Class != SurfaceClass::Floor) {
   14435          547 :                             spaceHasOnlyFloors = false;
   14436          547 :                             break;
   14437              :                         }
   14438              :                     }
   14439              :                 }
   14440          673 :                 if (spaceEnclosureNum == 0 && spaceHasOnlyFloors) {
   14441           69 :                     anyGroupedSpaces = true;
   14442           69 :                     if (newEnclosureNum == 0) {
   14443              :                         // Assign one new enclosure for all loose floors in this zone
   14444           47 :                         ++enclosureNum;
   14445           47 :                         newEnclosureNum = enclosureNum;
   14446              :                     }
   14447           69 :                     if (radiantSetup) {
   14448           36 :                         state.dataHeatBal->space(spaceNum).radiantEnclosureNum = enclosureNum;
   14449              :                     } else {
   14450           33 :                         state.dataHeatBal->space(spaceNum).solarEnclosureNum = enclosureNum;
   14451              :                     }
   14452           69 :                     auto &thisEnclosure = Enclosures(enclosureNum);
   14453              :                     // Give this enclosure the zone name and assign this to the zone-remainder space if it exists
   14454           69 :                     thisEnclosure.Name = zone.Name;
   14455           69 :                     thisEnclosure.spaceNames.push_back(state.dataHeatBal->space(spaceNum).Name);
   14456           69 :                     thisEnclosure.spaceNums.push_back(spaceNum);
   14457           69 :                     thisEnclosure.FloorArea = state.dataHeatBal->space(spaceNum).FloorArea;
   14458           69 :                     thisEnclosure.ExtWindowArea = state.dataHeatBal->space(spaceNum).extWindowArea;
   14459           69 :                     thisEnclosure.TotalSurfArea = state.dataHeatBal->space(spaceNum).totalSurfArea;
   14460              :                 }
   14461              :             }
   14462              :         }
   14463              : 
   14464          416 :         if (anyGroupedSpaces) {
   14465              :             // All grouped spaces have been assigned to an enclosure, now assign remaining spaces
   14466          207 :             for (int spaceNum = 1; spaceNum <= state.dataGlobal->numSpaces; ++spaceNum) {
   14467          156 :                 auto &curSpace = state.dataHeatBal->space(spaceNum);
   14468          156 :                 int spaceEnclosureNum = 0;
   14469          156 :                 if (radiantSetup) {
   14470           80 :                     spaceEnclosureNum = curSpace.radiantEnclosureNum;
   14471              :                 } else {
   14472           76 :                     spaceEnclosureNum = curSpace.solarEnclosureNum;
   14473              :                 }
   14474          156 :                 if (spaceEnclosureNum == 0) {
   14475           31 :                     if (Util::SameString(curSpace.Name, state.dataHeatBal->Zone(curSpace.zoneNum).Name + "-REMAINDER")) {
   14476              :                         // Search for existing enclosure with same name as the zone
   14477            0 :                         spaceEnclosureNum = Util::FindItemInList(state.dataHeatBal->Zone(curSpace.zoneNum).Name, Enclosures);
   14478              :                     }
   14479           31 :                     if (spaceEnclosureNum == 0) {
   14480              :                         // Otherwise add a new one named for the space
   14481           31 :                         ++enclosureNum;
   14482           31 :                         spaceEnclosureNum = enclosureNum;
   14483           31 :                         Enclosures(spaceEnclosureNum).Name = curSpace.Name;
   14484              :                     }
   14485           31 :                     if (radiantSetup) {
   14486           16 :                         curSpace.radiantEnclosureNum = spaceEnclosureNum;
   14487              :                     } else {
   14488           15 :                         curSpace.solarEnclosureNum = spaceEnclosureNum;
   14489              :                     }
   14490           31 :                     auto &thisEnclosure = Enclosures(spaceEnclosureNum);
   14491           31 :                     thisEnclosure.spaceNames.push_back(curSpace.Name);
   14492           31 :                     thisEnclosure.spaceNums.push_back(spaceNum);
   14493           31 :                     thisEnclosure.FloorArea += curSpace.FloorArea;
   14494           31 :                     thisEnclosure.ExtWindowArea += curSpace.extWindowArea;
   14495           31 :                     thisEnclosure.TotalSurfArea += curSpace.totalSurfArea;
   14496              :                 }
   14497              :             }
   14498           51 :             if (radiantSetup) {
   14499           27 :                 state.dataViewFactor->NumOfRadiantEnclosures = enclosureNum;
   14500              :             } else {
   14501           24 :                 state.dataViewFactor->NumOfSolarEnclosures = enclosureNum;
   14502              :             }
   14503              :         } else {
   14504              :             // There are no grouped radiant air boundaries, assign each space to it's own radiant enclosure
   14505          882 :             for (int spaceNum = 1; spaceNum <= state.dataGlobal->numSpaces; ++spaceNum) {
   14506          517 :                 auto &thisEnclosure = Enclosures(spaceNum);
   14507          517 :                 thisEnclosure.Name = state.dataHeatBal->space(spaceNum).Name;
   14508          517 :                 thisEnclosure.spaceNames.push_back(state.dataHeatBal->space(spaceNum).Name);
   14509          517 :                 thisEnclosure.spaceNums.push_back(spaceNum);
   14510          517 :                 thisEnclosure.FloorArea = state.dataHeatBal->space(spaceNum).FloorArea;
   14511          517 :                 if (radiantSetup) {
   14512          296 :                     state.dataHeatBal->space(spaceNum).radiantEnclosureNum = spaceNum;
   14513              :                 } else {
   14514          221 :                     state.dataHeatBal->space(spaceNum).solarEnclosureNum = spaceNum;
   14515          221 :                     thisEnclosure.ExtWindowArea = state.dataHeatBal->space(spaceNum).extWindowArea;
   14516          221 :                     thisEnclosure.TotalSurfArea = state.dataHeatBal->space(spaceNum).totalSurfArea;
   14517              :                 }
   14518              :             }
   14519          365 :             if (radiantSetup) {
   14520          197 :                 state.dataViewFactor->NumOfRadiantEnclosures = state.dataGlobal->numSpaces;
   14521              :             } else {
   14522          168 :                 state.dataViewFactor->NumOfSolarEnclosures = state.dataGlobal->numSpaces;
   14523              :             }
   14524              :         }
   14525          416 :         if (radiantSetup) {
   14526          224 :             assert(state.dataViewFactor->NumOfRadiantEnclosures <= int(Enclosures.size()));
   14527          224 :             Enclosures.resize(state.dataViewFactor->NumOfRadiantEnclosures);
   14528              :         } else {
   14529          192 :             assert(state.dataViewFactor->NumOfSolarEnclosures <= int(Enclosures.size()));
   14530          192 :             Enclosures.resize(state.dataViewFactor->NumOfSolarEnclosures);
   14531              :         }
   14532              : 
   14533         1029 :         for (auto &thisEnclosure : state.dataViewFactor->EnclRadInfo) {
   14534         1226 :             SetupOutputVariable(state,
   14535              :                                 "Enclosure Mean Radiant Temperature",
   14536              :                                 Constant::Units::C,
   14537          613 :                                 thisEnclosure.MRT,
   14538              :                                 OutputProcessor::TimeStepType::Zone,
   14539              :                                 OutputProcessor::StoreType::Average,
   14540          613 :                                 thisEnclosure.Name);
   14541              :         }
   14542              : 
   14543              :         // TODO MJW: For now, set the max and min enclosure numbers for each zone to be used in CalcInteriorRadExchange with ZoneToResimulate
   14544         1045 :         for (int zoneNum = 1; zoneNum <= state.dataGlobal->NumOfZones; ++zoneNum) {
   14545         1302 :             for (int spaceNum : state.dataHeatBal->Zone(zoneNum).spaceIndexes) {
   14546          673 :                 if (state.dataHeatBal->Zone(zoneNum).zoneRadEnclosureFirst == -1) { // initial value
   14547          354 :                     state.dataHeatBal->Zone(zoneNum).zoneRadEnclosureFirst = state.dataHeatBal->space(spaceNum).radiantEnclosureNum;
   14548              :                 } else {
   14549          319 :                     state.dataHeatBal->Zone(zoneNum).zoneRadEnclosureFirst =
   14550          319 :                         min(state.dataHeatBal->Zone(zoneNum).zoneRadEnclosureFirst, state.dataHeatBal->space(spaceNum).radiantEnclosureNum);
   14551              :                 }
   14552          673 :                 state.dataHeatBal->Zone(zoneNum).zoneRadEnclosureLast =
   14553          673 :                     max(state.dataHeatBal->Zone(zoneNum).zoneRadEnclosureLast, state.dataHeatBal->space(spaceNum).radiantEnclosureNum);
   14554              :             }
   14555          629 :             assert(state.dataHeatBal->Zone(zoneNum).zoneRadEnclosureFirst != -1);
   14556          629 :             assert(state.dataHeatBal->Zone(zoneNum).zoneRadEnclosureLast != -1);
   14557          629 :             assert(state.dataHeatBal->Zone(zoneNum).zoneRadEnclosureFirst <= state.dataHeatBal->Zone(zoneNum).zoneRadEnclosureLast);
   14558              :         }
   14559          416 :     }
   14560              : 
   14561         2203 :     void CheckConvexity(EnergyPlusData &state,
   14562              :                         int const SurfNum, // Current surface number
   14563              :                         int const NSides   // Number of sides to figure
   14564              :     )
   14565              :     {
   14566              :         // SUBROUTINE INFORMATION:
   14567              :         //       AUTHOR         Tyler Hoyt
   14568              :         //       DATE WRITTEN   December 2010
   14569              :         //       MODIFIED       CR8752 - incorrect note of non-convex polygons
   14570              : 
   14571              :         // PURPOSE OF THIS SUBROUTINE: This subroutine verifies the convexity of a
   14572              :         // surface that is exposed to the sun in the case that full shading calculations
   14573              :         // are required. The calculation conveniently detects collinear points as well,
   14574              :         // and returns a list of indices that are collinear within the plane of the surface.
   14575              : 
   14576              :         // METHODOLOGY EMPLOYED: First the surface is determined to have dimension 2 in
   14577              :         // either the xy, yz, or xz plane. That plane is selected to do the testing.
   14578              :         // Vectors representing the edges of the polygon and the perpendicular dot product
   14579              :         // between adjacent edges are computed. This allows the turning angle to be determined.
   14580              :         // If the turning angle is greater than pi/2, it turns to the right, and if it is
   14581              :         // less than pi/2, it turns left. The direction of the turn is stored, and if it
   14582              :         // changes as the edges are iterated the surface is not convex. Meanwhile it stores
   14583              :         // the indices of vertices that are collinear and are later removed.
   14584              : 
   14585              :         // REFERENCES:
   14586              :         // http://mathworld.wolfram.com/ConvexPolygon.html
   14587              : 
   14588         2203 :         constexpr Real64 TurnThreshold = 0.000001; // Sensitivity of convexity test, in radians
   14589              : 
   14590         2203 :         Real64 LastTheta = 0.0;                 // Angle between edge vectors
   14591              :         bool SignFlag;                          // Direction of edge turn : true is right, false is left
   14592         2203 :         bool PrevSignFlag(false);               // Container for the sign of the previous iteration's edge turn
   14593         2203 :         bool PrevSignFlagInitialized(false);    // Whether we picked a PrevSignFlag already or not
   14594         2203 :         auto &X = state.dataSurfaceGeometry->X; // containers for x,y,z vertices of the surface
   14595         2203 :         auto &Y = state.dataSurfaceGeometry->Y;
   14596         2203 :         auto &Z = state.dataSurfaceGeometry->Z;
   14597         2203 :         auto &A = state.dataSurfaceGeometry->A; // containers for convexity test
   14598         2203 :         auto &B = state.dataSurfaceGeometry->B;
   14599         2203 :         auto &VertSize = state.dataSurfaceGeometry->VertSize; // size of X,Y,Z,A,B arrays
   14600              : 
   14601         2203 :         std::vector<int> surfCollinearVerts; // index of vertices to remove, 1-indexed
   14602         2203 :         surfCollinearVerts.reserve(NSides + 2);
   14603              : 
   14604         2203 :         if (state.dataSurfaceGeometry->CheckConvexityFirstTime) {
   14605          225 :             X.allocate(state.dataSurface->MaxVerticesPerSurface + 2);
   14606          225 :             Y.allocate(state.dataSurface->MaxVerticesPerSurface + 2);
   14607          225 :             Z.allocate(state.dataSurface->MaxVerticesPerSurface + 2);
   14608          225 :             A.allocate(state.dataSurface->MaxVerticesPerSurface + 2);
   14609          225 :             B.allocate(state.dataSurface->MaxVerticesPerSurface + 2);
   14610          225 :             VertSize = state.dataSurface->MaxVerticesPerSurface;
   14611          225 :             state.dataSurfaceGeometry->CheckConvexityFirstTime = false;
   14612              :         }
   14613              : 
   14614         2203 :         if (NSides > VertSize) {
   14615            7 :             X.deallocate();
   14616            7 :             Y.deallocate();
   14617            7 :             Z.deallocate();
   14618            7 :             A.deallocate();
   14619            7 :             B.deallocate();
   14620            7 :             X.allocate(state.dataSurface->MaxVerticesPerSurface + 2);
   14621            7 :             Y.allocate(state.dataSurface->MaxVerticesPerSurface + 2);
   14622            7 :             Z.allocate(state.dataSurface->MaxVerticesPerSurface + 2);
   14623            7 :             A.allocate(state.dataSurface->MaxVerticesPerSurface + 2);
   14624            7 :             B.allocate(state.dataSurface->MaxVerticesPerSurface + 2);
   14625            7 :             VertSize = state.dataSurface->MaxVerticesPerSurface;
   14626              :         }
   14627              : 
   14628         2203 :         auto &surfaceTmp = state.dataSurfaceGeometry->SurfaceTmp(SurfNum);
   14629         2203 :         auto &vertices = surfaceTmp.Vertex;
   14630              : 
   14631        11079 :         for (int n = 1; n <= NSides; ++n) {
   14632         8876 :             X(n) = vertices(n).x;
   14633         8876 :             Y(n) = vertices(n).y;
   14634         8876 :             Z(n) = vertices(n).z;
   14635              :         }
   14636         2203 :         X(NSides + 1) = vertices(1).x;
   14637         2203 :         Y(NSides + 1) = vertices(1).y;
   14638         2203 :         Z(NSides + 1) = vertices(1).z;
   14639         2203 :         X(NSides + 2) = vertices(2).x;
   14640         2203 :         Y(NSides + 2) = vertices(2).y;
   14641         2203 :         Z(NSides + 2) = vertices(2).z;
   14642              : 
   14643              :         // Determine a suitable plane in which to do the tests
   14644         2203 :         Real64 Det = 0.0;
   14645        11079 :         for (int n = 1; n <= NSides; ++n) {
   14646         8876 :             Det += X(n) * Y(n + 1) - X(n + 1) * Y(n);
   14647              :         }
   14648         2203 :         if (std::abs(Det) > Constant::SmallDistance) {
   14649          852 :             A = X;
   14650          852 :             B = Y;
   14651              :         } else {
   14652         1351 :             Det = 0.0;
   14653         6755 :             for (int n = 1; n <= NSides; ++n) {
   14654         5404 :                 Det += X(n) * Z(n + 1) - X(n + 1) * Z(n);
   14655              :             }
   14656         1351 :             if (std::abs(Det) > Constant::SmallDistance) {
   14657          848 :                 A = X;
   14658          848 :                 B = Z;
   14659              :             } else {
   14660          503 :                 Det = 0.0;
   14661         2514 :                 for (int n = 1; n <= NSides; ++n) {
   14662         2011 :                     Det += Y(n) * Z(n + 1) - Y(n + 1) * Z(n);
   14663              :                 }
   14664          503 :                 if (std::abs(Det) > Constant::SmallDistance) {
   14665          502 :                     A = Y;
   14666          502 :                     B = Z;
   14667              :                 } else {
   14668              :                     // This condition should not be reached if the surfaces are guaranteed to be planar already
   14669            1 :                     ShowSevereError(state, format("CheckConvexity: Surface=\"{}\" is non-planar.", surfaceTmp.Name));
   14670            2 :                     ShowContinueError(state, "Coincident Vertices will be removed as possible.");
   14671            4 :                     for (int n = 1; n <= surfaceTmp.Sides; ++n) {
   14672            3 :                         auto const &point = vertices(n);
   14673              :                         static constexpr std::string_view ErrFmt = " ({:8.3F},{:8.3F},{:8.3F})";
   14674            3 :                         ShowContinueError(state, format(ErrFmt, point.x, point.y, point.z));
   14675              :                     }
   14676              :                 }
   14677              :             }
   14678              :         }
   14679              : 
   14680        11079 :         for (int n = 1; n <= NSides; ++n) { // perform convexity test in the plane determined above.
   14681              : 
   14682         8876 :             DataVectorTypes::Vector_2d pt0(A(n), B(n));
   14683         8876 :             DataVectorTypes::Vector_2d pt1(A(n + 1), B(n + 1));
   14684         8876 :             DataVectorTypes::Vector_2d pt2(A(n + 2), B(n + 2));
   14685              : 
   14686         8876 :             DataVectorTypes::Vector_2d V1 = pt1 - pt0;
   14687         8876 :             DataVectorTypes::Vector_2d V2 = pt2 - pt1;
   14688              : 
   14689         8876 :             Real64 V1len = V1.length(); // = norm_L2()
   14690         8876 :             Real64 V2len = V2.length();
   14691         8876 :             if (V1len <= 1.e-8 || V2len <= 1.e-8) {
   14692              :                 // At least two points are coincident. Should this happen? GetVertices is supposed to pop these vertices
   14693            0 :                 continue;
   14694              :             }
   14695         8876 :             Real64 CrossProd = V1.cross(V2);
   14696         8876 :             Real64 sinarg = CrossProd / (V1len * V2len);
   14697         8876 :             if (sinarg < -1.0) {
   14698           16 :                 sinarg = -1.0;
   14699         8860 :             } else if (sinarg > 1.0) {
   14700           12 :                 sinarg = 1.0;
   14701              :             }
   14702         8876 :             Real64 Theta = std::asin(sinarg);
   14703         8876 :             if (Theta > TurnThreshold) {
   14704         4530 :                 SignFlag = true;
   14705         4346 :             } else if (Theta < -TurnThreshold) {
   14706         4322 :                 SignFlag = false;
   14707              :             } else { // std::abs(Theta) < TurnThreshold
   14708              :                 // Store the index of the collinear vertex for removal
   14709           24 :                 int colinearIndex = n + 1;
   14710           24 :                 if (colinearIndex > NSides) {
   14711            2 :                     colinearIndex -= NSides;
   14712              :                 }
   14713           24 :                 if (state.dataGlobal->DisplayExtraWarnings) {
   14714            0 :                     ShowWarningError(
   14715              :                         state,
   14716            0 :                         format("CheckConvexity: Surface=\"{}\", vertex {} is colinear with previous and next.", surfaceTmp.Name, colinearIndex));
   14717              :                 }
   14718           24 :                 ++state.dataErrTracking->TotalCoincidentVertices;
   14719           24 :                 surfCollinearVerts.push_back(colinearIndex);
   14720           24 :                 continue;
   14721           24 :             }
   14722              : 
   14723         8852 :             if (!PrevSignFlagInitialized) {
   14724         2203 :                 PrevSignFlag = SignFlag;
   14725         2203 :                 LastTheta = Theta;
   14726         2203 :                 PrevSignFlagInitialized = true;
   14727         2203 :                 continue;
   14728              :             }
   14729              : 
   14730         6649 :             if (SignFlag != PrevSignFlag) {
   14731           37 :                 if (state.dataGlobal->DisplayExtraWarnings && surfaceTmp.ExtSolar &&
   14732            0 :                     (state.dataHeatBal->SolarDistribution != DataHeatBalance::Shadowing::Minimal) && surfaceTmp.IsConvex &&
   14733           37 :                     !state.dataSysVars->SutherlandHodgman &&
   14734            0 :                     (state.dataSysVars->shadingMethod == DataSystemVariables::ShadingMethod::PolygonClipping)) {
   14735            0 :                     ShowWarningError(state,
   14736            0 :                                      format("CheckConvexity: Zone=\"{}\", Surface=\"{}\" is non-convex.",
   14737            0 :                                             state.dataHeatBal->Zone(surfaceTmp.Zone).Name,
   14738            0 :                                             surfaceTmp.Name));
   14739            0 :                     int Np1 = n + 1;
   14740            0 :                     if (Np1 > NSides) {
   14741            0 :                         Np1 -= NSides;
   14742              :                     }
   14743            0 :                     int Np2 = n + 2;
   14744            0 :                     if (Np2 > NSides) {
   14745            0 :                         Np2 -= NSides;
   14746              :                     }
   14747            0 :                     ShowContinueError(state, format("...vertex {} to vertex {} to vertex {}", n, Np1, Np2));
   14748            0 :                     ShowContinueError(state, format("...vertex {}=[{:.2R},{:.2R},{:.2R}]", n, X(n), Y(n), Z(n)));
   14749            0 :                     ShowContinueError(state, format("...vertex {}=[{:.2R},{:.2R},{:.2R}]", Np1, X(n + 1), Y(n + 1), Z(n + 1)));
   14750            0 :                     ShowContinueError(state, format("...vertex {}=[{:.2R},{:.2R},{:.2R}]", Np2, X(n + 2), Y(n + 2), Z(n + 2)));
   14751              :                     // ShowContinueError(state, format("...theta angle=[{:.6R}]", Theta));
   14752              :                     // ShowContinueError(state, format("...last theta angle=[{:.6R}]", LastTheta));
   14753              :                 }
   14754           34 :                 surfaceTmp.IsConvex = false;
   14755              :                 // #10103 - We do not want to break early, because we do want to consistently remove colinear vertices
   14756              :                 // to avoid potential vertex size mismatch fatal errors
   14757              :                 // break;
   14758              :             }
   14759         6649 :             PrevSignFlag = SignFlag;
   14760         6649 :             LastTheta = Theta;
   14761        17784 :         }
   14762              : 
   14763              :         // must check to make sure don't remove NSides below 3
   14764         2203 :         int M = surfCollinearVerts.size();
   14765         2203 :         if (M > 0) { // Remove the collinear points determined above
   14766            6 :             if (NSides - M >= 3) {
   14767            6 :                 surfaceTmp.Sides = NSides - M;
   14768            6 :                 if (state.dataGlobal->DisplayExtraWarnings) {
   14769            0 :                     ShowWarningError(state,
   14770            0 :                                      format("CheckConvexity: Surface=\"{}\" has [{}] collinear points that have been removed.", surfaceTmp.Name, M));
   14771              :                 }
   14772              :             } else { // too many
   14773            0 :                 if (state.dataGlobal->DisplayExtraWarnings) {
   14774            0 :                     ShowWarningError(state, format("CheckConvexity: Surface=\"{}\" has [{}] collinear points.", surfaceTmp.Name, M));
   14775            0 :                     ShowContinueError(state, "...too many to remove all.  Will leave the surface with 3 sides. But this is now a degenerate surface");
   14776              :                 }
   14777            0 :                 ++state.dataErrTracking->TotalDegenerateSurfaces;
   14778            0 :                 surfaceTmp.Sides = 3; // max(NSides - M, 3) = 3 since NSide - M is < 3;
   14779            0 :                 surfCollinearVerts.resize(NSides - 3);
   14780              :             }
   14781              : 
   14782              :             // remove duplicated points: For that we construct a new array of vertices, only copying indices that aren't in SurfCollinearVerts
   14783              :             // Then we move that array into the original one
   14784            6 :             Array1D<Vector> newVertices;
   14785            6 :             newVertices.allocate(surfaceTmp.Sides);
   14786              : 
   14787            6 :             int n = 0;
   14788           58 :             for (int i = 1; i <= NSides; ++i) {
   14789           52 :                 if (std::find(surfCollinearVerts.cbegin(), surfCollinearVerts.cend(), i) == surfCollinearVerts.cend()) {
   14790           28 :                     newVertices(++n) = vertices(i);
   14791              :                 }
   14792              :             }
   14793            6 :             vertices = std::move(newVertices);
   14794              : 
   14795            6 :             if (state.dataGlobal->DisplayExtraWarnings) {
   14796            0 :                 ShowWarningError(state,
   14797            0 :                                  format("CheckConvexity: Surface=\"{}\": The vertex points has been reprocessed as Sides = {}",
   14798            0 :                                         surfaceTmp.Name,
   14799            0 :                                         surfaceTmp.Sides));
   14800              :             }
   14801            6 :         }
   14802         2203 :     }
   14803              : 
   14804         1664 :     bool isRectangle(EnergyPlusData &state, int const ThisSurf // Surface number
   14805              :     )
   14806              :     {
   14807              :         // SUBROUTINE INFORMATION:
   14808              :         //       AUTHOR         M.J. Witte
   14809              :         //       DATE WRITTEN   October 2015
   14810              : 
   14811              :         // PURPOSE: Check if a 4-sided surface is a rectangle
   14812              : 
   14813              :         Real64 Diagonal1;                                            // Length of diagonal of 4-sided figure from vertex 1 to vertex 3 (m)
   14814              :         Real64 Diagonal2;                                            // Length of diagonal of 4-sided figure from vertex 2 to vertex 4 (m)
   14815              :         Real64 DotProd;                                              // Dot product of two adjacent sides - to test for right angle
   14816         1664 :         Real64 const cos89deg = std::cos(89.0 * Constant::DegToRad); // tolerance for right angle
   14817         1664 :         Vector Vect32;                                               // normalized vector from vertex 3 to vertex 2
   14818         1664 :         Vector Vect21;                                               // normalized vector from vertex 2 to vertex 1
   14819              : 
   14820         1664 :         auto &surf = state.dataSurface->Surface(ThisSurf);
   14821         1664 :         Diagonal1 = Vectors::VecLength(surf.Vertex(1) - surf.Vertex(3));
   14822         1664 :         Diagonal2 = Vectors::VecLength(surf.Vertex(2) - surf.Vertex(4));
   14823              :         // Test for rectangularity
   14824         1664 :         if (std::abs(Diagonal1 - Diagonal2) < 0.020) { // This tolerance based on coincident vertex tolerance of 0.01
   14825         1615 :             Vect32 = Vectors::VecNormalize(surf.Vertex(3) - surf.Vertex(2));
   14826         1615 :             Vect21 = Vectors::VecNormalize(surf.Vertex(2) - surf.Vertex(1));
   14827         1615 :             DotProd = dot(Vect32, Vect21);
   14828         1615 :             if (std::abs(DotProd) <= cos89deg) {
   14829         1531 :                 return true;
   14830              :             } else {
   14831           84 :                 return false;
   14832              :             }
   14833              :         } else {
   14834           49 :             return false;
   14835              :         }
   14836         1664 :     }
   14837              : 
   14838            6 :     void MakeEquivalentRectangle(EnergyPlusData &state,
   14839              :                                  int const SurfNum, // Surface number
   14840              :                                  bool &ErrorsFound  // Error flag indicator (true if errors found)
   14841              :     )
   14842              :     {
   14843              :         // SUBROUTINE INFORMATION:
   14844              :         //       AUTHOR         R. Zhang, LBNL
   14845              :         //       DATE WRITTEN   September 2016
   14846              : 
   14847              :         // PURPOSE OF THIS SUBROUTINE:
   14848              :         // Processing of 4-sided but non-rectangular Window, Door or GlassDoor.
   14849              :         // Calculate the effective height and width of the surface.
   14850              :         //
   14851              :         // METHODOLOGY EMPLOYED:
   14852              :         // Transform the surface into an equivalent rectangular surface with the same area and aspect ratio.
   14853              : 
   14854              :         Real64 AspectRatio; // Aspect ratio
   14855              :         Real64 WidthEff;    // Effective width of the surface
   14856              :         Real64 WidthMax;    // X difference between the vertex on the most left and the one on the most right
   14857              :         Real64 HeightEff;   // Effective height of the surface
   14858              :         Real64 HeightMax;   // Y difference between the lowest and highest vertices
   14859              :         Real64 Xp;
   14860              :         Real64 Yp;
   14861              :         Real64 Zp;
   14862              :         Real64 XLLC;
   14863              :         Real64 YLLC;
   14864              :         Real64 ZLLC;
   14865              : 
   14866            6 :         if (SurfNum == 0) {
   14867              :             // invalid surface
   14868            0 :             ErrorsFound = true;
   14869            0 :             return;
   14870              :         }
   14871              : 
   14872            6 :         auto &surf = state.dataSurface->Surface(SurfNum);
   14873            6 :         if (surf.Sides != 4) {
   14874              :             // the method is designed for 4-sided surface
   14875            0 :             return;
   14876            6 :         } else if (isRectangle(state, SurfNum)) {
   14877              :             // no need to transform
   14878            1 :             return;
   14879              :         }
   14880              : 
   14881            5 :         Real64 SurfWorldAz = surf.Azimuth;
   14882            5 :         Real64 SurfTilt = surf.Tilt;
   14883            5 :         Real64 BaseCosAzimuth = std::cos(SurfWorldAz * Constant::DegToRad);
   14884            5 :         Real64 BaseSinAzimuth = std::sin(SurfWorldAz * Constant::DegToRad);
   14885            5 :         Real64 BaseCosTilt = std::cos(SurfTilt * Constant::DegToRad);
   14886            5 :         Real64 BaseSinTilt = std::sin(SurfTilt * Constant::DegToRad);
   14887            5 :         int NumSurfSides = surf.Sides;
   14888              : 
   14889              :         // Calculate WidthMax and HeightMax
   14890            5 :         WidthMax = 0.0;
   14891            5 :         HeightMax = 0.0;
   14892           20 :         for (int i = 1; i < NumSurfSides; ++i) {
   14893           45 :             for (int j = i + 1; j <= NumSurfSides; ++j) {
   14894              : 
   14895           30 :                 Xp = surf.Vertex(j).x - surf.Vertex(i).x;
   14896           30 :                 Yp = surf.Vertex(j).y - surf.Vertex(i).y;
   14897           30 :                 Zp = surf.Vertex(j).z - surf.Vertex(i).z;
   14898              : 
   14899           30 :                 XLLC = -Xp * BaseCosAzimuth + Yp * BaseSinAzimuth;
   14900           30 :                 YLLC = -Xp * BaseSinAzimuth * BaseCosTilt - Yp * BaseCosAzimuth * BaseCosTilt + Zp * BaseSinTilt;
   14901           30 :                 ZLLC = Xp * BaseSinAzimuth * BaseSinTilt + Yp * BaseCosAzimuth * BaseSinTilt + Zp * BaseCosTilt;
   14902              : 
   14903           30 :                 if (std::abs(XLLC) > WidthMax) WidthMax = std::abs(XLLC);
   14904           30 :                 if (std::abs(YLLC) > WidthMax) HeightMax = std::abs(YLLC);
   14905              :             }
   14906              :         }
   14907              : 
   14908              :         // Perform transformation by calculating WidthEff and HeightEff
   14909            5 :         if ((WidthMax > 0) && (HeightMax > 0)) {
   14910            2 :             AspectRatio = WidthMax / HeightMax;
   14911              :         } else {
   14912            3 :             AspectRatio = 1;
   14913              :         }
   14914            5 :         WidthEff = std::sqrt(surf.Area * AspectRatio);
   14915            5 :         HeightEff = std::sqrt(surf.Area / AspectRatio);
   14916              : 
   14917              :         // Assign the effective width and length to the surface
   14918            5 :         surf.Width = WidthEff;
   14919            5 :         surf.Height = HeightEff;
   14920              :     }
   14921              : 
   14922          201 :     void CheckForReversedLayers(EnergyPlusData &state,
   14923              :                                 bool &RevLayerDiffs,    // true when differences are discovered in interzone constructions
   14924              :                                 int const ConstrNum,    // construction index
   14925              :                                 int const ConstrNumRev, // construction index for reversed construction
   14926              :                                 int const TotalLayers   // total layers for construction definition
   14927              :     )
   14928              :     {
   14929          201 :         auto &s_mat = state.dataMaterial;
   14930          201 :         RevLayerDiffs = false;
   14931              : 
   14932          625 :         for (int LayerNo = 1; LayerNo <= TotalLayers; ++LayerNo) {
   14933              : 
   14934          427 :             int thisConstLayer = state.dataConstruction->Construct(ConstrNum).LayerPoint(LayerNo);
   14935          427 :             int revConstLayer = state.dataConstruction->Construct(ConstrNumRev).LayerPoint(TotalLayers - LayerNo + 1);
   14936          427 :             if (thisConstLayer == revConstLayer) continue;
   14937              : 
   14938            6 :             auto const *mat = s_mat->materials(thisConstLayer);
   14939            6 :             auto const *matRev = s_mat->materials(revConstLayer);
   14940              : 
   14941              :             // If not point to the same layer, check to see if this is window glass which might need to have
   14942              :             // front and back material properties reversed.
   14943            6 :             Real64 constexpr SmallDiff = 0.0001;
   14944            6 :             if ((mat->group == Material::Group::Glass) && (matRev->group == Material::Group::Glass)) {
   14945            3 :                 auto const *matGlass = dynamic_cast<Material::MaterialGlass const *>(mat);
   14946            3 :                 auto const *matGlassRev = dynamic_cast<Material::MaterialGlass const *>(matRev);
   14947            3 :                 assert(matGlass != nullptr);
   14948            3 :                 assert(matGlassRev != nullptr);
   14949              : 
   14950              :                 // Both layers are window glass, so need to check to see if the properties are reversed
   14951            6 :                 if ((abs(matGlass->Thickness - matGlassRev->Thickness) > SmallDiff) ||
   14952            6 :                     (abs(matGlass->ReflectSolBeamBack - matGlassRev->ReflectSolBeamFront) > SmallDiff) ||
   14953            6 :                     (abs(matGlass->ReflectSolBeamFront - matGlassRev->ReflectSolBeamBack) > SmallDiff) ||
   14954            6 :                     (abs(matGlass->TransVis - matGlassRev->TransVis) > SmallDiff) ||
   14955            5 :                     (abs(matGlass->ReflectVisBeamBack - matGlassRev->ReflectVisBeamFront) > SmallDiff) ||
   14956            4 :                     (abs(matGlass->ReflectVisBeamFront - matGlassRev->ReflectVisBeamBack) > SmallDiff) ||
   14957            4 :                     (abs(matGlass->TransThermal - matGlassRev->TransThermal) > SmallDiff) ||
   14958            4 :                     (abs(matGlass->AbsorpThermalBack - matGlassRev->AbsorpThermalFront) > SmallDiff) ||
   14959            4 :                     (abs(matGlass->AbsorpThermalFront - matGlassRev->AbsorpThermalBack) > SmallDiff) ||
   14960            4 :                     (abs(matGlass->Conductivity - matGlassRev->Conductivity) > SmallDiff) ||
   14961            2 :                     (abs(matGlass->GlassTransDirtFactor - matGlassRev->GlassTransDirtFactor) > SmallDiff) ||
   14962            4 :                     (matGlass->SolarDiffusing != matGlassRev->SolarDiffusing) ||
   14963            8 :                     (abs(matGlass->YoungModulus - matGlassRev->YoungModulus) > SmallDiff) ||
   14964            2 :                     (abs(matGlass->PoissonsRatio - matGlassRev->PoissonsRatio) > SmallDiff)) {
   14965            1 :                     RevLayerDiffs = true;
   14966            1 :                     break; // exit when diff
   14967              :                 }          // If none of the above conditions is met, then these should be the same layers in reverse (RevLayersDiffs = false)
   14968            5 :             } else if ((mat->group == Material::Group::GlassEQL) && (matRev->group == Material::Group::GlassEQL)) {
   14969            2 :                 auto const *matGlass = dynamic_cast<Material::MaterialGlassEQL const *>(mat);
   14970            2 :                 auto const *matGlassRev = dynamic_cast<Material::MaterialGlassEQL const *>(matRev);
   14971              : 
   14972            4 :                 if ((abs(matGlass->TAR.Sol.Bk.Bm[0].BmTra - matGlassRev->TAR.Sol.Ft.Bm[0].BmTra) > SmallDiff) ||
   14973            4 :                     (abs(matGlass->TAR.Sol.Ft.Bm[0].BmTra - matGlassRev->TAR.Sol.Bk.Bm[0].BmTra) > SmallDiff) ||
   14974            4 :                     (abs(matGlass->TAR.Sol.Bk.Bm[0].BmRef - matGlassRev->TAR.Sol.Ft.Bm[0].BmRef) > SmallDiff) ||
   14975            4 :                     (abs(matGlass->TAR.Sol.Ft.Bm[0].BmRef - matGlassRev->TAR.Sol.Bk.Bm[0].BmRef) > SmallDiff) ||
   14976            4 :                     (abs(matGlass->TAR.Vis.Bk.Bm[0].BmTra - matGlassRev->TAR.Vis.Ft.Bm[0].BmTra) > SmallDiff) ||
   14977            4 :                     (abs(matGlass->TAR.Vis.Ft.Bm[0].BmTra - matGlassRev->TAR.Vis.Bk.Bm[0].BmTra) > SmallDiff) ||
   14978            4 :                     (abs(matGlass->TAR.Vis.Bk.Bm[0].BmRef - matGlassRev->TAR.Vis.Ft.Bm[0].BmRef) > SmallDiff) ||
   14979            4 :                     (abs(matGlass->TAR.Vis.Ft.Bm[0].BmRef - matGlassRev->TAR.Vis.Bk.Bm[0].BmRef) > SmallDiff) ||
   14980            4 :                     (abs(matGlass->TAR.Sol.Bk.Bm[0].DfTra - matGlassRev->TAR.Sol.Ft.Bm[0].DfTra) > SmallDiff) ||
   14981            4 :                     (abs(matGlass->TAR.Sol.Ft.Bm[0].DfTra - matGlassRev->TAR.Sol.Bk.Bm[0].DfTra) > SmallDiff) ||
   14982            4 :                     (abs(matGlass->TAR.Sol.Bk.Bm[0].DfRef - matGlassRev->TAR.Sol.Ft.Bm[0].DfRef) > SmallDiff) ||
   14983            4 :                     (abs(matGlass->TAR.Sol.Ft.Bm[0].DfRef - matGlassRev->TAR.Sol.Bk.Bm[0].DfRef) > SmallDiff) ||
   14984            4 :                     (abs(matGlass->TAR.Vis.Bk.Bm[0].DfTra - matGlassRev->TAR.Vis.Ft.Bm[0].DfTra) > SmallDiff) ||
   14985            4 :                     (abs(matGlass->TAR.Vis.Ft.Bm[0].DfTra - matGlassRev->TAR.Vis.Bk.Bm[0].DfTra) > SmallDiff) ||
   14986            4 :                     (abs(matGlass->TAR.Vis.Bk.Bm[0].DfRef - matGlassRev->TAR.Vis.Ft.Bm[0].DfRef) > SmallDiff) ||
   14987            4 :                     (abs(matGlass->TAR.Vis.Ft.Bm[0].DfRef - matGlassRev->TAR.Vis.Bk.Bm[0].DfRef) > SmallDiff) ||
   14988            4 :                     (abs(matGlass->TAR.Sol.Ft.Df.Tra - matGlassRev->TAR.Sol.Ft.Df.Tra) > SmallDiff) ||
   14989            4 :                     (abs(matGlass->TAR.Sol.Bk.Df.Ref - matGlassRev->TAR.Sol.Ft.Df.Ref) > SmallDiff) ||
   14990            4 :                     (abs(matGlass->TAR.Sol.Ft.Df.Ref - matGlassRev->TAR.Sol.Bk.Df.Ref) > SmallDiff) ||
   14991            4 :                     (abs(matGlass->TAR.Vis.Ft.Df.Tra - matGlassRev->TAR.Vis.Ft.Df.Tra) > SmallDiff) ||
   14992            4 :                     (abs(matGlass->TAR.Vis.Bk.Df.Ref - matGlassRev->TAR.Vis.Ft.Df.Ref) > SmallDiff) ||
   14993            4 :                     (abs(matGlass->TAR.Vis.Ft.Df.Ref - matGlassRev->TAR.Vis.Bk.Df.Ref) > SmallDiff) ||
   14994            4 :                     (abs(matGlass->TAR.IR.Ft.Tra - matGlassRev->TAR.IR.Ft.Tra) > SmallDiff) ||
   14995            3 :                     (abs(matGlass->TAR.IR.Bk.Emi - matGlassRev->TAR.IR.Ft.Emi) > SmallDiff) ||
   14996            5 :                     (abs(matGlass->TAR.IR.Ft.Emi - matGlassRev->TAR.IR.Bk.Emi) > SmallDiff) ||
   14997            1 :                     (abs(matGlass->Resistance - matGlassRev->Resistance) > SmallDiff)) {
   14998            1 :                     RevLayerDiffs = true;
   14999            1 :                     break; // exit when diff
   15000              :                 }          // If none of the above conditions is met, then these should be the same layers in reverse (RevLayersDiffs = false)
   15001              : 
   15002            1 :             } else {
   15003              :                 // Other material types do not have reversed constructions so if they are not the same layer there is a problem
   15004              :                 // (RevLayersDiffs = true)
   15005            1 :                 RevLayerDiffs = true;
   15006            1 :                 break; // exit when diff
   15007              :             }          // End check of whether or not these are WindowGlass
   15008              :         }
   15009          201 :     }
   15010              : 
   15011          134 :     void GetGeoSummaryRoof(EnergyPlusData const &state, GeoSummary &geoSummaryRoof)
   15012              :     {
   15013          134 :         std::vector<Vector> uniqueRoofVertices;
   15014          134 :         std::vector<SurfaceGeometry::EdgeOfSurf> uniqEdgeOfSurfs; // I'm only partially using this
   15015          990 :         for (const auto &surface : state.dataSurface->Surface) {
   15016              : 
   15017          856 :             if (surface.ExtBoundCond != DataSurfaces::ExternalEnvironment) {
   15018          264 :                 continue;
   15019              :             }
   15020          592 :             if (!surface.HeatTransSurf) {
   15021           20 :                 continue;
   15022              :             }
   15023              : 
   15024          572 :             if (surface.Tilt > 45.0) { // TODO Double check tilt wrt outside vs inside?
   15025          448 :                 continue;
   15026              :             }
   15027              : 
   15028          124 :             Real64 const z_min(minval(surface.Vertex, &Vector::z));
   15029          124 :             Real64 const z_max(maxval(surface.Vertex, &Vector::z));
   15030          124 :             Real64 const verticalHeight = z_max - z_min;
   15031          124 :             geoSummaryRoof.Height += verticalHeight * surface.Area;
   15032          124 :             geoSummaryRoof.Tilt += surface.Tilt * surface.Area;
   15033          124 :             geoSummaryRoof.Azimuth += surface.Azimuth * surface.Area;
   15034          124 :             geoSummaryRoof.Area += surface.Area;
   15035              : 
   15036          620 :             for (auto it = surface.Vertex.begin(); it != surface.Vertex.end(); ++it) {
   15037              : 
   15038          496 :                 auto itnext = std::next(it);
   15039          992 :                 if (itnext == std::end(surface.Vertex)) {
   15040          248 :                     itnext = std::begin(surface.Vertex);
   15041              :                 }
   15042              : 
   15043          496 :                 auto &curVertex = *it;
   15044          496 :                 auto &nextVertex = *itnext;
   15045          496 :                 auto it2 = std::find_if(uniqueRoofVertices.begin(), uniqueRoofVertices.end(), [&curVertex](const auto &unqV) {
   15046         1008 :                     return SurfaceGeometry::isAlmostEqual3dPt(curVertex, unqV);
   15047              :                 });
   15048          496 :                 if (it2 == std::end(uniqueRoofVertices)) {
   15049          421 :                     uniqueRoofVertices.emplace_back(curVertex);
   15050              :                 }
   15051              : 
   15052          496 :                 SurfaceGeometry::EdgeOfSurf thisEdge;
   15053          496 :                 thisEdge.start = std::move(curVertex);
   15054          496 :                 thisEdge.end = std::move(nextVertex);
   15055          496 :                 thisEdge.count = 1;
   15056              : 
   15057              :                 // Uses the custom operator== that uses isAlmostEqual3dPt internally and doesn't care about order of the start/end
   15058          496 :                 auto itEdge = std::find(uniqEdgeOfSurfs.begin(), uniqEdgeOfSurfs.end(), thisEdge);
   15059          496 :                 if (itEdge == uniqEdgeOfSurfs.end()) {
   15060          431 :                     uniqEdgeOfSurfs.emplace_back(std::move(thisEdge));
   15061              :                 } else {
   15062           65 :                     ++(itEdge->count);
   15063              :                 }
   15064          496 :             }
   15065              :         }
   15066              : 
   15067          134 :         if (geoSummaryRoof.Area > 0) {
   15068           95 :             geoSummaryRoof.Height /= geoSummaryRoof.Area;
   15069           95 :             geoSummaryRoof.Tilt /= geoSummaryRoof.Area;
   15070           95 :             geoSummaryRoof.Azimuth /= geoSummaryRoof.Area;
   15071              :         } else {
   15072           39 :             geoSummaryRoof.Height = 0.0;
   15073           39 :             geoSummaryRoof.Tilt = 0.0;
   15074           39 :             geoSummaryRoof.Azimuth = 0.0;
   15075              :         }
   15076              : 
   15077              :         // Remove the ones that are already used twice
   15078          268 :         uniqEdgeOfSurfs.erase(
   15079          565 :             std::remove_if(uniqEdgeOfSurfs.begin(), uniqEdgeOfSurfs.end(), [](const auto &edge) -> bool { return edge.count == 2; }),
   15080          134 :             uniqEdgeOfSurfs.end());
   15081              : 
   15082              :         // Intersect with unique vertices as much as needed
   15083          134 :         bool insertedVertext = true;
   15084          272 :         while (insertedVertext) {
   15085          138 :             insertedVertext = false;
   15086              : 
   15087          547 :             for (auto &edge : uniqEdgeOfSurfs) {
   15088              : 
   15089              :                 // now go through all the vertices and see if they are colinear with start and end vertices
   15090         2564 :                 for (const auto &testVertex : uniqueRoofVertices) {
   15091         2155 :                     if (edge.containsPoints(testVertex)) {
   15092            4 :                         SurfaceGeometry::EdgeOfSurf newEdgeOfSurface;
   15093            4 :                         newEdgeOfSurface.start = testVertex;
   15094            4 :                         newEdgeOfSurface.end = edge.end;
   15095            4 :                         edge.end = testVertex;
   15096            4 :                         uniqEdgeOfSurfs.emplace_back(std::move(newEdgeOfSurface));
   15097            4 :                         insertedVertext = true;
   15098            4 :                         break;
   15099            4 :                     }
   15100              :                 }
   15101              :                 // Break out of the loop on edges, and start again at the while
   15102          413 :                 if (insertedVertext) {
   15103            4 :                     break;
   15104              :                 }
   15105              :             }
   15106              :         }
   15107              : 
   15108              :         // recount
   15109          520 :         for (auto &edge : uniqEdgeOfSurfs) {
   15110          386 :             edge.count = std::count(uniqEdgeOfSurfs.begin(), uniqEdgeOfSurfs.end(), edge);
   15111              :         }
   15112              : 
   15113          268 :         uniqEdgeOfSurfs.erase(
   15114          520 :             std::remove_if(uniqEdgeOfSurfs.begin(), uniqEdgeOfSurfs.end(), [](const auto &edge) -> bool { return edge.count == 2; }),
   15115          134 :             uniqEdgeOfSurfs.end());
   15116              : 
   15117          134 :         geoSummaryRoof.Perimeter =
   15118          134 :             std::accumulate(uniqEdgeOfSurfs.cbegin(), uniqEdgeOfSurfs.cend(), 0.0, [](const double &sum, const SurfaceGeometry::EdgeOfSurf &edge) {
   15119          380 :                 return sum + edge.length();
   15120              :             });
   15121          134 :     }
   15122              : 
   15123              : } // namespace SurfaceGeometry
   15124              : 
   15125              : } // namespace EnergyPlus
        

Generated by: LCOV version 2.0-1