diff --git a/design/FY2020/A new algorithm for polygon clipping in solar calculations for rectangular surfaces.md b/design/FY2020/A new algorithm for polygon clipping in solar calculations for rectangular surfaces.md new file mode 100644 index 00000000000..ac0faff4b1e --- /dev/null +++ b/design/FY2020/A new algorithm for polygon clipping in solar calculations for rectangular surfaces.md @@ -0,0 +1,142 @@ +A new algorithm for polygon clipping in solar calculations for rectangular surfaces + +================ + +**Xuan Luo, Jerome Wei, Tianzhen Hong** + +**Lawrence Berkeley National Laboratory** + + - October 21, 2019 + +## Justification for New Feature + +There exists an extensive amount of literature on polygon clipping when constrained to rectangular surfaces. The current polygon clipping method implemented in EnergyPlus, using the *Sutherland-Hodgman* algorithm, is a performance hotspot. The method is generalized for clipping area of all shapes, but in EnergyPlus simulations runs, are often called with only rectangular surfaces. + +We propose a negligible amount of code to check if the clipping surface is rectangular. And if so, +we redirect to a new method using the `Slater & Barsky` algorithm. + + +## Overview + +To clip a polygon against a rectangular region, we can go segment by segment and clip each line individually, saving the unique points of intersection as we go. Then, we add the necessary corners of the clipping rectangle making sure that clockwise order is preserved. + +The `Slater & Barsky` algorithm relies on converting the line segment to be clipped into a parametric equation. Below is the general form for the x- and y- components of a parametric line: + +- + +- + +Letting our subject line be starting at (x_0, y_0) and ending at (x_1, x_1): + +- + +- + +Distances from the endpoints to the edges of the clipping rectangle that collide with the line are used to obtain two values of *t* that parameterize the equation, representing the pair of new endpoints. + +Once we have the two values of t, t_1 and t_2, we can calculate the clipped line endpoints (Note that t_2 > t_1). + +- + +- + +- + +- + +The `Slater & Barsky` algorithm uses space subdivision to reduce the number of pre-emptive calculations. We break the plane into 9 parts, where region (4) is the clipping region. + + +| 6 | 7 | 8 | + +| 3 | 4 | 5 | + +| 0 | 1 | 2 | + +With this method, calculating deltas and plugging in the final parametric equations can be skipped if the subject line obeys certain conditions. For example, if the line begins in region (0) and ends in region (6), then no new endpoints need to be calculated. + +Below are performance results for the calls to the solar clipping function `CLIPPOLY` in EnergyPlus. We see that the method provided by Slater & Barsky 1994 has a 31% speedup over all rectangular inputs in the **SolarShadingTest.idf** test file. Note that this performance gain is limited to rectangular inputs, so an estimate of the performance gain to the existing algorithm overall then is a function of the percentage of calls which apply a rectangular window. For example, if 33% of the calls are rectangles then the overall speedup to `CLIPPOLY` would be diminished by a factor 0.33. + +#### Best case taken from 5 trials (SolarShadingTest.idf) + +| | Slater-Barsky 1994 | +|----------------------------|--------------------| +| Rectangular inputs | 31% speedup | +| Overall assuming 50% rects | 15% speedup | + +#### Worst case taken from 5 trials (SolarShadingTest.idf) + +| | Slater-Barsky 1994 | +|----------------------------|--------------------| +| Rectangular inputs | 23% speedup | +| Overall assuming 50% rects | 11% speedup | + + +## Approach ## + +We propose to add a new key, `SlaterBarskyandSutherlHodgman`, to the existing `ShadowCalculation` object, `Polygon Clipping Algorithm` field, for global shadow calculation control: + + ShadowCalculation, + \unique-object + \memo This object is used to control details of the solar, shading, and daylighting models + \extensible:1 + ... + A2 , \field Polygon Clipping Algorithm + \note Advanced Feature. Internal default is SutherlandHodgman + \note Refer to InputOutput Reference and Engineering Reference for more information + \type choice + \key ConvexWeilerAtherton + \key SutherlandHodgman + \key SlaterBarskyandSutherlHodgman + \default SutherlandHodgman + +If `SlaterBarskyandSutherlHodgman` is chosen, the polygon clipping for rectangular surfaces will be calculated using the *Slater and Barsky* algorithm, while the rest adopts the default *Sutherl and Hodgman* algorithm. + +## Testing/Validation/Data Sources ## + +The current test file, "SolarShadingTest.idf", is used for performance and accuracy evaluation and validation. + +## Input Output Reference Documentation ## + +TBD + +## Input Description ## + +N/A + +## Outputs Description ## + +N/A + +## Engineering Reference ## + +TBD + +## Example File and Transition Changes ## + +An example file "SolarShadingTest-Slater-Barsky.idf" will be developed based on the existing test case for testing the new algorithm implementation. + +No transition change is required. + +## References ## + +insert text + + + + + + + + + + + + + + + + + + + diff --git a/doc/engineering-reference/src/climate-sky-and-solar-shading-calculations/shading-module.tex b/doc/engineering-reference/src/climate-sky-and-solar-shading-calculations/shading-module.tex index d292b1f1611..44788fa8d57 100644 --- a/doc/engineering-reference/src/climate-sky-and-solar-shading-calculations/shading-module.tex +++ b/doc/engineering-reference/src/climate-sky-and-solar-shading-calculations/shading-module.tex @@ -270,13 +270,15 @@ \subsection{Homogeneous Coordinates}\label{homogeneous-coordinates} \subsection{Polygon Clipping Algorithms}\label{polygon-clipping-algorithms} -Two methods for polygon clipping (treating of overlapping shadows) are currently in use in EnergyPlus. +Three methods for polygon clipping (treating of overlapping shadows) are currently in use in EnergyPlus. \begin{itemize} \item - Convex Weiler - Atherton + Convex Weiler-Atherton \item - Sutherland -- Hodgman + Sutherland-Hodgman +\item + Slater-Barsky (for rectangular surfaces only) \end{itemize} The original EnergyPlus method for polygon clipping is a special version of the Weiler-Atherton model (Weiler, Atherton, 1977). It was developed to be sufficiently general to clip concave polygons with holes. The implementation in the current version of EnergyPlus, however, does not support concave shadowing surfaces or holes. The relative computational complexity is preserved -- the algorithm is carried out in four steps. For example, if A and B are polygons (see Figure~\ref{fig:point-a-vertex-of-a-enclosed-by-b}). @@ -291,6 +293,53 @@ \subsection{Polygon Clipping Algorithms}\label{polygon-clipping-algorithms} The Sutherland-Hodgman algorithm (Sutherland, Hodgman, 1974) is less complex compared to the Weiler-Atherton method and is well-suited to clipping convex polygons. In actuality, only convex shading surfaces are currently supported by EnergyPlus. Let X be a polygon called the ``subject polygon'' (SP) and Y be a polygon called the ``clipping polygon'' (CP). The method performs the computation by iterating over the edges of the CP and removing points from the SP that fall in the clipping plane, i.e.~points that fall to the left of the edge of the CP. Intersections between the clip edge and the edges of the SP are added appropriately, and points falling outside of the clipping plane, i.e.~to the right of the edge of the CP, are added the output polygon as well. This resultant polygon is stored and the process is repeated for the rest of the clip edges in CP. The process is analogous to cutting off pieces of the SP one-by-one with respect to each edge of the CP. The result is ordered and identical to the polygon produced by the Weiler-Atherton method. +The Slater-Barsky algorithm (Slater, M., Barsky, B.A., 1994) can also be chosen for clipping surfaces which are rectangular. The algorithm further saves computational cost. It relies on converting the line segment to be clipped into a parametric equation. Below is the general form for the x- and y- components of a parametric line: + +\begin{equation} +x = x_0 + t \Delta x +\end{equation} + +\begin{equation} +y = y_0 + t \Delta y +\end{equation} + +Letting our subject line be starting at ($x_0$, $y_0$) and ending at ($x_1$, $x_1$): + +\begin{equation} +\Delta x = x_1 - x_0 +\end{equation} + +\begin{equation} +\Delta y = y_1 - y_0 +\end{equation} + +Distances from the endpoints to the edges of the clipping rectangle that collide with the line are used to obtain two values of $t$ that parameterize the equation, representing the pair of new endpoints. + +Once we have the two values of $t, t_1$ and $t_2$, we can calculate the clipped line endpoints (Note that $t_2$ > $t_1$). + +\begin{equation} +x'_1 = x_0 + t_1 \Delta x +\end{equation} +\begin{equation} +y'_1 = y_0 + t_1 \Delta y +\end{equation} +\begin{equation} +x'_2 = x_0 + t_2 \Delta x +\end{equation} +\begin{equation} +y'_2 = y_0 + t_2 \Delta y +\end{equation} + +The Slater-Barsky algorithm uses space subdivision to reduce the number of pre-emptive calculations. We break the plane into 9 parts, where region (4) is the clipping region. + + +| 6 | 7 | 8 | \\ +| 3 | 4 | 5 | \\ +| 0 | 1 | 2 | \\ + + +With this method, calculating deltas and plugging in the final parametric equations can be skipped if the subject line obeys certain conditions. For example, if the line begins in region (0) and ends in region (6), then no new endpoints need to be calculated. + \subsection{Overlapping Shadows}\label{overlapping-shadows} After transforming the shadows onto the plane of the receiving surface, the basic job of the shadow algorithm is to determine the area of the overlap between the polygons representing the shadows and the polygon representing the receiving surface. Concave surfaces are supported only for exterior wall heat transfer surfaces, when using SutherlandHodgman option. Concave shading devices are not supported by the this option. Neither concave shading devices nor concave exterior wall heat transfer surfaces are supported by the ConvexWeilerAtherton clipping routine. @@ -758,6 +807,8 @@ \subsection{References}\label{references-041} Sutherland, I.E., and Hodgman, G.W. 1974. ``Reentrant Polygon Clipping'', Communication of Association for Computing Machinery (CACM), vol.~17, pp.~32-42. +Slater, M. and Barsky, B.A. 1994, "2D line and polygon clipping based on space subdivision". The Visual Computer, vol.10, pp.407–422. + Maillot,Patrick-Gilles.** ``**A New, Fast Method For 2D Polygon Clipping: Analysis and Software Implementation.'' Sun Microsystems, inc. Mountain View, CA: 1992. Wisstein, Eric W. ``Convex Polygon'' From Mathworld- A Wolfram Web Resource. diff --git a/doc/input-output-reference/src/overview/group-simulation-parameters.tex b/doc/input-output-reference/src/overview/group-simulation-parameters.tex index 36952458bce..dac4b946b4e 100644 --- a/doc/input-output-reference/src/overview/group-simulation-parameters.tex +++ b/doc/input-output-reference/src/overview/group-simulation-parameters.tex @@ -562,7 +562,15 @@ \subsubsection{Inputs}\label{inputs-10-019} \paragraph{Field: Polygon Clipping Algorithm}\label{field-polygon-clipping-algorithm} -This is an advanced feature. Prior to V7, the internal polygon clipping method was a special case of the Weiler-Atherton method. Now, two options are available: \textbf{SutherlandHodgman} (default) and \textbf{ConvexWeilerAtherton}. Theoretically, Sutherland-Hodgman is a simpler algorithm but it works well in cases where receiving surfaces (of shadows) are non-convex. The Weiler-Atherton implementation is only accurate where both casting and receiving surfaces are convex. Warnings/severe errors are displayed when necessary. More details on polygon clipping are contained in the Engineering Reference. +This is an advanced feature. Prior to V7, the internal polygon clipping method was a special case of the Weiler-Atherton method. Now, three options are available: + +\begin{description} + \item[SutherlandHodgman] A simpler algorithm but it works well in cases where receiving surfaces (of shadows) are non-convex. + \item[ConvexWeilerAtherton] Only accurate where both casting and receiving surfaces are convex. Warnings/severe errors are displayed when necessary. + \item[SlaterBarskyandSutherlandHodgman] Slater-Barsky only applies to rectangular surfaces. Polygon clipping for rectangular surfaces will be calculated using the Slater-Barsky algorithm, while the rest adopts the default Sutherl-Hodgman algorithm. +\end{description} + +Default is SutherlandHodgman. More details on polygon clipping are contained in the Engineering Reference. \paragraph{Field: Sky Diffuse Modeling Algorithm}\label{field-sky-diffuse-modeling-algorithm} diff --git a/idd/Energy+.idd.in b/idd/Energy+.idd.in index 31a0cd7657a..cef71e59d5e 100644 --- a/idd/Energy+.idd.in +++ b/idd/Energy+.idd.in @@ -558,6 +558,7 @@ ShadowCalculation, \type choice \key ConvexWeilerAtherton \key SutherlandHodgman + \key SlaterBarskyandSutherlandHodgman \default SutherlandHodgman A3 , \field Sky Diffuse Modeling Algorithm \note Advanced Feature. Internal default is SimpleSkyDiffuseModeling diff --git a/src/EnergyPlus/DataSystemVariables.cc b/src/EnergyPlus/DataSystemVariables.cc index c6201d96c4f..5d20e85022b 100644 --- a/src/EnergyPlus/DataSystemVariables.cc +++ b/src/EnergyPlus/DataSystemVariables.cc @@ -118,6 +118,7 @@ namespace DataSystemVariables { std::string const cIgnoreBeamRadiation("IgnoreBeamRadiation"); std::string const cIgnoreDiffuseRadiation("IgnoreDiffuseRadiation"); std::string const cSutherlandHodgman("SutherlandHodgman"); + std::string const cSlaterBarsky("SlaterBarsky"); std::string const cMinimalSurfaceVariables("CreateMinimalSurfaceVariables"); std::string const cMinimalShadowing("MinimalShadowing"); std::string const cNumActiveSims("cntActv"); @@ -150,6 +151,7 @@ namespace DataSystemVariables { bool DeveloperFlag(false); // TRUE if developer flag is turned on. (turns on more displays to console) bool TimingFlag(false); // TRUE if timing flag is turned on. (turns on more timing displays to console) bool SutherlandHodgman(true); // TRUE if SutherlandHodgman algorithm for polygon clipping is to be used. + bool SlaterBarsky(false); // TRUE if SlaterBarsky algorithm for polygon clipping is to be used for vertical polygons. bool DetailedSkyDiffuseAlgorithm(false); // use detailed diffuse shading algorithm for sky (shading transmittance varies) bool DetailedSolarTimestepIntegration(false); // when true, use detailed timestep integration for all solar,shading, etc. bool TrackAirLoopEnvFlag(false); // If TRUE generates a file with runtime statistics for each HVAC @@ -375,6 +377,7 @@ namespace DataSystemVariables { DeveloperFlag = false; TimingFlag = false; SutherlandHodgman = true; + SlaterBarsky = false; DetailedSkyDiffuseAlgorithm = false; DetailedSolarTimestepIntegration = false; TrackAirLoopEnvFlag = false; diff --git a/src/EnergyPlus/DataSystemVariables.hh b/src/EnergyPlus/DataSystemVariables.hh index 69b20117220..edda9370baa 100644 --- a/src/EnergyPlus/DataSystemVariables.hh +++ b/src/EnergyPlus/DataSystemVariables.hh @@ -87,6 +87,7 @@ namespace DataSystemVariables { extern std::string const cIgnoreBeamRadiation; extern std::string const cIgnoreDiffuseRadiation; extern std::string const cSutherlandHodgman; + extern std::string const cSlaterBarsky; extern std::string const cMinimalSurfaceVariables; extern std::string const cMinimalShadowing; extern std::string const cNumActiveSims; @@ -118,6 +119,7 @@ namespace DataSystemVariables { extern bool DeveloperFlag; // TRUE if developer flag is turned on. (turns on more displays to console) extern bool TimingFlag; // TRUE if timing flag is turned on. (turns on more timing displays to console) extern bool SutherlandHodgman; // TRUE if SutherlandHodgman algorithm for polygon clipping is to be used. + extern bool SlaterBarsky; // TRUE if SlaterBarsky algorithm for polygon clipping is to be used for vertical polygons. extern bool DetailedSkyDiffuseAlgorithm; // use detailed diffuse shading algorithm for sky (shading transmittance varies) extern bool DetailedSolarTimestepIntegration; // when true, use detailed timestep integration for all solar,shading, etc. extern bool TrackAirLoopEnvFlag; // If TRUE generates a file with runtime statistics for each HVAC diff --git a/src/EnergyPlus/EnergyPlusPgm.cc b/src/EnergyPlus/EnergyPlusPgm.cc index 321848c2840..b368c94b669 100644 --- a/src/EnergyPlus/EnergyPlusPgm.cc +++ b/src/EnergyPlus/EnergyPlusPgm.cc @@ -391,6 +391,9 @@ int RunEnergyPlus(std::string const & filepath) get_environment_variable(cSutherlandHodgman, cEnvValue); if (!cEnvValue.empty()) SutherlandHodgman = env_var_on(cEnvValue); // Yes or True + get_environment_variable(cSlaterBarsky, cEnvValue); + if (!cEnvValue.empty()) SlaterBarsky = env_var_on(cEnvValue); // Yes or True + get_environment_variable(cMinimalShadowing, cEnvValue); if (!cEnvValue.empty()) lMinimalShadowing = env_var_on(cEnvValue); // Yes or True diff --git a/src/EnergyPlus/SimulationManager.cc b/src/EnergyPlus/SimulationManager.cc index 1d1bddbb17f..e59f2953b48 100644 --- a/src/EnergyPlus/SimulationManager.cc +++ b/src/EnergyPlus/SimulationManager.cc @@ -1785,7 +1785,11 @@ namespace SimulationManager { ObjexxFCL::gio::write(EchoInputFile, fmtLD) << "NumReportList=" << NumReportList; ObjexxFCL::gio::write(EchoInputFile, fmtLD) << "InstMeterCacheSize=" << InstMeterCacheSize; if (SutherlandHodgman) { - ObjexxFCL::gio::write(EchoInputFile, fmtLD) << "ClippingAlgorithm=SutherlandHodgman"; + if (SlaterBarsky) { + ObjexxFCL::gio::write(EchoInputFile, fmtLD) << "ClippingAlgorithm=SlaterBarskyandSutherlandHodgman"; + } else { + ObjexxFCL::gio::write(EchoInputFile, fmtLD) << "ClippingAlgorithm=SutherlandHodgman"; + } } else { ObjexxFCL::gio::write(EchoInputFile, fmtLD) << "ClippingAlgorithm=ConvexWeilerAtherton"; } diff --git a/src/EnergyPlus/SolarShading.cc b/src/EnergyPlus/SolarShading.cc index 4a138e56c90..c4b9cec0c27 100644 --- a/src/EnergyPlus/SolarShading.cc +++ b/src/EnergyPlus/SolarShading.cc @@ -579,6 +579,7 @@ namespace SolarShading { using DataSystemVariables::DisableGroupSelfShading; using DataSystemVariables::ReportExtShadingSunlitFrac; using DataSystemVariables::SutherlandHodgman; + using DataSystemVariables::SlaterBarsky; using DataSystemVariables::UseImportedSunlitFrac; using DataSystemVariables::UseScheduledSunlitFrac; using ScheduleManager::ScheduleFileShadingProcessed; @@ -657,25 +658,42 @@ namespace SolarShading { } else if (UtilityRoutines::SameString(cAlphaArgs(2), "ConvexWeilerAtherton")) { SutherlandHodgman = false; cAlphaArgs(2) = "ConvexWeilerAtherton"; + } else if (UtilityRoutines::SameString(cAlphaArgs(2), "SlaterBarskyandSutherlandHodgman")) { + SutherlandHodgman = true; + SlaterBarsky = true; + cAlphaArgs(2) = "SlaterBarskyandSutherlandHodgman"; } else if (lAlphaFieldBlanks(2)) { if (!SutherlandHodgman) { // if already set. cAlphaArgs(2) = "ConvexWeilerAtherton"; } else { - cAlphaArgs(2) = "SutherlandHodgman"; + if (!SlaterBarsky) { + cAlphaArgs(2) = "SutherlandHodgman"; + } else { + cAlphaArgs(2) = "SlaterBarskyandSutherlandHodgman"; + } } } else { ShowWarningError(cCurrentModuleObject + ": invalid " + cAlphaFieldNames(2)); if (!SutherlandHodgman) { ShowContinueError("Value entered=\"" + cAlphaArgs(2) + "\", ConvexWeilerAtherton will be used."); } else { - ShowContinueError("Value entered=\"" + cAlphaArgs(2) + "\", SutherlandHodgman will be used."); + if (!SlaterBarsky) { + ShowContinueError("Value entered=\"" + cAlphaArgs(2) + "\", SutherlandHodgman will be used."); + } else { + ShowContinueError("Value entered=\"" + cAlphaArgs(2) + "\", SlaterBarskyandSutherlandHodgman will be used."); + } + } } } else { if (!SutherlandHodgman) { cAlphaArgs(2) = "ConvexWeilerAtherton"; } else { - cAlphaArgs(2) = "SutherlandHodgman"; + if (!SlaterBarsky) { + cAlphaArgs(2) = "SutherlandHodgman"; + } else { + cAlphaArgs(2) = "SlaterBarskyandSutherlandHodgman"; + } } } @@ -3790,13 +3808,403 @@ namespace SolarShading { } } + inline bool neq(Real64 a, Real64 b) { + return std::abs(a-b) > 2.0; + } + + inline bool d_eq(Real64 a, Real64 b) { + return std::abs(a-b) < 2.0; + } + + void CLIPLINE(Real64 &x1, Real64 &x2, Real64 &y1, Real64 &y2, + Real64 maxX, Real64 minX, Real64 maxY, Real64 minY, bool &visible, bool &rev) { + // Line segment clipping + // Reference: + // Slater, M., Barsky, B.A. + // 2D line and polygon clipping based on space subdivision. + // The Visual Computer 10, 407–422 (1994). + Real64 dx, dy, e, xinc, yinc, tempVar; + bool needX = true, needY = true; + int c1, c2; + + if (x1 > x2) { //reverse for efficiency + tempVar = x1; + x1 = x2; + x2 = tempVar; + tempVar = y1; + y1 = y2; + y2 = tempVar; + rev = true; + } + if (x1 > maxX || x2 < minX) return; // x is positive + if (x1 < minX) { + if (y1 < minY) { + if (y2 < minY) return; + c1 = 0; + dx = x2 - x1; + dy = y2 - y1; + e = dy*(minX-x1) + dx*(y1-minY); + } else if (y1 > maxY) { + if (y2 > maxY) return; + c1 = 6; + dx = x2 - x1; + dy = y2 - y1; + e = dy*(minX-x1) + dx*(y1-maxY); + } else { + c1 = 3; + dx = x2 - x1; + dy = y2 - y1; + if (dy > 0) { + e = dy*(minX-x1) + dx*(y1-maxY); + } else { + e = dy*(minX-x1) + dx*(y1-minY); + } + } + } else { + if (y1 < minY) { + if (y2 < minY) return; + c1 = 1; + dx = x2 - x1; + dy = y2 - y1; + e = dy*(maxX-x1) + dx*(y1-minY); + } else if (y1 > maxY) { + if (y2 > maxY) return; + c1 = 7; + dx = x2 - x1; + dy = y2 - y1; + e = dy*(maxX-x1) + dx*(y1-maxY); + } else { + visible = true; + if (x2 <= maxX && (y2 >= minY && y2 <= maxY)) return; + c1 = 4; + dx = x2 - x1; + dy = y2 - y1; + if (dy > 0) { + e = dy*(maxX-x1) + dx*(y1-maxY); + } else { + e = dy*(maxX-x1) + dx*(y1-minY); + } + } + } + c2 = c1; + if (dy > 0) { + while(true) { + if (e < 0.0) { + if (c2 == 1) return; + else if (c2 == 3) { + visible = true; + x1 = minX; + y1 = maxY + e/dx; + if (x2 <= maxX && y2 <= maxY) return; + } else if (c2 == 4) { + x2 = maxX; + y2 = maxY + e/dx; + return; + } + if (needX) { + xinc = dy*(maxX - minX); + needX = false; + } + e += xinc; + c2 += 1; + } else { + if (c2 == 3) return; + else if (c2 == 1) { + visible = true; + x1 = maxX - e/dy; + y1 = minY; + if (x2 <= maxX && y2 <= maxY) return; + } else if (c2 == 4) { + x2 = maxX - e/dy; + y2 = maxY; + return; + } + if (needY) { + yinc = dx*(maxY - minY); + needY = false; + } + e -= yinc; + c2 += 3; + } + } + } else { + while(true) { + if (e >= 0.0) { + if (c2 == 7) return; + else if (c2 == 3) { + visible = true; + x1 = minX; + y1 = minY + e/dx; + if (x2 <= maxX && y2 >= minY) return; + } else if (c2 == 4) { + x2 = maxX; + y2 = minY + e/dx; + return; + } + if (needX) { + xinc = dy*(maxX - minX); + needX = false; + } + e += xinc; + c2 += 1; + } else { + if (c2 == 3) return; + else if (c2 == 7) { + visible = true; + x1 = maxX - e/dy; + y1 = maxY; + if (x2 <= maxX && y2 >= minY) return; + } else if (c2 == 4) { + x2 = maxX - e/dy; + y2 = minY; + return; + } + if (needY) { + yinc = dx*(maxY - minY); + needY = false; + } + e += yinc; + c2 -= 3; + } + } + } + } + + void CLIPRECT(int const NS2, int const NV1, int &NV3) { + // Polygon clipping by line segment clipping for rectangles + // Reference: + // Slater, M., Barsky, B.A. + // 2D line and polygon clipping based on space subdivision. + // The Visual Computer 10, 407–422 (1994). + bool INTFLAG = false; + auto l(HCA.index(NS2, 1)); + Real64 maxX, minX, maxY, minY; + if (HCX[l] > HCX[l+2]) { + maxX = HCX[l]; + minX = HCX[l+2]; + } else { + maxX = HCX[l+2]; + minX = HCX[l]; + } + if (HCY[l] > HCY[l+2]) { + maxY = HCY[l]; + minY = HCY[l+2]; + } else { + maxY = HCY[l+2]; + minY = HCY[l]; + } + + Real64 arrx[20]; //Temp array for output X + Real64 arry[20]; //Temp array for output Y + int arrc = 0; //Number of items in output + + for (int j = 0; j < NV1; ++j) { + Real64 x_1 = XTEMP[j]; + Real64 y_1 = YTEMP[j]; + Real64 x_2 = XTEMP[(j+1) % NV1]; + Real64 y_2 = YTEMP[(j+1) % NV1]; + Real64 x1 = x_1, x2 = x_2, y1 = y_1, y2 = y_2; + + bool visible = false; + bool rev = false; + CLIPLINE(x_1, x_2,y_1, y_2, maxX, minX, maxY, minY, visible, rev); + if (visible) { + if ((x_1 != x1 || y_1 != y1) || (x_2 != x2 || y_2 != y2)) { + INTFLAG = true; + } + if (rev) { //undo reverse + auto tempVar = x_1; + x_1 = x_2; + x_2 = tempVar; + tempVar = y_1; + y_1 = y_2; + y_2 = tempVar; + } + //if line on edge, or inside, add both points + if (arrc == 0 || ((neq(arrx[arrc-1], x_1) || neq(arry[arrc-1], y_1)) && (neq(arrx[0], x_1) || neq(arry[0], y_1)))) { + arrx[arrc] = x_1; + arry[arrc] = y_1; + arrc += 1; + if ((neq(x_1, x_2) || neq(y_1, y_2)) && (neq(arrx[0], x_2) || neq(arry[0], y_2))) { + arrx[arrc] = x_2; + arry[arrc] = y_2; + arrc += 1; + } + } else if ((neq(arrx[arrc-1], x_2) || neq(arry[arrc-1], y_2)) && (neq(arrx[0], x_2) || neq(arry[0], y_2))) { + arrx[arrc] = x_2; + arry[arrc] = y_2; + arrc += 1; + } + } + } + NV3 = arrc; + + // Re-populate XTEMP/YTEMP + if (NV3 > 1) { + int LastEdgeIndex = -1, incr = 0; + double cornerXs[4] = {minX, minX, maxX, maxX}; + double cornerYs[4] = {minY, maxY, maxY, minY}; + Real64 edges[4] = { minX, maxY, maxX, minY }; + Real64 LastEdgeX, LastEdgeY; + for (int i = 0; i <= arrc; i++) { + int k = i % arrc; + + Real64 currX = arrx[k], currY = arry[k]; + + int edgeCount = 0, EdgeIndex = -1; + for (int m = 0; m < 4; m++) { + if (m%2 == 0 && d_eq(currX, edges[m])) { //MinX or MaxX + edgeCount ++; + EdgeIndex = m; + } else if (m%2 == 1 && d_eq(currY, edges[m])) { + edgeCount ++; + EdgeIndex = m; + } + } + if (edgeCount == 0) { //On inside + if (i != arrc) { + XTEMP[incr] = currX; + YTEMP[incr] = currY; + incr ++; + } + continue; + } else if (edgeCount > 1) { //On corner + if (d_eq(currX, minX)) { + if (d_eq(currY, minY)) { + EdgeIndex = 3; + } else { + EdgeIndex = 0; + } + } else { + if (d_eq(currY, maxY)) { + EdgeIndex = 1; + } else { + EdgeIndex = 2; + } + } + } + if ((LastEdgeIndex > -1 && EdgeIndex > -1) && LastEdgeIndex != EdgeIndex) { + int jumpCount = 0; + if ((EdgeIndex == 0 && LastEdgeIndex == 3) || (EdgeIndex - LastEdgeIndex == 1)) { + jumpCount = 1; + } else if (EdgeIndex%2 == LastEdgeIndex%2) { + //Clockwise double jump + jumpCount = 2; + } else if ((EdgeIndex == 3 && LastEdgeIndex == 0) || (LastEdgeIndex - EdgeIndex == 1)) { + //Clockwise triple jump + jumpCount = 3; + } + if (jumpCount > 0) { + Real64 cornerX; + Real64 cornerY; + int startIndex = (LastEdgeIndex + 1) % 4; + int added = 0; + for (int i1 = startIndex, j1 = 0; j1 < jumpCount; i1 = (i1 + 1) % 4, j1++) { + cornerX = cornerXs[i1]; + cornerY = cornerYs[i1]; + if (cornerX == LastEdgeX && cornerY == LastEdgeY) continue; //skip if jump started on corner + + bool insideFlag = true; + for (int j = 0; j < NV1; ++j) { + if ((ATEMP[j] * cornerX) + (cornerY * BTEMP[j]) + CTEMP[j] > 0.0) { + insideFlag = false; + break; + } + } + + if (insideFlag && (incr == 0 || ((neq(cornerX, XTEMP[incr-1]) || neq(cornerY, YTEMP[incr-1])) && (neq(cornerX, XTEMP[0]) || neq(cornerY, YTEMP[0]))))) + { + XTEMP[incr] = cornerX; + YTEMP[incr] = cornerY; + incr ++; + added ++; + } + } + if (jumpCount > 2 && (added == jumpCount && edgeCount == 1)) { + if (i != arrc) { + XTEMP[incr] = currX; + YTEMP[incr] = currY; + incr ++; + } + break; + } + } + } + if (i != arrc) { + XTEMP[incr] = currX; + YTEMP[incr] = currY; + incr ++; + } + LastEdgeIndex = EdgeIndex; + LastEdgeX = currX; + LastEdgeY = currY; + } + NV3 = incr; + + } else { + if (NV3 == 1) { + XTEMP[0] = arrx[0]; + YTEMP[0] = arry[0]; + } if (NV3 == 0) { + double cornerXs[4] = {minX, minX, maxX, maxX}; + double cornerYs[4] = {minY, maxY, maxY, minY}; + Real64 cornerX = cornerXs[0]; + Real64 cornerY = cornerYs[0]; + bool insideFlag = true; + for (int j = 0; j < NV1; ++j) { + if ((ATEMP[j] * cornerX) + (cornerY * BTEMP[j]) + CTEMP[j] >= 0.0) { + insideFlag = false; + break; + } + } + if (insideFlag) { + for (int i1 = 0; i1 < 4; i1++){ + XTEMP[i1] = cornerXs[i1]; + YTEMP[i1] = cornerYs[i1]; + } + NV3 = 4; + INTFLAG = true; + } + } + } + + // update homogenous edges A,B,C + if (NV3 > 0) { + Real64 const X_0(XTEMP[0]); + Real64 const Y_0(YTEMP[0]); + Real64 XP_0 = X_0, XP_1; + Real64 YP_0 = Y_0, YP_1; + for (int P = 0; P < NV3-1; ++P) { + XP_1 = XTEMP[P + 1]; + YP_1 = YTEMP[P + 1]; + + ATEMP[P] = YP_0 - YP_1; + BTEMP[P] = XP_1 - XP_0; + CTEMP[P] = XP_0 * YP_1 - YP_0 * XP_1; + XP_0 = XP_1; + YP_0 = YP_1; + } + + ATEMP[NV3-1] = YP_1 - Y_0; + BTEMP[NV3-1] = X_0 - XP_1; + CTEMP[NV3-1] = XP_1 * Y_0 - YP_1 * X_0; + } + + //Determine overlap status + if (NV3 < 3) { // Determine overlap status + OverlapStatus = NoOverlap; + } else if (!INTFLAG) { + OverlapStatus = FirstSurfWithinSecond; + } + } + + void CLIPPOLY(int const NS1, // Figure number of figure 1 (The subject polygon) int const NS2, // Figure number of figure 2 (The clipping polygon) int const NV1, // Number of vertices of figure 1 int const NV2, // Number of vertices of figure 2 int &NV3 // Number of vertices of figure 3 - ) - { + ) { // SUBROUTINE INFORMATION: // AUTHOR Tyler Hoyt @@ -3867,6 +4275,21 @@ namespace SolarShading { NVTEMP = 0; KK = 0; + //Check if clipping polygon is rectangle + if (DataSystemVariables::SlaterBarsky) { + auto l1(HCA.index(NS2, 1)); + bool rectFlag = ((NV2 == 4) && (((((HCX[l1] == HCX[l1 + 1] && HCY[l1] != HCY[l1 + 1]) && + ((HCY[l1 + 2] == HCY[l1 + 1] && HCY[l1 + 3] == HCY[l1]))) && + HCX[l1 + 2] == HCX[l1 + 3]) || + ((((HCY[l1] == HCY[l1 + 1] && HCX[l1] != HCX[l1 + 1]) && + (HCX[l1 + 2] == HCX[l1 + 1] && HCX[l1 + 3] == HCX[l1])) && + (HCY[l1 + 2] == HCY[l1 + 3])))))); + if (rectFlag) { + CLIPRECT(NS2, NV1, NV3); + return; + } + } + auto l(HCA.index(NS2, 1)); for (int E = 1; E <= NV2; ++E, ++l) { // Loop over edges of the clipping polygon for (int P = 1; P <= NVOUT; ++P) { diff --git a/tst/EnergyPlus/unit/HeatBalanceSurfaceManager.unit.cc b/tst/EnergyPlus/unit/HeatBalanceSurfaceManager.unit.cc index 6c3f770d50b..869e1d801da 100644 --- a/tst/EnergyPlus/unit/HeatBalanceSurfaceManager.unit.cc +++ b/tst/EnergyPlus/unit/HeatBalanceSurfaceManager.unit.cc @@ -346,14 +346,6 @@ TEST_F(EnergyPlusFixture, HeatBalanceSurfaceManager_TestSurfTempCalcHeatBalanceI " 25, !- Maximum Number of Warmup Days", " 6; !- Minimum Number of Warmup Days", - " Timestep,6;", - - " SurfaceConvectionAlgorithm:Inside,TARP;", - - " SurfaceConvectionAlgorithm:Outside,DOE-2;", - - " HeatBalanceAlgorithm,ConductionTransferFunction;", - " Output:DebuggingData,0,0;", " SimulationControl,", diff --git a/tst/EnergyPlus/unit/SolarShading.unit.cc b/tst/EnergyPlus/unit/SolarShading.unit.cc index ea71f2e8a9a..f24015cdce7 100644 --- a/tst/EnergyPlus/unit/SolarShading.unit.cc +++ b/tst/EnergyPlus/unit/SolarShading.unit.cc @@ -671,6 +671,8 @@ TEST_F(EnergyPlusFixture, SolarShadingTest_FigureSolarBeamAtTimestep) EXPECT_NEAR(0.6504, DifShdgRatioIsoSkyHRTS(4, 9, 6), 0.0001); EXPECT_NEAR(0.9152, DifShdgRatioHorizHRTS(4, 9, 6), 0.0001); + + } TEST_F(EnergyPlusFixture, SolarShadingTest_ExternalShadingIO) @@ -1462,3 +1464,383 @@ TEST_F(EnergyPlusFixture, SolarShadingTest_DisableGroupSelfShading) } } } + +TEST_F(EnergyPlusFixture, SolarShadingTest_PolygonClippingDirect) +{ + std::string const idf_objects = delimited_string({" Building, ", + " DemoFDT, !- Name ", + " 0, !- North Axis {deg} ", + " Suburbs, !- Terrain ", + " 3.9999999E-02, !- Loads Convergence Tolerance Value ", + " 4.0000002E-03, !- Temperature Convergence Tolerance Value {deltaC} ", + " FullExterior, !- Solar Distribution ", + " , !- Maximum Number of Warmup Days ", + " 6; !- Minimum Number of Warmup Days ", + " ShadowCalculation, ", + " TimestepFrequency, !- Calculation Method ", + " , !- Calculation Frequency ", + " , !- Maximum Figures in Shadow Overlap Calculations ", + " , !- Polygon Clipping Algorithm ", + " DetailedSkyDiffuseModeling; !- Sky Diffuse Modeling Algorithm ", + " SurfaceConvectionAlgorithm:Inside,TARP; ", + " SurfaceConvectionAlgorithm:Outside,TARP; ", + " HeatBalanceAlgorithm,ConductionTransferFunction; ", + " Timestep,6; ", + " RunPeriod, ", + " RP1, !- Name ", + " 1, !- Begin Month ", + " 1, !- Begin Day of Month ", + " , !- Begin Year ", + " 12, !- End Month ", + " 31, !- End Day of Month ", + " , !- End Year ", + " , !- Day of Week for Start Day ", + " , !- Use Weather File Holidays and Special Days ", + " , !- Use Weather File Daylight Saving Period ", + " , !- Apply Weekend Holiday Rule ", + " , !- Use Weather File Rain Indicators ", + " ; !- Use Weather File Snow Indicators ", + " ScheduleTypeLimits, ", + " Fraction, !- Name ", + " 0.0, !- Lower Limit Value ", + " 1.0, !- Upper Limit Value ", + " Continuous; !- Numeric Type ", + " ScheduleTypeLimits, ", + " ON/OFF, !- Name ", + " 0, !- Lower Limit Value ", + " 1, !- Upper Limit Value ", + " Discrete; !- Numeric Type ", + " Schedule:Compact, ", + " SunShading, !- Name ", + " ON/OFF, !- Schedule Type Limits Name ", + " Through: 4/30, !- Field 1 ", + " For: AllDays, !- Field 2 ", + " until: 24:00,1, !- Field 3 ", + " Through: 10/31, !- Field 5 ", + " For: AllDays, !- Field 6 ", + " until: 24:00,0, !- Field 7 ", + " Through: 12/31, !- Field 9 ", + " For: AllDays, !- Field 10 ", + " until: 24:00,1; !- Field 11 ", + " Material, ", + " A2 - 4 IN DENSE FACE BRICK, !- Name ", + " Rough, !- Roughness ", + " 0.1014984, !- Thickness {m} ", + " 1.245296, !- Conductivity {W/m-K} ", + " 2082.400, !- Density {kg/m3} ", + " 920.4800, !- Specific Heat {J/kg-K} ", + " 0.9000000, !- Thermal Absorptance ", + " 0.9300000, !- Solar Absorptance ", + " 0.9300000; !- Visible Absorptance ", + " Material, ", + " E1 - 3 / 4 IN PLASTER OR GYP BOARD, !- Name ", + " Smooth, !- Roughness ", + " 1.9050000E-02, !- Thickness {m} ", + " 0.7264224, !- Conductivity {W/m-K} ", + " 1601.846, !- Density {kg/m3} ", + " 836.8000, !- Specific Heat {J/kg-K} ", + " 0.9000000, !- Thermal Absorptance ", + " 0.9200000, !- Solar Absorptance ", + " 0.9200000; !- Visible Absorptance ", + " Material, ", + " E2 - 1 / 2 IN SLAG OR STONE, !- Name ", + " Rough, !- Roughness ", + " 1.2710161E-02, !- Thickness {m} ", + " 1.435549, !- Conductivity {W/m-K} ", + " 881.0155, !- Density {kg/m3} ", + " 1673.600, !- Specific Heat {J/kg-K} ", + " 0.9000000, !- Thermal Absorptance ", + " 0.5500000, !- Solar Absorptance ", + " 0.5500000; !- Visible Absorptance ", + " Material, ", + " C12 - 2 IN HW CONCRETE, !- Name ", + " MediumRough, !- Roughness ", + " 5.0901599E-02, !- Thickness {m} ", + " 1.729577, !- Conductivity {W/m-K} ", + " 2242.585, !- Density {kg/m3} ", + " 836.8000, !- Specific Heat {J/kg-K} ", + " 0.9000000, !- Thermal Absorptance ", + " 0.6500000, !- Solar Absorptance ", + " 0.6500000; !- Visible Absorptance ", + " Material:NoMass, ", + " R13LAYER, !- Name ", + " Rough, !- Roughness ", + " 2.290965, !- Thermal Resistance {m2-K/W} ", + " 0.9000000, !- Thermal Absorptance ", + " 0.7500000, !- Solar Absorptance ", + " 0.7500000; !- Visible Absorptance ", + " WindowMaterial:Glazing, ", + " GLASS - CLEAR PLATE 1 / 4 IN, !- Name ", + " SpectralAverage, !- Optical Data Type ", + " , !- Window Glass Spectral Data Set Name ", + " 0.006, !- Thickness {m} ", + " 0.80, !- Solar Transmittance at Normal Incidence ", + " 0.10, !- Front Side Solar Reflectance at Normal Incidence ", + " 0.10, !- Back Side Solar Reflectance at Normal Incidence ", + " 0.80, !- Visible Transmittance at Normal Incidence ", + " 0.10, !- Front Side Visible Reflectance at Normal Incidence ", + " 0.10, !- Back Side Visible Reflectance at Normal Incidence ", + " 0.0, !- Infrared Transmittance at Normal Incidence ", + " 0.84, !- Front Side Infrared Hemispherical Emissivity ", + " 0.84, !- Back Side Infrared Hemispherical Emissivity ", + " 0.9; !- Conductivity {W/m-K} ", + " WindowMaterial:Gas, ", + " AIRGAP, !- Name ", + " AIR, !- Gas Type ", + " 0.0125; !- Thickness {m} ", + " Construction, ", + " R13WALL, !- Name ", + " R13LAYER; !- Outside Layer ", + " Construction, ", + " EXTWALL09, !- Name ", + " A2 - 4 IN DENSE FACE BRICK, !- Outside Layer ", + " E1 - 3 / 4 IN PLASTER OR GYP BOARD; !- Layer 4 ", + " Construction, ", + " INTERIOR, !- Name ", + " C12 - 2 IN HW CONCRETE; !- Layer 4 ", + " Construction, ", + " SLAB FLOOR, !- Name ", + " C12 - 2 IN HW CONCRETE; !- Layer 4 ", + " Construction, ", + " ROOF31, !- Name ", + " E2 - 1 / 2 IN SLAG OR STONE, !- Outside Layer ", + " C12 - 2 IN HW CONCRETE; !- Layer 4 ", + " Construction, ", + " DOUBLE PANE HW WINDOW, !- Name ", + " GLASS - CLEAR PLATE 1 / 4 IN, !- Outside Layer ", + " AIRGAP, !- Layer 2 ", + " GLASS - CLEAR PLATE 1 / 4 IN; !- Layer 3 ", + " Construction, ", + " PARTITION02, !- Name ", + " E1 - 3 / 4 IN PLASTER OR GYP BOARD, !- Outside Layer ", + " C12 - 2 IN HW CONCRETE, !- Layer 4 ", + " E1 - 3 / 4 IN PLASTER OR GYP BOARD; !- Layer 3 ", + " Construction, ", + " single PANE HW WINDOW, !- Name ", + " GLASS - CLEAR PLATE 1 / 4 IN; !- Outside Layer ", + " Construction, ", + " EXTWALLdemo, !- Name ", + " A2 - 4 IN DENSE FACE BRICK, !- Outside Layer ", + " E1 - 3 / 4 IN PLASTER OR GYP BOARD; !- Layer 4 ", + " GlobalGeometryRules, ", + " UpperLeftCorner, !- Starting Vertex Position ", + " Counterclockwise, !- Vertex Entry Direction ", + " Relative; !- Coordinate System ", + " Zone, ", + " ZONE ONE, !- Name ", + " 0, !- Direction of Relative North {deg} ", + " 0, !- X Origin {m} ", + " 0, !- Y Origin {m} ", + " 0, !- Z Origin {m} ", + " 1, !- Type ", + " 1, !- Multiplier ", + " 0, !- Ceiling Height {m} ", + " 0; !- Volume {m3} ", + " BuildingSurface:Detailed, ", + " Zn001:Wall-North, !- Name ", + " Wall, !- Surface Type ", + " EXTWALLdemo, !- Construction Name ", + " ZONE ONE, !- Zone Name ", + " Outdoors, !- Outside Boundary Condition ", + " , !- Outside Boundary Condition Object ", + " SunExposed, !- Sun Exposure ", + " WindExposed, !- Wind Exposure ", + " 0.5000000, !- View Factor to Ground ", + " 4, !- Number of Vertices ", + " 5,5,3, !- X,Y,Z ==> Vertex 1 {m} ", + " 5,5,0, !- X,Y,Z ==> Vertex 2 {m} ", + " -5,5,0, !- X,Y,Z ==> Vertex 3 {m} ", + " -5,5,3; !- X,Y,Z ==> Vertex 4 {m} ", + " BuildingSurface:Detailed, ", + " Zn001:Wall-East, !- Name ", + " Wall, !- Surface Type ", + " EXTWALL09, !- Construction Name ", + " ZONE ONE, !- Zone Name ", + " Outdoors, !- Outside Boundary Condition ", + " , !- Outside Boundary Condition Object ", + " SunExposed, !- Sun Exposure ", + " WindExposed, !- Wind Exposure ", + " 0.5000000, !- View Factor to Ground ", + " 4, !- Number of Vertices ", + " 5,-5,3, !- X,Y,Z ==> Vertex 1 {m} ", + " 5,-5,0, !- X,Y,Z ==> Vertex 2 {m} ", + " 5,5,0, !- X,Y,Z ==> Vertex 3 {m} ", + " 5,5,3; !- X,Y,Z ==> Vertex 4 {m} ", + " BuildingSurface:Detailed, ", + " Zn001:Wall-South, !- Name ", + " Wall, !- Surface Type ", + " R13WALL, !- Construction Name ", + " ZONE ONE, !- Zone Name ", + " Outdoors, !- Outside Boundary Condition ", + " , !- Outside Boundary Condition Object ", + " SunExposed, !- Sun Exposure ", + " WindExposed, !- Wind Exposure ", + " 0.5000000, !- View Factor to Ground ", + " 4, !- Number of Vertices ", + " -5,-5,3, !- X,Y,Z ==> Vertex 1 {m} ", + " -5,-5,0, !- X,Y,Z ==> Vertex 2 {m} ", + " 5,-5,0, !- X,Y,Z ==> Vertex 3 {m} ", + " 5,-5,3; !- X,Y,Z ==> Vertex 4 {m} ", + " BuildingSurface:Detailed, ", + " Zn001:Wall-West, !- Name ", + " Wall, !- Surface Type ", + " EXTWALL09, !- Construction Name ", + " ZONE ONE, !- Zone Name ", + " Outdoors, !- Outside Boundary Condition ", + " , !- Outside Boundary Condition Object ", + " SunExposed, !- Sun Exposure ", + " WindExposed, !- Wind Exposure ", + " 0.5000000, !- View Factor to Ground ", + " 4, !- Number of Vertices ", + " -5,5,3, !- X,Y,Z ==> Vertex 1 {m} ", + " -5,5,0, !- X,Y,Z ==> Vertex 2 {m} ", + " -5,-5,0, !- X,Y,Z ==> Vertex 3 {m} ", + " -5,-5,3; !- X,Y,Z ==> Vertex 4 {m} ", + " BuildingSurface:Detailed, ", + " Zn001:roof, !- Name ", + " Roof, !- Surface Type ", + " ROOF31, !- Construction Name ", + " ZONE ONE, !- Zone Name ", + " Outdoors, !- Outside Boundary Condition ", + " , !- Outside Boundary Condition Object ", + " SunExposed, !- Sun Exposure ", + " WindExposed, !- Wind Exposure ", + " 0.0000000, !- View Factor to Ground ", + " 4, !- Number of Vertices ", + " -5,-5,3, !- X,Y,Z ==> Vertex 1 {m} ", + " 5,-5,3, !- X,Y,Z ==> Vertex 2 {m} ", + " 5,5,3, !- X,Y,Z ==> Vertex 3 {m} ", + " -5,5,3; !- X,Y,Z ==> Vertex 4 {m} ", + " BuildingSurface:Detailed, ", + " Zn001:floor, !- Name ", + " Floor, !- Surface Type ", + " SLAB FLOOR, !- Construction Name ", + " ZONE ONE, !- Zone Name ", + " Outdoors, !- Outside Boundary Condition ", + " , !- Outside Boundary Condition Object ", + " SunExposed, !- Sun Exposure ", + " WindExposed, !- Wind Exposure ", + " 0.0000000, !- View Factor to Ground ", + " 4, !- Number of Vertices ", + " -5,5,0, !- X,Y,Z ==> Vertex 1 {m} ", + " 5,5,0, !- X,Y,Z ==> Vertex 2 {m} ", + " 5,-5,0, !- X,Y,Z ==> Vertex 3 {m} ", + " -5,-5,0; !- X,Y,Z ==> Vertex 4 {m} ", + " FenestrationSurface:Detailed, ", + " Zn001:Wall-South:Win001, !- Name ", + " Window, !- Surface Type ", + " DOUBLE PANE HW WINDOW, !- Construction Name ", + " Zn001:Wall-South, !- Building Surface Name ", + " , !- Outside Boundary Condition Object ", + " 0.5000000, !- View Factor to Ground ", + " TestFrameAndDivider, !- Frame and Divider Name ", + " 1.0, !- Multiplier ", + " 4, !- Number of Vertices ", + " -3,-5,2.5, !- X,Y,Z ==> Vertex 1 {m} ", + " -3,-5,0.5, !- X,Y,Z ==> Vertex 2 {m} ", + " 3,-5,0.5, !- X,Y,Z ==> Vertex 3 {m} ", + " 3,-5,2.5; !- X,Y,Z ==> Vertex 4 {m} ", + " WindowProperty:FrameAndDivider, ", + " TestFrameAndDivider, !- Name ", + " 0.05, !- Frame Width {m} ", + " 0.05, !- Frame Outside Projection {m} ", + " 0.05, !- Frame Inside Projection {m} ", + " 5.0, !- Frame Conductance {W/m2-K} ", + " 1.2, !- Ratio of Frame-Edge Glass Conductance to Center-Of-Gl", + " 0.8, !- Frame Solar Absorptance ", + " 0.8, !- Frame Visible Absorptance ", + " 0.9, !- Frame Thermal Hemispherical Emissivity ", + " DividedLite, !- Divider Type ", + " 0.02, !- Divider Width {m} ", + " 2, !- Number of Horizontal Dividers ", + " 2, !- Number of Vertical Dividers ", + " 0.02, !- Divider Outside Projection {m} ", + " 0.02, !- Divider Inside Projection {m} ", + " 5.0, !- Divider Conductance {W/m2-K} ", + " 1.2, !- Ratio of Divider-Edge Glass Conductance to Center-Of-", + " 0.8, !- Divider Solar Absorptance ", + " 0.8, !- Divider Visible Absorptance ", + " 0.9; !- Divider Thermal Hemispherical Emissivity ", + " Shading:Zone:Detailed, ", + " Zn001:Wall-South:Shade001, !- Name ", + " Zn001:Wall-South, !- Base Surface Name ", + " SunShading, !- Transmittance Schedule Name ", + " 4, !- Number of Vertices ", + " -3,-5,2.5, !- X,Y,Z ==> Vertex 1 {m} ", + " -3,-6,2.5, !- X,Y,Z ==> Vertex 2 {m} ", + " 3,-6,2.5, !- X,Y,Z ==> Vertex 3 {m} ", + " 3,-5,2.5; !- X,Y,Z ==> Vertex 4 {m} ", + " ShadingProperty:Reflectance, ", + " Zn001:Wall-South:Shade001, !- Shading Surface Name ", + " 0.2, !- Diffuse Solar Reflectance of Unglazed Part of Shading", + " 0.2; !- Diffuse Visible Reflectance of Unglazed Part of Shadi"}); + + ASSERT_TRUE(process_idf(idf_objects)); + + SimulationManager::GetProjectData(OutputFiles::getSingleton()); + bool FoundError = false; + + HeatBalanceManager::GetProjectControlData(OutputFiles::getSingleton(), FoundError); // read project control data + EXPECT_FALSE(FoundError); // expect no errors + + HeatBalanceManager::SetPreConstructionInputParameters(); + ScheduleManager::ProcessScheduleInput(OutputFiles::getSingleton()); // read schedules + + HeatBalanceManager::GetMaterialData(OutputFiles::getSingleton(), FoundError); + EXPECT_FALSE(FoundError); + + HeatBalanceManager::GetFrameAndDividerData(FoundError); + EXPECT_FALSE(FoundError); + + HeatBalanceManager::GetConstructData(FoundError); + EXPECT_FALSE(FoundError); + + HeatBalanceManager::GetZoneData(FoundError); // Read Zone data from input file + EXPECT_FALSE(FoundError); + + SurfaceGeometry::GetGeometryParameters(OutputFiles::getSingleton(), FoundError); + EXPECT_FALSE(FoundError); + + SurfaceGeometry::CosZoneRelNorth.allocate(1); + SurfaceGeometry::SinZoneRelNorth.allocate(1); + + SurfaceGeometry::CosZoneRelNorth(1) = std::cos(-Zone(1).RelNorth * DegToRadians); + SurfaceGeometry::SinZoneRelNorth(1) = std::sin(-Zone(1).RelNorth * DegToRadians); + SurfaceGeometry::CosBldgRelNorth = 1.0; + SurfaceGeometry::SinBldgRelNorth = 0.0; + + SurfaceGeometry::GetSurfaceData(OutputFiles::getSingleton(), FoundError); // setup zone geometry and get zone data + EXPECT_FALSE(FoundError); // expect no errors + + // compare_err_stream( "" ); // just for debugging + + SurfaceGeometry::SetupZoneGeometry(OutputFiles::getSingleton(), FoundError); // this calls GetSurfaceData() + EXPECT_FALSE(FoundError); + + SolarShading::AllocateModuleArrays(); + SolarShading::DetermineShadowingCombinations(); + DataEnvironment::DayOfYear_Schedule = 168; + DataEnvironment::DayOfWeek = 6; + DataGlobals::TimeStep = 4; + DataGlobals::HourOfDay = 9; + + // compare_err_stream( "" ); // just for debugging + EXPECT_FALSE(DataSystemVariables::SlaterBarsky); + + DataSurfaces::ShadingTransmittanceVaries = true; + DataSystemVariables::DetailedSkyDiffuseAlgorithm = true; + SolarDistribution = FullExterior; + DataSystemVariables::SlaterBarsky = true; + + CalcSkyDifShading = true; + SolarShading::InitSolarCalculations(); + SolarShading::SkyDifSolarShading(); + CalcSkyDifShading = false; + + FigureSolarBeamAtTimestep(DataGlobals::HourOfDay, DataGlobals::TimeStep); + + EXPECT_NEAR(0.6504, DifShdgRatioIsoSkyHRTS(4, 9, 6), 0.0001); + EXPECT_NEAR(0.9152, DifShdgRatioHorizHRTS(4, 9, 6), 0.0001); + + DataSystemVariables::SlaterBarsky = false; +}