LCOV - code coverage report
Current view: top level - EnergyPlus - DataSurfaces.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 344 385 89.4 %
Date: 2023-01-17 19:17:23 Functions: 23 23 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 <algorithm>
      50             : #include <cassert>
      51             : #include <cmath>
      52             : #include <limits>
      53             : #include <tuple>
      54             : 
      55             : // EnergyPlus Headers
      56             : #include <EnergyPlus/Construction.hh>
      57             : #include <EnergyPlus/Data/EnergyPlusData.hh>
      58             : #include <EnergyPlus/DataEnvironment.hh>
      59             : #include <EnergyPlus/DataHeatBalSurface.hh>
      60             : #include <EnergyPlus/DataHeatBalance.hh>
      61             : #include <EnergyPlus/DataLoopNode.hh>
      62             : #include <EnergyPlus/DataZoneEquipment.hh>
      63             : #include <EnergyPlus/Psychrometrics.hh>
      64             : #include <EnergyPlus/UtilityRoutines.hh>
      65             : #include <EnergyPlus/WindowManager.hh>
      66             : #include <EnergyPlus/ZoneTempPredictorCorrector.hh>
      67             : 
      68             : namespace EnergyPlus::DataSurfaces {
      69             : 
      70             : // MODULE INFORMATION:
      71             : //       AUTHOR         Linda Lawrie
      72             : //       DATE WRITTEN   May 2000
      73             : //       MODIFIED       July 2003, (CC) added a flag for reference air temperature
      74             : //                      Dec 2006, DJS (PSU) added logical ecoroof variable
      75             : //                      Dec 2008, TH added new properties to SurfaceWindowCalc for thermochromic windows
      76             : //                      Jul 2011, M.J. Witte and C.O. Pedersen, add new fields to OSC for last T, max and min
      77             : //       RE-ENGINEERED  na
      78             : 
      79             : // Using/Aliasing
      80             : using namespace DataVectorTypes;
      81             : using namespace DataBSDFWindow;
      82             : using namespace DataHeatBalance;
      83             : using namespace DataZoneEquipment;
      84             : using namespace DataLoopNode;
      85             : using namespace Psychrometrics;
      86             : using namespace DataEnvironment;
      87             : using namespace WindowManager;
      88             : 
      89         771 : Array1D_string const cExtBoundCondition({-6, 0}, {"KivaFoundation", "FCGround", "OSCM", "OSC", "OSC", "Ground", "ExternalEnvironment"});
      90             : 
      91             : // Parameters to indicate surface classes
      92             : // Surface Class (FLOOR, WALL, ROOF (incl's CEILING), WINDOW, DOOR, GLASSDOOR,
      93             : // SHADING (includes OVERHANG, WING), DETACHED, INTMASS),
      94             : // TDD:DOME, TDD:DIFFUSER (for tubular daylighting device)
      95             : // (Note: GLASSDOOR and TDD:DIFFUSER get overwritten as WINDOW
      96             : // in SurfaceGeometry.cc, SurfaceWindow%OriginalClass holds the true value)
      97             : // why aren't these sequential (LKL - 13 Aug 2007)
      98             : 
      99             : // Constructor
     100       41478 : Surface2D::Surface2D(ShapeCat const shapeCat, int const axis, Vertices const &v, Vector2D const &vl, Vector2D const &vu)
     101       41478 :     : axis(axis), vertices(v), vl(vl), vu(vu)
     102             : {
     103       41478 :     size_type const n(vertices.size());
     104       41478 :     assert(n >= 3);
     105             : 
     106             :     // Reverse vertices order if clockwise
     107             :     // If sorting by y for slab method can detect clockwise faster by just comparing edges at bottom or top-most vertex
     108       41478 :     Real64 area(0.0); // Actually 2x the signed area
     109      208063 :     for (Vertices::size_type i = 0; i < n; ++i) {
     110      166585 :         Vector2D const &v(vertices[i]);
     111      166585 :         Vector2D const &w(vertices[(i + 1) % n]);
     112      166585 :         area += (v.x * w.y) - (w.x * v.y);
     113             :     }
     114       41478 :     if (area < 0.0) std::reverse(vertices.begin() + 1, vertices.end()); // Vertices in clockwise order: Reverse all but first
     115             : 
     116             :     // Set up edge vectors for ray--surface intersection tests
     117       41478 :     edges.reserve(n);
     118      208063 :     for (Vertices::size_type i = 0; i < n; ++i) {
     119      166585 :         edges.push_back(vertices[(i + 1) % n] - vertices[i]);
     120             :     }
     121       41478 :     if (shapeCat == ShapeCat::Rectangular) { // Set side length squared for ray--surface intersection tests
     122       36242 :         assert(n == 4u);
     123       36242 :         s1 = edges[0].magnitude_squared();
     124       36242 :         s3 = edges[3].magnitude_squared();
     125        5236 :     } else if ((shapeCat == ShapeCat::Nonconvex) || (n >= nVerticesBig)) { // Set up slabs
     126         167 :         assert(n >= 4u);
     127         167 :         slabYs.reserve(n);
     128        1691 :         for (size_type i = 0; i < n; ++i)
     129        1524 :             slabYs.push_back(vertices[i].y);
     130         167 :         std::sort(slabYs.begin(), slabYs.end());                     // Sort the vertex y coordinates
     131         334 :         auto const iClip(std::unique(slabYs.begin(), slabYs.end())); // Remove duplicate y-coordinate elements
     132         167 :         slabYs.erase(iClip, slabYs.end());
     133         167 :         slabYs.shrink_to_fit();
     134         746 :         for (size_type iSlab = 0, iSlab_end = slabYs.size() - 1; iSlab < iSlab_end; ++iSlab) { // Create slabs
     135         579 :             Real64 xl(std::numeric_limits<Real64>::max());
     136         579 :             Real64 xu(std::numeric_limits<Real64>::lowest());
     137         579 :             Real64 const yl(slabYs[iSlab]);
     138         579 :             Real64 const yu(slabYs[iSlab + 1]);
     139         579 :             slabs.push_back(Slab(yl, yu));
     140         579 :             Slab &slab(slabs.back());
     141             :             using CrossEdge = std::tuple<Real64, Real64, size_type>;
     142             :             using CrossEdges = std::vector<CrossEdge>;
     143        1158 :             CrossEdges crossEdges;
     144        6709 :             for (size_type i = 0; i < n; ++i) { // Find edges crossing slab
     145        6130 :                 Vector2D const &v(vertices[i]);
     146        6130 :                 Vector2D const &w(vertices[(i + 1) % n]);
     147       11448 :                 if (((v.y <= yl) && (yu <= w.y)) || // Crosses upward
     148        8419 :                     ((yu <= v.y) && (w.y <= yl)))   // Crosses downward
     149             :                 {
     150        1624 :                     Edge const &e(edges[i]);
     151        1624 :                     assert(e.y != 0.0);
     152        1624 :                     Real64 const exy(e.x / e.y);
     153        1624 :                     Real64 const xb(v.x + (yl - v.y) * exy); // x_bot coordinate where edge intersects yl
     154        1624 :                     Real64 const xt(v.x + (yu - v.y) * exy); // x_top coordinate where edge intersects yu
     155        1624 :                     xl = std::min(xl, std::min(xb, xt));
     156        1624 :                     xu = std::max(xu, std::max(xb, xt));
     157        1624 :                     crossEdges.push_back(std::make_tuple(xb, xt, i));
     158             :                 }
     159             :             }
     160         579 :             slab.xl = xl;
     161         579 :             slab.xu = xu;
     162         579 :             assert(crossEdges.size() >= 2u);
     163         579 :             std::sort(crossEdges.begin(),
     164        1158 :                       crossEdges.end(),
     165        2248 :                       [](CrossEdge const &e1, CrossEdge const &e2) -> bool // Lambda to sort by x_mid
     166             :                       {
     167        2248 :                           return std::get<0>(e1) + std::get<1>(e1) <
     168        2248 :                                  std::get<0>(e2) + std::get<1>(e2); // Sort edges by x_mid: x_bot or x_top could have repeats with shared vertex
     169             :                       });
     170             : #ifndef NDEBUG // Check x_bot and x_top are also sorted
     171         579 :             Real64 xb(std::get<0>(crossEdges[0]));
     172         579 :             Real64 xt(std::get<1>(crossEdges[0]));
     173         579 :             Real64 const tol(1.0e-9 * std::max(std::abs(xl), std::abs(xu))); // EnergyPlus vertex precision is not tight so tolerance isn't either
     174        2203 :             for (auto const &edge : crossEdges) {                            // Detect non-simple polygon with crossing edges
     175        1624 :                 Real64 const xbe(std::get<0>(edge));
     176        1624 :                 Real64 const xte(std::get<1>(edge));
     177        1624 :                 assert(xb <= xbe + tol);
     178        1624 :                 assert(xt <= xte + tol);
     179        1624 :                 xb = xbe;
     180        1624 :                 xt = xte;
     181             :             }
     182             : #endif
     183         579 :             assert((shapeCat == ShapeCat::Nonconvex) || (crossEdges.size() == 2));
     184        2203 :             for (auto const &edge : crossEdges) {
     185        1624 :                 size_type const iEdge(std::get<2>(edge));
     186        1624 :                 slab.edges.push_back(iEdge); // Add edge to slab
     187        1624 :                 Vector2D const &e(edges[iEdge]);
     188        1624 :                 assert(e.y != 0.0);                                   // Constant y edge can't be a crossing edge
     189        1624 :                 slab.edgesXY.push_back(e.y != 0.0 ? e.x / e.y : 0.0); // Edge inverse slope
     190             :             }
     191         579 :             assert(slab.edges.size() % 2 == 0u);
     192         579 :             assert(slab.edges.size() == slab.edgesXY.size());
     193             :         }
     194             :     }
     195       41478 : }
     196             : 
     197             : // Set Precomputed Parameters
     198       43762 : void SurfaceData::set_computed_geometry()
     199             : {
     200       43762 :     if (Vertex.size() >= 3) { // Skip no-vertex "surfaces"
     201       41478 :         shapeCat = computed_shapeCat();
     202       41478 :         plane = computed_plane();
     203       41478 :         surface2d = computed_surface2d();
     204             :     }
     205       43762 : }
     206             : 
     207   438248263 : Real64 SurfaceData::getInsideAirTemperature(EnergyPlusData &state, const int t_SurfNum) const
     208             : {
     209             :     // SUBROUTINE INFORMATION:
     210             :     //       AUTHOR         Simon Vidanovic
     211             :     //       DATE WRITTEN   June 2016
     212             :     //       MODIFIED       na
     213             :     //       RE-ENGINEERED  na
     214             : 
     215             :     // PURPOSE OF THIS SUBROUTINE:
     216             :     // Routine calculates reference air temperature for given surface (refactoring from the code)
     217             :     //
     218             :     // NOTE: This routine has been copy/pasted in the past in several different modules with slight
     219             :     //       modifications at some of those places. It is quite logical that reference air temperature
     220             :     //       for the surface is calculated as public function of SurfaceData structure (class) and is
     221             :     //       later called as needed. Note that SurfaceNum had to be passed to this routine because of
     222             :     //       access to global array SurfTempEffBulkAir. I would propose refactoring where SurfTempEffBulkAir
     223             :     //       is part of SurfaceData structure and instead of calling SurfTempEffBulkAir( SurfNum ) it should
     224             :     //       be called Surface( SurfNum ).TempEffBulkAir (Simon Vidanovic)
     225             : 
     226   438248263 :     Real64 RefAirTemp = 0;
     227             : 
     228             :     // determine reference air temperature for this surface
     229   438248263 :     auto &thisZoneHB = state.dataZoneTempPredictorCorrector->zoneHeatBalance(this->Zone);
     230   438248263 :     switch (state.dataSurface->SurfTAirRef(t_SurfNum)) {
     231     2492921 :     case RefAirTemp::ZoneMeanAirTemp: {
     232     2492921 :         RefAirTemp = thisZoneHB.MAT;
     233     2492921 :     } break;
     234     4037270 :     case RefAirTemp::AdjacentAirTemp: {
     235     4037270 :         RefAirTemp = state.dataHeatBal->SurfTempEffBulkAir(t_SurfNum);
     236     4037270 :     } break;
     237           0 :     case RefAirTemp::ZoneSupplyAirTemp: {
     238             :         // determine ZoneEquipConfigNum for this zone
     239             :         //            ControlledZoneAirFlag = .FALSE.
     240             :         // ZoneEquipConfigNum = ZoneNum;
     241             :         // check whether this zone is a controlled zone or not
     242           0 :         if (!state.dataHeatBal->Zone(Zone).IsControlled) {
     243           0 :             ShowFatalError(
     244           0 :                 state, "Zones must be controlled for Ceiling-Diffuser Convection model. No system serves zone " + state.dataHeatBal->Zone(Zone).Name);
     245             :             // return;
     246             :         }
     247             :         // determine supply air conditions
     248           0 :         Real64 SumSysMCp = 0;
     249           0 :         Real64 SumSysMCpT = 0;
     250           0 :         for (int NodeNum = 1; NodeNum <= state.dataZoneEquip->ZoneEquipConfig(Zone).NumInletNodes; ++NodeNum) {
     251           0 :             Real64 NodeTemp = state.dataLoopNodes->Node(state.dataZoneEquip->ZoneEquipConfig(Zone).InletNode(NodeNum)).Temp;
     252           0 :             Real64 MassFlowRate = state.dataLoopNodes->Node(state.dataZoneEquip->ZoneEquipConfig(Zone).InletNode(NodeNum)).MassFlowRate;
     253           0 :             Real64 CpAir = PsyCpAirFnW(thisZoneHB.ZoneAirHumRat);
     254           0 :             SumSysMCp += MassFlowRate * CpAir;
     255           0 :             SumSysMCpT += MassFlowRate * CpAir * NodeTemp;
     256             :         }
     257             :         // a weighted average of the inlet temperatures.
     258           0 :         if (SumSysMCp > 0.0) {
     259             :             // a weighted average of the inlet temperatures.
     260           0 :             RefAirTemp = SumSysMCpT / SumSysMCp;
     261             :         } else {
     262           0 :             RefAirTemp = thisZoneHB.MAT;
     263             :         }
     264           0 :     } break;
     265   431718072 :     default: {
     266             :         // currently set to mean air temp but should add error warning here
     267   431718072 :         RefAirTemp = thisZoneHB.MAT;
     268   431718072 :     } break;
     269             :     }
     270             : 
     271   438248263 :     return RefAirTemp;
     272             : }
     273             : 
     274        8064 : Real64 SurfaceData::getOutsideAirTemperature(EnergyPlusData &state, const int t_SurfNum) const
     275             : {
     276             :     // SUBROUTINE INFORMATION:
     277             :     //       AUTHOR         Simon Vidanovic
     278             :     //       DATE WRITTEN   June 2016
     279             :     //       MODIFIED       na
     280             :     //       RE-ENGINEERED  na
     281             : 
     282             :     // PURPOSE OF THIS SUBROUTINE:
     283             :     // Routine calculates outside air temperature for given surface.
     284             :     // Routine will return inside air temperature if it is interior surface. (refactoring from the code)
     285             :     //
     286             :     // NOTE: This routine has been copy/pasted in the past in several different modules with slight
     287             :     //       modifications at some of those places. Exterior/interior surface air temperature is tied to surface.
     288        8064 :     Real64 temperature = 0;
     289             : 
     290        8064 :     if (ExtBoundCond > 0) // Interzone window
     291             :     {
     292           0 :         temperature = getInsideAirTemperature(state, t_SurfNum);
     293             :     } else {
     294        8064 :         if (ExtWind) {
     295             :             // Window is exposed to wind (and possibly rain)
     296        8064 :             if (state.dataEnvrn->IsRain) {
     297             :                 // Raining: since wind exposed, outside window surface gets wet
     298           0 :                 temperature = state.dataSurface->SurfOutWetBulbTemp(t_SurfNum);
     299             :             } else {
     300             :                 // Dry
     301        8064 :                 temperature = state.dataSurface->SurfOutDryBulbTemp(t_SurfNum);
     302             :             }
     303             :         } else {
     304             :             // Window not exposed to wind
     305           0 :             temperature = state.dataSurface->SurfOutDryBulbTemp(t_SurfNum);
     306             :         }
     307             :     }
     308             : 
     309        8064 :     return temperature;
     310             : }
     311             : 
     312        4032 : Real64 SurfaceData::getOutsideIR(EnergyPlusData &state, const int t_SurfNum) const
     313             : {
     314             :     // SUBROUTINE INFORMATION:
     315             :     //       AUTHOR         Simon Vidanovic
     316             :     //       DATE WRITTEN   July 2016
     317             :     //       MODIFIED       na
     318             :     //       RE-ENGINEERED  na
     319             : 
     320             :     // PURPOSE OF THIS SUBROUTINE:
     321             :     // Calculates outside infrared radiation
     322        4032 :     Real64 value = 0;
     323        4032 :     if (ExtBoundCond > 0) {
     324           0 :         value = state.dataSurface->SurfWinIRfromParentZone(ExtBoundCond) + state.dataHeatBalSurf->SurfQdotRadHVACInPerArea(ExtBoundCond);
     325             :     } else {
     326        4032 :         Real64 tout = getOutsideAirTemperature(state, t_SurfNum) + DataGlobalConstants::KelvinConv;
     327        4032 :         value = state.dataWindowManager->sigma * pow_4(tout);
     328       12096 :         value = ViewFactorSkyIR *
     329       12096 :                     (state.dataSurface->SurfAirSkyRadSplit(t_SurfNum) * state.dataWindowManager->sigma * pow_4(state.dataEnvrn->SkyTempKelvin) +
     330        4032 :                      (1.0 - state.dataSurface->SurfAirSkyRadSplit(t_SurfNum)) * value) +
     331        4032 :                 ViewFactorGroundIR * value;
     332             :     }
     333        4032 :     return value;
     334             : }
     335             : 
     336        4032 : Real64 SurfaceData::getSWIncident(EnergyPlusData &state, const int t_SurfNum)
     337             : {
     338             :     // SUBROUTINE INFORMATION:
     339             :     //       AUTHOR         Simon Vidanovic
     340             :     //       DATE WRITTEN   July 2016
     341             :     //       MODIFIED       na
     342             :     //       RE-ENGINEERED  na
     343             : 
     344             :     // PURPOSE OF THIS SUBROUTINE:
     345             :     // Return total short wave incident to the surface
     346             : 
     347        4032 :     return state.dataHeatBal->SurfQRadSWOutIncident(t_SurfNum) +
     348        4032 :            state.dataHeatBal->EnclSolQSWRad(state.dataSurface->Surface(t_SurfNum).SolarEnclIndex);
     349             : }
     350             : 
     351       10752 : int SurfaceData::getTotLayers(EnergyPlusData &state) const
     352             : {
     353             :     // SUBROUTINE INFORMATION:
     354             :     //       AUTHOR         Simon Vidanovic
     355             :     //       DATE WRITTEN   August 2016
     356             :     //       MODIFIED       na
     357             :     //       RE-ENGINEERED  na
     358             : 
     359             :     // PURPOSE OF THIS SUBROUTINE:
     360             :     // Returns total number of layer for current surface
     361             : 
     362       10752 :     auto &construction(state.dataConstruction->Construct(Construction));
     363       10752 :     return construction.TotLayers;
     364             : }
     365             : 
     366             : // Computed Shape Category
     367       41478 : ShapeCat SurfaceData::computed_shapeCat() const
     368             : {
     369       41478 :     if (Shape == SurfaceShape::Triangle) {
     370         181 :         return ShapeCat::Triangular;
     371       41297 :     } else if (Shape == SurfaceShape::TriangularWindow) {
     372           2 :         return ShapeCat::Triangular;
     373       41295 :     } else if (Shape == SurfaceShape::TriangularDoor) {
     374           0 :         return ShapeCat::Triangular;
     375       41295 :     } else if (Shape == SurfaceShape::Rectangle) {
     376       29804 :         return ShapeCat::Rectangular;
     377       11491 :     } else if (Shape == SurfaceShape::RectangularDoorWindow) {
     378        6438 :         return ShapeCat::Rectangular;
     379        5053 :     } else if (Shape == SurfaceShape::RectangularOverhang) {
     380           0 :         return ShapeCat::Rectangular;
     381        5053 :     } else if (Shape == SurfaceShape::RectangularLeftFin) {
     382           0 :         return ShapeCat::Rectangular;
     383        5053 :     } else if (Shape == SurfaceShape::RectangularRightFin) {
     384           0 :         return ShapeCat::Rectangular;
     385        5053 :     } else if (IsConvex) {
     386        4886 :         return ShapeCat::Convex;
     387             :     } else {
     388         167 :         return ShapeCat::Nonconvex;
     389             :     }
     390             : }
     391             : 
     392             : // Computed Plane
     393       82956 : SurfaceData::Plane SurfaceData::computed_plane() const
     394             : {
     395       82956 :     Vertices::size_type const n(Vertex.size());
     396       82956 :     assert(n >= 3);
     397      165912 :     Vector center(0.0);                           // Center (vertex average) point (not mass centroid)
     398       82956 :     Real64 a(0.0), b(0.0), c(0.0), d(0.0);        // Plane coefficients
     399      416126 :     for (Vertices::size_type i = 0; i < n; ++i) { // Newell's method for robustness (not speed)
     400      333170 :         Vector const &v(Vertex[i]);
     401      333170 :         Vector const &w(Vertex[(i + 1) % n]);
     402      333170 :         a += (v.y - w.y) * (v.z + w.z);
     403      333170 :         b += (v.z - w.z) * (v.x + w.x);
     404      333170 :         c += (v.x - w.x) * (v.y + w.y);
     405      333170 :         center += v;
     406             :     }
     407       82956 :     d = -(dot(center, Vector(a, b, c)) / n); // center/n is the center point
     408      165912 :     return Plane(a, b, c, d);                // a*x + b*y + c*z + d = 0
     409             : }
     410             : 
     411             : // Computed axis-projected 2D surface
     412       41478 : Surface2D SurfaceData::computed_surface2d() const
     413             : {
     414             :     // Project along axis of min surface range for 2D intersection use
     415       41478 :     Vertices::size_type const n(Vertex.size());
     416       41478 :     assert(n >= 3);
     417       41478 :     assert(plane == computed_plane()); // Set plane first
     418             :     using Vertex2D = ObjexxFCL::Vector2<Real64>;
     419             :     using Vertices2D = ObjexxFCL::Array1D<Vertex2D>;
     420             : 
     421             :     // Select axis to project along
     422       41478 :     Real64 const a(std::abs(plane.x));                                       // Plane normal x coordinate magnitude
     423       41478 :     Real64 const b(std::abs(plane.y));                                       // Plane normal y coordinate magnitude
     424       41478 :     Real64 const c(std::abs(plane.z));                                       // Plane normal z coordinate magnitude
     425       41478 :     int const axis(a >= std::max(b, c) ? 0 : (b >= std::max(a, c) ? 1 : 2)); // Project along plane's normal's largest magnitude coordinate
     426             : 
     427             :     // Set up 2D surface
     428       82956 :     Vertices2D v2d(n);
     429       41478 :     Vector const &v0(Vertex[0]);
     430       41478 :     if (axis == 0) {               // Use y,z for 2D surface
     431       12845 :         Real64 yl(v0.y), yu(v0.y); // y coordinate ranges
     432       12845 :         Real64 zl(v0.z), zu(v0.z); // z coordinate ranges
     433       64139 :         for (Vertices::size_type i = 0; i < n; ++i) {
     434       51294 :             Vector const &v(Vertex[i]);
     435       51294 :             v2d[i] = Vertex2D(v.y, v.z);
     436       51294 :             yl = std::min(yl, v.y);
     437       51294 :             yu = std::max(yu, v.y);
     438       51294 :             zl = std::min(zl, v.z);
     439       51294 :             zu = std::max(zu, v.z);
     440             :         }
     441       12845 :         return Surface2D(shapeCat, axis, v2d, Vertex2D(yl, zl), Vertex2D(yu, zu));
     442       28633 :     } else if (axis == 1) {        // Use x,z for 2D surface
     443       14880 :         Real64 xl(v0.x), xu(v0.x); // x coordinate ranges
     444       14880 :         Real64 zl(v0.z), zu(v0.z); // z coordinate ranges
     445       74362 :         for (Vertices::size_type i = 0; i < n; ++i) {
     446       59482 :             Vector const &v(Vertex[i]);
     447       59482 :             v2d[i] = Vertex2D(v.x, v.z);
     448       59482 :             xl = std::min(xl, v.x);
     449       59482 :             xu = std::max(xu, v.x);
     450       59482 :             zl = std::min(zl, v.z);
     451       59482 :             zu = std::max(zu, v.z);
     452             :         }
     453       14880 :         return Surface2D(shapeCat, axis, v2d, Vertex2D(xl, zl), Vertex2D(xu, zu));
     454             :     } else {                       // Use x,y for 2D surface
     455       13753 :         Real64 xl(v0.x), xu(v0.x); // x coordinate ranges
     456       13753 :         Real64 yl(v0.y), yu(v0.y); // y coordinate ranges
     457       69562 :         for (Vertices::size_type i = 0; i < n; ++i) {
     458       55809 :             Vector const &v(Vertex[i]);
     459       55809 :             v2d[i] = Vertex2D(v.x, v.y);
     460       55809 :             xl = std::min(xl, v.x);
     461       55809 :             xu = std::max(xu, v.x);
     462       55809 :             yl = std::min(yl, v.y);
     463       55809 :             yu = std::max(yu, v.y);
     464             :         }
     465       13753 :         return Surface2D(shapeCat, axis, v2d, Vertex2D(xl, yl), Vertex2D(xu, yu));
     466             :     }
     467             : }
     468             : 
     469          15 : Real64 SurfaceData::get_average_height(EnergyPlusData &state) const
     470             : {
     471          15 :     if (std::abs(SinTilt) < 1.e-4) {
     472           0 :         return 0.0;
     473             :     }
     474             :     using Vertex2D = ObjexxFCL::Vector2<Real64>;
     475             :     using Vertices2D = ObjexxFCL::Array1D<Vertex2D>;
     476          15 :     Vertices::size_type const n(Vertex.size());
     477          15 :     assert(n >= 3);
     478             : 
     479          30 :     Vertices2D v2d(n);
     480             : 
     481             :     // project onto 2D vertical plane
     482          15 :     Real64 xRef = Vertex[0].x;
     483          15 :     Real64 yRef = Vertex[0].y;
     484          15 :     Real64 const &saz(SinAzim);
     485          15 :     Real64 const &caz(CosAzim);
     486          75 :     for (Vertices::size_type i = 0; i < n; ++i) {
     487          60 :         Vector const &v(Vertex[i]);
     488          60 :         v2d[i] = Vertex2D(-(v.x - xRef) * caz + (v.y - yRef) * saz, v.z);
     489             :     }
     490             : 
     491             :     // piecewise linear integration
     492             : 
     493             :     // Get total width of polygon
     494          15 :     Real64 minX(v2d[0].x), maxX(v2d[0].x);
     495          75 :     for (Vertices::size_type i = 0; i < n; ++i) {
     496          60 :         Vertex2D const &v(v2d[i]);
     497          60 :         minX = std::min(minX, v.x);
     498          60 :         maxX = std::max(maxX, v.x);
     499             :     }
     500          15 :     Real64 totalWidth = maxX - minX;
     501             : 
     502          15 :     if (totalWidth == 0.0) {
     503             :         // This should never happen, but if it does, print a somewhat meaningful fatal error
     504             :         // (instead of allowing a divide by zero).
     505           0 :         ShowFatalError(state, "Calculated projected surface width is zero for surface=\"" + Name + "\"");
     506             :     }
     507             : 
     508          15 :     Real64 averageHeight = 0.0;
     509          75 :     for (Vertices::size_type i = 0; i < n; ++i) {
     510          60 :         Vertex2D const &v(v2d[i]);
     511             : 
     512             :         Vertex2D *v2;
     513          60 :         if (i == n - 1) {
     514          15 :             v2 = &v2d[0];
     515             :         } else {
     516          45 :             v2 = &v2d[i + 1];
     517             :         }
     518          60 :         averageHeight += 0.5 * (v.y + v2->y) * (v2->x - v.x) / totalWidth;
     519             :     }
     520          15 :     return std::abs(averageHeight) / SinTilt;
     521             : }
     522             : 
     523         579 : void SurfaceData::make_hash_key(EnergyPlusData &state, const int SurfNum)
     524             : {
     525         579 :     calcHashKey = SurfaceCalcHashKey();
     526         579 :     calcHashKey.Construction = Construction;
     527         579 :     calcHashKey.Azimuth = round(Azimuth * 10.0) / 10.0;
     528         579 :     calcHashKey.Tilt = round(Tilt * 10.0) / 10.0;
     529         579 :     calcHashKey.Height = round(Height * 10.0) / 10.0;
     530         579 :     calcHashKey.Zone = Zone;
     531         579 :     calcHashKey.EnclIndex = SolarEnclIndex;
     532         579 :     calcHashKey.TAirRef = state.dataSurface->SurfTAirRef(SurfNum);
     533             : 
     534         579 :     auto extBoundCond = state.dataSurface->Surface(SurfNum).ExtBoundCond;
     535         579 :     if (extBoundCond > 0) {
     536         256 :         calcHashKey.ExtZone = state.dataSurface->Surface(extBoundCond).Zone;
     537         256 :         calcHashKey.ExtEnclIndex = state.dataSurface->Surface(extBoundCond).SolarEnclIndex;
     538         256 :         calcHashKey.ExtCond = 1;
     539             :     } else {
     540         323 :         calcHashKey.ExtZone = 0;
     541         323 :         calcHashKey.ExtEnclIndex = 0;
     542         323 :         calcHashKey.ExtCond = extBoundCond;
     543             :     }
     544             : 
     545         579 :     calcHashKey.ExtSolar = ExtSolar;
     546         579 :     calcHashKey.ExtWind = ExtWind;
     547         579 :     calcHashKey.ViewFactorGround = round(ViewFactorGround * 10.0) / 10.0;
     548         579 :     calcHashKey.ViewFactorSky = round(ViewFactorSky * 10.0) / 10.0;
     549             : 
     550         579 :     calcHashKey.HeatTransferAlgorithm = HeatTransferAlgorithm;
     551         579 :     calcHashKey.IntConvCoeff = state.dataSurface->SurfIntConvCoeffIndex(SurfNum);
     552         579 :     calcHashKey.ExtConvCoeff = state.dataSurface->SurfExtConvCoeffIndex(SurfNum);
     553         579 :     calcHashKey.OSCPtr = OSCPtr;
     554         579 :     calcHashKey.OSCMPtr = OSCMPtr;
     555             : 
     556         579 :     calcHashKey.FrameDivider = FrameDivider;
     557         579 :     calcHashKey.SurfWinStormWinConstr = state.dataSurface->SurfWinStormWinConstr(SurfNum);
     558             : 
     559         579 :     calcHashKey.MaterialMovInsulExt = state.dataSurface->SurfMaterialMovInsulExt(SurfNum);
     560         579 :     calcHashKey.MaterialMovInsulInt = state.dataSurface->SurfMaterialMovInsulInt(SurfNum);
     561         579 :     calcHashKey.SchedMovInsulExt = state.dataSurface->SurfSchedMovInsulExt(SurfNum);
     562         579 :     calcHashKey.SchedMovInsulInt = state.dataSurface->SurfSchedMovInsulInt(SurfNum);
     563         579 :     calcHashKey.ExternalShadingSchInd = state.dataSurface->Surface(SurfNum).SurfExternalShadingSchInd;
     564         579 :     calcHashKey.SurroundingSurfacesNum = state.dataSurface->Surface(SurfNum).SurfSurroundingSurfacesNum;
     565         579 :     calcHashKey.LinkedOutAirNode = state.dataSurface->Surface(SurfNum).SurfLinkedOutAirNode;
     566         579 :     calcHashKey.OutsideHeatSourceTermSchedule = OutsideHeatSourceTermSchedule;
     567         579 :     calcHashKey.InsideHeatSourceTermSchedule = InsideHeatSourceTermSchedule;
     568         579 : }
     569             : 
     570         579 : void SurfaceData::set_representative_surface(EnergyPlusData &state, const int SurfNum)
     571             : {
     572             :     // Make hash key for this surface (used to determine uniqueness)
     573         579 :     state.dataSurface->Surface(SurfNum).make_hash_key(state, SurfNum);
     574             :     // Insert surface key into map. If key already exists, it will not be added.
     575             :     // Assign the representative surface number based on the first instance of the identical key
     576         579 :     state.dataSurface->Surface(SurfNum).RepresentativeCalcSurfNum =
     577        1158 :         state.dataSurface->RepresentativeSurfaceMap.insert({state.dataSurface->Surface(SurfNum).calcHashKey, SurfNum}).first->second;
     578             : 
     579         579 :     state.dataSurface->Surface(state.dataSurface->Surface(SurfNum).RepresentativeCalcSurfNum).ConstituentSurfaceNums.push_back(SurfNum);
     580         579 : }
     581             : 
     582             : // Functions
     583             : 
     584     2568509 : void SetSurfaceOutBulbTempAt(EnergyPlusData &state)
     585             : {
     586     2568509 :     if (state.dataEnvrn->SiteTempGradient == 0.0) {
     587           0 :         for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; SurfNum++) {
     588           0 :             state.dataSurface->SurfOutDryBulbTemp(SurfNum) = state.dataEnvrn->OutDryBulbTemp;
     589           0 :             state.dataSurface->SurfOutWetBulbTemp(SurfNum) = state.dataEnvrn->OutWetBulbTemp;
     590             :         }
     591             :     } else {
     592     2568509 :         Real64 const BaseDryTemp(state.dataEnvrn->OutDryBulbTemp + state.dataEnvrn->WeatherFileTempModCoeff);
     593     2568509 :         Real64 const BaseWetTemp(state.dataEnvrn->OutWetBulbTemp + state.dataEnvrn->WeatherFileTempModCoeff);
     594   166715563 :         for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; SurfNum++) {
     595             :             // Base temperatures at Z = 0 (C)
     596   164147054 :             Real64 const Z(state.dataSurface->Surface(SurfNum).Centroid.z); // Centroid value
     597   164147054 :             if (Z <= 0.0) {
     598    22838190 :                 state.dataSurface->SurfOutDryBulbTemp(SurfNum) = BaseDryTemp;
     599    22838190 :                 state.dataSurface->SurfOutWetBulbTemp(SurfNum) = BaseWetTemp;
     600             :             } else {
     601   141308864 :                 Real64 GradientDividend = state.dataEnvrn->SiteTempGradient * DataEnvironment::EarthRadius * Z;
     602   141308864 :                 Real64 GradientDivisor = DataEnvironment::EarthRadius + Z;
     603   141308864 :                 state.dataSurface->SurfOutDryBulbTemp(SurfNum) = BaseDryTemp - GradientDividend / GradientDivisor;
     604   141308864 :                 state.dataSurface->SurfOutWetBulbTemp(SurfNum) = BaseWetTemp - GradientDividend / GradientDivisor;
     605             :             }
     606             :         }
     607             :     }
     608     2568509 : }
     609             : 
     610     2568509 : void CheckSurfaceOutBulbTempAt(EnergyPlusData &state)
     611             : {
     612             :     // Using/Aliasing
     613             :     using DataEnvironment::SetOutBulbTempAt_error;
     614             : 
     615     2568509 :     Real64 minBulb = 0.0;
     616   166715563 :     for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; SurfNum++) {
     617   164147054 :         minBulb = min(minBulb, state.dataSurface->SurfOutDryBulbTemp(SurfNum), state.dataSurface->SurfOutWetBulbTemp(SurfNum));
     618   164147054 :         if (minBulb < -100.0)
     619           0 :             SetOutBulbTempAt_error(state, "Surface", state.dataSurface->Surface(SurfNum).Centroid.z, state.dataSurface->Surface(SurfNum).Name);
     620             :     }
     621     2568509 : }
     622             : 
     623     2568509 : void SetSurfaceWindSpeedAt(EnergyPlusData &state)
     624             : {
     625     2568509 :     Real64 const fac(state.dataEnvrn->WindSpeed * state.dataEnvrn->WeatherFileWindModCoeff *
     626     2568509 :                      std::pow(state.dataEnvrn->SiteWindBLHeight, -state.dataEnvrn->SiteWindExp));
     627     2568509 :     if (state.dataEnvrn->SiteWindExp == 0.0) {
     628           0 :         for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; SurfNum++) {
     629           0 :             state.dataSurface->SurfOutWindSpeed(SurfNum) = state.dataEnvrn->WindSpeed;
     630             :         }
     631             :     } else {
     632             : 
     633   166715563 :         for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; SurfNum++) {
     634   164147054 :             if (!state.dataSurface->Surface(SurfNum).ExtWind) continue;
     635    64897072 :             Real64 const Z(state.dataSurface->Surface(SurfNum).Centroid.z); // Centroid value
     636    64897072 :             if (Z <= 0.0) {
     637       72555 :                 state.dataSurface->SurfOutWindSpeed(SurfNum) = 0.0;
     638             :             } else {
     639             :                 //  [Met] - at meterological Station, Height of measurement is usually 10m above ground
     640             :                 //  LocalWindSpeed = Windspeed [Met] * (Wind Boundary LayerThickness [Met]/Height [Met])**Wind Exponent[Met] &
     641             :                 //                     * (Height above ground / Site Wind Boundary Layer Thickness) ** Site Wind Exponent
     642    64824517 :                 state.dataSurface->SurfOutWindSpeed(SurfNum) = fac * std::pow(Z, state.dataEnvrn->SiteWindExp);
     643             :             }
     644             :         }
     645             :     }
     646     2568509 : }
     647             : 
     648     2568509 : void SetSurfaceWindDirAt(EnergyPlusData &state)
     649             : {
     650   166715563 :     for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; SurfNum++) {
     651   164147054 :         state.dataSurface->SurfOutWindDir(SurfNum) = state.dataEnvrn->WindDir;
     652             :     }
     653     2568509 : }
     654             : 
     655       37314 : std::string cSurfaceClass(SurfaceClass const ClassNo)
     656             : {
     657             : 
     658             :     // FUNCTION INFORMATION:
     659             :     //       AUTHOR         Linda Lawrie
     660             :     //       DATE WRITTEN   May 2006
     661             :     //       MODIFIED       na
     662             :     //       RE-ENGINEERED  na
     663             : 
     664             :     // PURPOSE OF THIS FUNCTION:
     665             :     // This function returns a string based on class number.
     666             : 
     667             :     // Return value
     668       37314 :     std::string ClassName;
     669             : 
     670       37314 :     switch (ClassNo) {
     671       17593 :     case SurfaceClass::Wall: {
     672       17593 :         ClassName = "Wall";
     673       17593 :     } break;
     674        5461 :     case SurfaceClass::Floor: {
     675        5461 :         ClassName = "Floor";
     676        5461 :     } break;
     677        4687 :     case SurfaceClass::Roof: {
     678        4687 :         ClassName = "Roof";
     679        4687 :     } break;
     680        5398 :     case SurfaceClass::Window: {
     681        5398 :         ClassName = "Window";
     682        5398 :     } break;
     683           0 :     case SurfaceClass::GlassDoor: {
     684           0 :         ClassName = "Glass Door";
     685           0 :     } break;
     686         412 :     case SurfaceClass::Door: {
     687         412 :         ClassName = "Door";
     688         412 :     } break;
     689           4 :     case SurfaceClass::TDD_Dome: {
     690           4 :         ClassName = "TubularDaylightDome";
     691           4 :     } break;
     692           0 :     case SurfaceClass::TDD_Diffuser: {
     693           0 :         ClassName = "TubularDaylightDiffuser";
     694           0 :     } break;
     695        3119 :     case SurfaceClass::IntMass: {
     696        3119 :         ClassName = "Internal Mass";
     697        3119 :     } break;
     698         556 :     case SurfaceClass::Shading: {
     699         556 :         ClassName = "Shading";
     700         556 :     } break;
     701          30 :     case SurfaceClass::Detached_B: {
     702          30 :         ClassName = "Detached Shading:Building";
     703          30 :     } break;
     704          54 :     case SurfaceClass::Detached_F: {
     705          54 :         ClassName = "Detached Shading:Fixed";
     706          54 :     } break;
     707           0 :     default: {
     708           0 :         ClassName = "Invalid/Unknown";
     709           0 :     } break;
     710             :     }
     711             : 
     712       37314 :     return ClassName;
     713             : }
     714       71522 : Real64 AbsFrontSide(EnergyPlusData &state, int SurfNum)
     715             : {
     716             :     Real64 AbsorptanceFromExteriorFrontSide =
     717       71522 :         (state.dataSurface->SurfWinExtBeamAbsByShade(SurfNum) + state.dataSurface->SurfWinExtDiffAbsByShade(SurfNum)) *
     718       71522 :         state.dataSurface->SurfWinShadeAbsFacFace1(SurfNum);
     719             :     Real64 AbsorptanceFromInteriorFrontSide =
     720       71522 :         (state.dataSurface->SurfWinIntBeamAbsByShade(SurfNum) + state.dataSurface->SurfWinIntSWAbsByShade(SurfNum)) *
     721       71522 :         state.dataSurface->SurfWinShadeAbsFacFace2(SurfNum);
     722       71522 :     return AbsorptanceFromExteriorFrontSide + AbsorptanceFromInteriorFrontSide;
     723             : }
     724             : 
     725       71522 : Real64 AbsBackSide(EnergyPlusData &state, int SurfNum)
     726             : {
     727             :     Real64 AbsorptanceFromInteriorBackSide =
     728       71522 :         (state.dataSurface->SurfWinIntBeamAbsByShade(SurfNum) + state.dataSurface->SurfWinIntSWAbsByShade(SurfNum)) *
     729       71522 :         state.dataSurface->SurfWinShadeAbsFacFace1(SurfNum);
     730             :     Real64 AbsorptanceFromExteriorBackSide =
     731       71522 :         (state.dataSurface->SurfWinExtBeamAbsByShade(SurfNum) + state.dataSurface->SurfWinExtDiffAbsByShade(SurfNum)) *
     732       71522 :         state.dataSurface->SurfWinShadeAbsFacFace2(SurfNum);
     733       71522 :     return AbsorptanceFromExteriorBackSide + AbsorptanceFromInteriorBackSide;
     734             : }
     735             : 
     736        2313 : } // namespace EnergyPlus::DataSurfaces

Generated by: LCOV version 1.13