LCOV - code coverage report
Current view: top level - EnergyPlus - OutputReports.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 780 938 83.2 %
Date: 2023-01-17 19:17:23 Functions: 12 12 100.0 %

          Line data    Source code
       1             : // EnergyPlus, Copyright (c) 1996-2023, 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 <cmath>
      50             : 
      51             : // ObjexxFCL Headers
      52             : #include <ObjexxFCL/Array.functions.hh>
      53             : #include <ObjexxFCL/Array1D.hh>
      54             : #include <ObjexxFCL/Fmath.hh>
      55             : 
      56             : // EnergyPlus Headers
      57             : #include <EnergyPlus/Construction.hh>
      58             : #include <EnergyPlus/DXFEarClipping.hh>
      59             : #include <EnergyPlus/Data/EnergyPlusData.hh>
      60             : #include <EnergyPlus/DataDaylighting.hh>
      61             : #include <EnergyPlus/DataErrorTracking.hh>
      62             : #include <EnergyPlus/DataHeatBalance.hh>
      63             : #include <EnergyPlus/DataStringGlobals.hh>
      64             : #include <EnergyPlus/DataSurfaceColors.hh>
      65             : #include <EnergyPlus/DataSurfaces.hh>
      66             : #include <EnergyPlus/General.hh>
      67             : #include <EnergyPlus/OutputReports.hh>
      68             : #include <EnergyPlus/ScheduleManager.hh>
      69             : #include <EnergyPlus/UtilityRoutines.hh>
      70             : 
      71             : namespace EnergyPlus {
      72             : 
      73         771 : void ReportSurfaces(EnergyPlusData &state)
      74             : {
      75             : 
      76             :     // SUBROUTINE INFORMATION:
      77             :     //       AUTHOR         Linda K. Lawrie
      78             :     //       DATE WRITTEN   February 1999
      79             :     //       MODIFIED       na
      80             :     //       RE-ENGINEERED  na
      81             : 
      82             :     // PURPOSE OF THIS SUBROUTINE:
      83             :     // This subroutine calls several optional routines to report
      84             :     // the surfaces to output formats that can render the data
      85             :     // into a descriptive picture.
      86             : 
      87             :     // METHODOLOGY EMPLOYED:
      88             :     // Use a REPORT command to determine if there should be
      89             :     // a file created.
      90             : 
      91             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
      92             : 
      93         771 :     state.dataErrTracking->AskForSurfacesReport = false;
      94             : 
      95         771 :     int SurfDetails = 0;
      96         771 :     bool SurfVert = false;
      97         771 :     bool SurfDet = false;
      98         771 :     bool DXFDone = false;
      99         771 :     bool VRMLDone = false;
     100        1542 :     std::string Option1;
     101        1542 :     std::string Option2;
     102             :     bool DoReport;
     103             : 
     104         771 :     General::ScanForReports(state, "Surfaces", DoReport, "Lines", Option1);
     105         771 :     if (DoReport) LinesOut(state, Option1);
     106             : 
     107         771 :     General::ScanForReports(state, "Surfaces", DoReport, "Vertices");
     108         771 :     if (DoReport) {
     109           5 :         if (!SurfVert) {
     110           5 :             ++SurfDetails;
     111           5 :             SurfVert = true;
     112             :         }
     113             :     }
     114             : 
     115         771 :     General::ScanForReports(state, "Surfaces", DoReport, "Details");
     116         771 :     if (DoReport) {
     117         140 :         if (!SurfDet) {
     118         140 :             SurfDetails += 10;
     119         140 :             SurfDet = true;
     120             :         }
     121             :     }
     122             : 
     123         771 :     General::ScanForReports(state, "Surfaces", DoReport, "DetailsWithVertices");
     124         771 :     if (DoReport) {
     125          31 :         if (!SurfDet) {
     126          31 :             SurfDetails += 10;
     127          31 :             SurfDet = true;
     128             :         }
     129          31 :         if (!SurfVert) {
     130          31 :             ++SurfDetails;
     131          31 :             SurfVert = true;
     132             :         }
     133             :     }
     134             : 
     135         771 :     General::ScanForReports(state, "Surfaces", DoReport, "DXF", Option1, Option2);
     136         771 :     if (DoReport) {
     137         468 :         if (!DXFDone) {
     138         468 :             if (!Option2.empty()) {
     139           0 :                 DataSurfaceColors::SetUpSchemeColors(state, Option2, "DXF");
     140             :             }
     141         468 :             DXFOut(state, Option1, Option2);
     142         468 :             DXFDone = true;
     143             :         } else {
     144           0 :             ShowWarningError(state, "ReportSurfaces: DXF output already generated.  DXF with option=[" + Option1 + "] will not be generated.");
     145             :         }
     146             :     }
     147             : 
     148         771 :     General::ScanForReports(state, "Surfaces", DoReport, "DXF:WireFrame", Option1, Option2);
     149         771 :     if (DoReport) {
     150          27 :         if (!DXFDone) {
     151          27 :             if (!Option2.empty()) {
     152           0 :                 DataSurfaceColors::SetUpSchemeColors(state, Option2, "DXF");
     153             :             }
     154          27 :             DXFOutWireFrame(state, Option2);
     155          27 :             DXFDone = true;
     156             :         } else {
     157           0 :             ShowWarningError(state, "ReportSurfaces: DXF output already generated.  DXF:WireFrame will not be generated.");
     158             :         }
     159             :     }
     160             : 
     161         771 :     General::ScanForReports(state, "Surfaces", DoReport, "VRML", Option1, Option2);
     162         771 :     if (DoReport) {
     163          33 :         if (!VRMLDone) {
     164          33 :             VRMLOut(state, Option1, Option2);
     165          33 :             VRMLDone = true;
     166             :         } else {
     167           0 :             ShowWarningError(state, "ReportSurfaces: VRML output already generated.  VRML with option=[" + Option1 + "] will not be generated.");
     168             :         }
     169             :     }
     170             : 
     171         771 :     General::ScanForReports(state, "Surfaces", DoReport, "CostInfo");
     172         771 :     if (DoReport) {
     173           7 :         CostInfoOut(state);
     174             :     }
     175             : 
     176         771 :     if (SurfDet || SurfVert) {
     177         176 :         DetailsForSurfaces(state, SurfDetails);
     178             :     }
     179         771 : }
     180             : 
     181          50 : void LinesOut(EnergyPlusData &state, std::string const &option)
     182             : {
     183             :     // SUBROUTINE INFORMATION:
     184             :     //       AUTHOR         Linda K. Lawrie
     185             :     //       DATE WRITTEN   March 1999
     186             :     //       MODIFIED       March 2006 -- add option for "IDF segments out"
     187             :     //       RE-ENGINEERED  na
     188             : 
     189             :     // PURPOSE OF THIS SUBROUTINE:
     190             :     // This subroutine produces a file of lines in the surfaces.
     191             : 
     192             :     // METHODOLOGY EMPLOYED:
     193             :     // Use the surface absolute coordinate information to produce
     194             :     // lines.
     195             : 
     196             :     static constexpr std::string_view vertexstring("X,Y,Z ==> Vertex");
     197             : 
     198          50 :     if (state.dataSurface->TotSurfaces > 0 && !allocated(state.dataSurface->Surface)) {
     199             :         // no error needed, probably in end processing, just return
     200           0 :         return;
     201             :     }
     202             : 
     203          50 :     if (state.dataOutputReports->optiondone) {
     204           0 :         ShowWarningError(state, "Report of Surfaces/Lines Option has already been completed with option=" + state.dataOutputReports->lastoption);
     205           0 :         ShowContinueError(state, "..option=\"" + option + "\" will not be done this time.");
     206           0 :         return;
     207             :     }
     208             : 
     209          50 :     state.dataOutputReports->lastoption = option;
     210          50 :     state.dataOutputReports->optiondone = true;
     211             : 
     212         100 :     auto slnfile = state.files.sln.open(state, "LinesOut", state.files.outputControl.sln);
     213             : 
     214          50 :     if (option != "IDF") {
     215        2180 :         for (int surf : state.dataSurface->AllSurfaceListReportOrder) {
     216        2135 :             auto &thisSurface = state.dataSurface->Surface(surf);
     217        2135 :             if (thisSurface.Class == DataSurfaces::SurfaceClass::IntMass) continue;
     218        2135 :             if (thisSurface.Sides == 0) continue;
     219        2135 :             print<FormatSyntax::FMT>(slnfile, "{}:{}\n", thisSurface.ZoneName, thisSurface.Name);
     220       10675 :             for (int vert = 1; vert <= thisSurface.Sides; ++vert) {
     221             :                 static constexpr std::string_view fmt700("{:10.2F},{:10.2F},{:10.2F},{:10.2F},{:10.2F},{:10.2F}\n");
     222             : 
     223        8540 :                 if (vert != thisSurface.Sides) {
     224       38430 :                     print<check_syntax(fmt700)>(slnfile,
     225             :                                                 fmt700,
     226        6405 :                                                 thisSurface.Vertex(vert).x,
     227        6405 :                                                 thisSurface.Vertex(vert).y,
     228        6405 :                                                 thisSurface.Vertex(vert).z,
     229        6405 :                                                 thisSurface.Vertex(vert + 1).x,
     230        6405 :                                                 thisSurface.Vertex(vert + 1).y,
     231        6405 :                                                 thisSurface.Vertex(vert + 1).z);
     232             :                 } else {
     233       12810 :                     print<check_syntax(fmt700)>(slnfile,
     234             :                                                 fmt700,
     235        2135 :                                                 thisSurface.Vertex(vert).x,
     236        2135 :                                                 thisSurface.Vertex(vert).y,
     237        2135 :                                                 thisSurface.Vertex(vert).z,
     238        2135 :                                                 thisSurface.Vertex(1).x,
     239        2135 :                                                 thisSurface.Vertex(1).y,
     240        2135 :                                                 thisSurface.Vertex(1).z);
     241             :                 }
     242             :             }
     243             :         }
     244             :     } else {
     245           5 :         print<FormatSyntax::FMT>(slnfile, "{}\n", " Building North Axis = 0");
     246           5 :         print<FormatSyntax::FMT>(slnfile, "{}\n", "GlobalGeometryRules,UpperLeftCorner,CounterClockwise,WorldCoordinates;");
     247         367 :         for (int surf : state.dataSurface->AllSurfaceListReportOrder) {
     248         362 :             auto &thisSurface = state.dataSurface->Surface(surf);
     249         362 :             if (thisSurface.Class == DataSurfaces::SurfaceClass::IntMass) continue;
     250         322 :             if (thisSurface.Sides == 0) continue;
     251             :             // process heat transfer surfaces
     252         322 :             print(slnfile, " Surface={}, Name={}, Azimuth={:.1R}\n", cSurfaceClass(thisSurface.Class), thisSurface.Name, thisSurface.Azimuth);
     253         322 :             print<FormatSyntax::FMT>(slnfile, "  {},  !- Number of (X,Y,Z) groups in this surface\n", thisSurface.Sides);
     254        1610 :             for (int vert = 1; vert <= thisSurface.Sides; ++vert) {
     255        2576 :                 std::string optcommasemi = ",";
     256        1288 :                 if (vert == thisSurface.Sides) optcommasemi = ";";
     257             :                 static constexpr std::string_view fmtcoord("  {:10.2F},{:10.2F},{:10.2F}{}  !- {} {}\n");
     258        3864 :                 print<check_syntax(fmtcoord)>(slnfile,
     259             :                                               fmtcoord,
     260        1288 :                                               thisSurface.Vertex(vert).x,
     261        1288 :                                               thisSurface.Vertex(vert).y,
     262        1288 :                                               thisSurface.Vertex(vert).z,
     263             :                                               optcommasemi,
     264             :                                               vertexstring,
     265             :                                               vert);
     266             :             }
     267             :         }
     268             :     }
     269             : }
     270             : 
     271        8677 : static std::string normalizeName(std::string name)
     272             : {
     273        8677 :     std::replace(begin(name), end(name), ' ', '_');
     274        8677 :     std::replace(begin(name), end(name), ':', '_');
     275        8677 :     return name;
     276             : }
     277             : 
     278         495 : static void WriteDXFCommon(EnergyPlusData &state, InputOutputFile &of, const std::string &ColorScheme)
     279             : {
     280             :     static constexpr std::string_view Format_800(
     281             :         "  0\nTEXT\n  8\n1\n  6\nContinuous\n 62\n{:3}\n 10\n{:15.5F}\n 20\n{:15.5F}\n 30\n{:15.5F}\n 40\n .25\n  "
     282             :         "1\nTrue North\n 41\n 0.0\n  7\nMONOTXT\n210\n0.0\n220\n0.0\n230\n1.0\n");
     283             :     static constexpr std::string_view Format_801(
     284             :         "  0\nTEXT\n  8\n1\n  6\nContinuous\n 62\n{:3}\n 10\n{:15.5F}\n 20\n{:15.5F}\n 30\n{:15.5F}\n 40\n .4\n  "
     285             :         "1\n{}\n 41\n 0.0\n  7\nMONOTXT\n210\n0.0\n220\n0.0\n230\n1.0\n");
     286             : 
     287             :     static constexpr std::string_view Format_703_0("  0\n3DFACE\n  8\n1\n 62\n{:3}\n");
     288             :     static constexpr std::string_view Format_703_1(" 10\n{:15.5F}\n 20\n{:15.5F}\n 30\n{:15.5F}\n");
     289             :     static constexpr std::string_view Format_703_2(" 11\n{:15.5F}\n 21\n{:15.5F}\n 31\n{:15.5F}\n");
     290             :     static constexpr std::string_view Format_703_3(" 12\n{:15.5F}\n 22\n{:15.5F}\n 32\n{:15.5F}\n");
     291             :     static constexpr std::string_view Format_703_4(" 13\n{:15.5F}\n 23\n{:15.5F}\n 33\n{:15.5F}\n");
     292             : 
     293             :     static constexpr std::string_view Format_708{"999\n{}{}{}\n"};
     294             :     static constexpr std::string_view Format_710{"999\n{}\n"};
     295             : 
     296         495 :     constexpr int lenArr = 4;
     297         495 :     std::array<Real64, lenArr> StemX = {-10.0, -10.0, -10.0, -10.0};
     298         495 :     std::array<Real64, lenArr> StemY = {3.0, 3.0, 0.0, 0.0};
     299         495 :     std::array<Real64, lenArr> StemZ = {0.1, 0.0, 0.0, 0.1};
     300         495 :     std::array<Real64, lenArr> Head1X = {-10.0, -10.0, -10.5, -10.5};
     301         495 :     std::array<Real64, lenArr> Head1Y = {3.0, 3.0, 2.133975, 2.133975};
     302         495 :     std::array<Real64, lenArr> Head1Z = {0.1, 0.0, 0.0, 0.1};
     303         495 :     std::array<Real64, lenArr> Head2X = {-10.0, -10.0, -9.5, -9.5};
     304         495 :     std::array<Real64, lenArr> Head2Y = {3.0, 3.0, 2.133975, 2.133975};
     305         495 :     std::array<Real64, lenArr> Head2Z = {0.1, 0.0, 0.0, 0.1};
     306         495 :     std::array<Real64, lenArr> NSide1X = {-10.5, -10.5, -10.5, -10.5};
     307         495 :     std::array<Real64, lenArr> NSide1Y = {4.5, 4.5, 3.5, 3.5};
     308         495 :     std::array<Real64, lenArr> NSide1Z = {0.1, 0.0, 0.0, 0.1};
     309         495 :     std::array<Real64, lenArr> NSide2X = {-10.5, -10.5, -9.5, -9.5};
     310         495 :     std::array<Real64, lenArr> NSide2Y = {4.5, 4.5, 3.5, 3.5};
     311         495 :     std::array<Real64, lenArr> NSide2Z = {0.1, 0.0, 0.0, 0.1};
     312         495 :     std::array<Real64, lenArr> NSide3X = {-9.5, -9.5, -9.5, -9.5};
     313         495 :     std::array<Real64, lenArr> NSide3Y = {4.5, 4.5, 3.5, 3.5};
     314         495 :     std::array<Real64, lenArr> NSide3Z = {0.1, 0.0, 0.0, 0.1};
     315             : 
     316         495 :     if (ColorScheme.empty()) {
     317         495 :         print(of, Format_708, "Color Scheme", ",", "Default");
     318             :     } else {
     319           0 :         print(of, Format_708, "Color Scheme", ",", ColorScheme);
     320             :     }
     321             : 
     322         495 :     Real64 minx = 99999.0;
     323         495 :     Real64 miny = 99999.0;
     324       35037 :     for (int surf : state.dataSurface->AllSurfaceListReportOrder) {
     325       34542 :         auto &thisSurface = state.dataSurface->Surface(surf);
     326       34542 :         if (thisSurface.Class == DataSurfaces::SurfaceClass::IntMass) continue;
     327      162787 :         for (int vert = 1; vert <= thisSurface.Sides; ++vert) {
     328      130367 :             minx = min(minx, thisSurface.Vertex(vert).x);
     329      130367 :             miny = min(miny, thisSurface.Vertex(vert).y);
     330             :         }
     331             :     }
     332             : 
     333        2475 :     for (int vert = 0; vert < lenArr; ++vert) {
     334        1980 :         StemX[vert] += minx;
     335        1980 :         StemY[vert] += miny;
     336        1980 :         Head1X[vert] += minx;
     337        1980 :         Head1Y[vert] += miny;
     338        1980 :         Head2X[vert] += minx;
     339        1980 :         Head2Y[vert] += miny;
     340        1980 :         NSide1X[vert] += minx;
     341        1980 :         NSide1Y[vert] += miny;
     342        1980 :         NSide2X[vert] += minx;
     343        1980 :         NSide2Y[vert] += miny;
     344        1980 :         NSide3X[vert] += minx;
     345        1980 :         NSide3Y[vert] += miny;
     346             :     }
     347             : 
     348         495 :     auto &DXFcolorno = state.dataSurfColor->DXFcolorno;
     349             : 
     350             :     // This writes "True North" above the Arrow Head
     351         495 :     print(of, Format_710, "Text - True North");
     352         495 :     print<check_syntax(Format_800)>(
     353         990 :         of, Format_800, DXFcolorno[static_cast<int>(DataSurfaceColors::ColorNo::Text)], StemX[0] - 1.0, StemY[0], StemZ[0]);
     354             : 
     355         495 :     print(of, Format_710, "Text - Building Title");
     356         495 :     print<check_syntax(Format_801)>(of,
     357             :                                     Format_801,
     358         495 :                                     DXFcolorno[static_cast<int>(DataSurfaceColors::ColorNo::Text)],
     359         990 :                                     StemX[0] - 4.0,
     360         990 :                                     StemY[0] - 4.0,
     361         495 :                                     StemZ[0],
     362         990 :                                     "Building - " + state.dataHeatBal->BuildingName);
     363             : 
     364             :     // We want to point the north arrow to true north
     365         495 :     print(of, Format_710, "North Arrow Stem");
     366         495 :     print(of, Format_703_0, DXFcolorno[static_cast<int>(DataSurfaceColors::ColorNo::Text)]);
     367         495 :     print(of, Format_703_1, StemX[0], StemY[0], StemZ[0]);
     368         495 :     print(of, Format_703_2, StemX[1], StemY[1], StemZ[1]);
     369         495 :     print(of, Format_703_3, StemX[2], StemY[2], StemZ[2]);
     370         495 :     print(of, Format_703_4, StemX[3], StemY[3], StemZ[3]);
     371             : 
     372         495 :     print(of, Format_710, "North Arrow Head 1");
     373         495 :     print(of, Format_703_0, DXFcolorno[static_cast<int>(DataSurfaceColors::ColorNo::Text)]);
     374         495 :     print(of, Format_703_1, Head1X[0], Head1Y[0], Head1Z[0]);
     375         495 :     print(of, Format_703_2, Head1X[1], Head1Y[1], Head1Z[1]);
     376         495 :     print(of, Format_703_3, Head1X[2], Head1Y[2], Head1Z[2]);
     377         495 :     print(of, Format_703_4, Head1X[3], Head1Y[3], Head1Z[3]);
     378             : 
     379         495 :     print(of, Format_710, "North Arrow Head 2");
     380         495 :     print(of, Format_703_0, DXFcolorno[static_cast<int>(DataSurfaceColors::ColorNo::Text)]);
     381         495 :     print(of, Format_703_1, Head2X[0], Head2Y[0], Head2Z[0]);
     382         495 :     print(of, Format_703_2, Head2X[1], Head2Y[1], Head2Z[1]);
     383         495 :     print(of, Format_703_3, Head2X[2], Head2Y[2], Head2Z[2]);
     384         495 :     print(of, Format_703_4, Head2X[3], Head2Y[3], Head2Z[3]);
     385             : 
     386         495 :     print(of, Format_710, "North Arrow Side 1");
     387         495 :     print(of, Format_703_0, DXFcolorno[static_cast<int>(DataSurfaceColors::ColorNo::Text)]);
     388         495 :     print(of, Format_703_1, NSide1X[0], NSide1Y[0], NSide1Z[0]);
     389         495 :     print(of, Format_703_2, NSide1X[1], NSide1Y[1], NSide1Z[1]);
     390         495 :     print(of, Format_703_3, NSide1X[2], NSide1Y[2], NSide1Z[2]);
     391         495 :     print(of, Format_703_4, NSide1X[3], NSide1Y[3], NSide1Z[3]);
     392             : 
     393         495 :     print(of, Format_710, "North Arrow Side 2");
     394         495 :     print(of, Format_703_0, DXFcolorno[static_cast<int>(DataSurfaceColors::ColorNo::Text)]);
     395         495 :     print(of, Format_703_1, NSide2X[0], NSide2Y[0], NSide2Z[0]);
     396         495 :     print(of, Format_703_2, NSide2X[1], NSide2Y[1], NSide2Z[1]);
     397         495 :     print(of, Format_703_3, NSide2X[2], NSide2Y[2], NSide2Z[2]);
     398         495 :     print(of, Format_703_4, NSide2X[3], NSide2Y[3], NSide2Z[3]);
     399             : 
     400         495 :     print(of, Format_710, "North Arrow Side 3");
     401         495 :     print(of, Format_703_0, DXFcolorno[static_cast<int>(DataSurfaceColors::ColorNo::Text)]);
     402         495 :     print(of, Format_703_1, NSide3X[0], NSide3Y[0], NSide3Z[0]);
     403         495 :     print(of, Format_703_2, NSide3X[1], NSide3Y[1], NSide3Z[1]);
     404         495 :     print(of, Format_703_3, NSide3X[2], NSide3Y[2], NSide3Z[2]);
     405         495 :     print(of, Format_703_4, NSide3X[3], NSide3Y[3], NSide3Z[3]);
     406             : 
     407         495 :     print(of, Format_710, "Zone Names");
     408             : 
     409        4236 :     for (int zones = 1; zones <= state.dataGlobal->NumOfZones; ++zones) {
     410        7482 :         print<check_syntax(Format_710)>(of, Format_710, fmt::format("Zone={}:{}", zones, normalizeName(state.dataHeatBal->Zone(zones).Name)));
     411             :     }
     412         495 : }
     413             : 
     414         495 : static void DXFDaylightingReferencePoints(EnergyPlusData &state, InputOutputFile &of)
     415             : {
     416             : 
     417             :     static constexpr std::string_view Format_709("  0\nCIRCLE\n  8\n{}\n 62\n{:3}\n 10\n{:15.5F}\n 20\n{:15.5F}\n 30\n{:15.5F}\n 40\n{:15.5F}\n");
     418             : 
     419             :     // Do any daylighting reference points on layer for zone
     420         495 :     if ((int)state.dataDaylightingData->DaylRefPt.size() > 0) {
     421         334 :         for (int daylightCtrlNum = 1; daylightCtrlNum <= (int)state.dataDaylightingData->daylightControl.size(); ++daylightCtrlNum) {
     422         278 :             auto &thisDaylightControl = state.dataDaylightingData->daylightControl(daylightCtrlNum);
     423         278 :             auto curcolorno = DataSurfaceColors::ColorNo::DaylSensor1;
     424         556 :             std::string refPtType;
     425         278 :             if (thisDaylightControl.DaylightMethod == DataDaylighting::DaylightingMethod::DElight) {
     426           3 :                 refPtType = "DEDayRefPt";
     427         275 :             } else if (thisDaylightControl.DaylightMethod == DataDaylighting::DaylightingMethod::SplitFlux) {
     428         275 :                 refPtType = "DayRefPt";
     429             :             }
     430             : 
     431         731 :             for (int refpt = 1; refpt <= thisDaylightControl.TotalDaylRefPoints; ++refpt) {
     432         906 :                 print<FormatSyntax::FMT>(of,
     433             :                                          "999\n{}:{}:{}\n",
     434             :                                          thisDaylightControl.ZoneName,
     435             :                                          refPtType,
     436         906 :                                          state.dataDaylightingData->DaylRefPt(thisDaylightControl.DaylRefPtNum(refpt)).Name);
     437        1359 :                 print<check_syntax(Format_709)>(of,
     438             :                                                 Format_709,
     439         906 :                                                 normalizeName(thisDaylightControl.ZoneName),
     440         453 :                                                 state.dataSurfColor->DXFcolorno[static_cast<int>(curcolorno)],
     441             :                                                 thisDaylightControl.DaylRefPtAbsCoord(1, refpt),
     442             :                                                 thisDaylightControl.DaylRefPtAbsCoord(2, refpt),
     443             :                                                 thisDaylightControl.DaylRefPtAbsCoord(3, refpt),
     444             :                                                 0.2);
     445         453 :                 curcolorno = DataSurfaceColors::ColorNo::DaylSensor2; // ref pts 2 and later are this color
     446             :             }
     447             :         }
     448             :     }
     449         495 : }
     450             : 
     451         468 : void DXFOut(EnergyPlusData &state,
     452             :             std::string const &PolygonAction,
     453             :             std::string const &ColorScheme // Name from user for color scheme or blank
     454             : )
     455             : {
     456             : 
     457             :     // SUBROUTINE INFORMATION:
     458             :     //       AUTHOR         Linda K. Lawrie
     459             :     //       DATE WRITTEN   March 1999
     460             :     //       MODIFIED       na
     461             :     //       RE-ENGINEERED  na
     462             : 
     463             :     // PURPOSE OF THIS SUBROUTINE:
     464             :     // This subroutine produces a file of DXF objects for the surfaces.
     465             : 
     466             :     // METHODOLOGY EMPLOYED:
     467             :     // Use the surface absolute coordinate information to produce
     468             :     // lines.
     469             : 
     470         468 :     bool ThickPolyline(false);
     471         468 :     bool RegularPolyline(false);
     472         936 :     std::string PolylineWidth(" 0.55");
     473         468 :     bool TriangulateFace(false);
     474             : 
     475             :     // Formats
     476         468 :     constexpr auto Format_702("  0\nSECTION\n  2\nENTITIES\n");
     477         468 :     constexpr auto Format_707("999\nDXF created from EnergyPlus\n");
     478         468 :     constexpr auto Format_708("999\n{}{}{}\n");
     479             : 
     480         468 :     constexpr auto Format_715("  0\nPOLYLINE\n  8\n{}\n 62\n{:3}\n 66\n  1\n 10\n 0.0\n 20\n 0.0\n 30\n{:15.5F}\n 70\n   9\n 40\n{}\n 41\n{}\n");
     481         468 :     constexpr auto Format_716("  0\nVERTEX\n  8\n{}\n 10\n{:15.5F}\n 20\n{:15.5F}\n 30\n{:15.5F}\n");
     482         468 :     constexpr auto Format_717("  0\nSEQEND\n  8\n{}\n");
     483         468 :     constexpr auto Format_704("  0\n3DFACE\n  8\n{}\n 62\n{:3}\n 10\n{:15.5F}\n 20\n{:15.5F}\n 30\n{:15.5F}\n 11\n{:15.5F}\n 21\n{:15.5F}\n "
     484             :                               "31\n{:15.5F}\n 12\n{:15.5F}\n 22\n{:15.5F}\n 32\n{:15.5F}\n");
     485         468 :     constexpr auto Format_704_0("  0\n3DFACE\n  8\n{}\n 62\n{:3}\n");
     486         468 :     constexpr auto Format_704_1(" 10\n{:15.5F}\n 20\n{:15.5F}\n 30\n{:15.5F}\n");
     487         468 :     constexpr auto Format_704_2(" 11\n{:15.5F}\n 21\n{:15.5F}\n 31\n{:15.5F}\n");
     488         468 :     constexpr auto Format_704_3(" 12\n{:15.5F}\n 22\n{:15.5F}\n 32\n{:15.5F}\n");
     489         468 :     constexpr auto Format_705(" 13\n{:15.5F}\n 23\n{:15.5F}\n 33\n{:15.5F}\n");
     490         468 :     constexpr auto Format_706("  0\nENDSEC\n  0\nEOF\n");
     491         468 :     constexpr auto Format_709("  0\nCIRCLE\n  8\n{}\n 62\n{:3}\n 10\n{:15.5F}\n 20\n{:15.5F}\n 30\n{:15.5F}\n 40\n{:15.5F}\n");
     492         468 :     constexpr auto Format_710("999\n{}\n");
     493             : 
     494         468 :     if (PolygonAction == "TRIANGULATE3DFACE" || PolygonAction == "TRIANGULATE" || PolygonAction.empty()) {
     495         463 :         TriangulateFace = true;
     496         463 :         RegularPolyline = false;
     497         463 :         ThickPolyline = false;
     498           5 :     } else if (PolygonAction == "THICKPOLYLINE") {
     499           1 :         ThickPolyline = true;
     500           1 :         RegularPolyline = false;
     501           1 :         TriangulateFace = false;
     502           4 :     } else if (PolygonAction == "REGULARPOLYLINE") {
     503           4 :         RegularPolyline = true;
     504           4 :         TriangulateFace = false;
     505           4 :         ThickPolyline = false;
     506           4 :         PolylineWidth = " 0";
     507             :     } else {
     508           0 :         ShowWarningError(state, "DXFOut: Illegal key specified for Surfaces with > 4 sides=" + PolygonAction);
     509           0 :         ShowContinueError(state, R"(...Valid keys are: "ThickPolyline", "RegularPolyline", "Triangulate3DFace".)");
     510           0 :         ShowContinueError(state, "\"Triangulate3DFace\" will be used for any surfaces with > 4 sides.");
     511           0 :         TriangulateFace = true;
     512           0 :         RegularPolyline = false;
     513           0 :         ThickPolyline = false;
     514             :     }
     515             : 
     516         468 :     if (state.dataSurface->TotSurfaces > 0 && !allocated(state.dataSurface->Surface)) {
     517             :         // no error needed, probably in end processing, just return
     518           0 :         return;
     519             :     }
     520             : 
     521         936 :     auto dxffile = state.files.dxf.open(state, "DXFOut", state.files.outputControl.dxf);
     522             : 
     523         468 :     print(dxffile, Format_702); // Start of Entities section
     524             : 
     525         468 :     print(dxffile, Format_707); // Comment
     526             : 
     527         468 :     print(dxffile, Format_708, "Program Version", ",", state.dataStrGlobals->VerStringVar);
     528             : 
     529         468 :     if (PolygonAction.empty()) {
     530         458 :         print(dxffile, Format_708, "Polygon Action", ",", "ThickPolyline");
     531             :     } else {
     532          10 :         print(dxffile, Format_708, "Polygon Action", ",", PolygonAction);
     533             :     }
     534             : 
     535         468 :     WriteDXFCommon(state, dxffile, ColorScheme);
     536         468 :     auto &DXFcolorno = state.dataSurfColor->DXFcolorno;
     537         468 :     auto colorindex = DataSurfaceColors::ColorNo::ShdDetFix;
     538             :     //  Do all detached shading surfaces first
     539       34351 :     for (int surf : state.dataSurface->AllSurfaceListReportOrder) {
     540       33995 :         std::string ShadeType;
     541       33883 :         auto &thisSurface = state.dataSurface->Surface(surf);
     542             : 
     543       33883 :         if (thisSurface.HeatTransSurf) continue;
     544        1071 :         if (thisSurface.Class == DataSurfaces::SurfaceClass::Shading) continue;
     545         112 :         if (thisSurface.Sides == 0) continue;
     546         112 :         if (thisSurface.Class == DataSurfaces::SurfaceClass::Detached_F) colorindex = DataSurfaceColors::ColorNo::ShdDetFix;
     547         112 :         if (thisSurface.Class == DataSurfaces::SurfaceClass::Detached_B) colorindex = DataSurfaceColors::ColorNo::ShdDetBldg;
     548         112 :         if (state.dataSurface->SurfIsPV(surf)) colorindex = DataSurfaceColors::ColorNo::PV;
     549         112 :         if (thisSurface.Class == DataSurfaces::SurfaceClass::Detached_F) {
     550          76 :             ShadeType = "Fixed Shading";
     551          76 :             print(dxffile, Format_710, "Fixed Shading:" + thisSurface.Name);
     552          36 :         } else if (thisSurface.Class == DataSurfaces::SurfaceClass::Detached_B) {
     553          28 :             ShadeType = "Building Shading";
     554          28 :             print(dxffile, Format_710, "Building Shading:" + thisSurface.Name);
     555             :         }
     556         112 :         if (thisSurface.Sides <= 4) {
     557         112 :             print(dxffile, Format_704_0, ShadeType, DXFcolorno[static_cast<int>(colorindex)]);
     558         112 :             print(dxffile, Format_704_1, thisSurface.Vertex(1).x, thisSurface.Vertex(1).y, thisSurface.Vertex(1).z);
     559         112 :             print(dxffile, Format_704_2, thisSurface.Vertex(2).x, thisSurface.Vertex(2).y, thisSurface.Vertex(2).z);
     560         112 :             print(dxffile, Format_704_3, thisSurface.Vertex(3).x, thisSurface.Vertex(3).y, thisSurface.Vertex(3).z);
     561         112 :             if (thisSurface.Sides == 3) {
     562          40 :                 print(dxffile, Format_705, thisSurface.Vertex(3).x, thisSurface.Vertex(3).y, thisSurface.Vertex(3).z);
     563             :             } else {
     564          72 :                 print(dxffile, Format_705, thisSurface.Vertex(4).x, thisSurface.Vertex(4).y, thisSurface.Vertex(4).z);
     565             :             }
     566             :         } else { // polygon
     567           0 :             if (!TriangulateFace) {
     568           0 :                 Real64 minz = 99999.0;
     569           0 :                 for (int vert = 1; vert <= thisSurface.Sides; ++vert) {
     570           0 :                     minz = min(minz, thisSurface.Vertex(vert).z);
     571             :                 }
     572           0 :                 print(dxffile, Format_715, ShadeType, DXFcolorno[static_cast<int>(colorindex)], minz, PolylineWidth, PolylineWidth);
     573           0 :                 for (int vert = 1; vert <= thisSurface.Sides; ++vert) {
     574           0 :                     print(dxffile, Format_716, ShadeType, thisSurface.Vertex(vert).x, thisSurface.Vertex(vert).y, thisSurface.Vertex(vert).z);
     575             :                 }
     576           0 :                 print(dxffile, Format_717, ShadeType);
     577             :             } else {
     578           0 :                 Array1D<DataVectorTypes::dTriangle> mytriangles;
     579             : 
     580           0 :                 const auto ntri = DXFEarClipping::Triangulate(state,
     581             :                                                               thisSurface.Sides,
     582             :                                                               thisSurface.Vertex,
     583             :                                                               mytriangles,
     584             :                                                               thisSurface.Azimuth,
     585             :                                                               thisSurface.Tilt,
     586             :                                                               thisSurface.Name,
     587           0 :                                                               thisSurface.Class);
     588           0 :                 for (int svert = 1; svert <= ntri; ++svert) {
     589           0 :                     const auto vv0 = mytriangles(svert).vv0;
     590           0 :                     const auto vv1 = mytriangles(svert).vv1;
     591           0 :                     const auto vv2 = mytriangles(svert).vv2;
     592           0 :                     print(dxffile,
     593             :                           Format_704,
     594             :                           ShadeType,
     595           0 :                           DXFcolorno[static_cast<int>(colorindex)],
     596           0 :                           thisSurface.Vertex(vv0).x,
     597           0 :                           thisSurface.Vertex(vv0).y,
     598           0 :                           thisSurface.Vertex(vv0).z,
     599           0 :                           thisSurface.Vertex(vv1).x,
     600           0 :                           thisSurface.Vertex(vv1).y,
     601           0 :                           thisSurface.Vertex(vv1).z,
     602           0 :                           thisSurface.Vertex(vv2).x,
     603           0 :                           thisSurface.Vertex(vv2).y,
     604           0 :                           thisSurface.Vertex(vv2).z);
     605           0 :                     print(dxffile, Format_705, thisSurface.Vertex(vv2).x, thisSurface.Vertex(vv2).y, thisSurface.Vertex(vv2).z);
     606             :                 }
     607           0 :                 mytriangles.deallocate();
     608             :             }
     609             :         }
     610             :     }
     611             : 
     612             :     // now do zone surfaces, by zone
     613        4127 :     for (int zones = 1; zones <= state.dataGlobal->NumOfZones; ++zones) {
     614        7318 :         const auto TempZoneName = normalizeName(state.dataHeatBal->Zone(zones).Name);
     615             : 
     616     1080991 :         for (int surf : state.dataSurface->AllSurfaceListReportOrder) {
     617     1077332 :             auto &thisSurface = state.dataSurface->Surface(surf);
     618     1077332 :             if (thisSurface.Zone != zones) continue;
     619       32819 :             if (thisSurface.Sides == 0) continue;
     620       30697 :             if (thisSurface.Class == DataSurfaces::SurfaceClass::IntMass) continue;
     621       30697 :             if (thisSurface.Class == DataSurfaces::SurfaceClass::Wall) colorindex = DataSurfaceColors::ColorNo::Wall;
     622       30697 :             if (thisSurface.Class == DataSurfaces::SurfaceClass::Roof) colorindex = DataSurfaceColors::ColorNo::Roof;
     623       30697 :             if (thisSurface.Class == DataSurfaces::SurfaceClass::Floor) colorindex = DataSurfaceColors::ColorNo::Floor;
     624       30697 :             if (thisSurface.Class == DataSurfaces::SurfaceClass::Door) colorindex = DataSurfaceColors::ColorNo::Door;
     625       30697 :             if (thisSurface.Class == DataSurfaces::SurfaceClass::Window) {
     626        4832 :                 if (state.dataSurface->SurfWinOriginalClass(surf) == DataSurfaces::SurfaceClass::Window)
     627        4547 :                     colorindex = DataSurfaceColors::ColorNo::Window;
     628        4832 :                 if (state.dataSurface->SurfWinOriginalClass(surf) == DataSurfaces::SurfaceClass::GlassDoor)
     629         283 :                     colorindex = DataSurfaceColors::ColorNo::GlassDoor;
     630        4832 :                 if (state.dataSurface->SurfWinOriginalClass(surf) == DataSurfaces::SurfaceClass::TDD_Dome)
     631           0 :                     colorindex = DataSurfaceColors::ColorNo::TDDDome;
     632        4832 :                 if (state.dataSurface->SurfWinOriginalClass(surf) == DataSurfaces::SurfaceClass::TDD_Diffuser)
     633           2 :                     colorindex = DataSurfaceColors::ColorNo::TDDDiffuser;
     634             :             }
     635       30697 :             if (state.dataSurface->SurfIsPV(surf)) colorindex = DataSurfaceColors::ColorNo::PV;
     636             : 
     637       30697 :             print(dxffile, Format_710, thisSurface.ZoneName + ':' + thisSurface.Name);
     638       30697 :             if (thisSurface.Sides <= 4) {
     639       30533 :                 print(dxffile, Format_704_0, TempZoneName, DXFcolorno[static_cast<int>(colorindex)]);
     640       30533 :                 print(dxffile, Format_704_1, thisSurface.Vertex(1).x, thisSurface.Vertex(1).y, thisSurface.Vertex(1).z);
     641       30533 :                 print(dxffile, Format_704_2, thisSurface.Vertex(2).x, thisSurface.Vertex(2).y, thisSurface.Vertex(2).z);
     642       30533 :                 print(dxffile, Format_704_3, thisSurface.Vertex(3).x, thisSurface.Vertex(3).y, thisSurface.Vertex(3).z);
     643       30533 :                 if (thisSurface.Sides == 3) {
     644         113 :                     print(dxffile, Format_705, thisSurface.Vertex(3).x, thisSurface.Vertex(3).y, thisSurface.Vertex(3).z);
     645             :                 } else {
     646       30420 :                     print(dxffile, Format_705, thisSurface.Vertex(4).x, thisSurface.Vertex(4).y, thisSurface.Vertex(4).z);
     647             :                 }
     648             :             } else { // polygon surface
     649         164 :                 if (!TriangulateFace) {
     650          24 :                     Real64 minz = 99999.0;
     651         408 :                     for (int vert = 1; vert <= thisSurface.Sides; ++vert) {
     652         384 :                         minz = min(minz, thisSurface.Vertex(vert).z);
     653             :                     }
     654          24 :                     print(dxffile, Format_715, TempZoneName, DXFcolorno[static_cast<int>(colorindex)], minz, PolylineWidth, PolylineWidth);
     655         408 :                     for (int vert = 1; vert <= thisSurface.Sides; ++vert) {
     656         384 :                         print(dxffile, Format_716, TempZoneName, thisSurface.Vertex(vert).x, thisSurface.Vertex(vert).y, thisSurface.Vertex(vert).z);
     657             :                     }
     658          24 :                     print(dxffile, Format_717, TempZoneName);
     659             :                 } else {
     660         280 :                     Array1D<DataVectorTypes::dTriangle> mytriangles;
     661             : 
     662         140 :                     const auto ntri = DXFEarClipping::Triangulate(state,
     663             :                                                                   thisSurface.Sides,
     664             :                                                                   thisSurface.Vertex,
     665             :                                                                   mytriangles,
     666             :                                                                   thisSurface.Azimuth,
     667             :                                                                   thisSurface.Tilt,
     668             :                                                                   thisSurface.Name,
     669         140 :                                                                   thisSurface.Class);
     670         970 :                     for (int svert = 1; svert <= ntri; ++svert) {
     671         830 :                         const auto vv0 = mytriangles(svert).vv0;
     672         830 :                         const auto vv1 = mytriangles(svert).vv1;
     673         830 :                         const auto vv2 = mytriangles(svert).vv2;
     674        8300 :                         print(dxffile,
     675             :                               Format_704,
     676             :                               TempZoneName,
     677         830 :                               DXFcolorno[static_cast<int>(colorindex)],
     678         830 :                               thisSurface.Vertex(vv0).x,
     679         830 :                               thisSurface.Vertex(vv0).y,
     680         830 :                               thisSurface.Vertex(vv0).z,
     681         830 :                               thisSurface.Vertex(vv1).x,
     682         830 :                               thisSurface.Vertex(vv1).y,
     683         830 :                               thisSurface.Vertex(vv1).z,
     684         830 :                               thisSurface.Vertex(vv2).x,
     685         830 :                               thisSurface.Vertex(vv2).y,
     686        1660 :                               thisSurface.Vertex(vv2).z);
     687         830 :                         print(dxffile, Format_705, thisSurface.Vertex(vv2).x, thisSurface.Vertex(vv2).y, thisSurface.Vertex(vv2).z);
     688             :                     }
     689         140 :                     mytriangles.deallocate();
     690             :                 }
     691             :             }
     692             :         }
     693             :         // still have to do shading surfaces for zone
     694     1080991 :         for (int surf : state.dataSurface->AllSurfaceListReportOrder) {
     695     1077332 :             auto &thisSurface = state.dataSurface->Surface(surf);
     696             :             // if (surface(surf)%heattranssurf) CYCLE ! Shading with a construction is allowed to be HT surf for daylighting shelves
     697     1077332 :             if (thisSurface.Class != DataSurfaces::SurfaceClass::Shading) continue;
     698        6166 :             if (thisSurface.ZoneName != state.dataHeatBal->Zone(zones).Name) continue;
     699         960 :             if (thisSurface.Sides == 0) continue;
     700         960 :             colorindex = DataSurfaceColors::ColorNo::ShdAtt;
     701         960 :             if (state.dataSurface->SurfIsPV(surf)) colorindex = DataSurfaceColors::ColorNo::PV;
     702         960 :             print(dxffile, Format_710, thisSurface.ZoneName + ':' + thisSurface.Name);
     703         960 :             if (thisSurface.Sides <= 4) {
     704         960 :                 print(dxffile, Format_704_0, TempZoneName, DXFcolorno[static_cast<int>(colorindex)]);
     705         960 :                 print(dxffile, Format_704_1, thisSurface.Vertex(1).x, thisSurface.Vertex(1).y, thisSurface.Vertex(1).z);
     706         960 :                 print(dxffile, Format_704_2, thisSurface.Vertex(2).x, thisSurface.Vertex(2).y, thisSurface.Vertex(2).z);
     707         960 :                 print(dxffile, Format_704_3, thisSurface.Vertex(3).x, thisSurface.Vertex(3).y, thisSurface.Vertex(3).z);
     708         960 :                 if (thisSurface.Sides == 3) {
     709           0 :                     print(dxffile, Format_705, thisSurface.Vertex(3).x, thisSurface.Vertex(3).y, thisSurface.Vertex(3).z);
     710             :                 } else {
     711         960 :                     print(dxffile, Format_705, thisSurface.Vertex(4).x, thisSurface.Vertex(4).y, thisSurface.Vertex(4).z);
     712             :                 }
     713             :             } else { // polygon attached shading
     714           0 :                 if (!TriangulateFace) {
     715           0 :                     Real64 minz = 99999.0;
     716           0 :                     for (int vert = 1; vert <= thisSurface.Sides; ++vert) {
     717           0 :                         minz = min(minz, thisSurface.Vertex(vert).z);
     718             :                     }
     719           0 :                     print(dxffile, Format_715, TempZoneName, DXFcolorno[static_cast<int>(colorindex)], minz, PolylineWidth, PolylineWidth);
     720           0 :                     for (int vert = 1; vert <= thisSurface.Sides; ++vert) {
     721           0 :                         print(dxffile, Format_716, TempZoneName, thisSurface.Vertex(vert).x, thisSurface.Vertex(vert).y, thisSurface.Vertex(vert).z);
     722             :                     }
     723           0 :                     print(dxffile, Format_717, TempZoneName);
     724             :                 } else {
     725           0 :                     Array1D<DataVectorTypes::dTriangle> mytriangles;
     726           0 :                     int ntri = 0;
     727           0 :                     if (thisSurface.Shape == DataSurfaces::SurfaceShape::RectangularOverhang) {
     728           0 :                         ntri = DXFEarClipping::Triangulate(state,
     729             :                                                            thisSurface.Sides,
     730             :                                                            thisSurface.Vertex,
     731             :                                                            mytriangles,
     732             :                                                            thisSurface.Azimuth,
     733             :                                                            thisSurface.Tilt,
     734             :                                                            thisSurface.Name,
     735             :                                                            DataSurfaces::SurfaceClass::Overhang);
     736             :                     } else {
     737           0 :                         ntri = DXFEarClipping::Triangulate(state,
     738             :                                                            thisSurface.Sides,
     739             :                                                            thisSurface.Vertex,
     740             :                                                            mytriangles,
     741             :                                                            thisSurface.Azimuth,
     742             :                                                            thisSurface.Tilt,
     743             :                                                            thisSurface.Name,
     744             :                                                            DataSurfaces::SurfaceClass::Fin);
     745             :                     }
     746           0 :                     for (int svert = 1; svert <= ntri; ++svert) {
     747           0 :                         const auto vv0 = mytriangles(svert).vv0;
     748           0 :                         const auto vv1 = mytriangles(svert).vv1;
     749           0 :                         const auto vv2 = mytriangles(svert).vv2;
     750           0 :                         print(dxffile,
     751             :                               Format_704,
     752             :                               TempZoneName,
     753           0 :                               DXFcolorno[static_cast<int>(colorindex)],
     754           0 :                               thisSurface.Vertex(vv0).x,
     755           0 :                               thisSurface.Vertex(vv0).y,
     756           0 :                               thisSurface.Vertex(vv0).z,
     757           0 :                               thisSurface.Vertex(vv1).x,
     758           0 :                               thisSurface.Vertex(vv1).y,
     759           0 :                               thisSurface.Vertex(vv1).z,
     760           0 :                               thisSurface.Vertex(vv2).x,
     761           0 :                               thisSurface.Vertex(vv2).y,
     762           0 :                               thisSurface.Vertex(vv2).z);
     763           0 :                         print(dxffile, Format_705, thisSurface.Vertex(vv2).x, thisSurface.Vertex(vv2).y, thisSurface.Vertex(vv2).z);
     764             :                     }
     765           0 :                     mytriangles.deallocate();
     766             :                 }
     767             :             }
     768             :         }
     769             :     }
     770             : 
     771         468 :     DXFDaylightingReferencePoints(state, dxffile);
     772             : 
     773        4127 :     for (int zones = 1; zones <= state.dataGlobal->NumOfZones; ++zones) {
     774        3659 :         const auto curcolorno = DataSurfaceColors::ColorNo::DaylSensor1;
     775             : 
     776        3679 :         for (int mapnum = 1; mapnum <= (int)state.dataDaylightingData->IllumMap.size(); ++mapnum) {
     777          20 :             if (state.dataDaylightingData->IllumMapCalc(mapnum).zoneIndex != zones) continue;
     778         557 :             for (int refpt = 1; refpt <= state.dataDaylightingData->IllumMapCalc(mapnum).TotalMapRefPoints; ++refpt) {
     779         550 :                 print(dxffile, Format_710, format("{}:MapRefPt:{}", state.dataHeatBal->Zone(zones).Name, refpt));
     780        3300 :                 print(dxffile,
     781             :                       Format_709,
     782        1100 :                       normalizeName(state.dataHeatBal->Zone(zones).Name),
     783         550 :                       DXFcolorno[static_cast<int>(curcolorno)],
     784         550 :                       state.dataDaylightingData->IllumMapCalc(mapnum).MapRefPtAbsCoord(1, refpt),
     785         550 :                       state.dataDaylightingData->IllumMapCalc(mapnum).MapRefPtAbsCoord(2, refpt),
     786         550 :                       state.dataDaylightingData->IllumMapCalc(mapnum).MapRefPtAbsCoord(3, refpt),
     787         550 :                       0.05);
     788             :             }
     789             :         }
     790             :     }
     791             : 
     792         468 :     print(dxffile, Format_706);
     793             : }
     794             : 
     795          27 : void DXFOutWireFrame(EnergyPlusData &state, std::string const &ColorScheme)
     796             : {
     797             : 
     798             :     // SUBROUTINE INFORMATION:
     799             :     //       AUTHOR         Linda K. Lawrie
     800             :     //       DATE WRITTEN   August 2005
     801             :     //       MODIFIED       na
     802             :     //       RE-ENGINEERED  na
     803             : 
     804             :     // PURPOSE OF THIS SUBROUTINE:
     805             :     // This subroutine produces a file of DXF objects for the surfaces (all lines -- wireframe).
     806             : 
     807             :     // METHODOLOGY EMPLOYED:
     808             :     // Use the surface absolute coordinate information to produce
     809             :     // lines.
     810             : 
     811          54 :     std::string const PolylineWidth(" 0.55");
     812             : 
     813          27 :     constexpr auto Format_702("  0\nSECTION\n  2\nENTITIES\n");
     814          27 :     constexpr auto Format_707("999\nDXF created from EnergyPlus\n");
     815          27 :     constexpr auto Format_708("999\n{}{}{}\n");
     816             : 
     817          27 :     constexpr auto Format_715("  0\nPOLYLINE\n  8\n{}\n 62\n{:3}\n 66\n  1\n 10\n 0.0\n 20\n 0.0\n 30\n{:15.5F}\n 70\n   9\n 40\n{}\n 41\n{}\n");
     818          27 :     constexpr auto Format_716("  0\nVERTEX\n  8\n{}\n 10\n{:15.5F}\n 20\n{:15.5F}\n 30\n{:15.5F}\n");
     819          27 :     constexpr auto Format_717("  0\nSEQEND\n  8\n{}\n");
     820          27 :     constexpr auto Format_706("  0\nENDSEC\n  0\nEOF\n");
     821          27 :     constexpr auto Format_710("999\n{}\n");
     822             : 
     823          27 :     if (state.dataSurface->TotSurfaces > 0 && !allocated(state.dataSurface->Surface)) {
     824             :         // no error needed, probably in end processing, just return
     825           0 :         return;
     826             :     }
     827             : 
     828          54 :     auto dxffile = state.files.dxf.open(state, "DXFOutWireFrame", state.files.outputControl.dxf);
     829             : 
     830          27 :     print(dxffile, Format_702); // Start of Entities section
     831             : 
     832          27 :     print(dxffile, Format_707); // Comment
     833             : 
     834          27 :     print(dxffile, Format_708, "Program Version", ",", state.dataStrGlobals->VerStringVar);
     835          27 :     print(dxffile, Format_708, "DXF using Wireframe", ' ', ' ');
     836             : 
     837          27 :     WriteDXFCommon(state, dxffile, ColorScheme);
     838             : 
     839             :     //  Do all detached shading surfaces first
     840          27 :     int surfcount = 0;
     841          27 :     DataSurfaceColors::ColorNo colorindex = DataSurfaceColors::ColorNo::Invalid;
     842         686 :     for (int surf : state.dataSurface->AllSurfaceListReportOrder) {
     843         659 :         std::string ShadeType;
     844         659 :         auto &thisSurface = state.dataSurface->Surface(surf);
     845         659 :         if (thisSurface.HeatTransSurf) continue;
     846          44 :         if (thisSurface.Class == DataSurfaces::SurfaceClass::Shading) continue;
     847           0 :         if (thisSurface.Class == DataSurfaces::SurfaceClass::Detached_F) colorindex = DataSurfaceColors::ColorNo::ShdDetFix;
     848           0 :         if (thisSurface.Class == DataSurfaces::SurfaceClass::Detached_B) colorindex = DataSurfaceColors::ColorNo::ShdDetBldg;
     849           0 :         if (state.dataSurface->SurfIsPV(surf)) colorindex = DataSurfaceColors::ColorNo::PV;
     850           0 :         if (thisSurface.Class == DataSurfaces::SurfaceClass::Detached_F) {
     851           0 :             ShadeType = "Fixed Shading";
     852           0 :             print(dxffile, Format_710, "Fixed Shading:" + thisSurface.Name);
     853           0 :         } else if (thisSurface.Class == DataSurfaces::SurfaceClass::Detached_B) {
     854           0 :             ShadeType = "Building Shading";
     855           0 :             print(dxffile, Format_710, "Building Shading:" + thisSurface.Name);
     856             :         }
     857           0 :         ++surfcount;
     858           0 :         ShadeType += format("_{}", surfcount);
     859           0 :         Real64 minz = 99999.0;
     860           0 :         for (int vert = 1; vert <= thisSurface.Sides; ++vert) {
     861           0 :             minz = min(minz, thisSurface.Vertex(vert).z);
     862             :         }
     863             : 
     864           0 :         print(dxffile, Format_715, ShadeType, state.dataSurfColor->DXFcolorno[static_cast<int>(colorindex)], minz, PolylineWidth, PolylineWidth);
     865           0 :         for (int vert = 1; vert <= thisSurface.Sides; ++vert) {
     866           0 :             print(dxffile, Format_716, ShadeType, thisSurface.Vertex(vert).x, thisSurface.Vertex(vert).y, thisSurface.Vertex(vert).z);
     867             :         }
     868           0 :         print(dxffile, Format_717, ShadeType);
     869             :     }
     870             : 
     871             :     // now do zone surfaces, by zone
     872         109 :     for (int zones = 1; zones <= state.dataGlobal->NumOfZones; ++zones) {
     873         164 :         const auto SaveZoneName = normalizeName(state.dataHeatBal->Zone(zones).Name);
     874             : 
     875          82 :         surfcount = 0;
     876        3491 :         for (int surf : state.dataSurface->AllSurfaceListReportOrder) {
     877        3409 :             auto &thisSurface = state.dataSurface->Surface(surf);
     878        6203 :             if (thisSurface.Zone != zones) continue;
     879         615 :             if (thisSurface.Class == DataSurfaces::SurfaceClass::IntMass) continue;
     880         615 :             if (thisSurface.Class == DataSurfaces::SurfaceClass::Wall) colorindex = DataSurfaceColors::ColorNo::Wall;
     881         615 :             if (thisSurface.Class == DataSurfaces::SurfaceClass::Roof) colorindex = DataSurfaceColors::ColorNo::Roof;
     882         615 :             if (thisSurface.Class == DataSurfaces::SurfaceClass::Floor) colorindex = DataSurfaceColors::ColorNo::Floor;
     883         615 :             if (thisSurface.Class == DataSurfaces::SurfaceClass::Door) colorindex = DataSurfaceColors::ColorNo::Door;
     884         615 :             if (thisSurface.Class == DataSurfaces::SurfaceClass::Window) {
     885          68 :                 if (state.dataSurface->SurfWinOriginalClass(surf) == DataSurfaces::SurfaceClass::Window)
     886          46 :                     colorindex = DataSurfaceColors::ColorNo::Window;
     887          68 :                 if (state.dataSurface->SurfWinOriginalClass(surf) == DataSurfaces::SurfaceClass::GlassDoor)
     888          22 :                     colorindex = DataSurfaceColors::ColorNo::GlassDoor;
     889          68 :                 if (state.dataSurface->SurfWinOriginalClass(surf) == DataSurfaces::SurfaceClass::TDD_Dome)
     890           0 :                     colorindex = DataSurfaceColors::ColorNo::TDDDome;
     891          68 :                 if (state.dataSurface->SurfWinOriginalClass(surf) == DataSurfaces::SurfaceClass::TDD_Diffuser)
     892           0 :                     colorindex = DataSurfaceColors::ColorNo::TDDDiffuser;
     893             :             }
     894         615 :             if (state.dataSurface->SurfIsPV(surf)) colorindex = DataSurfaceColors::ColorNo::PV;
     895         615 :             ++surfcount;
     896             : 
     897         615 :             print(dxffile, Format_710, thisSurface.ZoneName + ':' + thisSurface.Name);
     898        1230 :             const auto TempZoneName = SaveZoneName + '_' + fmt::to_string(surfcount);
     899         615 :             Real64 minz = 99999.0;
     900        3075 :             for (int vert = 1; vert <= thisSurface.Sides; ++vert) {
     901        2460 :                 minz = min(minz, thisSurface.Vertex(vert).z);
     902             :             }
     903             : 
     904         615 :             print(
     905         615 :                 dxffile, Format_715, TempZoneName, state.dataSurfColor->DXFcolorno[static_cast<int>(colorindex)], minz, PolylineWidth, PolylineWidth);
     906        3075 :             for (int vert = 1; vert <= thisSurface.Sides; ++vert) {
     907        2460 :                 print(dxffile, Format_716, TempZoneName, thisSurface.Vertex(vert).x, thisSurface.Vertex(vert).y, thisSurface.Vertex(vert).z);
     908             :             }
     909         615 :             print(dxffile, Format_717, TempZoneName);
     910             :         }
     911             :         // still have to do shading surfaces for zone
     912          82 :         surfcount = 0;
     913        3491 :         for (int surf : state.dataSurface->AllSurfaceListReportOrder) {
     914        3409 :             auto &thisSurface = state.dataSurface->Surface(surf);
     915        6774 :             if (thisSurface.Class != DataSurfaces::SurfaceClass::Shading) continue;
     916         264 :             if (thisSurface.ZoneName != state.dataHeatBal->Zone(zones).Name) continue;
     917          44 :             colorindex = DataSurfaceColors::ColorNo::ShdAtt;
     918          44 :             if (state.dataSurface->SurfIsPV(surf)) colorindex = DataSurfaceColors::ColorNo::PV;
     919          44 :             ++surfcount;
     920             : 
     921          44 :             print(dxffile, Format_710, thisSurface.ZoneName + ':' + thisSurface.Name);
     922          88 :             const auto TempZoneName = SaveZoneName + '_' + fmt::to_string(surfcount);
     923          44 :             Real64 minz = 99999.0;
     924         220 :             for (int vert = 1; vert <= thisSurface.Sides; ++vert) {
     925         176 :                 minz = min(minz, thisSurface.Vertex(vert).z);
     926             :             }
     927             : 
     928          44 :             print(
     929          44 :                 dxffile, Format_715, TempZoneName, state.dataSurfColor->DXFcolorno[static_cast<int>(colorindex)], minz, PolylineWidth, PolylineWidth);
     930         220 :             for (int vert = 1; vert <= thisSurface.Sides; ++vert) {
     931         176 :                 print(dxffile, Format_716, TempZoneName, thisSurface.Vertex(vert).x, thisSurface.Vertex(vert).y, thisSurface.Vertex(vert).z);
     932             :             }
     933          44 :             print(dxffile, Format_717, TempZoneName);
     934             :         }
     935             :     }
     936             : 
     937          27 :     DXFDaylightingReferencePoints(state, dxffile);
     938             : 
     939          27 :     print(dxffile, Format_706);
     940             : }
     941             : 
     942         176 : void DetailsForSurfaces(EnergyPlusData &state, int const RptType) // (1=Vertices only, 10=Details only, 11=Details with vertices)
     943             : {
     944             : 
     945             :     // SUBROUTINE INFORMATION:
     946             :     //       AUTHOR         Linda Lawrie
     947             :     //       DATE WRITTEN   February 2002
     948             :     //       MODIFIED       na
     949             :     //       RE-ENGINEERED  na
     950             : 
     951             :     // PURPOSE OF THIS SUBROUTINE:
     952             :     // This subroutine provides an optional detailed surface report
     953             :     // for each surface in the input file.
     954             : 
     955             :     // SUBROUTINE PARAMETER DEFINITIONS:
     956             :     constexpr static std::array<std::string_view, 9> ConvCoeffCalcs = {
     957             :         "ASHRAESimple", "ASHRAETARP", "CeilingDiffuser", "TrombeWall", "TARP", "MoWitt", "DOE-2", "BLAST", "AdaptiveConvectionAlgorithm"};
     958             : 
     959             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     960         352 :     std::string BaseSurfName;
     961         352 :     std::string ConstructionName;
     962         352 :     std::string ScheduleName;
     963         352 :     std::string IntConvCoeffCalc;
     964         352 :     std::string ExtConvCoeffCalc;
     965             :     Real64 NominalUwithConvCoeffs;
     966         352 :     std::string cNominalU;
     967         352 :     std::string cNominalUwithConvCoeffs;
     968         352 :     std::string cSchedMin;
     969         352 :     std::string cSchedMax;
     970         352 :     std::string SolarDiffusing;
     971         352 :     std::string AlgoName;
     972             : 
     973         176 :     if (state.dataSurface->TotSurfaces > 0 && !allocated(state.dataSurface->Surface)) {
     974             :         // no error needed, probably in end processing, just return
     975           0 :         return;
     976             :     }
     977             : 
     978         352 :     std::stringstream ss;
     979         176 :     auto *eiostream = &ss;
     980             :     //!!!    Write Header lines for report
     981         176 :     if (RptType == 10) {                                                                                          // Details only
     982         140 :         *eiostream << "! <Zone Surfaces>,Zone Name,# Surfaces\n";                                                 // Format_700
     983         140 :         *eiostream << "! <Shading Surfaces>,Number of Shading Surfaces,# Surfaces\n";                             // Format_700b
     984         140 :         *eiostream << "! <HeatTransfer Surface>,Surface Name,Surface Class,Base Surface,Heat Transfer Algorithm"; // Format_701
     985         140 :         *eiostream << ",Construction,Nominal U (w/o film coefs) {W/m2-K},Nominal U (with film coefs) {W/m2-K},Solar Diffusing,Area (Net) {m2},Area "
     986             :                       "(Gross) {m2},Area (Sunlit Calc) {m2},Azimuth {deg},Tilt {deg},~Width {m},~Height {m},Reveal "
     987             :                       "{m},ExtBoundCondition,ExtConvCoeffCalc,IntConvCoeffCalc,SunExposure,WindExposure,ViewFactorToGround,ViewFactorToSky,"
     988         140 :                       "ViewFactorToGround-IR,ViewFactorToSky-IR,#Sides\n";                                   // Format_7011
     989         140 :         *eiostream << "! <Shading Surface>,Surface Name,Surface Class,Base Surface,Heat Transfer Algorithm"; // Format_701b
     990         140 :         *eiostream << ",Transmittance Schedule,Min Schedule Value,Max Schedule Value,Solar Diffusing,Area (Net) {m2},Area (Gross) {m2},Area (Sunlit "
     991             :                       "Calc) {m2},Azimuth {deg},Tilt {deg},~Width {m},~Height {m},Reveal "
     992             :                       "{m},ExtBoundCondition,ExtConvCoeffCalc,IntConvCoeffCalc,SunExposure,WindExposure,ViewFactorToGround,ViewFactorToSky,"
     993         140 :                       "ViewFactorToGround-IR,ViewFactorToSky-IR,#Sides\n";                                         // Format_7011b
     994         140 :         *eiostream << "! <Frame/Divider Surface>,Surface Name,Surface Class,Base Surface,Heat Transfer Algorithm"; // Format_701c
     995         140 :         *eiostream << ",Construction,Nominal U (w/o film coefs) {W/m2-K},Nominal U (with film coefs) {W/m2-K},Solar Diffusing,Area (Net) {m2},Area "
     996         140 :                       "(Gross) {m2},Area (Sunlit Calc) {m2},Azimuth {deg},Tilt {deg},~Width {m},~Height {m},Reveal {m}\n"; // Format_7011c
     997          36 :     } else if (RptType == 11) {                                                                                            // Details with Vertices
     998          31 :         *eiostream << "! <Zone Surfaces>,Zone Name,# Surfaces";                                                            // Format_700
     999          31 :         *eiostream << ", Vertices are shown starting at Upper-Left-Corner => Counter-Clockwise => World Coordinates\n";    // Format_710
    1000          31 :         *eiostream << "! <Shading Surfaces>,Number of Shading Surfaces,# Surfaces";                                        // Format_700b
    1001          31 :         *eiostream << ", Vertices are shown starting at Upper-Left-Corner => Counter-Clockwise => World Coordinates\n";    // Format_710
    1002          31 :         *eiostream << "! <HeatTransfer Surface>,Surface Name,Surface Class,Base Surface,Heat Transfer Algorithm";          // Format_701
    1003          31 :         *eiostream << ",Construction,Nominal U (w/o film coefs) {W/m2-K},Nominal U (with film coefs) {W/m2-K},Solar Diffusing,Area (Net) {m2},Area "
    1004             :                       "(Gross) {m2},Area (Sunlit Calc) {m2},Azimuth {deg},Tilt {deg},~Width {m},~Height {m},Reveal "
    1005             :                       "{m},ExtBoundCondition,ExtConvCoeffCalc,IntConvCoeffCalc,SunExposure,WindExposure,ViewFactorToGround,ViewFactorToSky,"
    1006          31 :                       "ViewFactorToGround-IR,ViewFactorToSky-IR,#Sides"; // Format_7011
    1007          31 :         *eiostream << ",Vertex 1 X {m},Vertex 1 Y {m},Vertex 1 Z {m},Vertex 2 X {m},Vertex 2 Y {m},Vertex 2 Z {m},Vertex 3 X {m},Vertex 3 Y "
    1008          31 :                       "{m},Vertex 3 Z {m},Vertex 4 X {m},Vertex 4 Z {m},Vertex 4 Z {m},{etc}\n";             // Format_707
    1009          31 :         *eiostream << "! <Shading Surface>,Surface Name,Surface Class,Base Surface,Heat Transfer Algorithm"; // Format_701b
    1010          31 :         *eiostream << ",Transmittance Schedule,Min Schedule Value,Max Schedule Value,Solar Diffusing,Area (Net) {m2},Area (Gross) {m2},Area (Sunlit "
    1011             :                       "Calc) {m2},Azimuth {deg},Tilt {deg},~Width {m},~Height {m},Reveal "
    1012             :                       "{m},ExtBoundCondition,ExtConvCoeffCalc,IntConvCoeffCalc,SunExposure,WindExposure,ViewFactorToGround,ViewFactorToSky,"
    1013          31 :                       "ViewFactorToGround-IR,ViewFactorToSky-IR,#Sides"; // Format_7011b
    1014          31 :         *eiostream << ",Vertex 1 X {m},Vertex 1 Y {m},Vertex 1 Z {m},Vertex 2 X {m},Vertex 2 Y {m},Vertex 2 Z {m},Vertex 3 X {m},Vertex 3 Y "
    1015          31 :                       "{m},Vertex 3 Z {m},Vertex 4 X {m},Vertex 4 Z {m},Vertex 4 Z {m},{etc}\n";                   // Format_707
    1016          31 :         *eiostream << "! <Frame/Divider Surface>,Surface Name,Surface Class,Base Surface,Heat Transfer Algorithm"; // Format_701c
    1017             :         // Vertices are not applicable for window frame and divider, so skip 707
    1018          31 :         *eiostream << ",Construction,Nominal U (w/o film coefs) {W/m2-K},Nominal U (with film coefs) {W/m2-K},Solar Diffusing,Area (Net) {m2},Area "
    1019          31 :                       "(Gross) {m2},Area (Sunlit Calc) {m2},Azimuth {deg},Tilt {deg},~Width {m},~Height {m},Reveal {m}\n"; // Format_7011c
    1020             :     } else {                                                                                                               // Vertices only
    1021           5 :         *eiostream << "! <Zone Surfaces>,Zone Name,# Surfaces";                                                            // Format_700
    1022           5 :         *eiostream << ", Vertices are shown starting at Upper-Left-Corner => Counter-Clockwise => World Coordinates\n";    // Format_710
    1023           5 :         *eiostream << "! <Shading Surfaces>,Number of Shading Surfaces,# Surfaces";                                        // Format_700b
    1024           5 :         *eiostream << ", Vertices are shown starting at Upper-Left-Corner => Counter-Clockwise => World Coordinates\n";    // Format_710
    1025           5 :         *eiostream << "! <HeatTransfer Surface>,Surface Name,Surface Class,Base Surface,Heat Transfer Algorithm";          // Format_701
    1026           5 :         *eiostream << ",#Sides";                                                                                           // Format_7012
    1027           5 :         *eiostream << ",Vertex 1 X {m},Vertex 1 Y {m},Vertex 1 Z {m},Vertex 2 X {m},Vertex 2 Y {m},Vertex 2 Z {m},Vertex 3 X {m},Vertex 3 Y "
    1028           5 :                       "{m},Vertex 3 Z {m},Vertex 4 X {m},Vertex 4 Z {m},Vertex 4 Z {m},{etc}\n";             // Format_707
    1029           5 :         *eiostream << "! <Shading Surface>,Surface Name,Surface Class,Base Surface,Heat Transfer Algorithm"; // Format_701b
    1030           5 :         *eiostream << ",#Sides";                                                                             // Format_7012
    1031           5 :         *eiostream << ",Vertex 1 X {m},Vertex 1 Y {m},Vertex 1 Z {m},Vertex 2 X {m},Vertex 2 Y {m},Vertex 2 Z {m},Vertex 3 X {m},Vertex 3 Y "
    1032           5 :                       "{m},Vertex 3 Z {m},Vertex 4 X {m},Vertex 4 Z {m},Vertex 4 Z {m},{etc}\n"; // Format_707
    1033             :         // Vertices are not applicable for window frame and divider, so skip 701c here
    1034             :     }
    1035             : 
    1036             :     // Do just "detached" shading first
    1037         176 :     int surf2 = 0;
    1038         634 :     for (int surf : state.dataSurface->AllSurfaceListReportOrder) {
    1039         634 :         surf2 = surf;
    1040         634 :         auto &thisSurface = state.dataSurface->Surface(surf);
    1041         634 :         if (thisSurface.Zone != 0) break;
    1042             :     }
    1043         176 :     if ((surf2 - 1) > 0) {
    1044             :         *eiostream << "Shading Surfaces,"
    1045          47 :                    << "Number of Shading Surfaces," << surf2 - 1 << '\n';
    1046         505 :         for (int surf : state.dataSurface->AllSurfaceListReportOrder) {
    1047         505 :             auto &thisSurface = state.dataSurface->Surface(surf);
    1048         505 :             if (thisSurface.Zone != 0) break;
    1049         458 :             AlgoName = "None";
    1050         916 :             *eiostream << "Shading Surface," << thisSurface.Name << "," << cSurfaceClass(thisSurface.Class) << "," << thisSurface.BaseSurfName << ","
    1051         916 :                        << AlgoName << ",";
    1052         458 :             if (RptType == 10) {
    1053         358 :                 if (thisSurface.SchedShadowSurfIndex > 0) {
    1054         248 :                     ScheduleName = ScheduleManager::GetScheduleName(state, thisSurface.SchedShadowSurfIndex);
    1055         248 :                     cSchedMin = format("{:.2R}", ScheduleManager::GetScheduleMinValue(state, thisSurface.SchedShadowSurfIndex));
    1056         248 :                     cSchedMax = format("{:.2R}", ScheduleManager::GetScheduleMaxValue(state, thisSurface.SchedShadowSurfIndex));
    1057             :                 } else {
    1058         110 :                     ScheduleName = "";
    1059         110 :                     cSchedMin = "0.0";
    1060         110 :                     cSchedMax = "0.0";
    1061             :                 }
    1062         716 :                 *eiostream << ScheduleName << "," << cSchedMin << "," << cSchedMax << "," << ' ' << "," << format("{:.2R}", thisSurface.Area) << ","
    1063        1074 :                            << format("{:.2R}", thisSurface.GrossArea) << "," << format("{:.2R}", thisSurface.NetAreaShadowCalc) << ","
    1064        1074 :                            << format("{:.2R}", thisSurface.Azimuth) << "," << format("{:.2R}", thisSurface.Tilt) << ","
    1065        2148 :                            << format("{:.2R}", thisSurface.Width) << "," << format("{:.2R}", thisSurface.Height) << ",";
    1066         358 :                 *eiostream << ",,,,,,,,,," << fmt::to_string(thisSurface.Sides) << '\n';
    1067         100 :             } else if (RptType == 1) {
    1068           0 :                 *eiostream << fmt::to_string(thisSurface.Sides) << ",";
    1069             :             } else {
    1070         100 :                 if (thisSurface.SchedShadowSurfIndex > 0) {
    1071          60 :                     ScheduleName = ScheduleManager::GetScheduleName(state, thisSurface.SchedShadowSurfIndex);
    1072          60 :                     cSchedMin = format("{:.2R}", ScheduleManager::GetScheduleMinValue(state, thisSurface.SchedShadowSurfIndex));
    1073          60 :                     cSchedMax = format("{:.2R}", ScheduleManager::GetScheduleMaxValue(state, thisSurface.SchedShadowSurfIndex));
    1074             :                 } else {
    1075          40 :                     ScheduleName = "";
    1076          40 :                     cSchedMin = "0.0";
    1077          40 :                     cSchedMax = "0.0";
    1078             :                 }
    1079         200 :                 *eiostream << ScheduleName << "," << cSchedMin << "," << cSchedMax << "," << ' ' << "," << format("{:.2R}", thisSurface.Area) << ","
    1080         300 :                            << format("{:.2R}", thisSurface.GrossArea) << "," << format("{:.2R}", thisSurface.NetAreaShadowCalc) << ","
    1081         300 :                            << format("{:.2R}", thisSurface.Azimuth) << "," << format("{:.2R}", thisSurface.Tilt) << ","
    1082         600 :                            << format("{:.2R}", thisSurface.Width) << "," << format("{:.2R}", thisSurface.Height) << ",";
    1083         100 :                 *eiostream << ",,,,,,,,,," << fmt::to_string(thisSurface.Sides) << ",";
    1084             :             }
    1085         458 :             if (RptType == 10) continue;
    1086         488 :             for (int vert = 1; vert <= thisSurface.Sides; ++vert) {
    1087         388 :                 if (vert != thisSurface.Sides) {
    1088         864 :                     *eiostream << format("{:.2R}", thisSurface.Vertex(vert).x) << "," << format("{:.2R}", thisSurface.Vertex(vert).y) << ","
    1089         864 :                                << format("{:.2R}", thisSurface.Vertex(vert).z) << ",";
    1090             :                 } else {
    1091         300 :                     *eiostream << format("{:.2R}", thisSurface.Vertex(vert).x) << "," << format("{:.2R}", thisSurface.Vertex(vert).y) << ","
    1092         300 :                                << format("{:.2R}", thisSurface.Vertex(vert).z) << '\n';
    1093             :                 }
    1094             :             }
    1095             :             //  This shouldn't happen with shading surface -- always have vertices
    1096         100 :             if (thisSurface.Sides == 0) *eiostream << '\n';
    1097             :         }
    1098             :     }
    1099             : 
    1100        2584 :     for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
    1101        2408 :         *eiostream << "Zone Surfaces," << state.dataHeatBal->Zone(ZoneNum).Name << ","
    1102        2408 :                    << (state.dataHeatBal->Zone(ZoneNum).AllSurfaceLast - state.dataHeatBal->Zone(ZoneNum).AllSurfaceFirst + 1) << '\n';
    1103     1016217 :         for (int surf : state.dataSurface->AllSurfaceListReportOrder) {
    1104     1013809 :             auto &thisSurface = state.dataSurface->Surface(surf);
    1105     1013809 :             if (thisSurface.Zone != ZoneNum) continue;
    1106       22692 :             SolarDiffusing = "";
    1107       22692 :             if (RptType == 10 || RptType == 11) { // Details and Details with Vertices
    1108       22359 :                 if (thisSurface.BaseSurf == surf) {
    1109       18590 :                     BaseSurfName = "";
    1110             :                 } else {
    1111        3769 :                     BaseSurfName = thisSurface.BaseSurfName;
    1112             :                 }
    1113             : 
    1114       22359 :                 AlgoName = DataSurfaces::HeatTransAlgoStrs[(int)thisSurface.HeatTransferAlgorithm];
    1115             : 
    1116             :                 // Default Convection Coefficient Calculation Algorithms
    1117       22359 :                 IntConvCoeffCalc = ConvCoeffCalcs[state.dataHeatBal->Zone(ZoneNum).InsideConvectionAlgo - 1];
    1118       22359 :                 ExtConvCoeffCalc = ConvCoeffCalcs[state.dataHeatBal->Zone(ZoneNum).OutsideConvectionAlgo - 1];
    1119             : 
    1120       44718 :                 *eiostream << "HeatTransfer Surface," << thisSurface.Name << "," << cSurfaceClass(thisSurface.Class) << "," << BaseSurfName << ","
    1121       44718 :                            << AlgoName << ",";
    1122             : 
    1123             :                 // NOTE - THIS CODE IS REPEATED IN SurfaceGeometry.cc IN SetupZoneGeometry
    1124             :                 // Calculate Nominal U-value with convection/film coefficients for reporting by adding on
    1125             :                 // prescribed R-values for interior and exterior convection coefficients as found in ASHRAE 90.1-2004, Appendix A
    1126       22359 :                 if (thisSurface.Construction > 0 && thisSurface.Construction <= state.dataHeatBal->TotConstructs) {
    1127       22359 :                     cNominalUwithConvCoeffs = "";
    1128       22359 :                     ConstructionName = state.dataConstruction->Construct(thisSurface.Construction).Name;
    1129       22359 :                     switch (thisSurface.Class) {
    1130       10540 :                     case DataSurfaces::SurfaceClass::Wall: {
    1131             :                         // Interior:  vertical, still air, Rcin = 0.68 ft2-F-hr/BTU
    1132             :                         // Exterior:  vertical, exterior wind exposure, Rcout = 0.17 ft2-F-hr/BTU
    1133       10540 :                         if (state.dataHeatBal->NominalU(thisSurface.Construction) > 0.0) {
    1134       10526 :                             NominalUwithConvCoeffs = 1.0 / (0.1197548 + (1.0 / state.dataHeatBal->NominalU(thisSurface.Construction)) + 0.0299387);
    1135             :                         } else {
    1136          14 :                             cNominalUwithConvCoeffs = "[invalid]";
    1137             :                         }
    1138       10540 :                     } break;
    1139        3266 :                     case DataSurfaces::SurfaceClass::Floor: {
    1140             :                         // Interior:  horizontal, still air, heat flow downward, Rcin = 0.92 ft2-F-hr/BTU
    1141             :                         // Exterior:  horizontal, semi-exterior (crawlspace), Rcout = 0.46 ft2-F-hr/BTU
    1142        3266 :                         if (state.dataHeatBal->NominalU(thisSurface.Construction) > 0.0) {
    1143        3266 :                             NominalUwithConvCoeffs = 1.0 / (0.1620212 + (1.0 / state.dataHeatBal->NominalU(thisSurface.Construction)) + 0.0810106);
    1144             :                         } else {
    1145           0 :                             cNominalUwithConvCoeffs = "[invalid]";
    1146             :                         }
    1147        3266 :                     } break;
    1148        2824 :                     case DataSurfaces::SurfaceClass::Roof: {
    1149             :                         // Interior:  horizontal, still air, heat flow upward, Rcin = 0.61 ft2-F-hr/BTU
    1150             :                         // Exterior:  horizontal, semi-exterior (attic), Rcout = 0.46 ft2-F-hr/BTU
    1151        2824 :                         if (state.dataHeatBal->NominalU(thisSurface.Construction) > 0.0) {
    1152        2824 :                             NominalUwithConvCoeffs = 1.0 / (0.1074271 + (1.0 / state.dataHeatBal->NominalU(thisSurface.Construction)) + 0.0810106);
    1153             :                         } else {
    1154           0 :                             cNominalUwithConvCoeffs = "[invalid]";
    1155             :                         }
    1156        2824 :                     } break;
    1157        5729 :                     default: {
    1158        5729 :                         if (state.dataHeatBal->NominalU(thisSurface.Construction) > 0.0) {
    1159        5729 :                             NominalUwithConvCoeffs = state.dataHeatBal->NominalU(thisSurface.Construction);
    1160             :                         } else {
    1161           0 :                             cNominalUwithConvCoeffs = "[invalid]";
    1162             :                         }
    1163        5729 :                     } break;
    1164             :                     }
    1165       22359 :                     if (cNominalUwithConvCoeffs.empty()) {
    1166       22345 :                         cNominalUwithConvCoeffs = format("{:.3R}", NominalUwithConvCoeffs);
    1167             :                     } else {
    1168          14 :                         cNominalUwithConvCoeffs = "[invalid]";
    1169             :                     }
    1170       22359 :                     if ((thisSurface.Class == DataSurfaces::SurfaceClass::Window) || (thisSurface.Class == DataSurfaces::SurfaceClass::TDD_Dome)) {
    1171             :                         // DataSurfaces::SurfaceClass::Window also covers glass doors and TDD:Diffusers
    1172        3468 :                         cNominalU = "N/A";
    1173        6936 :                         if (state.dataSurface->SurfWinSolarDiffusing(surf)) {
    1174           0 :                             SolarDiffusing = "Yes";
    1175             :                         } else {
    1176        3468 :                             SolarDiffusing = "No";
    1177             :                         }
    1178             :                     } else {
    1179       18891 :                         cNominalU = format("{:.3R}", state.dataHeatBal->NominalU(thisSurface.Construction));
    1180             :                     }
    1181             :                 } else {
    1182           0 :                     cNominalUwithConvCoeffs = "**";
    1183           0 :                     cNominalU = "**";
    1184           0 :                     ConstructionName = "**invalid**";
    1185             :                 }
    1186             : 
    1187             :                 *eiostream << ConstructionName << "," << cNominalU << "," << cNominalUwithConvCoeffs << "," << SolarDiffusing << ","
    1188       67077 :                            << format("{:.2R}", thisSurface.Area) << "," << format("{:.2R}", thisSurface.GrossArea) << ","
    1189       67077 :                            << format("{:.2R}", thisSurface.NetAreaShadowCalc) << "," << format("{:.2R}", thisSurface.Azimuth) << ","
    1190       67077 :                            << format("{:.2R}", thisSurface.Tilt) << "," << format("{:.2R}", thisSurface.Width) << ","
    1191      156513 :                            << format("{:.2R}", thisSurface.Height) << "," << format("{:.2R}", thisSurface.Reveal) << ",";
    1192             : 
    1193             :                 static constexpr std::array<std::string_view, (int)ConvectionConstants::ConvCoefOverrideType::Num> overrideTypeStrs = {
    1194             :                     "User Supplied Value", "User Supplied Schedule", "User Supplied Curve", "User Specified Model"};
    1195             : 
    1196       22359 :                 if (state.dataSurface->SurfIntConvCoeffIndex(surf) > 0) {
    1197          14 :                     IntConvCoeffCalc =
    1198          14 :                         overrideTypeStrs[(int)state.dataSurface->UserIntConvectionCoeffs(state.dataSurface->SurfIntConvCoeffIndex(surf))
    1199          14 :                                              .OverrideType];
    1200       22345 :                 } else if (state.dataSurface->SurfIntConvCoeffIndex(surf) < 0) { // not in use yet.
    1201           0 :                     IntConvCoeffCalc = ConvCoeffCalcs[std::abs(state.dataSurface->SurfIntConvCoeffIndex(surf)) - 1];
    1202             :                 }
    1203       22359 :                 if (state.dataSurface->SurfExtConvCoeffIndex(surf) > 0) {
    1204          14 :                     ExtConvCoeffCalc =
    1205          14 :                         overrideTypeStrs[(int)state.dataSurface->UserExtConvectionCoeffs(state.dataSurface->SurfExtConvCoeffIndex(surf))
    1206          14 :                                              .OverrideType];
    1207       22345 :                 } else if (state.dataSurface->SurfExtConvCoeffIndex(surf) < 0) {
    1208           6 :                     ExtConvCoeffCalc = ConvCoeffCalcs[std::abs(state.dataSurface->SurfExtConvCoeffIndex(surf)) - 1];
    1209             :                 }
    1210       22359 :                 if (thisSurface.ExtBoundCond == DataSurfaces::ExternalEnvironment) {
    1211             :                     *eiostream << "ExternalEnvironment"
    1212        7917 :                                << "," << ExtConvCoeffCalc << "," << IntConvCoeffCalc << ",";
    1213       14442 :                 } else if (thisSurface.ExtBoundCond == DataSurfaces::Ground) {
    1214             :                     *eiostream << "Ground"
    1215             :                                << ","
    1216             :                                << "N/A-Ground"
    1217         842 :                                << "," << IntConvCoeffCalc << ",";
    1218       13600 :                 } else if (thisSurface.ExtBoundCond == DataSurfaces::GroundFCfactorMethod) {
    1219             :                     *eiostream << "FCGround"
    1220             :                                << ","
    1221             :                                << "N/A-FCGround"
    1222         160 :                                << "," << IntConvCoeffCalc << ",";
    1223       13440 :                 } else if (thisSurface.ExtBoundCond == DataSurfaces::KivaFoundation) {
    1224             :                     *eiostream << "Foundation"
    1225             :                                << ","
    1226             :                                << "N/A-Foundation"
    1227          15 :                                << "," << IntConvCoeffCalc << ",";
    1228       26847 :                 } else if (thisSurface.ExtBoundCond == DataSurfaces::OtherSideCoefNoCalcExt ||
    1229       13422 :                            thisSurface.ExtBoundCond == DataSurfaces::OtherSideCoefCalcExt) {
    1230           4 :                     *eiostream << state.dataSurface->OSC(thisSurface.OSCPtr).Name << ","
    1231             :                                << "N/A-OSC"
    1232           8 :                                << "," << IntConvCoeffCalc << ",";
    1233       13421 :                 } else if (thisSurface.ExtBoundCond == DataSurfaces::OtherSideCondModeledExt) {
    1234           3 :                     *eiostream << state.dataSurface->OSCM(thisSurface.OSCMPtr).Name << ","
    1235             :                                << "N/A-OSCM"
    1236           6 :                                << "," << IntConvCoeffCalc << ",";
    1237             :                 } else {
    1238             :                     *eiostream << thisSurface.ExtBoundCondName << ","
    1239             :                                << "Other/Same Surface Int Conv"
    1240       13418 :                                << "," << IntConvCoeffCalc << ",";
    1241             :                 }
    1242       22359 :                 if (thisSurface.ExtSolar) {
    1243             :                     *eiostream << "SunExposed"
    1244        7844 :                                << ",";
    1245             :                 } else {
    1246             :                     *eiostream << "NoSun"
    1247       14515 :                                << ",";
    1248             :                 }
    1249       22359 :                 if (thisSurface.ExtWind) {
    1250             :                     *eiostream << "WindExposed"
    1251        7907 :                                << ",";
    1252             :                 } else {
    1253             :                     *eiostream << "NoWind"
    1254       14452 :                                << ",";
    1255             :                 }
    1256       22359 :                 if (RptType == 10) {
    1257       64479 :                     *eiostream << format("{:.2R}", thisSurface.ViewFactorGround) << "," << format("{:.2R}", thisSurface.ViewFactorSky) << ","
    1258       64479 :                                << format("{:.2R}", thisSurface.ViewFactorGroundIR) << "," << format("{:.2R}", thisSurface.ViewFactorSkyIR) << ","
    1259      107465 :                                << fmt::to_string(thisSurface.Sides) << '\n';
    1260             :                 } else {
    1261        2598 :                     *eiostream << format("{:.2R}", thisSurface.ViewFactorGround) << "," << format("{:.2R}", thisSurface.ViewFactorSky) << ","
    1262        2598 :                                << format("{:.2R}", thisSurface.ViewFactorGroundIR) << "," << format("{:.2R}", thisSurface.ViewFactorSkyIR) << ","
    1263        4330 :                                << fmt::to_string(thisSurface.Sides) << ",";
    1264        3990 :                     for (int vert = 1; vert <= thisSurface.Sides; ++vert) {
    1265        3124 :                         if (vert != thisSurface.Sides) {
    1266        7053 :                             *eiostream << format("{:.2R}", thisSurface.Vertex(vert).x) << "," << format("{:.2R}", thisSurface.Vertex(vert).y) << ","
    1267        7053 :                                        << format("{:.2R}", thisSurface.Vertex(vert).z) << ",";
    1268             :                         } else {
    1269        2319 :                             *eiostream << format("{:.2R}", thisSurface.Vertex(vert).x) << "," << format("{:.2R}", thisSurface.Vertex(vert).y) << ","
    1270        2319 :                                        << format("{:.2R}", thisSurface.Vertex(vert).z) << '\n';
    1271             :                         }
    1272             :                     }
    1273         866 :                     if (thisSurface.Sides == 0) *eiostream << '\n';
    1274             :                 }
    1275             :                 // if window, report frame/divider as appropriate
    1276       22359 :                 if (thisSurface.FrameDivider > 0) {
    1277         274 :                     int fd = thisSurface.FrameDivider;
    1278         274 :                     if (state.dataSurface->FrameDivider(fd).FrameWidth > 0.0) {
    1279          69 :                         AlgoName = DataSurfaces::HeatTransAlgoStrs[(int)thisSurface.HeatTransferAlgorithm];
    1280          69 :                         *eiostream << "Frame/Divider Surface," << state.dataSurface->FrameDivider(fd).Name << ","
    1281         138 :                                    << "Frame," << thisSurface.Name << "," << AlgoName << ",";
    1282         138 :                         *eiostream << ",N/A,N/A,," << format("{:.2R}", state.dataSurface->SurfWinFrameArea(surf)) << ","
    1283         138 :                                    << format("{:.2R}", state.dataSurface->SurfWinFrameArea(surf) / thisSurface.Multiplier) << ",*"
    1284             :                                    << ",N/A"
    1285         207 :                                    << ",N/A," << format("{:.2R}", state.dataSurface->FrameDivider(fd).FrameWidth) << ",N/A" << '\n';
    1286             :                     }
    1287         274 :                     if (state.dataSurface->FrameDivider(fd).DividerWidth > 0.0) {
    1288           5 :                         if (state.dataSurface->FrameDivider(fd).DividerType == DataSurfaces::FrameDividerType::DividedLite) {
    1289           0 :                             *eiostream << "Frame/Divider Surface," << state.dataSurface->FrameDivider(fd).Name << ","
    1290           0 :                                        << "Divider:DividedLite," << thisSurface.Name << ",,";
    1291             :                         } else {
    1292           5 :                             *eiostream << "Frame/Divider Surface," << state.dataSurface->FrameDivider(fd).Name << ","
    1293          10 :                                        << "Divider:Suspended," << thisSurface.Name << ",,";
    1294             :                         }
    1295          10 :                         *eiostream << ",N/A,N/A,," << format("{:.2R}", state.dataSurface->SurfWinDividerArea(surf)) << ","
    1296          10 :                                    << format("{:.2R}", state.dataSurface->SurfWinDividerArea(surf) / thisSurface.Multiplier) << ",*"
    1297             :                                    << ",N/A"
    1298          15 :                                    << ",N/A," << format("{:.2R}", state.dataSurface->FrameDivider(fd).DividerWidth) << ",N/A" << '\n';
    1299             :                     }
    1300       22359 :                 }
    1301             :             } else { // RptType=1  Vertices only
    1302         333 :                 if (thisSurface.BaseSurf == surf) {
    1303         286 :                     BaseSurfName = "";
    1304             :                 } else {
    1305          47 :                     BaseSurfName = thisSurface.BaseSurfName;
    1306             :                 }
    1307             : 
    1308         333 :                 AlgoName = DataSurfaces::HeatTransAlgoStrs[(int)thisSurface.HeatTransferAlgorithm];
    1309             : 
    1310         666 :                 *eiostream << "HeatTransfer Surface," << thisSurface.Name << "," << cSurfaceClass(thisSurface.Class) << "," << BaseSurfName << ","
    1311         666 :                            << AlgoName << ",";
    1312         333 :                 *eiostream << fmt::to_string(thisSurface.Sides) << ",";
    1313        1505 :                 for (int vert = 1; vert <= thisSurface.Sides; ++vert) {
    1314        1172 :                     if (vert != thisSurface.Sides) {
    1315        2637 :                         *eiostream << format("{:.2R}", thisSurface.Vertex(vert).x) << "," << format("{:.2R}", thisSurface.Vertex(vert).y) << ","
    1316        2637 :                                    << format("{:.2R}", thisSurface.Vertex(vert).z) << ",";
    1317             :                     } else {
    1318         879 :                         *eiostream << format("{:.2R}", thisSurface.Vertex(vert).x) << "," << format("{:.2R}", thisSurface.Vertex(vert).y) << ","
    1319         879 :                                    << format("{:.2R}", thisSurface.Vertex(vert).z) << '\n';
    1320             :                     }
    1321             :                 }
    1322         333 :                 if (thisSurface.Sides == 0) *eiostream << '\n';
    1323             :             }
    1324             :         } // surfaces
    1325             :     }     // zones
    1326             : 
    1327         176 :     print(state.files.eio, "{}", eiostream->str());
    1328             : }
    1329             : 
    1330           7 : void CostInfoOut(EnergyPlusData &state)
    1331             : {
    1332             : 
    1333             :     // SUBROUTINE INFORMATION:
    1334             :     //       AUTHOR         Brent Griffith
    1335             :     //       DATE WRITTEN   April 2003
    1336             :     //       MODIFIED       na
    1337             :     //       RE-ENGINEERED  na
    1338             : 
    1339             :     // PURPOSE OF THIS SUBROUTINE:
    1340             :     // This subroutine produces a file with information about surfaces.
    1341             :     // for the purpose of producing first cost estimates to include in objective value functions
    1342             :     // for design optimization
    1343             : 
    1344             :     // METHODOLOGY EMPLOYED:
    1345             :     // Access data in DataSurfaces and report
    1346             : 
    1347             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1348          14 :     Array1D_bool uniqueSurf;
    1349             : 
    1350           7 :     if (state.dataSurface->TotSurfaces > 0 && !allocated(state.dataSurface->Surface)) {
    1351             :         // no error needed, probably in end processing, just return
    1352           0 :         return;
    1353             :     }
    1354             : 
    1355             :     // need to determine unique surfaces... some surfaces are shared by zones and hence doubled
    1356           7 :     uniqueSurf.dimension(state.dataSurface->TotSurfaces, true);
    1357             : 
    1358         428 :     for (int surf : state.dataSurface->AllSurfaceListReportOrder) {
    1359         421 :         auto &thisSurface = state.dataSurface->Surface(surf);
    1360         421 :         if (thisSurface.ExtBoundCond > 0) {
    1361         209 :             if (thisSurface.ExtBoundCond < surf) { // already cycled through
    1362          82 :                 uniqueSurf(surf) = false;
    1363             :             }
    1364             :         }
    1365         421 :         if (thisSurface.Construction == 0) { // throw out others for now
    1366          30 :             uniqueSurf(surf) = false;
    1367             :         }
    1368             :     }
    1369             : 
    1370          14 :     auto scifile = state.files.sci.open(state, "CostInfoOut", state.files.outputControl.sci);
    1371             : 
    1372           7 :     print(scifile, "{:12}{:12}\n", state.dataSurface->TotSurfaces, count(uniqueSurf));
    1373           7 :     print(scifile, "{}\n", " data for surfaces useful for cost information");
    1374           7 :     print(scifile, "{}\n", " Number, Name, Construction, class, area, grossarea");
    1375             : 
    1376         428 :     for (int surf : state.dataSurface->AllSurfaceListReportOrder) {
    1377             :         // if (surface(surf)%class .eq. DataSurfaces::SurfaceClass::IntMass) CYCLE
    1378         421 :         if (!uniqueSurf(surf)) continue;
    1379             :         // why the heck are constructions == 0 ?
    1380         309 :         auto &thisSurface = state.dataSurface->Surface(surf);
    1381         309 :         if (thisSurface.Construction != 0) {
    1382             :             // Formats
    1383             :             static constexpr std::string_view Format_801("{:5},{},{},{},{:14.5F},{:14.5F}\n");
    1384         618 :             print<check_syntax(Format_801)>(scifile,
    1385             :                                             Format_801,
    1386             :                                             surf,
    1387             :                                             thisSurface.Name,
    1388         309 :                                             state.dataConstruction->Construct(thisSurface.Construction).Name,
    1389         618 :                                             cSurfaceClass(thisSurface.Class),
    1390             :                                             thisSurface.Area,
    1391             :                                             thisSurface.GrossArea);
    1392             :         }
    1393             :     }
    1394             : 
    1395           7 :     uniqueSurf.deallocate();
    1396             : }
    1397             : 
    1398          33 : void VRMLOut(EnergyPlusData &state, const std::string &PolygonAction, const std::string &ColorScheme)
    1399             : {
    1400             : 
    1401             :     // SUBROUTINE INFORMATION:
    1402             :     //       AUTHOR         Linda K. Lawrie
    1403             :     //       DATE WRITTEN   August 2006
    1404             :     //       MODIFIED       na
    1405             :     //       RE-ENGINEERED  na
    1406             : 
    1407             :     // PURPOSE OF THIS SUBROUTINE:
    1408             :     // This subroutine produces a file of VRML output for the surfaces.
    1409             : 
    1410             :     // METHODOLOGY EMPLOYED:
    1411             :     // Use the surface absolute coordinate information to produce
    1412             :     // lines.
    1413             : 
    1414             :     // SUBROUTINE PARAMETER DEFINITIONS:
    1415             :     enum class Color
    1416             :     {
    1417             :         Invalid = -1,
    1418             :         Wall,
    1419             :         Window,
    1420             :         FixedShade,
    1421             :         SubShade,
    1422             :         Roof,
    1423             :         Floor,
    1424             :         BldgShade,
    1425             :         Num
    1426             :     };
    1427             : 
    1428             :     constexpr static std::array<std::string_view, static_cast<int>(Color::Num)> colorstring = {
    1429             :         "WALL", "WINDOW", "FIXEDSHADE", "SUBSHADE", "ROOF", "FLOOR", "BLDGSHADE"};
    1430             : 
    1431             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1432          66 :     std::string ShadeType;
    1433          33 :     bool ThickPolyline(false);
    1434          33 :     bool RegularPolyline(false);
    1435          66 :     std::string PolylineWidth(" 0.55");
    1436          33 :     bool TriangulateFace(false);
    1437             : 
    1438             :     // Formats
    1439             :     static constexpr std::string_view Format_702("#VRML V2.0 utf8\n");
    1440             :     static constexpr std::string_view Format_707(
    1441             :         "WorldInfo {{\n   title \"Building - {}\"\n   info [\"EnergyPlus Program Version {}\"]\n   info [\"Surface Color Scheme {}\"]\n}}\n");
    1442             :     static constexpr std::string_view Format_800("Shape {{\nappearance DEF {} Appearance {{\nmaterial Material {{ diffuseColor {} }}\n}}\n}}\n");
    1443             :     static constexpr std::string_view Format_801(
    1444             :         "Shape {{\nappearance USE {}\ngeometry IndexedFaceSet {{\nsolid TRUE\ncoord DEF {}{} Coordinate {{\npoint [\n");
    1445             :     static constexpr std::string_view Format_802("{:15.5F} {:15.5F} {:15.5F},\n");
    1446             :     static constexpr std::string_view Format_803("]\n}}\ncoordIndex [\n");
    1447             :     static constexpr std::string_view Format_805("]\nccw TRUE\nsolid TRUE\n}}\n}}\n");
    1448             : 
    1449          33 :     if (PolygonAction == "TRIANGULATE3DFACE" || PolygonAction == "TRIANGULATE") {
    1450           1 :         TriangulateFace = true;
    1451          32 :     } else if (PolygonAction == "THICKPOLYLINE" || PolygonAction.empty()) {
    1452          32 :         ThickPolyline = true;
    1453           0 :     } else if (PolygonAction == "REGULARPOLYLINE") {
    1454           0 :         RegularPolyline = true;
    1455           0 :         PolylineWidth = " 0";
    1456             :     } else {
    1457           0 :         ShowWarningError(state, "VRMLOut: Illegal key specified for Surfaces with > 4 sides=" + PolygonAction);
    1458           0 :         ShowContinueError(state, "\"TRIANGULATE 3DFACE\" will be used for any surfaces with > 4 sides.");
    1459           0 :         TriangulateFace = true;
    1460             :     }
    1461             : 
    1462          33 :     if (state.dataSurface->TotSurfaces > 0 && !allocated(state.dataSurface->Surface)) {
    1463             :         // no error needed, probably in end processing, just return
    1464           0 :         return;
    1465             :     }
    1466             : 
    1467          66 :     auto wrlfile = state.files.wrl.open(state, "VRMLOut", state.files.outputControl.wrl);
    1468             : 
    1469          33 :     print(wrlfile, Format_702);
    1470             : 
    1471          33 :     if (ColorScheme.empty()) {
    1472          66 :         print<check_syntax(Format_707)>(
    1473          66 :             wrlfile, Format_707, state.dataHeatBal->BuildingName, state.dataStrGlobals->VerStringVar, "Default"); // World Info
    1474             :     } else {
    1475           0 :         print<check_syntax(Format_707)>(
    1476           0 :             wrlfile, Format_707, state.dataHeatBal->BuildingName, state.dataStrGlobals->VerStringVar, ColorScheme); // World Info
    1477             :     }
    1478             : 
    1479          33 :     print(wrlfile, "# Zone Names\n");
    1480         225 :     for (int zones = 1; zones <= state.dataGlobal->NumOfZones; ++zones) {
    1481         192 :         print(wrlfile, "# Zone={}:{}\n", zones, normalizeName(state.dataHeatBal->Zone(zones).Name));
    1482             :     }
    1483             : 
    1484             :     // Define the colors:
    1485             : 
    1486          33 :     print<check_syntax(Format_800)>(wrlfile, Format_800, "FLOOR", "0.502 0.502 0.502");
    1487          33 :     print<check_syntax(Format_800)>(wrlfile, Format_800, "ROOF", "1 1 0");
    1488          33 :     print<check_syntax(Format_800)>(wrlfile, Format_800, "WALL", "0 1 0");
    1489          33 :     print<check_syntax(Format_800)>(wrlfile, Format_800, "WINDOW", "0 1 1");
    1490          33 :     print<check_syntax(Format_800)>(wrlfile, Format_800, "DOOR", "0 1 1");
    1491          33 :     print<check_syntax(Format_800)>(wrlfile, Format_800, "GLASSDOOR", "0 1 1");
    1492          33 :     print<check_syntax(Format_800)>(wrlfile, Format_800, "FIXEDSHADE", "1 0 1");
    1493          33 :     print<check_syntax(Format_800)>(wrlfile, Format_800, "BLDGSHADE", "0 0 1");
    1494          33 :     print<check_syntax(Format_800)>(wrlfile, Format_800, "SUBSHADE", "1 0 1");
    1495          33 :     print<check_syntax(Format_800)>(wrlfile, Format_800, "BACKCOLOR", "0.502 0.502 0.784");
    1496             : 
    1497          33 :     Color colorindex = Color::Invalid;
    1498             : 
    1499             :     //  Do all detached shading surfaces first
    1500        1653 :     for (int surf : state.dataSurface->AllSurfaceListReportOrder) {
    1501        1620 :         auto &thisSurface = state.dataSurface->Surface(surf);
    1502        1620 :         if (thisSurface.HeatTransSurf) continue;
    1503         138 :         if (thisSurface.IsAirBoundarySurf) continue;
    1504         124 :         if (thisSurface.Class == DataSurfaces::SurfaceClass::Shading) continue;
    1505           0 :         if (thisSurface.Sides == 0) continue;
    1506           0 :         if (thisSurface.Class == DataSurfaces::SurfaceClass::Detached_F) colorindex = Color::FixedShade;
    1507           0 :         if (thisSurface.Class == DataSurfaces::SurfaceClass::Detached_B) colorindex = Color::BldgShade;
    1508           0 :         if (thisSurface.Class == DataSurfaces::SurfaceClass::Detached_F) {
    1509           0 :             ShadeType = "Fixed Shading";
    1510           0 :             print(wrlfile, "# Fixed Shading:{}\n", thisSurface.Name);
    1511           0 :         } else if (thisSurface.Class == DataSurfaces::SurfaceClass::Detached_B) {
    1512           0 :             ShadeType = "Building Shading";
    1513           0 :             print(wrlfile, "# Building Shading:{}", thisSurface.Name);
    1514             :         }
    1515           0 :         print<check_syntax(Format_801)>(wrlfile, Format_801, colorstring[static_cast<int>(colorindex)], "Surf", surf);
    1516           0 :         for (int vert = 1; vert <= thisSurface.Sides; ++vert) {
    1517           0 :             print<check_syntax(Format_802)>(wrlfile, Format_802, thisSurface.Vertex(vert).x, thisSurface.Vertex(vert).y, thisSurface.Vertex(vert).z);
    1518             :         }
    1519           0 :         print<check_syntax(Format_803)>(wrlfile, Format_803);
    1520           0 :         if (thisSurface.Sides <= 4 || !TriangulateFace) {
    1521           0 :             for (int vert = 1; vert <= thisSurface.Sides; ++vert) {
    1522           0 :                 print<FormatSyntax::FMT>(wrlfile, " {}", vert - 1);
    1523           0 :                 if (vert == thisSurface.Sides) print(wrlfile, " -1\n");
    1524             :             }
    1525           0 :             print<check_syntax(Format_805)>(wrlfile, Format_805);
    1526             :         } else { // will be >4 sided polygon with triangulate option
    1527           0 :             Array1D<DataVectorTypes::dTriangle> mytriangles;
    1528           0 :             const auto ntri = DXFEarClipping::Triangulate(state,
    1529             :                                                           thisSurface.Sides,
    1530             :                                                           thisSurface.Vertex,
    1531             :                                                           mytriangles,
    1532             :                                                           thisSurface.Azimuth,
    1533             :                                                           thisSurface.Tilt,
    1534             :                                                           thisSurface.Name,
    1535           0 :                                                           thisSurface.Class);
    1536           0 :             for (int svert = 1; svert <= ntri; ++svert) {
    1537           0 :                 const auto vv0 = mytriangles(svert).vv0;
    1538           0 :                 const auto vv1 = mytriangles(svert).vv1;
    1539           0 :                 const auto vv2 = mytriangles(svert).vv2;
    1540           0 :                 print(wrlfile, " {} {} {} -1\n", vv0 - 1, vv1 - 1, vv2 - 1);
    1541             :             }
    1542           0 :             print(wrlfile, Format_805);
    1543           0 :             mytriangles.deallocate();
    1544             :         }
    1545             :     }
    1546             :     //  ! now do zone surfaces, by zone
    1547         225 :     for (int zoneNum = 1; zoneNum <= state.dataGlobal->NumOfZones; ++zoneNum) {
    1548         192 :         int oldSurfNum = 0;
    1549        9831 :         for (int surf : state.dataSurface->AllSurfaceListReportOrder) {
    1550        9639 :             auto &thisSurface = state.dataSurface->Surface(surf);
    1551        9639 :             ++oldSurfNum;
    1552        9639 :             if (thisSurface.Zone != zoneNum) continue;
    1553        1496 :             if (thisSurface.Sides == 0) continue;
    1554        1492 :             if (thisSurface.Class == DataSurfaces::SurfaceClass::IntMass) continue;
    1555        1492 :             if (thisSurface.Class == DataSurfaces::SurfaceClass::Wall) colorindex = Color::Wall;
    1556        1492 :             if (thisSurface.Class == DataSurfaces::SurfaceClass::Roof) colorindex = Color::Roof;
    1557        1492 :             if (thisSurface.Class == DataSurfaces::SurfaceClass::TDD_Dome) colorindex = Color::Window;
    1558        1492 :             if (thisSurface.Class == DataSurfaces::SurfaceClass::Floor) colorindex = Color::Floor;
    1559        1492 :             if (thisSurface.Class == DataSurfaces::SurfaceClass::Window) colorindex = Color::Window;
    1560        1492 :             if (thisSurface.Class == DataSurfaces::SurfaceClass::Door) colorindex = Color::Window;
    1561             : 
    1562        1492 :             print(wrlfile, "# {}:{}\n", thisSurface.ZoneName, thisSurface.Name);
    1563        1492 :             print<check_syntax(Format_801)>(wrlfile, Format_801, colorstring[static_cast<int>(colorindex)], "Surf", oldSurfNum);
    1564        7465 :             for (int vert = 1; vert <= thisSurface.Sides; ++vert) {
    1565        5973 :                 print(wrlfile, Format_802, thisSurface.Vertex(vert).x, thisSurface.Vertex(vert).y, thisSurface.Vertex(vert).z);
    1566             :             }
    1567        1492 :             print<check_syntax(Format_803)>(wrlfile, Format_803);
    1568        1492 :             if (thisSurface.Sides <= 4 || !TriangulateFace) {
    1569        7447 :                 for (int vert = 1; vert <= thisSurface.Sides; ++vert) {
    1570        5957 :                     print(wrlfile, " {}", vert - 1);
    1571        5957 :                     if (vert == thisSurface.Sides) print(wrlfile, " -1\n");
    1572             :                 }
    1573        1490 :                 print<check_syntax(Format_805)>(wrlfile, Format_805);
    1574             :             } else { // will be >4 sided polygon with triangulate option
    1575           4 :                 Array1D<DataVectorTypes::dTriangle> mytriangles;
    1576           2 :                 const auto ntri = DXFEarClipping::Triangulate(state,
    1577             :                                                               thisSurface.Sides,
    1578             :                                                               thisSurface.Vertex,
    1579             :                                                               mytriangles,
    1580             :                                                               thisSurface.Azimuth,
    1581             :                                                               thisSurface.Tilt,
    1582             :                                                               thisSurface.Name,
    1583           2 :                                                               thisSurface.Class);
    1584          14 :                 for (int svert = 1; svert <= ntri; ++svert) {
    1585          12 :                     const auto vv0 = mytriangles(svert).vv0;
    1586          12 :                     const auto vv1 = mytriangles(svert).vv1;
    1587          12 :                     const auto vv2 = mytriangles(svert).vv2;
    1588          12 :                     print(wrlfile, " {} {} {} -1\n", vv0 - 1, vv1 - 1, vv2 - 1);
    1589             :                 }
    1590           2 :                 print(wrlfile, Format_805);
    1591           2 :                 mytriangles.deallocate();
    1592             :             }
    1593             :         }
    1594             :         // still have to do shading surfaces for zone
    1595         192 :         colorindex = Color::SubShade;
    1596        9831 :         for (int surf : state.dataSurface->AllSurfaceListReportOrder) {
    1597        9639 :             auto &thisSurface = state.dataSurface->Surface(surf);
    1598             :             //      !if (surface(surf)%heattranssurf) CYCLE ! Shading with a construction is allowed to be HT surf for daylighting shelves
    1599        9639 :             if (thisSurface.Class != DataSurfaces::SurfaceClass::Shading) continue;
    1600         748 :             if (thisSurface.ZoneName != state.dataHeatBal->Zone(zoneNum).Name) continue;
    1601         124 :             if (thisSurface.Sides == 0) continue;
    1602         124 :             print(wrlfile, "# {}:{}\n", thisSurface.ZoneName, thisSurface.Name);
    1603         124 :             print<check_syntax(Format_801)>(wrlfile, Format_801, colorstring[static_cast<int>(colorindex)], "Surf", surf);
    1604         620 :             for (int vert = 1; vert <= thisSurface.Sides; ++vert) {
    1605         496 :                 print(wrlfile, Format_802, thisSurface.Vertex(vert).x, thisSurface.Vertex(vert).y, thisSurface.Vertex(vert).z);
    1606             :             }
    1607         124 :             print(wrlfile, Format_803);
    1608         124 :             if (thisSurface.Sides <= 4 || !TriangulateFace) {
    1609         620 :                 for (int vert = 1; vert <= thisSurface.Sides; ++vert) {
    1610         496 :                     print(wrlfile, " {}", vert - 1);
    1611         496 :                     if (vert == thisSurface.Sides) print(wrlfile, " -1\n");
    1612             :                 }
    1613         124 :                 print(wrlfile, Format_805);
    1614             :             } else { // will be >4 sided polygon with triangulate option
    1615           0 :                 Array1D<DataVectorTypes::dTriangle> mytriangles;
    1616           0 :                 const auto ntri = DXFEarClipping::Triangulate(state,
    1617             :                                                               thisSurface.Sides,
    1618             :                                                               thisSurface.Vertex,
    1619             :                                                               mytriangles,
    1620             :                                                               thisSurface.Azimuth,
    1621             :                                                               thisSurface.Tilt,
    1622             :                                                               thisSurface.Name,
    1623           0 :                                                               thisSurface.Class);
    1624           0 :                 for (int svert = 1; svert <= ntri; ++svert) {
    1625           0 :                     const auto vv0 = mytriangles(svert).vv0;
    1626           0 :                     const auto vv1 = mytriangles(svert).vv1;
    1627           0 :                     const auto vv2 = mytriangles(svert).vv2;
    1628           0 :                     print(wrlfile, " {} {} {} -1\n", vv0 - 1, vv1 - 1, vv2 - 1);
    1629             :                 }
    1630           0 :                 print(wrlfile, Format_805);
    1631           0 :                 mytriangles.deallocate();
    1632             :             }
    1633             :         }
    1634             :     }
    1635             : 
    1636             :     // vrml does not have daylighting reference points included
    1637             : }
    1638             : 
    1639        2313 : } // namespace EnergyPlus

Generated by: LCOV version 1.13