diff --git a/src/EnergyPlus/DataSystemVariables.hh b/src/EnergyPlus/DataSystemVariables.hh index 7de50eec237..5d4eedc1c54 100644 --- a/src/EnergyPlus/DataSystemVariables.hh +++ b/src/EnergyPlus/DataSystemVariables.hh @@ -112,6 +112,11 @@ struct SystemVarsData : BaseGlobalStruct bool ReportExtShadingSunlitFrac = false; // when true, the sunlit fraction for all surfaces are exported as a csv format output bool DisableGroupSelfShading = false; // when true, defined shadowing surfaces group is ignored when calculating sunlit fraction bool DisableAllSelfShading = false; // when true, all external shadowing surfaces is ignored when calculating sunlit fraction + bool DisableSelfShadingWithinGroup = false; + bool DisableSelfShadingBetweenGroup = false; + + int shadingGroupsNum = 0; // number of shading groups + Array1D_string shadingGroupZoneListNames; // array of zone names in user input bool TrackAirLoopEnvFlag = false; // If TRUE generates a file with runtime statistics for each HVAC // controller on each air loop diff --git a/src/EnergyPlus/HeatBalanceManager.cc b/src/EnergyPlus/HeatBalanceManager.cc index 5f791ee9e1a..bdae0b86662 100644 --- a/src/EnergyPlus/HeatBalanceManager.cc +++ b/src/EnergyPlus/HeatBalanceManager.cc @@ -1967,6 +1967,8 @@ namespace HeatBalanceManager { // METHODOLOGY EMPLOYED: // The GetObjectItem routines are employed to retrieve the data. + SolarShading::GetShadowingInput(state); + GetZoneData(state, ErrorsFound); // Read Zone data from input file SurfaceGeometry::SetupZoneGeometry(state, ErrorsFound); diff --git a/src/EnergyPlus/SolarShading.cc b/src/EnergyPlus/SolarShading.cc index adbeb77c6ce..6c95f90459a 100644 --- a/src/EnergyPlus/SolarShading.cc +++ b/src/EnergyPlus/SolarShading.cc @@ -196,7 +196,7 @@ void InitSolarCalculations(EnergyPlusData &state) if (state.dataSolarShading->GetInputFlag) { checkShadingSurfaceSchedules(state); - GetShadowingInput(state); + processShadowingInput(state); state.dataSolarShading->GetInputFlag = false; state.dataSolarShading->MaxHCV = (((max(15, state.dataSurface->MaxVerticesPerSurface) + 16) / 16) * 16) - 1; // Assure MaxHCV+1 is multiple of 16 for 128 B alignment @@ -514,18 +514,6 @@ void GetShadowingInput(EnergyPlusData &state) state.dataSysVars->shadingMethod = ShadingMethod::PolygonClipping; } - if ((state.dataSysVars->shadingMethod == DataSystemVariables::ShadingMethod::PixelCounting) && - state.dataSolarShading->anyScheduledShadingSurface) { - ShowSevereError(state, "The Shading Calculation Method of choice is \"PixelCounting\"; "); - ShowContinueError(state, "and there is at least one shading surface of type "); - ShowContinueError(state, "Shading:Site:Detailed, Shading:Building:Detailed, or Shading:Zone:Detailed, "); - ShowContinueError(state, "that has an active transmittance schedule value greater than zero or may vary."); - ShowContinueError(state, "With \"PixelCounting\" Shading Calculation Method, the shading surfaces will be treated as "); - ShowContinueError(state, "completely opaque (transmittance = 0) during the shading calculation, "); - ShowContinueError(state, "which may result in inaccurate or unexpected results."); - ShowContinueError(state, "It is suggested switching to another Shading Calculation Method, such as \"PolygonClipping\"."); - } - aNum++; if (NumAlphas >= aNum) { if (Util::SameString(state.dataIPShortCut->cAlphaArgs(aNum), "Periodic")) { @@ -629,30 +617,11 @@ void GetShadowingInput(EnergyPlusData &state) state.dataIPShortCut->cAlphaArgs(aNum) = "No"; state.dataSysVars->ReportExtShadingSunlitFrac = false; } - if (state.dataSysVars->shadingMethod == ShadingMethod::Imported) { - int ExtShadingSchedNum; - for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) { - ExtShadingSchedNum = ScheduleManager::GetScheduleIndex(state, state.dataSurface->Surface(SurfNum).Name + "_shading"); - if (ExtShadingSchedNum != 0) { - state.dataSurface->Surface(SurfNum).SurfSchedExternalShadingFrac = true; - state.dataSurface->Surface(SurfNum).SurfExternalShadingSchInd = ExtShadingSchedNum; - } else { - ShowWarningError(state, - format("{}: sunlit fraction schedule not found for {} when using ImportedShading.", - cCurrentModuleObject, - state.dataSurface->Surface(SurfNum).Name)); - ShowContinueError(state, "These values are set to 1.0."); - } - } - } - - bool DisableSelfShadingWithinGroup = false; - bool DisableSelfShadingBetweenGroup = false; aNum++; if (NumAlphas >= aNum) { if (Util::SameString(state.dataIPShortCut->cAlphaArgs(aNum), "Yes")) { - DisableSelfShadingWithinGroup = true; + state.dataSysVars->DisableSelfShadingWithinGroup = true; state.dataIPShortCut->cAlphaArgs(aNum) = "Yes"; } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(aNum), "No")) { state.dataIPShortCut->cAlphaArgs(aNum) = "No"; @@ -668,7 +637,7 @@ void GetShadowingInput(EnergyPlusData &state) aNum++; if (NumAlphas >= aNum) { if (Util::SameString(state.dataIPShortCut->cAlphaArgs(aNum), "Yes")) { - DisableSelfShadingBetweenGroup = true; + state.dataSysVars->DisableSelfShadingBetweenGroup = true; state.dataIPShortCut->cAlphaArgs(aNum) = "Yes"; } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(aNum), "No")) { state.dataIPShortCut->cAlphaArgs(aNum) = "No"; @@ -681,66 +650,17 @@ void GetShadowingInput(EnergyPlusData &state) state.dataIPShortCut->cAlphaArgs(aNum) = "No"; } - if (DisableSelfShadingBetweenGroup && DisableSelfShadingWithinGroup) { + if (state.dataSysVars->DisableSelfShadingBetweenGroup && state.dataSysVars->DisableSelfShadingWithinGroup) { state.dataSysVars->DisableAllSelfShading = true; - } else if (DisableSelfShadingBetweenGroup || DisableSelfShadingWithinGroup) { + } else if (state.dataSysVars->DisableSelfShadingBetweenGroup || state.dataSysVars->DisableSelfShadingWithinGroup) { state.dataSysVars->DisableGroupSelfShading = true; } aNum++; - int SurfZoneGroup, CurZoneGroup; - if (state.dataSysVars->DisableGroupSelfShading) { - Array1D_int DisableSelfShadingGroups; - int NumOfShadingGroups; - if (NumAlphas >= aNum) { - // Read all shading groups - NumOfShadingGroups = NumAlphas - (aNum - 1); - DisableSelfShadingGroups.allocate(NumOfShadingGroups); - for (int i = 1; i <= NumOfShadingGroups; i++) { - Found = Util::FindItemInList( - state.dataIPShortCut->cAlphaArgs(i + (aNum - 1)), state.dataHeatBal->ZoneList, state.dataHeatBal->NumOfZoneLists); - if (Found != 0) DisableSelfShadingGroups(i) = Found; - } - - for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; SurfNum++) { - if (state.dataSurface->Surface(SurfNum).ExtBoundCond == 0) { // Loop through all exterior surfaces - SurfZoneGroup = 0; - // Check the shading zone group of each exterior surface - for (int ZoneGroupLoop = 1; ZoneGroupLoop <= NumOfShadingGroups; ZoneGroupLoop++) { // Loop through all defined shading groups - CurZoneGroup = DisableSelfShadingGroups(ZoneGroupLoop); - for (int ZoneNum = 1; ZoneNum <= state.dataHeatBal->ZoneList(CurZoneGroup).NumOfZones; - ZoneNum++) { // Loop through all zones in the zone list - if (state.dataSurface->Surface(SurfNum).Zone == state.dataHeatBal->ZoneList(CurZoneGroup).Zone(ZoneNum)) { - SurfZoneGroup = CurZoneGroup; - break; - } - } - } - // if a surface is not in any zone group, no self shading is disabled for this surface - if (SurfZoneGroup != 0) { - // if DisableSelfShadingWithinGroup, add all zones in the same zone group to the surface's disabled zone list - // if DisableSelfShadingBetweenGroups, add all zones in all other zone groups to the surface's disabled zone list - for (int ZoneGroupLoop = 1; ZoneGroupLoop <= NumOfShadingGroups; ZoneGroupLoop++) { // Loop through all defined shading groups - CurZoneGroup = DisableSelfShadingGroups(ZoneGroupLoop); - if (SurfZoneGroup == CurZoneGroup && DisableSelfShadingWithinGroup) { - for (int ZoneNum = 1; ZoneNum <= state.dataHeatBal->ZoneList(CurZoneGroup).NumOfZones; - ZoneNum++) { // Loop through all zones in the zone list - state.dataSurface->SurfShadowDisabledZoneList(SurfNum).push_back( - state.dataHeatBal->ZoneList(CurZoneGroup).Zone(ZoneNum)); - } - } else if (SurfZoneGroup != CurZoneGroup && DisableSelfShadingBetweenGroup) { - for (int ZoneNum = 1; ZoneNum <= state.dataHeatBal->ZoneList(CurZoneGroup).NumOfZones; ZoneNum++) { - state.dataSurface->SurfShadowDisabledZoneList(SurfNum).push_back( - state.dataHeatBal->ZoneList(CurZoneGroup).Zone(ZoneNum)); - } - } - } - } - } - } - } else { - ShowFatalError(state, "No Shading groups are defined when disabling grouped self shading."); - } + state.dataSysVars->shadingGroupsNum = NumAlphas - (aNum - 1); + state.dataSysVars->shadingGroupZoneListNames.allocate(state.dataSysVars->shadingGroupsNum); + for (int numZone = 1; numZone <= state.dataSysVars->shadingGroupsNum; ++numZone) { + state.dataSysVars->shadingGroupZoneListNames(numZone) = state.dataIPShortCut->cAlphaArgs(aNum - 1 + numZone); } if (!state.dataSysVars->DetailedSolarTimestepIntegration && state.dataSurface->ShadingTransmittanceVaries && @@ -797,6 +717,93 @@ void GetShadowingInput(EnergyPlusData &state) state.dataIPShortCut->cAlphaArgs(7)); } +void processShadowingInput(EnergyPlusData &state) +{ + // all shadow input processing that needed zones and surfaces to already be read into data (part of fix for Defect #10299) + + if ((state.dataSysVars->shadingMethod == DataSystemVariables::ShadingMethod::PixelCounting) && + state.dataSolarShading->anyScheduledShadingSurface) { + ShowSevereError(state, "The Shading Calculation Method of choice is \"PixelCounting\"; "); + ShowContinueError(state, "and there is at least one shading surface of type "); + ShowContinueError(state, "Shading:Site:Detailed, Shading:Building:Detailed, or Shading:Zone:Detailed, "); + ShowContinueError(state, "that has an active transmittance schedule value greater than zero or may vary."); + ShowContinueError(state, "With \"PixelCounting\" Shading Calculation Method, the shading surfaces will be treated as "); + ShowContinueError(state, "completely opaque (transmittance = 0) during the shading calculation, "); + ShowContinueError(state, "which may result in inaccurate or unexpected results."); + ShowContinueError(state, "It is suggested switching to another Shading Calculation Method, such as \"PolygonClipping\"."); + } + + if (state.dataSysVars->shadingMethod == DataSystemVariables::ShadingMethod::Imported) { + int ExtShadingSchedNum; + for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) { + ExtShadingSchedNum = ScheduleManager::GetScheduleIndex(state, state.dataSurface->Surface(SurfNum).Name + "_shading"); + if (ExtShadingSchedNum != 0) { + state.dataSurface->Surface(SurfNum).SurfSchedExternalShadingFrac = true; + state.dataSurface->Surface(SurfNum).SurfExternalShadingSchInd = ExtShadingSchedNum; + } else { + ShowWarningError(state, + format("processShadowingInput: sunlit fraction schedule not found for {} when using ImportedShading.", + state.dataSurface->Surface(SurfNum).Name)); + ShowContinueError(state, "These values are set to 1.0."); + } + } + } + + int SurfZoneGroup, CurZoneGroup; + int Found = 0; + if (state.dataSysVars->DisableGroupSelfShading) { + Array1D_int DisableSelfShadingGroups; + int NumOfShadingGroups = state.dataSysVars->shadingGroupsNum; + if (NumOfShadingGroups > 0) { + DisableSelfShadingGroups.allocate(NumOfShadingGroups); + for (int i = 1; i <= NumOfShadingGroups; i++) { + Found = Util::FindItemInList( + state.dataSysVars->shadingGroupZoneListNames(i), state.dataHeatBal->ZoneList, state.dataHeatBal->NumOfZoneLists); + if (Found != 0) DisableSelfShadingGroups(i) = Found; + } + + for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; SurfNum++) { + if (state.dataSurface->Surface(SurfNum).ExtBoundCond == 0) { // Loop through all exterior surfaces + SurfZoneGroup = 0; + // Check the shading zone group of each exterior surface + for (int ZoneGroupLoop = 1; ZoneGroupLoop <= NumOfShadingGroups; ZoneGroupLoop++) { // Loop through all defined shading groups + CurZoneGroup = DisableSelfShadingGroups(ZoneGroupLoop); + for (int ZoneNum = 1; ZoneNum <= state.dataHeatBal->ZoneList(CurZoneGroup).NumOfZones; + ZoneNum++) { // Loop through all zones in the zone list + if (state.dataSurface->Surface(SurfNum).Zone == state.dataHeatBal->ZoneList(CurZoneGroup).Zone(ZoneNum)) { + SurfZoneGroup = CurZoneGroup; + break; + } + } + } + // if a surface is not in any zone group, no self shading is disabled for this surface + if (SurfZoneGroup != 0) { + // if DisableSelfShadingWithinGroup, add all zones in the same zone group to the surface's disabled zone list + // if DisableSelfShadingBetweenGroups, add all zones in all other zone groups to the surface's disabled zone list + for (int ZoneGroupLoop = 1; ZoneGroupLoop <= NumOfShadingGroups; ZoneGroupLoop++) { // Loop through all defined shading groups + CurZoneGroup = DisableSelfShadingGroups(ZoneGroupLoop); + if (SurfZoneGroup == CurZoneGroup && state.dataSysVars->DisableSelfShadingWithinGroup) { + for (int ZoneNum = 1; ZoneNum <= state.dataHeatBal->ZoneList(CurZoneGroup).NumOfZones; + ZoneNum++) { // Loop through all zones in the zone list + state.dataSurface->SurfShadowDisabledZoneList(SurfNum).push_back( + state.dataHeatBal->ZoneList(CurZoneGroup).Zone(ZoneNum)); + } + } else if (SurfZoneGroup != CurZoneGroup && state.dataSysVars->DisableSelfShadingBetweenGroup) { + for (int ZoneNum = 1; ZoneNum <= state.dataHeatBal->ZoneList(CurZoneGroup).NumOfZones; ZoneNum++) { + state.dataSurface->SurfShadowDisabledZoneList(SurfNum).push_back( + state.dataHeatBal->ZoneList(CurZoneGroup).Zone(ZoneNum)); + } + } + } + } + } + } + } else { + ShowFatalError(state, "No Shading groups are defined when disabling grouped self shading."); + } + } +} + void checkScheduledSurfacePresent(EnergyPlusData &state) { // User has chosen "Scheduled" for sunlit fraction so check to see which surfaces don't have a schedule diff --git a/src/EnergyPlus/SolarShading.hh b/src/EnergyPlus/SolarShading.hh index cb1dba901c0..5e3d62e5f41 100644 --- a/src/EnergyPlus/SolarShading.hh +++ b/src/EnergyPlus/SolarShading.hh @@ -99,6 +99,8 @@ namespace SolarShading { void GetShadowingInput(EnergyPlusData &state); + void processShadowingInput(EnergyPlusData &state); + void checkScheduledSurfacePresent(EnergyPlusData &state); void AllocateModuleArrays(EnergyPlusData &state); diff --git a/src/EnergyPlus/SurfaceGeometry.cc b/src/EnergyPlus/SurfaceGeometry.cc index c8191fa36c2..09b60d6a98f 100644 --- a/src/EnergyPlus/SurfaceGeometry.cc +++ b/src/EnergyPlus/SurfaceGeometry.cc @@ -68,6 +68,7 @@ #include #include #include +#include #include #include #include @@ -15680,9 +15681,9 @@ namespace SurfaceGeometry { if (SignFlag != PrevSignFlag) { if (state.dataGlobal->DisplayExtraWarnings && surfaceTmp.ExtSolar && - (state.dataHeatBal->SolarDistribution != DataHeatBalance::Shadowing::Minimal) && - // Warn only once - surfaceTmp.IsConvex) { + (state.dataHeatBal->SolarDistribution != DataHeatBalance::Shadowing::Minimal) && surfaceTmp.IsConvex && + !state.dataSysVars->SutherlandHodgman && + (state.dataSysVars->shadingMethod == DataSystemVariables::ShadingMethod::PolygonClipping)) { ShowWarningError(state, format("CheckConvexity: Zone=\"{}\", Surface=\"{}\" is non-convex.", state.dataHeatBal->Zone(surfaceTmp.Zone).Name, diff --git a/tst/EnergyPlus/unit/SolarShading.unit.cc b/tst/EnergyPlus/unit/SolarShading.unit.cc index 3dc05ae5ab4..aa28eb96a4a 100644 --- a/tst/EnergyPlus/unit/SolarShading.unit.cc +++ b/tst/EnergyPlus/unit/SolarShading.unit.cc @@ -1461,6 +1461,8 @@ TEST_F(EnergyPlusFixture, SolarShadingTest_DisableGroupSelfShading) HeatBalanceManager::GetConstructData(*state, FoundError); EXPECT_FALSE(FoundError); + SolarShading::GetShadowingInput(*state); + HeatBalanceManager::GetZoneData(*state, FoundError); // Read Zone data from input file EXPECT_FALSE(FoundError); @@ -1483,7 +1485,7 @@ TEST_F(EnergyPlusFixture, SolarShadingTest_DisableGroupSelfShading) compare_err_stream(""); // just for debugging - SolarShading::GetShadowingInput(*state); + SolarShading::processShadowingInput(*state); for (int SurfNum = 1; SurfNum <= state->dataSurface->TotSurfaces; SurfNum++) { if (state->dataSurface->Surface(SurfNum).ExtBoundCond == 0 && state->dataSurface->Surface(SurfNum).Zone != 0) { @@ -3867,6 +3869,8 @@ TEST_F(EnergyPlusFixture, SolarShadingTest_Warn_Pixel_Count_and_TM_Schedule) HeatBalanceManager::GetConstructData(*state, FoundError); EXPECT_FALSE(FoundError); + SolarShading::GetShadowingInput(*state); + HeatBalanceManager::GetZoneData(*state, FoundError); EXPECT_FALSE(FoundError); @@ -3888,27 +3892,36 @@ TEST_F(EnergyPlusFixture, SolarShadingTest_Warn_Pixel_Count_and_TM_Schedule) EXPECT_EQ(state->dataSolarShading->anyScheduledShadingSurface, true); +#ifdef EP_NO_OPENGL EXPECT_EQ(state->dataErrTracking->AskForSurfacesReport, true); - EXPECT_EQ(state->dataErrTracking->TotalWarningErrors, 0); - // Expect no severe errors at this point + EXPECT_EQ(state->dataErrTracking->TotalWarningErrors, 2); EXPECT_EQ(state->dataErrTracking->TotalSevereErrors, 0); +#else + if (!Penumbra::Penumbra::is_valid_context()) { + EXPECT_EQ(state->dataErrTracking->AskForSurfacesReport, true); + EXPECT_EQ(state->dataErrTracking->TotalWarningErrors, 2); + EXPECT_EQ(state->dataErrTracking->TotalSevereErrors, 0); + } else { + EXPECT_EQ(state->dataErrTracking->AskForSurfacesReport, true); + EXPECT_EQ(state->dataErrTracking->TotalWarningErrors, 1); + EXPECT_EQ(state->dataErrTracking->TotalSevereErrors, 0); + } +#endif - SolarShading::GetShadowingInput(*state); + SolarShading::processShadowingInput(*state); #ifdef EP_NO_OPENGL - EXPECT_EQ(state->dataErrTracking->TotalWarningErrors, 1); - EXPECT_EQ(state->dataErrTracking->TotalSevereErrors, 0); + EXPECT_EQ(state->dataErrTracking->TotalWarningErrors, 2); + EXPECT_EQ(state->dataErrTracking->TotalSevereErrors, 0; EXPECT_EQ(state->dataErrTracking->LastSevereError, ""); #else if (!Penumbra::Penumbra::is_valid_context()) { - EXPECT_EQ(state->dataErrTracking->TotalWarningErrors, 1); + EXPECT_EQ(state->dataErrTracking->TotalWarningErrors, 2); EXPECT_EQ(state->dataErrTracking->TotalSevereErrors, 0); EXPECT_EQ(state->dataErrTracking->LastSevereError, ""); } else { - EXPECT_EQ(state->dataErrTracking->TotalWarningErrors, 0); - // Now expect one severe error from GetShadowInput() + EXPECT_EQ(state->dataErrTracking->TotalWarningErrors, 1); EXPECT_EQ(state->dataErrTracking->TotalSevereErrors, 1); - // There should be a severe warning reported about the PixelCounting and the scheduled shading surface tm values > 0.0 combination. EXPECT_EQ(state->dataErrTracking->LastSevereError, "The Shading Calculation Method of choice is \"PixelCounting\"; "); } #endif @@ -4178,6 +4191,8 @@ TEST_F(EnergyPlusFixture, SolarShadingTest_PolygonOverlap) HeatBalanceManager::GetConstructData(*state, FoundError); EXPECT_FALSE(FoundError); + SolarShading::GetShadowingInput(*state); + HeatBalanceManager::GetZoneData(*state, FoundError); // Read Zone data from input file EXPECT_FALSE(FoundError); @@ -4200,6 +4215,8 @@ TEST_F(EnergyPlusFixture, SolarShadingTest_PolygonOverlap) SurfaceGeometry::GetSurfaceData(*state, FoundError); // setup zone geometry and get zone data EXPECT_FALSE(FoundError); // expect no errors + SolarShading::processShadowingInput(*state); + // compare_err_stream( "" ); // just for debugging SurfaceGeometry::SetupZoneGeometry(*state, FoundError); // this calls GetSurfaceData() @@ -5947,3 +5964,243 @@ TEST_F(EnergyPlusFixture, SolarShadingTest_CalcInteriorSolarDistribution_EQL) EXPECT_NEAR(0.0, state->dataHeatBalSurf->SurfWinInitialDifSolInTrans(windowSurfNum), 0.01); EXPECT_NEAR(1.4736, state->dataHeatBalSurf->SurfWinInitialDifSolInTrans(windowSurfNum2), 0.01); } + +TEST_F(EnergyPlusFixture, SolarShadingTest_GetShadowingInputTest1) +{ + // Tests for Defect #10299: Test GetShadowingInput for various combinations of input + // with a focus put on the correct setting of variables associated with calculation + // method and polygon clipping algorithm + std::string const idf_objects = delimited_string({ + " ShadowCalculation,", + " PolygonClipping, !- Shading Calculation Method", + " Timestep, !- Shading Calculation Update Frequency Method", + " 1, !- Shading Calculation Update Frequency", + " 200, !- Maximum Figures in Shadow Overlap Calculations", + " ConvexWeilerAtherton, !- Polygon Clipping Algorithm", + " 512.0, !- Pixel Counting Resolution", + " DetailedSkyDiffuseModeling; !- Sky Diffuse Modeling Algorithm", + }); + + ASSERT_TRUE(process_idf(idf_objects)); + + state->dataSolarShading->anyScheduledShadingSurface = false; + + // Test 1 of 6: Polygon Clipping and ConvexWeilerAtherton + SolarShading::GetShadowingInput(*state); + int expectedFrequency = 1; + int expectedOverlaps = 200; + EXPECT_TRUE(state->dataSysVars->DetailedSkyDiffuseAlgorithm); + EXPECT_TRUE(state->dataSysVars->DetailedSolarTimestepIntegration); + EXPECT_EQ(expectedFrequency, state->dataSolarShading->ShadowingCalcFrequency); + EXPECT_EQ(expectedOverlaps, state->dataSolarShading->MaxHCS); + EXPECT_FALSE(state->dataSysVars->SutherlandHodgman); + EXPECT_FALSE(state->dataSysVars->SlaterBarsky); + EXPECT_ENUM_EQ(state->dataSysVars->shadingMethod, ShadingMethod::PolygonClipping); +} + +TEST_F(EnergyPlusFixture, SolarShadingTest_GetShadowingInputTest2) +{ + // Tests for Defect #10299: Test GetShadowingInput for various combinations of input + // with a focus put on the correct setting of variables associated with calculation + // method and polygon clipping algorithm + std::string const idf_objects = delimited_string({ + " ShadowCalculation,", + " PolygonClipping, !- Shading Calculation Method", + " Periodic, !- Shading Calculation Update Frequency Method", + " 10, !- Shading Calculation Update Frequency", + " 2000, !- Maximum Figures in Shadow Overlap Calculations", + " SutherlandHodgman, !- Polygon Clipping Algorithm", + " 512.0, !- Pixel Counting Resolution", + " SimpleSkyDiffuseModeling; !- Sky Diffuse Modeling Algorithm", + }); + + ASSERT_TRUE(process_idf(idf_objects)); + + state->dataSolarShading->anyScheduledShadingSurface = false; + + // Test 2 of 6: Polygon Clipping and SutherlandHodgman + SolarShading::GetShadowingInput(*state); + int expectedFrequency = 10; + int expectedOverlaps = 2000; + EXPECT_FALSE(state->dataSysVars->DetailedSkyDiffuseAlgorithm); + EXPECT_FALSE(state->dataSysVars->DetailedSolarTimestepIntegration); + EXPECT_EQ(expectedFrequency, state->dataSolarShading->ShadowingCalcFrequency); + EXPECT_EQ(expectedOverlaps, state->dataSolarShading->MaxHCS); + EXPECT_TRUE(state->dataSysVars->SutherlandHodgman); + EXPECT_FALSE(state->dataSysVars->SlaterBarsky); + EXPECT_ENUM_EQ(state->dataSysVars->shadingMethod, ShadingMethod::PolygonClipping); +} + +TEST_F(EnergyPlusFixture, SolarShadingTest_GetShadowingInputTest3) +{ + // Tests for Defect #10299: Test GetShadowingInput for various combinations of input + // with a focus put on the correct setting of variables associated with calculation + // method and polygon clipping algorithm + std::string const idf_objects = delimited_string({ + " ShadowCalculation,", + " PolygonClipping, !- Shading Calculation Method", + " Timestep, !- Shading Calculation Update Frequency Method", + " 30, !- Shading Calculation Update Frequency", + " 15000, !- Maximum Figures in Shadow Overlap Calculations", + " SlaterBarskyandSutherlandHodgman, !- Polygon Clipping Algorithm", + " 512.0, !- Pixel Counting Resolution", + " DetailedSkyDiffuseModeling; !- Sky Diffuse Modeling Algorithm", + }); + + ASSERT_TRUE(process_idf(idf_objects)); + + state->dataSolarShading->anyScheduledShadingSurface = false; + + // Test 3 of 6: Polygon Clipping and SlaterBarskyandSutherlandHodgman + SolarShading::GetShadowingInput(*state); + int expectedFrequency = 30; + int expectedOverlaps = 15000; + EXPECT_TRUE(state->dataSysVars->DetailedSkyDiffuseAlgorithm); + EXPECT_TRUE(state->dataSysVars->DetailedSolarTimestepIntegration); + EXPECT_EQ(expectedFrequency, state->dataSolarShading->ShadowingCalcFrequency); + EXPECT_EQ(expectedOverlaps, state->dataSolarShading->MaxHCS); + EXPECT_TRUE(state->dataSysVars->SutherlandHodgman); + EXPECT_TRUE(state->dataSysVars->SlaterBarsky); + EXPECT_ENUM_EQ(state->dataSysVars->shadingMethod, ShadingMethod::PolygonClipping); +} + +TEST_F(EnergyPlusFixture, SolarShadingTest_GetShadowingInputTest4) +{ + // Tests for Defect #10299: Test GetShadowingInput for various combinations of input + // with a focus put on the correct setting of variables associated with calculation + // method and polygon clipping algorithm + std::string const idf_objects = delimited_string({ + " ShadowCalculation,", + " PixelCounting, !- Shading Calculation Method", + " Periodic, !- Shading Calculation Update Frequency Method", + " 1, !- Shading Calculation Update Frequency", + " 200, !- Maximum Figures in Shadow Overlap Calculations", + " ConvexWeilerAtherton, !- Polygon Clipping Algorithm", + " 512.0, !- Pixel Counting Resolution", + " DetailedSkyDiffuseModeling; !- Sky Diffuse Modeling Algorithm", + }); + + ASSERT_TRUE(process_idf(idf_objects)); + + state->dataSolarShading->anyScheduledShadingSurface = false; + + // Test 4 of 6: Pixel Counting and ConvexWeilerAtherton + SolarShading::GetShadowingInput(*state); + int expectedFrequency = 1; + int expectedOverlaps = 200; + EXPECT_TRUE(state->dataSysVars->DetailedSkyDiffuseAlgorithm); + EXPECT_FALSE(state->dataSysVars->DetailedSolarTimestepIntegration); + EXPECT_EQ(expectedFrequency, state->dataSolarShading->ShadowingCalcFrequency); + EXPECT_EQ(expectedOverlaps, state->dataSolarShading->MaxHCS); + EXPECT_FALSE(state->dataSysVars->SutherlandHodgman); + EXPECT_FALSE(state->dataSysVars->SlaterBarsky); + +#ifdef EP_NO_OPENGL + EXPECT_ENUM_EQ(state->dataSysVars->shadingMethod, ShadingMethod::PolygonClipping); +#else + if (!Penumbra::Penumbra::is_valid_context()) { + EXPECT_ENUM_EQ(state->dataSysVars->shadingMethod, ShadingMethod::PolygonClipping); + } else { + EXPECT_ENUM_EQ(state->dataSysVars->shadingMethod, ShadingMethod::PixelCounting); + } +#endif +} + +TEST_F(EnergyPlusFixture, SolarShadingTest_GetShadowingInputTest5) +{ + // Tests for Defect #10299: Test GetShadowingInput for various combinations of input + // with a focus put on the correct setting of variables associated with calculation + // method and polygon clipping algorithm + std::string const idf_objects = delimited_string({ + " ShadowCalculation,", + " PixelCounting, !- Shading Calculation Method", + " Periodic, !- Shading Calculation Update Frequency Method", + " 10, !- Shading Calculation Update Frequency", + " 2000, !- Maximum Figures in Shadow Overlap Calculations", + " SutherlandHodgman, !- Polygon Clipping Algorithm", + " 512.0, !- Pixel Counting Resolution", + " DetailedSkyDiffuseModeling; !- Sky Diffuse Modeling Algorithm", + }); + + ASSERT_TRUE(process_idf(idf_objects)); + + state->dataSolarShading->anyScheduledShadingSurface = false; + + // Test 5 of 6: Pixel Counting and SutherlandHodgman + SolarShading::GetShadowingInput(*state); + int expectedFrequency = 10; + int expectedOverlaps = 2000; + EXPECT_TRUE(state->dataSysVars->DetailedSkyDiffuseAlgorithm); + EXPECT_FALSE(state->dataSysVars->DetailedSolarTimestepIntegration); + EXPECT_EQ(expectedFrequency, state->dataSolarShading->ShadowingCalcFrequency); + EXPECT_EQ(expectedOverlaps, state->dataSolarShading->MaxHCS); + EXPECT_TRUE(state->dataSysVars->SutherlandHodgman); + EXPECT_FALSE(state->dataSysVars->SlaterBarsky); + +#ifdef EP_NO_OPENGL + EXPECT_ENUM_EQ(state->dataSysVars->shadingMethod, ShadingMethod::PolygonClipping); +#else + if (!Penumbra::Penumbra::is_valid_context()) { + EXPECT_ENUM_EQ(state->dataSysVars->shadingMethod, ShadingMethod::PolygonClipping); + } else { + EXPECT_ENUM_EQ(state->dataSysVars->shadingMethod, ShadingMethod::PixelCounting); + } +#endif +} + +TEST_F(EnergyPlusFixture, SolarShadingTest_GetShadowingInputTest6) +{ + // Tests for Defect #10299: Test GetShadowingInput for various combinations of input + // with a focus put on the correct setting of variables associated with calculation + // method and polygon clipping algorithm + std::string const idf_objects = delimited_string({ + " ShadowCalculation,", + " PixelCounting, !- Shading Calculation Method", + " Periodic, !- Shading Calculation Update Frequency Method", + " 56, !- Shading Calculation Update Frequency", + " 1234, !- Maximum Figures in Shadow Overlap Calculations", + " SlaterBarskyandSutherlandHodgman, !- Polygon Clipping Algorithm", + " 512.0, !- Pixel Counting Resolution", + " SimpleSkyDiffuseModeling; !- Sky Diffuse Modeling Algorithm", + }); + + ASSERT_TRUE(process_idf(idf_objects)); + + state->dataSolarShading->anyScheduledShadingSurface = false; + + // Test 36of 6: Pixel Counting and SlaterBarskyandSutherlandHodgman + SolarShading::GetShadowingInput(*state); + + int expectedFrequency = 56; + int expectedOverlaps = 1234; + EXPECT_FALSE(state->dataSysVars->DetailedSkyDiffuseAlgorithm); + EXPECT_FALSE(state->dataSysVars->DetailedSolarTimestepIntegration); + EXPECT_EQ(expectedFrequency, state->dataSolarShading->ShadowingCalcFrequency); + EXPECT_EQ(expectedOverlaps, state->dataSolarShading->MaxHCS); + EXPECT_TRUE(state->dataSysVars->SutherlandHodgman); + EXPECT_TRUE(state->dataSysVars->SlaterBarsky); + +#ifdef EP_NO_OPENGL + std::string const error_string = delimited_string({" ** Warning ** ShadowCalculation: suspect Shading Calculation Update Frequency", + " ** ~~~ ** Value entered=[56], Shadowing Calculations will be inaccurate.", + " ** Warning ** No GPU found (required for PixelCounting)", + " ** ~~~ ** PolygonClipping will be used instead"}); + EXPECT_TRUE(compare_err_stream(error_string, true)); + EXPECT_ENUM_EQ(state->dataSysVars->shadingMethod, ShadingMethod::PolygonClipping); + +#else + if (!Penumbra::Penumbra::is_valid_context()) { + std::string const error_string = delimited_string({" ** Warning ** ShadowCalculation: suspect Shading Calculation Update Frequency", + " ** ~~~ ** Value entered=[56], Shadowing Calculations will be inaccurate.", + " ** Warning ** No GPU found (required for PixelCounting)", + " ** ~~~ ** PolygonClipping will be used instead"}); + EXPECT_TRUE(compare_err_stream(error_string, true)); + EXPECT_ENUM_EQ(state->dataSysVars->shadingMethod, ShadingMethod::PolygonClipping); + } else { + std::string const error_string = delimited_string({" ** Warning ** ShadowCalculation: suspect Shading Calculation Update Frequency", + " ** ~~~ ** Value entered=[56], Shadowing Calculations will be inaccurate."}); + EXPECT_TRUE(compare_err_stream(error_string, true)); + EXPECT_ENUM_EQ(state->dataSysVars->shadingMethod, ShadingMethod::PixelCounting); + } +#endif +}