diff --git a/CMakeLists.txt b/CMakeLists.txt index 0c2bd82fd62..0ca2f9e753c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,8 +12,12 @@ cmake_policy(SET CMP0048 NEW) # handling project_version_* variables project(EnergyPlus) # Raise an error if attempting to compile on macOS older than 10.15 - it does not work -if (APPLE AND CMAKE_OSX_DEPLOYMENT_TARGET VERSION_LESS "10.15") - message(FATAL_ERROR "The minimum required version for macOS is 10.15, however CMAKE_OSX_DEPLOYMENT_TARGET is set to ${CMAKE_OSX_DEPLOYMENT_TARGET}. Please set CMAKE_OSX_DEPLOYMENT_TARGET to 10.15 or greater and try again.") +if (APPLE) + if(NOT CMAKE_OSX_DEPLOYMENT_TARGET) + message(FATAL_ERROR "CMAKE_OSX_DEPLOYMENT_TARGET not set. Please set CMAKE_OSX_DEPLOYMENT_TARGET to 10.15 or greater and try again.") + elseif (CMAKE_OSX_DEPLOYMENT_TARGET VERSION_LESS "10.15") + message(FATAL_ERROR "The minimum required version for macOS is 10.15, however CMAKE_OSX_DEPLOYMENT_TARGET is set to ${CMAKE_OSX_DEPLOYMENT_TARGET}.") + endif() endif() if(${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} VERSION_GREATER "3.0") diff --git a/doc/input-output-reference/src/overview/group-thermal-zone-description-geometry.tex b/doc/input-output-reference/src/overview/group-thermal-zone-description-geometry.tex index 9e81bf503f4..08d6679a5ed 100644 --- a/doc/input-output-reference/src/overview/group-thermal-zone-description-geometry.tex +++ b/doc/input-output-reference/src/overview/group-thermal-zone-description-geometry.tex @@ -3341,7 +3341,7 @@ \subsubsection{Surface Inside Face Conduction Heat Loss Rate {[}W{]}}\label{surf These ``inside face conduction'' output variables describe heat flow by conduction right at the inside face of an opaque heat transfer surface. A positive value means that the conduction is from just inside the inside face toward the inside face. A negative value means that the conduction is from the inside face into the core of the heat transfer surface. -Note that Inside Face Conduction, when positive, does \textbf{not} indicate the heat flow from the surface to the zone air, which is governed by the inside face convection coefficient and the difference in temperature between the inside face and the zone air. +Note that Inside Face Conduction, when positive, does \textbf{not} necessarily indicate the heat flow from the surface to the zone air, which is governed by the inside face convection coefficient, the difference in temperature between the inside face and the zone air, and various radiation terms due to solar, internal gains, and radiant exchange with other surfaces in the zone. Different versions of the reports are available. The basic heat gain rate (W) and a per unit area flux (W/m\(^{2}\)) can have positive or negative values with the sign convention that positive indicates heat flowing toward the face itself. There are also directed ``gain'' and ``loss'' versions that have only positive values or zero when the heat flow direction opposes. @@ -3359,7 +3359,9 @@ \subsubsection{Surface Outside Face Conduction Heat Loss Rate {[}W{]}}\label{sur These ``outside face conduction'' output variables describe heat flow by conduction right at the outside face of an opaque heat transfer surface. A positive value means that the conduction is from just inside the outside face toward the outside face. A negative value means that the conduction is from the outside face into the core of the heat transfer surface. -Note that outside face conduction, when positive, does \textbf{not} indicate the heat flow from the surface to the surrounding air, which is governed by the outside face convection coefficient and the difference in temperature between the inside face and the surrounding air. +Note that outside face conduction, when positive, does \textbf{not} necessarily indicate the heat flow from the surface to the surrounding air, due to the fact that there could be various terms such as convection and/or radiation terms based on whatever is the ''outside'' environment for this surface. + +When the surface in question is a partition, the output for this variable is set to zero because there is no outside face because the surface is fully exposed to the zone. When the surface is an interzone partition, the value will be non-zero because there will potentially be conduction into or out of the zone on the other side at this surface. Different versions of the reports are available. The basic heat transfer rate (W) and a per unit area flux (W/m\(^{2}\)) can have positive or negative values with the sign convention that positive indicates heat flowing toward the face itself. There are also directed ``gain'' and ``loss'' versions that have only positive values or zero when the heat flow direction opposes. diff --git a/src/EnergyPlus/HeatBalanceSurfaceManager.cc b/src/EnergyPlus/HeatBalanceSurfaceManager.cc index 51a7911f318..6a3096d9852 100644 --- a/src/EnergyPlus/HeatBalanceSurfaceManager.cc +++ b/src/EnergyPlus/HeatBalanceSurfaceManager.cc @@ -5178,8 +5178,6 @@ void UpdateThermalHistories(EnergyPlusData &state) state.dataHeatBalFanSys->CTFTuserConstPart(SurfNum); } - if (surface.ExtBoundCond > 0) continue; // Don't need to evaluate outside for partitions - // Set current outside flux: if (construct.SourceSinkPresent) { state.dataHeatBalSurf->SurfOutsideFluxHist(1)(SurfNum) = diff --git a/src/EnergyPlus/OutputProcessor.cc b/src/EnergyPlus/OutputProcessor.cc index 9a65ba0dbfb..54a5151c776 100644 --- a/src/EnergyPlus/OutputProcessor.cc +++ b/src/EnergyPlus/OutputProcessor.cc @@ -3154,6 +3154,7 @@ namespace OutputProcessor { state.dataGlobal->DayOfSim, state.dataEnvrn->CurEnvirNum, state.dataGlobal->CalendarYear, + state.dataEnvrn->CurrentYearIsLeapYear, Month, DayOfMonth, Hour, @@ -3182,6 +3183,7 @@ namespace OutputProcessor { state.dataGlobal->DayOfSim, state.dataEnvrn->CurEnvirNum, state.dataGlobal->CalendarYear, + state.dataEnvrn->CurrentYearIsLeapYear, Month, DayOfMonth, Hour, @@ -3207,6 +3209,7 @@ namespace OutputProcessor { state.dataGlobal->DayOfSim, state.dataEnvrn->CurEnvirNum, state.dataGlobal->CalendarYear, + state.dataEnvrn->CurrentYearIsLeapYear, Month, DayOfMonth, _, @@ -3225,6 +3228,7 @@ namespace OutputProcessor { state.dataGlobal->DayOfSim, state.dataEnvrn->CurEnvirNum, state.dataGlobal->CalendarYear, + state.dataEnvrn->CurrentYearIsLeapYear, Month); } break; @@ -3235,7 +3239,8 @@ namespace OutputProcessor { reportID, state.dataGlobal->DayOfSim, state.dataEnvrn->CurEnvirNum, - state.dataGlobal->CalendarYear); + state.dataGlobal->CalendarYear, + state.dataEnvrn->CurrentYearIsLeapYear); } break; default: diff --git a/src/EnergyPlus/OutputReportTabular.cc b/src/EnergyPlus/OutputReportTabular.cc index 2c8b6978677..773f1ac6d3c 100644 --- a/src/EnergyPlus/OutputReportTabular.cc +++ b/src/EnergyPlus/OutputReportTabular.cc @@ -3124,7 +3124,8 @@ void OpenOutputTabularFile(EnergyPlusData &state) open_tbl_stream(state, iStyle, state.dataStrGlobals->outputTblXmlFilePath, state.files.outputControl.tabular); tbl_stream << "\n"; tbl_stream << "\n"; - tbl_stream << " BuildingName>" << state.dataHeatBal->BuildingName << "BuildingName>\n"; + tbl_stream << " BuildingName>" << ConvertToEscaped(state.dataHeatBal->BuildingName) + << "BuildingName>\n"; tbl_stream << " " << state.dataEnvrn->EnvironmentName << "\n"; tbl_stream << " " << state.dataEnvrn->WeatherFileLocationTitle << "\n"; tbl_stream << " " << state.dataStrGlobals->VerStringVar << "\n"; @@ -16631,7 +16632,7 @@ void WriteReportHeaders(EnergyPlusData &state, tbl_stream << "prevReportName << ">\n"; // close the last element if it was used. } tbl_stream << "<" << ConvertToElementTag(modifiedReportName) << ">\n"; - tbl_stream << " " << objectName << "\n"; + tbl_stream << " " << ConvertToEscaped(objectName) << "\n"; ort->prevReportName = ConvertToElementTag(modifiedReportName); // save the name for next time } } diff --git a/src/EnergyPlus/SQLiteProcedures.cc b/src/EnergyPlus/SQLiteProcedures.cc index 01f9b3872d4..20016536130 100644 --- a/src/EnergyPlus/SQLiteProcedures.cc +++ b/src/EnergyPlus/SQLiteProcedures.cc @@ -1602,6 +1602,7 @@ void SQLite::createSQLiteTimeIndexRecord(int const reportingInterval, int const cumlativeSimulationDays, int const curEnvirNum, int const simulationYear, + bool const curYearIsLeapYear, ObjexxFCL::Optional_int_const month, ObjexxFCL::Optional_int_const dayOfMonth, ObjexxFCL::Optional_int_const hour, @@ -1615,7 +1616,10 @@ void SQLite::createSQLiteTimeIndexRecord(int const reportingInterval, int intStartMinute = 0; int intervalInMinutes = 60; - static const std::vector lastDayOfMonth = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + static std::vector lastDayOfMonth = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + if (curYearIsLeapYear) { + lastDayOfMonth[1] = 29; + } switch (reportingInterval) { case LocalReportEach: diff --git a/src/EnergyPlus/SQLiteProcedures.hh b/src/EnergyPlus/SQLiteProcedures.hh index 956a83827a6..31218178c22 100644 --- a/src/EnergyPlus/SQLiteProcedures.hh +++ b/src/EnergyPlus/SQLiteProcedures.hh @@ -194,6 +194,7 @@ public: int const CumlativeSimulationDays, int const curEnvirNum, int const simulationYear, + bool const curYearIsLeapYear, ObjexxFCL::Optional_int_const Month = _, ObjexxFCL::Optional_int_const DayOfMonth = _, ObjexxFCL::Optional_int_const Hour = _, diff --git a/src/EnergyPlus/WeatherManager.cc b/src/EnergyPlus/WeatherManager.cc index 4051c7ce412..ba7e65b6027 100644 --- a/src/EnergyPlus/WeatherManager.cc +++ b/src/EnergyPlus/WeatherManager.cc @@ -844,8 +844,6 @@ namespace WeatherManager { (state.dataGlobal->KindOfSim == Constant::KindOfSim::RunPeriodDesign)) { std::string kindOfRunPeriod = state.dataWeatherManager->Environment(state.dataWeatherManager->Envrn).cKindOfEnvrn; state.dataEnvrn->RunPeriodEnvironment = state.dataGlobal->KindOfSim == Constant::KindOfSim::RunPeriodWeather; - Array1D_int ActEndDayOfMonth(12); - ActEndDayOfMonth = state.dataWeatherManager->EndDayOfMonth; state.dataEnvrn->CurrentYearIsLeapYear = state.dataWeatherManager->Environment(state.dataWeatherManager->Envrn).IsLeapYear; if (state.dataEnvrn->CurrentYearIsLeapYear && state.dataWeatherManager->WFAllowsLeapYears) { state.dataWeatherManager->LeapYearAdd = 1; @@ -853,7 +851,8 @@ namespace WeatherManager { state.dataWeatherManager->LeapYearAdd = 0; } if (state.dataEnvrn->CurrentYearIsLeapYear) { - ActEndDayOfMonth(2) = state.dataWeatherManager->EndDayOfMonth(2) + state.dataWeatherManager->LeapYearAdd; + state.dataWeatherManager->EndDayOfMonthWithLeapDay(2) = + state.dataWeatherManager->EndDayOfMonth(2) + state.dataWeatherManager->LeapYearAdd; } state.dataWeatherManager->UseDaylightSaving = state.dataWeatherManager->Environment(state.dataWeatherManager->Envrn).UseDST; state.dataWeatherManager->UseSpecialDays = state.dataWeatherManager->Environment(state.dataWeatherManager->Envrn).UseHolidays; @@ -1578,11 +1577,8 @@ namespace WeatherManager { int ActStartDay; // Actual Start Day of Month int ActEndMonth; // Actual End Month int ActEndDay; // Actual End Day of Month - Array1D_int ActEndDayOfMonth(12); bool ErrorsFound = false; - ActEndDayOfMonth = state.dataWeatherManager->EndDayOfMonth; - ActEndDayOfMonth(2) = state.dataWeatherManager->EndDayOfMonth(2) + state.dataWeatherManager->LeapYearAdd; if (state.dataWeatherManager->DST.StDateType == DateType::MonthDay) { ActStartMonth = state.dataWeatherManager->DST.StMon; ActStartDay = state.dataWeatherManager->DST.StDay; @@ -1592,7 +1588,7 @@ namespace WeatherManager { ThisDay += 7; } ThisDay += 7 * (state.dataWeatherManager->DST.StDay - 1); - if (ThisDay > ActEndDayOfMonth(state.dataWeatherManager->DST.StMon)) { + if (ThisDay > state.dataWeatherManager->EndDayOfMonthWithLeapDay(state.dataWeatherManager->DST.StMon)) { ShowSevereError(state, format("{}Determining DST: DST Start Date, Nth Day of Month, not enough Nths", RoutineName)); ErrorsFound = true; } else { @@ -1601,7 +1597,7 @@ namespace WeatherManager { } } else { // LastWeekDayInMonth int ThisDay = state.dataWeatherManager->DST.StWeekDay - MonWeekDay(state.dataWeatherManager->DST.StMon) + 1; - while (ThisDay + 7 <= ActEndDayOfMonth(state.dataWeatherManager->DST.StMon)) { + while (ThisDay + 7 <= state.dataWeatherManager->EndDayOfMonthWithLeapDay(state.dataWeatherManager->DST.StMon)) { ThisDay += 7; } ActStartMonth = state.dataWeatherManager->DST.StMon; @@ -1617,7 +1613,7 @@ namespace WeatherManager { ThisDay += 7; } ThisDay += 7 * (state.dataWeatherManager->DST.EnDay - 1); - if (ThisDay > ActEndDayOfMonth(state.dataWeatherManager->DST.EnMon)) { + if (ThisDay >> state.dataWeatherManager->EndDayOfMonthWithLeapDay(state.dataWeatherManager->DST.EnMon)) { ActEndMonth = 0; // Suppress uninitialized warning ActEndDay = 0; // Suppress uninitialized warning ShowSevereError(state, format("{}Determining DST: DST End Date, Nth Day of Month, not enough Nths", RoutineName)); @@ -1628,7 +1624,7 @@ namespace WeatherManager { } } else { // LastWeekDayInMonth int ThisDay = state.dataWeatherManager->DST.EnWeekDay - MonWeekDay(state.dataWeatherManager->DST.EnMon) + 1; - while (ThisDay + 7 <= ActEndDayOfMonth(state.dataWeatherManager->DST.EnMon)) { + while (ThisDay + 7 <= state.dataWeatherManager->EndDayOfMonthWithLeapDay(state.dataWeatherManager->DST.EnMon)) { ThisDay += 7; } ActEndMonth = state.dataWeatherManager->DST.EnMon; @@ -1674,11 +1670,8 @@ namespace WeatherManager { static constexpr std::string_view RoutineName("SetSpecialDayDates: "); int JDay; - Array1D_int ActEndDayOfMonth(12); bool ErrorsFound = false; - ActEndDayOfMonth = state.dataWeatherManager->EndDayOfMonth; - ActEndDayOfMonth(2) = state.dataWeatherManager->EndDayOfMonth(2) + state.dataWeatherManager->LeapYearAdd; state.dataWeatherManager->SpecialDayTypes = 0; for (int i = 1; i <= state.dataWeatherManager->NumSpecialDays; ++i) { if (state.dataWeatherManager->SpecialDays(i).WthrFile && !state.dataWeatherManager->UseSpecialDays) continue; @@ -1709,7 +1702,7 @@ namespace WeatherManager { ThisDay += 7; } ThisDay += 7 * (state.dataWeatherManager->SpecialDays(i).Day - 1); - if (ThisDay > ActEndDayOfMonth(state.dataWeatherManager->SpecialDays(i).Month)) { + if (ThisDay > state.dataWeatherManager->EndDayOfMonthWithLeapDay(state.dataWeatherManager->SpecialDays(i).Month)) { ShowSevereError(state, format("{}Special Day Date, Nth Day of Month, not enough Nths, for SpecialDay={}", RoutineName, @@ -1722,7 +1715,7 @@ namespace WeatherManager { JDay = General::OrdinalDay(state.dataWeatherManager->SpecialDays(i).Month, ThisDay, state.dataWeatherManager->LeapYearAdd); } else { // LastWeekDayInMonth int ThisDay = state.dataWeatherManager->SpecialDays(i).WeekDay - MonWeekDay(state.dataWeatherManager->SpecialDays(i).Month) + 1; - while (ThisDay + 7 <= ActEndDayOfMonth(state.dataWeatherManager->SpecialDays(i).Month)) { + while (ThisDay + 7 <= state.dataWeatherManager->EndDayOfMonthWithLeapDay(state.dataWeatherManager->SpecialDays(i).Month)) { ThisDay += 7; } state.dataWeatherManager->SpecialDays(i).ActStMon = state.dataWeatherManager->SpecialDays(i).Month; @@ -1894,7 +1887,7 @@ namespace WeatherManager { } state.dataEnvrn->EndYearFlag = false; - if (state.dataEnvrn->DayOfMonth == state.dataWeatherManager->EndDayOfMonth(state.dataEnvrn->Month)) { + if (state.dataEnvrn->DayOfMonth == state.dataWeatherManager->EndDayOfMonthWithLeapDay(state.dataEnvrn->Month)) { state.dataEnvrn->EndMonthFlag = true; state.dataEnvrn->EndYearFlag = (state.dataEnvrn->Month == 12); } @@ -2935,6 +2928,7 @@ namespace WeatherManager { if (hour == 1 && CurTimeStep == 1) { if (WMonth == 2 && WDay == 29 && (!state.dataEnvrn->CurrentYearIsLeapYear || !state.dataWeatherManager->WFAllowsLeapYears)) { state.dataWeatherManager->EndDayOfMonth(2) = 28; + state.dataWeatherManager->EndDayOfMonthWithLeapDay(2) = 28; SkipThisDay = true; TryAgain = true; ShowWarningError(state, "ReadEPlusWeatherForDay: Feb29 data encountered but will not be processed."); diff --git a/src/EnergyPlus/WeatherManager.hh b/src/EnergyPlus/WeatherManager.hh index 21560b0c3b4..f3c990a79b2 100644 --- a/src/EnergyPlus/WeatherManager.hh +++ b/src/EnergyPlus/WeatherManager.hh @@ -971,14 +971,15 @@ struct WeatherManagerData : BaseGlobalStruct Array1D_string SPSiteScheduleUnits; // SP Site Schedule Units NOLINT(cert-err58-cpp) int NumSPSiteScheduleNamePtrs; // Number of SP Site Schedules (DesignDay only) // Number of hours of missing data - Array1D Interpolation; // Interpolation values based on Number of Time Steps in Hour NOLINT(cert-err58-cpp) - Array1D SolarInterpolation; // Solar Interpolation values based on Number of Time Steps in Hour NOLINT(cert-err58-cpp) - Array1D_int EndDayOfMonth; // NOLINT(cert-err58-cpp) - int LeapYearAdd; // Set during environment if leap year is active (adds 1 to number days in Feb) - bool DatesShouldBeReset; // True when weekdays should be reset - bool StartDatesCycleShouldBeReset; // True when start dates on repeat should be reset - bool Jan1DatesShouldBeReset; // True if Jan 1 should signal reset of dates - bool RPReadAllWeatherData; // True if need to read all weather data prior to simulation + Array1D Interpolation; // Interpolation values based on Number of Time Steps in Hour NOLINT(cert-err58-cpp) + Array1D SolarInterpolation; // Solar Interpolation values based on Number of Time Steps in Hour NOLINT(cert-err58-cpp) + Array1D_int EndDayOfMonth; // NOLINT(cert-err58-cpp) + Array1D_int EndDayOfMonthWithLeapDay; // end day of the month including Feb 29 for leap years instead of Feb 28 + int LeapYearAdd; // Set during environment if leap year is active (adds 1 to number days in Feb) + bool DatesShouldBeReset; // True when weekdays should be reset + bool StartDatesCycleShouldBeReset; // True when start dates on repeat should be reset + bool Jan1DatesShouldBeReset; // True if Jan 1 should signal reset of dates + bool RPReadAllWeatherData; // True if need to read all weather data prior to simulation // Object Data // NOLINTNEXTLINE(cert-err58-cpp) @@ -1284,7 +1285,8 @@ struct WeatherManagerData : BaseGlobalStruct DaylightSavingIsActive(false), WFAllowsLeapYears(false), curSimDayForEndOfRunPeriod(0), Envrn(0), NumOfEnvrn(0), NumEPWTypExtSets(0), NumWPSkyTemperatures(0), RptIsRain(0), RptIsSnow(0), RptDayType(0), HrAngle(0.0), SolarAltitudeAngle(0.0), SolarAzimuthAngle(0.0), HorizIRSky(0.0), TimeStepFraction(0.0), NumSPSiteScheduleNamePtrs(0), EndDayOfMonth(12, {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}), - LeapYearAdd(0), DatesShouldBeReset(false), StartDatesCycleShouldBeReset(false), Jan1DatesShouldBeReset(false), RPReadAllWeatherData(false) + EndDayOfMonthWithLeapDay(12, {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}), LeapYearAdd(0), DatesShouldBeReset(false), + StartDatesCycleShouldBeReset(false), Jan1DatesShouldBeReset(false), RPReadAllWeatherData(false) { } }; diff --git a/tst/EnergyPlus/unit/HeatBalanceSurfaceManager.unit.cc b/tst/EnergyPlus/unit/HeatBalanceSurfaceManager.unit.cc index 70edb8405c3..868c0d11ff4 100644 --- a/tst/EnergyPlus/unit/HeatBalanceSurfaceManager.unit.cc +++ b/tst/EnergyPlus/unit/HeatBalanceSurfaceManager.unit.cc @@ -8553,6 +8553,81 @@ TEST_F(EnergyPlusFixture, HeatBalanceSurfaceManager_TestUpdateVariableAbsorptanc EXPECT_NEAR(state->dataHeatBalSurf->SurfAbsSolarExt(2), 0.5, 1e-6); } +TEST_F(EnergyPlusFixture, HeatBalanceSurfaceManager_UpdateThermalHistoriesIZSurfaceCheck) +{ + state->dataSurface->TotSurfaces = 2; + state->dataGlobal->NumOfZones = 2; + state->dataHeatBal->TotConstructs = 1; + state->dataHeatBal->Zone.allocate(state->dataGlobal->NumOfZones); + state->dataSurface->Surface.allocate(state->dataSurface->TotSurfaces); + state->dataSurface->SurfaceWindow.allocate(state->dataSurface->TotSurfaces); + state->dataConstruction->Construct.allocate(state->dataHeatBal->TotConstructs); + state->dataHeatBal->AnyInternalHeatSourceInInput = false; + state->dataHeatBal->SimpleCTFOnly = false; + + AllocateSurfaceHeatBalArrays(*state); // allocates a host of variables related to CTF calculations + + state->dataSurface->Surface(1).Class = DataSurfaces::SurfaceClass::Wall; + state->dataSurface->Surface(1).HeatTransSurf = true; + state->dataSurface->Surface(1).HeatTransferAlgorithm = DataSurfaces::HeatTransferModel::CTF; + state->dataSurface->Surface(1).Construction = 1; + state->dataSurface->Surface(2).Class = DataSurfaces::SurfaceClass::Wall; + state->dataSurface->Surface(2).HeatTransSurf = true; + state->dataSurface->Surface(2).HeatTransferAlgorithm = DataSurfaces::HeatTransferModel::CTF; + state->dataSurface->Surface(2).Construction = 1; + state->dataHeatBal->space.allocate(2); + state->dataHeatBal->Zone(1).spaceIndexes.emplace_back(1); + state->dataHeatBal->space(1).OpaqOrIntMassSurfaceFirst = 1; + state->dataHeatBal->space(1).OpaqOrIntMassSurfaceLast = 1; + state->dataHeatBal->space(1).HTSurfaceFirst = 1; + state->dataHeatBal->space(1).HTSurfaceLast = 1; + state->dataHeatBal->Zone(2).spaceIndexes.emplace_back(2); + state->dataHeatBal->space(2).OpaqOrIntMassSurfaceFirst = 2; + state->dataHeatBal->space(2).OpaqOrIntMassSurfaceLast = 2; + state->dataHeatBal->space(2).HTSurfaceFirst = 2; + state->dataHeatBal->space(2).HTSurfaceLast = 2; + + state->dataConstruction->Construct(1).NumCTFTerms = 2; + state->dataConstruction->Construct(1).SourceSinkPresent = false; + state->dataConstruction->Construct(1).NumHistories = 1; + state->dataConstruction->Construct(1).CTFOutside[0] = 1.5; + state->dataConstruction->Construct(1).CTFCross[0] = 1.5; + state->dataConstruction->Construct(1).CTFInside[0] = 1.5; + + state->dataHeatBalSurf->SurfCurrNumHist(1) = 0; + state->dataHeatBalSurf->SurfOutsideTempHist(1)(1) = 20.0; + state->dataHeatBalSurf->SurfTempIn(1) = 10.0; + state->dataHeatBalSurf->SurfCTFConstInPart(1) = 0.0; + state->dataHeatBalSurf->SurfCurrNumHist(2) = 0; + state->dataHeatBalSurf->SurfOutsideTempHist(1)(2) = 10.0; + state->dataHeatBalSurf->SurfTempIn(2) = 20.0; + state->dataHeatBalSurf->SurfCTFConstInPart(2) = 0.0; + + // Test 1: Partition--outside should have a non-zero value (interzone and regular partitions treated the same) + state->dataSurface->Surface(1).ExtBoundCond = 1; + state->dataSurface->Surface(2).ExtBoundCond = 2; + + UpdateThermalHistories(*state); // Test to make sure that the outside surface flux is being set properly for interzone surfaces + + EXPECT_EQ(15.0, state->dataHeatBalSurf->SurfOpaqInsFaceCondFlux(1)); + EXPECT_EQ(-15.0, state->dataHeatBalSurf->SurfOpaqOutFaceCondFlux(1)); + EXPECT_EQ(-15.0, state->dataHeatBalSurf->SurfOpaqInsFaceCondFlux(2)); + EXPECT_EQ(15.0, state->dataHeatBalSurf->SurfOpaqOutFaceCondFlux(2)); + + // Test 2: Interzone Partition--outside should have a non-zero value + state->dataSurface->Surface(1).ExtBoundCond = 2; + state->dataSurface->Surface(2).ExtBoundCond = 1; + state->dataHeatBalSurf->SurfOpaqInsFaceCondFlux = 0.0; + state->dataHeatBalSurf->SurfOpaqOutFaceCondFlux = 0.0; + + UpdateThermalHistories(*state); // Test to make sure that the outside surface flux is being set properly for interzone surfaces + + EXPECT_EQ(15.0, state->dataHeatBalSurf->SurfOpaqInsFaceCondFlux(1)); + EXPECT_EQ(-15.0, state->dataHeatBalSurf->SurfOpaqOutFaceCondFlux(1)); + EXPECT_EQ(-15.0, state->dataHeatBalSurf->SurfOpaqInsFaceCondFlux(2)); + EXPECT_EQ(15.0, state->dataHeatBalSurf->SurfOpaqOutFaceCondFlux(2)); +} + TEST_F(EnergyPlusFixture, HeatBalanceSurfaceManager_TestSurfQdotRadSolarInRepPerAreaCalc) { Real64 const diffTol = 0.0000000001; diff --git a/tst/EnergyPlus/unit/OutputProcessor.unit.cc b/tst/EnergyPlus/unit/OutputProcessor.unit.cc index c007e7429b2..8c75f5f5e3e 100644 --- a/tst/EnergyPlus/unit/OutputProcessor.unit.cc +++ b/tst/EnergyPlus/unit/OutputProcessor.unit.cc @@ -776,7 +776,7 @@ namespace OutputProcessor { { state->dataGlobal->MinutesPerTimeStep = 10; - state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(4, 1, 1, 0, 2017); + state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(4, 1, 1, 0, 2017, false); state->dataSQLiteProcedures->sqlite->createSQLiteReportDictionaryRecord( 1, 1, "Zone", "Environment", "Site Outdoor Air Drybulb Temperature", 1, "C", 1, false); @@ -869,7 +869,7 @@ namespace OutputProcessor { TEST_F(SQLiteFixture, OutputProcessor_writeReportRealData) { - state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(4, 1, 1, 0, 2017); + state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(4, 1, 1, 0, 2017, false); state->dataSQLiteProcedures->sqlite->createSQLiteReportDictionaryRecord( 1, 1, "Zone", "Environment", "Site Outdoor Air Drybulb Temperature", 1, "C", 1, false); @@ -1033,7 +1033,7 @@ namespace OutputProcessor { TEST_F(SQLiteFixture, OutputProcessor_writeReportIntegerData) { - state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(4, 1, 1, 0, 2017); + state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(4, 1, 1, 0, 2017, false); state->dataSQLiteProcedures->sqlite->createSQLiteReportDictionaryRecord( 1, 1, "Zone", "Environment", "Site Outdoor Air Drybulb Temperature", 1, "C", 1, false); @@ -1118,7 +1118,7 @@ namespace OutputProcessor { TEST_F(SQLiteFixture, OutputProcessor_writeNumericData_1) { - state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(4, 1, 1, 0, 2017); + state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(4, 1, 1, 0, 2017, false); state->dataSQLiteProcedures->sqlite->createSQLiteReportDictionaryRecord( 1, 1, "Zone", "Environment", "Site Outdoor Air Drybulb Temperature", 1, "C", 1, false); @@ -1393,7 +1393,7 @@ namespace OutputProcessor { { InitializeOutput(*state); - state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(4, 1, 1, 0, 2017); + state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(4, 1, 1, 0, 2017, false); WriteMeterDictionaryItem(*state, ReportingFrequency::TimeStep, @@ -1827,7 +1827,7 @@ namespace OutputProcessor { { InitializeOutput(*state); - state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(4, 1, 1, 0, 2017); + state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(4, 1, 1, 0, 2017, false); // Store expected results std::vector> expectedReportDataDictionary; @@ -2384,7 +2384,7 @@ namespace OutputProcessor { TEST_F(SQLiteFixture, OutputProcessor_writeCumulativeReportMeterData) { - state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(4, 1, 1, 0, 2017); + state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(4, 1, 1, 0, 2017, false); state->dataSQLiteProcedures->sqlite->createSQLiteReportDictionaryRecord( 1, 1, "Zone", "Environment", "Site Outdoor Air Drybulb Temperature", 1, "C", 1, false); @@ -2420,7 +2420,7 @@ namespace OutputProcessor { TEST_F(SQLiteFixture, OutputProcessor_writeNumericData_2) { - state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(4, 1, 1, 0, 2017); + state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(4, 1, 1, 0, 2017, false); state->dataSQLiteProcedures->sqlite->createSQLiteReportDictionaryRecord( 1, 1, "Zone", "Environment", "Site Outdoor Air Drybulb Temperature", 1, "C", 1, false); diff --git a/tst/EnergyPlus/unit/SQLite.unit.cc b/tst/EnergyPlus/unit/SQLite.unit.cc index cd0bbaf6982..372e314cae2 100644 --- a/tst/EnergyPlus/unit/SQLite.unit.cc +++ b/tst/EnergyPlus/unit/SQLite.unit.cc @@ -293,13 +293,13 @@ TEST_F(SQLiteFixture, SQLiteProcedures_createSQLiteReportDictionaryRecord) TEST_F(SQLiteFixture, SQLiteProcedures_createSQLiteTimeIndexRecord) { state->dataSQLiteProcedures->sqlite->sqliteBegin(); - state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(4, 1, 1, 0, 2017); - state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(3, 1, 1, 0, 2017, 1); - state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(2, 1, 1, 0, 2017, 1, 1, 1, _, _, 0, "WinterDesignDay"); - state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(1, 1, 1, 0, 2017, 1, 2, 2, _, _, 0, "SummerDesignDay"); - state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(0, 1, 1, 0, 2017, 1, 1, 1, 60, 0, 0, "WinterDesignDay"); - state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(-1, 1, 1, 0, 2017, 1, 2, 2, 60, 0, 0, "SummerDesignDay"); - state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(-1, 1, 1, 1, 2017, 1, 3, 3, 60, 0, 0, "SummerDesignDay", true); + state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(4, 1, 1, 0, 2017, false); + state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(3, 1, 1, 0, 2017, false, 1); + state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(2, 1, 1, 0, 2017, false, 1, 1, 1, _, _, 0, "WinterDesignDay"); + state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(1, 1, 1, 0, 2017, false, 1, 2, 2, _, _, 0, "SummerDesignDay"); + state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(0, 1, 1, 0, 2017, false, 1, 1, 1, 60, 0, 0, "WinterDesignDay"); + state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(-1, 1, 1, 0, 2017, false, 1, 2, 2, 60, 0, 0, "SummerDesignDay"); + state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(-1, 1, 1, 1, 2017, false, 1, 3, 3, 60, 0, 0, "SummerDesignDay", true); auto result = queryResult("SELECT * FROM Time;", "Time"); state->dataSQLiteProcedures->sqlite->sqliteCommit(); @@ -321,7 +321,7 @@ TEST_F(SQLiteFixture, SQLiteProcedures_createSQLiteTimeIndexRecord) EXPECT_EQ(testResult6, result[6]); state->dataSQLiteProcedures->sqlite->sqliteBegin(); - state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(-999, 1, 1, 0, 2017); + state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(-999, 1, 1, 0, 2017, false); state->dataSQLiteProcedures->sqlite->sqliteCommit(); EXPECT_EQ("SQLite3 message, Illegal reportingInterval passed to CreateSQLiteTimeIndexRecord: -999\n", ss->str()); ss->str(std::string()); @@ -329,31 +329,81 @@ TEST_F(SQLiteFixture, SQLiteProcedures_createSQLiteTimeIndexRecord) EXPECT_EQ(7ul, result.size()); state->dataSQLiteProcedures->sqlite->sqliteBegin(); - state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(0, 1, 1, 1, 2017, 1, 3, 3, 60, 0, 0, _, true); - state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(0, 1, 1, 1, 2017, 1, 3, 3, 60, 0, _, "SummerDesignDay", true); - state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(0, 1, 1, 1, 2017, 1, 3, 3, 60, _, 0, "SummerDesignDay", true); - state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(0, 1, 1, 1, 2017, 1, 3, 3, _, 0, 0, "SummerDesignDay", true); - state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(0, 1, 1, 1, 2017, 1, 3, _, 60, 0, 0, "SummerDesignDay", true); - state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(0, 1, 1, 1, 2017, 1, _, 3, 60, 0, 0, "SummerDesignDay", true); - state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(0, 1, 1, 1, 2017, _, 3, 3, 60, 0, 0, "SummerDesignDay", true); - state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(1, 1, 1, 1, 2017, 1, 3, 3, 60, 0, 0, _, true); - state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(1, 1, 1, 1, 2017, 1, 3, 3, 60, 0, _, "SummerDesignDay", true); - state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(1, 1, 1, 1, 2017, 1, 3, _, 60, 0, 0, "SummerDesignDay", true); - state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(1, 1, 1, 1, 2017, 1, _, 3, 60, 0, 0, "SummerDesignDay", true); - state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(1, 1, 1, 1, 2017, _, 3, 3, 60, 0, 0, "SummerDesignDay", true); - state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(2, 1, 1, 1, 2017, 1, 3, 3, 60, 0, 0, _, true); - state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(2, 1, 1, 1, 2017, 1, 3, 3, 60, 0, _, "SummerDesignDay", true); - state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(2, 1, 1, 1, 2017, 1, 3, _, 60, 0, 0, "SummerDesignDay", true); - state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(2, 1, 1, 1, 2017, 1, _, 3, 60, 0, 0, "SummerDesignDay", true); - state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(2, 1, 1, 1, 2017, _, 3, 3, 60, 0, 0, "SummerDesignDay", true); - state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(3, 1, 1, 1, 2017, _, 3, 3, 60, 0, 0, "SummerDesignDay", true); + state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(0, 1, 1, 1, 2017, false, 1, 3, 3, 60, 0, 0, _, true); + state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(0, 1, 1, 1, 2017, false, 1, 3, 3, 60, 0, _, "SummerDesignDay", true); + state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(0, 1, 1, 1, 2017, false, 1, 3, 3, 60, _, 0, "SummerDesignDay", true); + state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(0, 1, 1, 1, 2017, false, 1, 3, 3, _, 0, 0, "SummerDesignDay", true); + state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(0, 1, 1, 1, 2017, false, 1, 3, _, 60, 0, 0, "SummerDesignDay", true); + state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(0, 1, 1, 1, 2017, false, 1, _, 3, 60, 0, 0, "SummerDesignDay", true); + state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(0, 1, 1, 1, 2017, false, _, 3, 3, 60, 0, 0, "SummerDesignDay", true); + state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(1, 1, 1, 1, 2017, false, 1, 3, 3, 60, 0, 0, _, true); + state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(1, 1, 1, 1, 2017, false, 1, 3, 3, 60, 0, _, "SummerDesignDay", true); + state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(1, 1, 1, 1, 2017, false, 1, 3, _, 60, 0, 0, "SummerDesignDay", true); + state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(1, 1, 1, 1, 2017, false, 1, _, 3, 60, 0, 0, "SummerDesignDay", true); + state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(1, 1, 1, 1, 2017, false, _, 3, 3, 60, 0, 0, "SummerDesignDay", true); + state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(2, 1, 1, 1, 2017, false, 1, 3, 3, 60, 0, 0, _, true); + state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(2, 1, 1, 1, 2017, false, 1, 3, 3, 60, 0, _, "SummerDesignDay", true); + state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(2, 1, 1, 1, 2017, false, 1, 3, _, 60, 0, 0, "SummerDesignDay", true); + state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(2, 1, 1, 1, 2017, false, 1, _, 3, 60, 0, 0, "SummerDesignDay", true); + state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(2, 1, 1, 1, 2017, false, _, 3, 3, 60, 0, 0, "SummerDesignDay", true); + state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(3, 1, 1, 1, 2017, false, _, 3, 3, 60, 0, 0, "SummerDesignDay", true); state->dataSQLiteProcedures->sqlite->sqliteCommit(); } +TEST_F(SQLiteFixture, SQLiteProcedures_createSQLiteTimeIndexRecord_NonLeapDay) +{ + // set the leap year flag to false (6th argument) and expect the last day of february to be the 28th + state->dataSQLiteProcedures->sqlite->sqliteBegin(); + state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(4, 1, 1, 0, 2012, false); + state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(3, 1, 1, 0, 2012, false, 1); + state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(3, 1, 1, 0, 2012, false, 2); // February + state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(3, 1, 1, 0, 2012, false, 3); + state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(3, 1, 1, 0, 2012, false, 4); + auto result = queryResult("SELECT * FROM Time;", "Time"); + state->dataSQLiteProcedures->sqlite->sqliteCommit(); + + ASSERT_EQ(5ul, result.size()); + std::vector testResult0{"1", "", "", "", "", "", "", "1440", "4", "1", "", "0", ""}; + std::vector testResult1{"2", "2012", "1", "31", "24", "0", "", "44640", "3", "1", "", "0", ""}; + std::vector testResult2{"3", "2012", "2", "28", "24", "0", "", "40320", "3", "1", "", "0", ""}; // February + std::vector testResult3{"4", "2012", "3", "31", "24", "0", "", "44640", "3", "1", "", "0", ""}; + std::vector testResult4{"5", "2012", "4", "30", "24", "0", "", "43200", "3", "1", "", "0", ""}; + EXPECT_EQ(testResult0, result[0]); + EXPECT_EQ(testResult1, result[1]); + EXPECT_EQ(testResult2, result[2]); + EXPECT_EQ(testResult3, result[3]); + EXPECT_EQ(testResult4, result[4]); +} + +TEST_F(SQLiteFixture, SQLiteProcedures_createSQLiteTimeIndexRecord_LeapDay) +{ + // set the leap year flag to true (6th argument) and expect the last day of february to be the 29th + state->dataSQLiteProcedures->sqlite->sqliteBegin(); + state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(4, 1, 1, 0, 2012, true); + state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(3, 1, 1, 0, 2012, true, 1); + state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(3, 1, 1, 0, 2012, true, 2); // February + state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(3, 1, 1, 0, 2012, true, 3); + state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(3, 1, 1, 0, 2012, true, 4); + auto result = queryResult("SELECT * FROM Time;", "Time"); + state->dataSQLiteProcedures->sqlite->sqliteCommit(); + + ASSERT_EQ(5ul, result.size()); + std::vector testResult0{"1", "", "", "", "", "", "", "1440", "4", "1", "", "0", ""}; + std::vector testResult1{"2", "2012", "1", "31", "24", "0", "", "44640", "3", "1", "", "0", ""}; + std::vector testResult2{"3", "2012", "2", "29", "24", "0", "", "41760", "3", "1", "", "0", ""}; // February + std::vector testResult3{"4", "2012", "3", "31", "24", "0", "", "44640", "3", "1", "", "0", ""}; + std::vector testResult4{"5", "2012", "4", "30", "24", "0", "", "43200", "3", "1", "", "0", ""}; + EXPECT_EQ(testResult0, result[0]); + EXPECT_EQ(testResult1, result[1]); + EXPECT_EQ(testResult2, result[2]); + EXPECT_EQ(testResult3, result[3]); + EXPECT_EQ(testResult4, result[4]); +} + TEST_F(SQLiteFixture, SQLiteProcedures_createSQLiteReportDataRecord) { state->dataSQLiteProcedures->sqlite->sqliteBegin(); - state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(4, 1, 1, 0, 2017); + state->dataSQLiteProcedures->sqlite->createSQLiteTimeIndexRecord(4, 1, 1, 0, 2017, false); state->dataSQLiteProcedures->sqlite->createSQLiteReportDictionaryRecord( 1, 1, "Zone", "Environment", "Site Outdoor Air Drybulb Temperature", 1, "C", 1, false); state->dataSQLiteProcedures->sqlite->createSQLiteReportDataRecord(1, 999.9);