From 1f3f4c01f2d187fd5bf95425699f70af6e62ab83 Mon Sep 17 00:00:00 2001 From: Phil Ahrenkiel Date: Mon, 1 Jan 2024 11:26:37 -0700 Subject: [PATCH 01/37] Create structures. --- src/HPWH.cc | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/HPWH.hh | 37 ++++++++++++++ 2 files changed, 180 insertions(+) diff --git a/src/HPWH.cc b/src/HPWH.cc index 99aa83c8..95f57c44 100644 --- a/src/HPWH.cc +++ b/src/HPWH.cc @@ -64,6 +64,54 @@ const double HPWH::MAXOUTLET_R410A = F_TO_C(140.); const double HPWH::MAXOUTLET_R744 = F_TO_C(190.); const double HPWH::MINSINGLEPASSLIFT = dF_TO_dC(15.); +HPWH::DrawPattern HPWH::verySmallUsage = { + {HM_TO_MIN(0, 00), 7.6, 3.8}, + {HM_TO_MIN(1, 00), 3.8, 3.8}, + {HM_TO_MIN(1, 05), 1.9, 3.8}, + {HM_TO_MIN(1, 10), 1.9, 3.8}, + {HM_TO_MIN(1, 15), 1.9, 3.8}, + {HM_TO_MIN(8, 00), 3.8, 3.8}, + {HM_TO_MIN(8, 15), 7.6, 3.8}, + {HM_TO_MIN(9, 00), 5.7, 3.8}, + {HM_TO_MIN(9, 15), 3.8, 3.8}, +}; + +HPWH::DrawPattern HPWH::lowUsage = { + {HM_TO_MIN(0, 00), 7.6, 3.8}, + {HM_TO_MIN(1, 00), 3.8, 3.8}, + {HM_TO_MIN(1, 05), 1.9, 3.8}, + {HM_TO_MIN(1, 10), 1.9, 3.8}, + {HM_TO_MIN(1, 15), 1.9, 3.8}, + {HM_TO_MIN(8, 00), 3.8, 3.8}, + {HM_TO_MIN(8, 15), 7.6, 3.8}, + {HM_TO_MIN(9, 00), 5.7, 3.8}, + {HM_TO_MIN(9, 15), 3.8, 3.8}, +}; + +HPWH::DrawPattern HPWH::mediumUsage = { + {HM_TO_MIN(0, 00), 7.6, 3.8}, + {HM_TO_MIN(1, 00), 3.8, 3.8}, + {HM_TO_MIN(1, 05), 1.9, 3.8}, + {HM_TO_MIN(1, 10), 1.9, 3.8}, + {HM_TO_MIN(1, 15), 1.9, 3.8}, + {HM_TO_MIN(8, 00), 3.8, 3.8}, + {HM_TO_MIN(8, 15), 7.6, 3.8}, + {HM_TO_MIN(9, 00), 5.7, 3.8}, + {HM_TO_MIN(9, 15), 3.8, 3.8}, +}; + +HPWH::DrawPattern HPWH::highUsage = { + {HM_TO_MIN(0, 00), 7.6, 3.8}, + {HM_TO_MIN(1, 00), 3.8, 3.8}, + {HM_TO_MIN(1, 05), 1.9, 3.8}, + {HM_TO_MIN(1, 10), 1.9, 3.8}, + {HM_TO_MIN(1, 15), 1.9, 3.8}, + {HM_TO_MIN(8, 00), 3.8, 3.8}, + {HM_TO_MIN(8, 15), 7.6, 3.8}, + {HM_TO_MIN(9, 00), 5.7, 3.8}, + {HM_TO_MIN(9, 15), 3.8, 3.8}, +}; + //----------------------------------------------------------------------------- /// @brief Samples a std::vector to extract a single value spanning the fractional /// coordinate range from frac_begin to frac_end. @@ -5346,3 +5394,98 @@ int HPWH::HPWHinit_file(string configFile) return 0; } #endif + +HPWH::Usage HPWH::findUsageFromFirstHourRating() { return Usage::Medium; } + +HPWH::Usage HPWH::findUsageFromMaximumGPM_Rating() { return Usage::Medium; } + +bool HPWH::calcUEF(const Usage usage, double& UEF) +{ + + DrawPattern* drawPattern = nullptr; + + switch (usage) + { + case Usage::VerySmall: + { + drawPattern = &verySmallUsage; + break; + } + case Usage::Low: + { + drawPattern = &lowUsage; + break; + } + case Usage::Medium: + { + drawPattern = &mediumUsage; + break; + } + case Usage::High: + { + drawPattern = &highUsage; + break; + } + } + + if (drawPattern == nullptr) + return false; + + const double inletT_C = 20.; + const double ambientT_C = 20.; + const double externalT_C = 20.; + const DRMODES drMode = DR_ALLOW; + + double totalVolumeRemoved_L = 0.; + double totalEnergyConsumed_kJ = 0.; + + int runTime_min = 0; + for (auto& draw : *drawPattern) + { + double drawnVolume_L = 0.; + + double incrementalDrawVolume_L = draw.flowRate_Lper_min * (1.); + if (incrementalDrawVolume_L > tankVolume_L) + { + incrementalDrawVolume_L = tankVolume_L; + } + + while ((drawnVolume_L < draw.volume_L) || (runTime_min < draw.startTime_min)) + { + if (drawnVolume_L + incrementalDrawVolume_L > draw.volume_L) + { + incrementalDrawVolume_L = draw.volume_L - drawnVolume_L; + } + + // run a step + int runResult = runOneStep(inletT_C, // inlet water temperature (C) + incrementalDrawVolume_L, // draw volume (L) + ambientT_C, // ambient Temp (C) + externalT_C, // external Temp (C) + drMode, // DDR Status + 0, // inlet-2 volume (L) + inletT_C, // inlet-2 Temp (C) + NULL); // no extra heat + + if (runResult == HPWH_ABORT) + { + return false; + } + + totalVolumeRemoved_L += incrementalDrawVolume_L; + for (int iHS = 0; iHS < getNumHeatSources(); ++iHS) + { + totalEnergyConsumed_kJ += getNthHeatSourceEnergyInput(iHS, HPWH::UNITS_KJ); + } + + ++runTime_min; + } + } + + double totalMassRemoved_kg = HPWH::DENSITYWATER_kgperL * totalVolumeRemoved_L; + double totalHeatCapacity_kJperC = HPWH::CPWATER_kJperkgC * totalMassRemoved_kg; + double refEnergy_kJ = totalHeatCapacity_kJperC * (51.7 - 14.4); + + UEF = refEnergy_kJ / totalEnergyConsumed_kJ; + return true; +} diff --git a/src/HPWH.hh b/src/HPWH.hh index 3a4a564a..dee07228 100644 --- a/src/HPWH.hh +++ b/src/HPWH.hh @@ -944,6 +944,41 @@ class HPWH /// Addition of extra heat handled separately from normal heat sources void addExtraHeatAboveNode(double qAdd_kJ, const int nodeNum); + /// Draw patterns corresponding to ratings for UEF calculation + enum class Usage + { + VerySmall, + Low, + Medium, + High + }; + + /// Determine usage using the first-hour rating method + Usage findUsageFromFirstHourRating(); + + /// Determine usage using the maximum GPM rating method + Usage findUsageFromMaximumGPM_Rating(); + + /// Calculate UEF + bool calcUEF(const Usage usage, double& UEF); + + struct Draw + { + double startTime_min; + double volume_L; + double flowRate_Lper_min; + + Draw(const double startTime_min_in,const double volume_L_in,const double flowRate_Lper_min_in): + startTime_min(startTime_min_in), volume_L(volume_L_in),flowRate_Lper_min(flowRate_Lper_min_in){} + }; + + typedef std::vector DrawPattern; + + static DrawPattern verySmallUsage; + static DrawPattern lowUsage; + static DrawPattern mediumUsage; + static DrawPattern highUsage; + private: class HeatSource; @@ -1527,6 +1562,8 @@ inline double FT2_TO_M2(double feet2) { return (feet2 / 10.7640); } inline double MIN_TO_SEC(double minute) { return minute * sec_per_min; } inline double MIN_TO_HR(double minute) { return minute / min_per_hr; } +inline double HM_TO_MIN(const double hours, const double minutes){return min_per_hr * hours + minutes;} + inline HPWH::DRMODES operator|(HPWH::DRMODES a, HPWH::DRMODES b) { return static_cast(static_cast(a) | static_cast(b)); From 2b87503f01ece73d270d3b7b3a83954ca8d12aee Mon Sep 17 00:00:00 2001 From: Phil Ahrenkiel Date: Mon, 1 Jan 2024 13:55:54 -0700 Subject: [PATCH 02/37] Add UEF test. --- src/HPWH.cc | 92 +++++++++++++++++++++++++++------------------ src/HPWH.hh | 15 ++++++-- test/CMakeLists.txt | 3 ++ test/testCalcUEF.cc | 33 ++++++++++++++++ 4 files changed, 104 insertions(+), 39 deletions(-) create mode 100644 test/testCalcUEF.cc diff --git a/src/HPWH.cc b/src/HPWH.cc index 95f57c44..1c226914 100644 --- a/src/HPWH.cc +++ b/src/HPWH.cc @@ -76,41 +76,45 @@ HPWH::DrawPattern HPWH::verySmallUsage = { {HM_TO_MIN(9, 15), 3.8, 3.8}, }; -HPWH::DrawPattern HPWH::lowUsage = { - {HM_TO_MIN(0, 00), 7.6, 3.8}, - {HM_TO_MIN(1, 00), 3.8, 3.8}, - {HM_TO_MIN(1, 05), 1.9, 3.8}, - {HM_TO_MIN(1, 10), 1.9, 3.8}, - {HM_TO_MIN(1, 15), 1.9, 3.8}, - {HM_TO_MIN(8, 00), 3.8, 3.8}, - {HM_TO_MIN(8, 15), 7.6, 3.8}, - {HM_TO_MIN(9, 00), 5.7, 3.8}, - {HM_TO_MIN(9, 15), 3.8, 3.8}, -}; - -HPWH::DrawPattern HPWH::mediumUsage = { - {HM_TO_MIN(0, 00), 7.6, 3.8}, - {HM_TO_MIN(1, 00), 3.8, 3.8}, - {HM_TO_MIN(1, 05), 1.9, 3.8}, - {HM_TO_MIN(1, 10), 1.9, 3.8}, - {HM_TO_MIN(1, 15), 1.9, 3.8}, - {HM_TO_MIN(8, 00), 3.8, 3.8}, - {HM_TO_MIN(8, 15), 7.6, 3.8}, - {HM_TO_MIN(9, 00), 5.7, 3.8}, - {HM_TO_MIN(9, 15), 3.8, 3.8}, -}; - -HPWH::DrawPattern HPWH::highUsage = { - {HM_TO_MIN(0, 00), 7.6, 3.8}, - {HM_TO_MIN(1, 00), 3.8, 3.8}, - {HM_TO_MIN(1, 05), 1.9, 3.8}, - {HM_TO_MIN(1, 10), 1.9, 3.8}, - {HM_TO_MIN(1, 15), 1.9, 3.8}, - {HM_TO_MIN(8, 00), 3.8, 3.8}, - {HM_TO_MIN(8, 15), 7.6, 3.8}, - {HM_TO_MIN(9, 00), 5.7, 3.8}, - {HM_TO_MIN(9, 15), 3.8, 3.8}, -}; +HPWH::DrawPattern HPWH::lowUsage = {{HM_TO_MIN(0, 00), 56.8, 6.4}, + {HM_TO_MIN(0, 30), 7.6, 3.8}, + {HM_TO_MIN(1, 00), 3.8, 3.8}, + {HM_TO_MIN(10, 30), 22.7, 6.4}, + {HM_TO_MIN(11, 30), 15.1, 6.4}, + {HM_TO_MIN(12, 00), 3.8, 3.8}, + {HM_TO_MIN(12, 45), 3.8, 3.8}, + {HM_TO_MIN(12, 50), 3.8, 3.8}, + {HM_TO_MIN(16, 15), 7.6, 3.8}, + {HM_TO_MIN(16, 45), 7.6, 6.4}, + {HM_TO_MIN(17, 00), 11.4, 6.4}}; + +HPWH::DrawPattern HPWH::mediumUsage = {{HM_TO_MIN(0, 00), 56.8, 6.4}, + {HM_TO_MIN(0, 30), 7.6, 3.8}, + {HM_TO_MIN(1, 40), 34.1, 6.4}, + {HM_TO_MIN(10, 30), 34.1, 6.4}, + {HM_TO_MIN(11, 30), 18.9, 6.4}, + {HM_TO_MIN(12, 00), 3.8, 3.8}, + {HM_TO_MIN(12, 45), 3.8, 3.8}, + {HM_TO_MIN(12, 50), 3.8, 3.8}, + {HM_TO_MIN(16, 00), 3.8, 3.8}, + {HM_TO_MIN(16, 15), 7.6, 3.8}, + {HM_TO_MIN(16, 45), 7.6, 6.4}, + {HM_TO_MIN(17, 00), 26.5, 6.4}}; + +HPWH::DrawPattern HPWH::highUsage = {{HM_TO_MIN(0, 00), 102, 11.4}, + {HM_TO_MIN(0, 30), 7.6, 3.8}, + {HM_TO_MIN(0, 40), 3.8, 3.8}, + {HM_TO_MIN(1, 40), 34.1, 6.4}, + {HM_TO_MIN(10, 30), 56.8, 11.4}, + {HM_TO_MIN(11, 30), 18.9, 6.4}, + {HM_TO_MIN(12, 00), 3.8, 3.8}, + {HM_TO_MIN(12, 45), 3.8, 3.8}, + {HM_TO_MIN(12, 50), 3.8, 3.8}, + {HM_TO_MIN(16, 00), 7.6, 3.8}, + {HM_TO_MIN(16, 15), 7.6, 3.8}, + {HM_TO_MIN(16, 30), 7.6, 6.4}, + {HM_TO_MIN(16, 45), 7.6, 6.4}, + {HM_TO_MIN(17, 00), 53.0, 11.4}}; //----------------------------------------------------------------------------- /// @brief Samples a std::vector to extract a single value spanning the fractional @@ -5397,7 +5401,22 @@ int HPWH::HPWHinit_file(string configFile) HPWH::Usage HPWH::findUsageFromFirstHourRating() { return Usage::Medium; } -HPWH::Usage HPWH::findUsageFromMaximumGPM_Rating() { return Usage::Medium; } +HPWH::Usage HPWH::findUsageFromMaximumGPM_Rating() +{ + if (tankVolume_L < L_TO_GAL(1.7)) + { + return Usage::VerySmall; + } + else if (tankVolume_L < L_TO_GAL(2.8)) + { + return Usage::Low; + } + else if (tankVolume_L < L_TO_GAL(4.)) + { + return Usage::Medium; + } + return Usage::High; +} bool HPWH::calcUEF(const Usage usage, double& UEF) { @@ -5478,6 +5497,7 @@ bool HPWH::calcUEF(const Usage usage, double& UEF) totalEnergyConsumed_kJ += getNthHeatSourceEnergyInput(iHS, HPWH::UNITS_KJ); } + drawnVolume_L += incrementalDrawVolume_L; ++runTime_min; } } diff --git a/src/HPWH.hh b/src/HPWH.hh index dee07228..7cc4a55d 100644 --- a/src/HPWH.hh +++ b/src/HPWH.hh @@ -968,8 +968,14 @@ class HPWH double volume_L; double flowRate_Lper_min; - Draw(const double startTime_min_in,const double volume_L_in,const double flowRate_Lper_min_in): - startTime_min(startTime_min_in), volume_L(volume_L_in),flowRate_Lper_min(flowRate_Lper_min_in){} + Draw(const double startTime_min_in, + const double volume_L_in, + const double flowRate_Lper_min_in) + : startTime_min(startTime_min_in) + , volume_L(volume_L_in) + , flowRate_Lper_min(flowRate_Lper_min_in) + { + } }; typedef std::vector DrawPattern; @@ -1562,7 +1568,10 @@ inline double FT2_TO_M2(double feet2) { return (feet2 / 10.7640); } inline double MIN_TO_SEC(double minute) { return minute * sec_per_min; } inline double MIN_TO_HR(double minute) { return minute / min_per_hr; } -inline double HM_TO_MIN(const double hours, const double minutes){return min_per_hr * hours + minutes;} +inline double HM_TO_MIN(const double hours, const double minutes) +{ + return min_per_hr * hours + minutes; +} inline HPWH::DRMODES operator|(HPWH::DRMODES a, HPWH::DRMODES b) { diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 8023f63b..9518fc25 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -12,6 +12,7 @@ add_executable(testPerformanceMaps testPerformanceMaps.cc) add_executable(testStateOfChargeFcts testStateOfChargeFcts.cc) add_executable(testHeatingLogics testHeatingLogics.cc) add_executable(testEnergyBalance testEnergyBalance.cc) +add_executable(testCalcUEF testCalcUEF.cc) set(libs libHPWHsim ${PROJECT_NAME}_common_interface) @@ -26,6 +27,7 @@ target_link_libraries(testPerformanceMaps PRIVATE ${libs}) target_link_libraries(testStateOfChargeFcts PRIVATE ${libs}) target_link_libraries(testHeatingLogics PRIVATE ${libs}) target_link_libraries(testEnergyBalance PRIVATE ${libs}) +target_link_libraries(testCalcUEF PRIVATE ${libs}) target_compile_features(testTool PRIVATE cxx_std_17) @@ -46,6 +48,7 @@ add_test(NAME "testPerformanceMaps" COMMAND $ $ add_test(NAME "testStateOfChargeFcts" COMMAND $ ${testArgs} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) add_test(NAME "testHeatingLogics" COMMAND $ ${testArgs} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) add_test(NAME "testEnergyBalance" COMMAND $ ${testArgs} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) +add_test(NAME "testCalcUEF" COMMAND $ ${testArgs} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) #add_test(NAME "testREGoesTo99C.AOSmithCAHP120" COMMAND $ "Preset" "AOSmithCAHP120" "testREGoesTo99C" #"${CMAKE_CURRENT_BINARY_DIR}/output" WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/test/testCalcUEF.cc b/test/testCalcUEF.cc new file mode 100644 index 00000000..69059a14 --- /dev/null +++ b/test/testCalcUEF.cc @@ -0,0 +1,33 @@ +/* + * test UEF calculation + */ +#include "HPWH.hh" +#include "testUtilityFcts.cc" + +#include + +/* Evaluate UEF based on simulations using standard profiles */ +static bool testCalcUEF(const std::string& sModelName, double& UEF) +{ + HPWH hpwh; + + HPWH::MODELS model = mapStringToPreset(sModelName); + if (hpwh.HPWHinit_presets(model) != 0) + { + return false; + } + + return hpwh.calcUEF(hpwh.findUsageFromMaximumGPM_Rating(), UEF); +} + +int main(int, char**) +{ + double UEF; + ASSERTTRUE(testCalcUEF("AOSmithHPTS50", UEF)); + ASSERTTRUE(cmpd(UEF, 4.4091)); + + ASSERTTRUE(testCalcUEF("AquaThermAire", UEF)); + ASSERTTRUE(cmpd(UEF, 3.5848)); + + return 0; +} From d62fa566ba513a0f726ebd5a7914a43bd9b7cd05 Mon Sep 17 00:00:00 2001 From: Phil Ahrenkiel Date: Thu, 4 Jan 2024 11:14:13 -0700 Subject: [PATCH 03/37] Organize test code. --- src/HPWH.cc | 9 ++++- test/testCalcUEF.cc | 94 ++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 96 insertions(+), 7 deletions(-) diff --git a/src/HPWH.cc b/src/HPWH.cc index 1c226914..40536c1a 100644 --- a/src/HPWH.cc +++ b/src/HPWH.cc @@ -5403,7 +5403,14 @@ HPWH::Usage HPWH::findUsageFromFirstHourRating() { return Usage::Medium; } HPWH::Usage HPWH::findUsageFromMaximumGPM_Rating() { - if (tankVolume_L < L_TO_GAL(1.7)) + // Assume flow rate unlimited for heat-exchange models + if (hasHeatExchanger) + { + return Usage::High; + } + + // Assume max. flow rate = tankVolume / (1 min) + else if (tankVolume_L < L_TO_GAL(1.7)) { return Usage::VerySmall; } diff --git a/test/testCalcUEF.cc b/test/testCalcUEF.cc index 69059a14..77f9b801 100644 --- a/test/testCalcUEF.cc +++ b/test/testCalcUEF.cc @@ -20,14 +20,96 @@ static bool testCalcUEF(const std::string& sModelName, double& UEF) return hpwh.calcUEF(hpwh.findUsageFromMaximumGPM_Rating(), UEF); } -int main(int, char**) +int main(int argc, char* argv[]) { - double UEF; - ASSERTTRUE(testCalcUEF("AOSmithHPTS50", UEF)); - ASSERTTRUE(cmpd(UEF, 4.4091)); + bool validNumArgs = false; + bool runUnitTests = false; - ASSERTTRUE(testCalcUEF("AquaThermAire", UEF)); - ASSERTTRUE(cmpd(UEF, 3.5848)); + // process command line arguments + std::string sPresetOrFile = "Preset"; + std::string sModelName; + if (argc == 1) + { + runUnitTests = true; + } + else if (argc == 2) + { + sModelName = argv[1]; + validNumArgs = true; + runUnitTests = false; + } + else if (argc == 3) + { + sPresetOrFile = argv[1]; + sModelName = argv[2]; + validNumArgs = true; + runUnitTests = false; + } + + if (runUnitTests) + { + double UEF; + ASSERTTRUE(testCalcUEF("AOSmithHPTS50", UEF)); + ASSERTTRUE(cmpd(UEF, 4.4091)); + + ASSERTTRUE(testCalcUEF("AquaThermAire", UEF)); + ASSERTTRUE(cmpd(UEF, 3.5848)); + + return 0; + } + + if (!validNumArgs) { + cout << "Invalid input:\n\ + To run all unit tests, provide ZERO arguments.\n\ + To determine the UEF for a particular model spec, provide ONE or TWO arguments:\n\ + \t[model spec Type (i.e., Preset (default) or File)]\n\ + \t[model spec Name (i.e., Sanden80)]\n"; + exit(1); + } + + for (auto& c : sPresetOrFile) + { + c = static_cast(std::tolower(static_cast(c))); + } + + HPWH hpwh; + bool validModel = false; + if (sPresetOrFile == "preset") + { + HPWH::MODELS model = mapStringToPreset(sModelName); + if (hpwh.HPWHinit_presets(model) == 0) + { + validModel = true; + } + } + else + { + std::string inputFile = sModelName + ".txt"; + if (hpwh.HPWHinit_file(inputFile) == 0) + { + validModel = true; + } + } + + if (!validModel) + { + cout << "Invalid input: Model name not found.\n"; + exit(1); + } + + sPresetOrFile[0] = static_cast(std::toupper(static_cast(sPresetOrFile[0]))); + std::cout << "Spec type: " << sPresetOrFile << "\n"; + std::cout << "Model name: " << sModelName << "\n"; + + double UEF = 0.; + if(hpwh.calcUEF(hpwh.findUsageFromMaximumGPM_Rating(), UEF)) + { + std::cout << "UEF: " << UEF << "\n"; + } + else + { + std::cout << "Unable to determine UEF.\n"; + } return 0; } From 5defbd38d8a346a47f4b20f884f8ab4d990c676c Mon Sep 17 00:00:00 2001 From: Phil Ahrenkiel Date: Thu, 4 Jan 2024 16:10:42 -0700 Subject: [PATCH 04/37] Calc additional values. --- src/HPWH.cc | 124 ++++++++++++++++++++++++++++++++++++++------ src/HPWH.hh | 13 ++++- test/testCalcUEF.cc | 10 ++-- 3 files changed, 125 insertions(+), 22 deletions(-) diff --git a/src/HPWH.cc b/src/HPWH.cc index 40536c1a..c61ae2e8 100644 --- a/src/HPWH.cc +++ b/src/HPWH.cc @@ -5425,11 +5425,17 @@ HPWH::Usage HPWH::findUsageFromMaximumGPM_Rating() return Usage::High; } -bool HPWH::calcUEF(const Usage usage, double& UEF) +//----------------------------------------------------------------------------- +/// @brief Calculates the uniform energy factor (UEF) +/// @note see https://www.regulations.gov/document/EERE-2019-BT-TP-0032-0058 +/// @param[in] usage Specification of draw pattern +/// @param[out] UEF Result of calculation +/// @return true (success), false (failure). +//----------------------------------------------------------------------------- +bool HPWH::runDailyTest(const Usage usage, DailyTestSummary &dailyTestSummary) { - + // select the draw pattern based on usage DrawPattern* drawPattern = nullptr; - switch (usage) { case Usage::VerySmall: @@ -5453,31 +5459,57 @@ bool HPWH::calcUEF(const Usage usage, double& UEF) break; } } - if (drawPattern == nullptr) + { return false; + } - const double inletT_C = 20.; - const double ambientT_C = 20.; - const double externalT_C = 20.; + const double setpointT_C = 51.7; // + const double inletT_C = 14.4; // p. 40433 + const double ambientT_C = 19.7; // p. 40435 + const double externalT_C = 19.7; const DRMODES drMode = DR_ALLOW; - double totalVolumeRemoved_L = 0.; - double totalEnergyConsumed_kJ = 0.; + double dailyRemovedVolume_L = 0.; + double dailyUsedEnergy_kJ = 0.; + + if (!isSetpointFixed()) + { + if (setSetpoint(setpointT_C, UNITS_C) == HPWH_ABORT) + { + return false; + } + } + + // first-recovery info + bool isFirstRecoveryPeriod = true; + double recoveryEfficiency = 0.; + + double dailyHeatingEnergy_kJ = 0.; // total energy added to water over 24-hr test + double dailyUsedElectricalEnergy_kJ = 0.; // total electrical energy consumed over 24-hr test + double dailyUsedFossilFuelEnergy_kJ = 0.; // total "fossil-fuel" energy consumed over 24-hr test int runTime_min = 0; for (auto& draw : *drawPattern) { double drawnVolume_L = 0.; + double recoveryVolume_L = 0.; + double recoveryVolumeTemperature_LC = 0.; + double recoveryUsedElectricalEnergy_kJ = 0.; + double recoveryUsedFossilFuelEnergy_kJ = 0.; + + // limit draw-volume increment to tank volume double incrementalDrawVolume_L = draw.flowRate_Lper_min * (1.); if (incrementalDrawVolume_L > tankVolume_L) { incrementalDrawVolume_L = tankVolume_L; } + // iterate until 1) specified draw volume has been reached and 2) next draw has started while ((drawnVolume_L < draw.volume_L) || (runTime_min < draw.startTime_min)) { + // do not exceed specified draw volume if (drawnVolume_L + incrementalDrawVolume_L > draw.volume_L) { incrementalDrawVolume_L = draw.volume_L - drawnVolume_L; @@ -5489,7 +5521,7 @@ bool HPWH::calcUEF(const Usage usage, double& UEF) ambientT_C, // ambient Temp (C) externalT_C, // external Temp (C) drMode, // DDR Status - 0, // inlet-2 volume (L) + 0., // inlet-2 volume (L) inletT_C, // inlet-2 Temp (C) NULL); // no extra heat @@ -5498,21 +5530,81 @@ bool HPWH::calcUEF(const Usage usage, double& UEF) return false; } - totalVolumeRemoved_L += incrementalDrawVolume_L; + // collect consumed electrical-energy info + double usedFossilFuelEnergy_kJ = 0.; + double usedElectricalEnergy_kJ = 0.; for (int iHS = 0; iHS < getNumHeatSources(); ++iHS) { - totalEnergyConsumed_kJ += getNthHeatSourceEnergyInput(iHS, HPWH::UNITS_KJ); + usedElectricalEnergy_kJ += getNthHeatSourceEnergyInput(iHS, HPWH::UNITS_KJ); } + // collect recovery info + recoveryVolume_L += incrementalDrawVolume_L; + recoveryVolumeTemperature_LC += incrementalDrawVolume_L * outletTemp_C; + recoveryUsedElectricalEnergy_kJ += usedElectricalEnergy_kJ; + recoveryUsedFossilFuelEnergy_kJ += usedFossilFuelEnergy_kJ; + drawnVolume_L += incrementalDrawVolume_L; ++runTime_min; } + + // collect end-of-draw info + double recoveryUsedEnergy_kJ = recoveryUsedElectricalEnergy_kJ + recoveryUsedFossilFuelEnergy_kJ; // see 6.4.3 + + double recoveryOutletT_C = 0.; + if (recoveryVolume_L > 0.) + { + recoveryOutletT_C = recoveryVolumeTemperature_LC / recoveryVolume_L; + } + double recoveryMassRemoved_kg = HPWH::DENSITYWATER_kgperL * drawnVolume_L; + double recoveryHeatCapacity_kJperC = HPWH::CPWATER_kJperkgC * recoveryMassRemoved_kg; + double recoveryHeatingEnergy_kJ = recoveryHeatCapacity_kJperC * (recoveryOutletT_C - inletT_C); + + if (isFirstRecoveryPeriod) + { + // find the "Recovery Efficiency" (6.4.2) + if (recoveryUsedEnergy_kJ > 0.) + { + recoveryEfficiency = recoveryHeatingEnergy_kJ / recoveryUsedEnergy_kJ; + } + isFirstRecoveryPeriod = false; + } + + dailyHeatingEnergy_kJ += recoveryHeatingEnergy_kJ; + + // collect 24-hr test info + dailyRemovedVolume_L += drawnVolume_L; + dailyUsedElectricalEnergy_kJ += recoveryUsedElectricalEnergy_kJ; + dailyUsedEnergy_kJ += recoveryUsedEnergy_kJ; } - double totalMassRemoved_kg = HPWH::DENSITYWATER_kgperL * totalVolumeRemoved_L; - double totalHeatCapacity_kJperC = HPWH::CPWATER_kJperkgC * totalMassRemoved_kg; - double refEnergy_kJ = totalHeatCapacity_kJperC * (51.7 - 14.4); + // find the "Adjusted Daily Water Heating Energy Consumption" (6.3.6) + if (recoveryEfficiency > 0.) + { + dailyTestSummary.adjustedDailyWaterHeatingEnergy_kJ = dailyHeatingEnergy_kJ / recoveryEfficiency; + } + + // find the "Uniform Energy Factor" (6.4.4) + double dailyMassRemoved_kg = HPWH::DENSITYWATER_kgperL * dailyRemovedVolume_L; + double dailyHeatCapacity_kJperC = HPWH::CPWATER_kJperkgC * dailyMassRemoved_kg; + double standardDailyHeatingEnergy_kJ = dailyHeatCapacity_kJperC * (setpointT_C - inletT_C); + dailyTestSummary.UEF = standardDailyHeatingEnergy_kJ / dailyUsedEnergy_kJ; + + // find the "Annual Energy Consumption" (6.4.5) + double annualEnergyConsumption_kJ = 0.; + if (dailyTestSummary.UEF > 0.) + { + constexpr double day_per_year = 365.; + const double nominalDifferenceT_C = F_TO_C(67.); + annualEnergyConsumption_kJ = dailyHeatCapacity_kJperC * nominalDifferenceT_C / dailyTestSummary.UEF; + } + + // find the "Annual Electrical Energy Consumption" (6.4.6) + dailyTestSummary.annualElectricalEnergyConsumption_kJ = 0.; + if (dailyUsedEnergy_kJ > 0.) + { + dailyTestSummary.annualElectricalEnergyConsumption_kJ = (dailyUsedElectricalEnergy_kJ / dailyUsedEnergy_kJ) * annualEnergyConsumption_kJ; + } - UEF = refEnergy_kJ / totalEnergyConsumed_kJ; return true; } diff --git a/src/HPWH.hh b/src/HPWH.hh index 7cc4a55d..d9f51d0c 100644 --- a/src/HPWH.hh +++ b/src/HPWH.hh @@ -959,8 +959,17 @@ class HPWH /// Determine usage using the maximum GPM rating method Usage findUsageFromMaximumGPM_Rating(); - /// Calculate UEF - bool calcUEF(const Usage usage, double& UEF); + struct DailyTestSummary + { + double UEF; + double recoveryEfficiency; + double adjustedDailyWaterHeatingEnergy_kJ; + double annualElectricalEnergyConsumption_kJ; + double annualEnergyConsumption_kJ; + }; + + /// run 24-hr draw pattern + bool runDailyTest(const Usage usage, DailyTestSummary &dailyTestSummary); struct Draw { diff --git a/test/testCalcUEF.cc b/test/testCalcUEF.cc index 77f9b801..0274a33c 100644 --- a/test/testCalcUEF.cc +++ b/test/testCalcUEF.cc @@ -17,7 +17,9 @@ static bool testCalcUEF(const std::string& sModelName, double& UEF) return false; } - return hpwh.calcUEF(hpwh.findUsageFromMaximumGPM_Rating(), UEF); + HPWH::DailyTestSummary dailyTestSummary; + return hpwh.runDailyTest(hpwh.findUsageFromMaximumGPM_Rating(), dailyTestSummary); + UEF = dailyTestSummary.UEF; } int main(int argc, char* argv[]) @@ -101,10 +103,10 @@ int main(int argc, char* argv[]) std::cout << "Spec type: " << sPresetOrFile << "\n"; std::cout << "Model name: " << sModelName << "\n"; - double UEF = 0.; - if(hpwh.calcUEF(hpwh.findUsageFromMaximumGPM_Rating(), UEF)) + HPWH::DailyTestSummary dailyTestSummary; + if(hpwh.runDailyTest(hpwh.findUsageFromMaximumGPM_Rating(), dailyTestSummary)) { - std::cout << "UEF: " << UEF << "\n"; + std::cout << "UEF: " << dailyTestSummary.UEF << "\n"; } else { From 900107a5009488039243ce716eb56bfcfe89ec56 Mon Sep 17 00:00:00 2001 From: Phil Ahrenkiel Date: Thu, 4 Jan 2024 16:37:21 -0700 Subject: [PATCH 05/37] Calc add'l params. --- src/HPWH.cc | 26 ++++++++++++++++---------- test/testCalcUEF.cc | 13 ++++++++----- 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/src/HPWH.cc b/src/HPWH.cc index c61ae2e8..798bd4c0 100644 --- a/src/HPWH.cc +++ b/src/HPWH.cc @@ -5464,7 +5464,6 @@ bool HPWH::runDailyTest(const Usage usage, DailyTestSummary &dailyTestSummary) return false; } - const double setpointT_C = 51.7; // const double inletT_C = 14.4; // p. 40433 const double ambientT_C = 19.7; // p. 40435 const double externalT_C = 19.7; @@ -5473,6 +5472,8 @@ bool HPWH::runDailyTest(const Usage usage, DailyTestSummary &dailyTestSummary) double dailyRemovedVolume_L = 0.; double dailyUsedEnergy_kJ = 0.; + /* + constexpr double setpointT_C = 51.7; // if (!isSetpointFixed()) { if (setSetpoint(setpointT_C, UNITS_C) == HPWH_ABORT) @@ -5480,10 +5481,10 @@ bool HPWH::runDailyTest(const Usage usage, DailyTestSummary &dailyTestSummary) return false; } } + */ // first-recovery info bool isFirstRecoveryPeriod = true; - double recoveryEfficiency = 0.; double dailyHeatingEnergy_kJ = 0.; // total energy added to water over 24-hr test double dailyUsedElectricalEnergy_kJ = 0.; // total electrical energy consumed over 24-hr test @@ -5565,7 +5566,7 @@ bool HPWH::runDailyTest(const Usage usage, DailyTestSummary &dailyTestSummary) // find the "Recovery Efficiency" (6.4.2) if (recoveryUsedEnergy_kJ > 0.) { - recoveryEfficiency = recoveryHeatingEnergy_kJ / recoveryUsedEnergy_kJ; + dailyTestSummary.recoveryEfficiency = recoveryHeatingEnergy_kJ / recoveryUsedEnergy_kJ; } isFirstRecoveryPeriod = false; } @@ -5575,35 +5576,40 @@ bool HPWH::runDailyTest(const Usage usage, DailyTestSummary &dailyTestSummary) // collect 24-hr test info dailyRemovedVolume_L += drawnVolume_L; dailyUsedElectricalEnergy_kJ += recoveryUsedElectricalEnergy_kJ; + dailyUsedFossilFuelEnergy_kJ += recoveryUsedFossilFuelEnergy_kJ; dailyUsedEnergy_kJ += recoveryUsedEnergy_kJ; } // find the "Adjusted Daily Water Heating Energy Consumption" (6.3.6) - if (recoveryEfficiency > 0.) + dailyTestSummary.adjustedDailyWaterHeatingEnergy_kJ = 0.; + if (dailyTestSummary.recoveryEfficiency > 0.) { - dailyTestSummary.adjustedDailyWaterHeatingEnergy_kJ = dailyHeatingEnergy_kJ / recoveryEfficiency; + dailyTestSummary.adjustedDailyWaterHeatingEnergy_kJ = dailyHeatingEnergy_kJ / dailyTestSummary.recoveryEfficiency; } // find the "Uniform Energy Factor" (6.4.4) + const double standardSetpointT_C = 51.7; // + const double standardInletT_C = 14.4; // + double dailyMassRemoved_kg = HPWH::DENSITYWATER_kgperL * dailyRemovedVolume_L; double dailyHeatCapacity_kJperC = HPWH::CPWATER_kJperkgC * dailyMassRemoved_kg; - double standardDailyHeatingEnergy_kJ = dailyHeatCapacity_kJperC * (setpointT_C - inletT_C); + double standardDailyHeatingEnergy_kJ = dailyHeatCapacity_kJperC * (standardSetpointT_C - standardInletT_C); dailyTestSummary.UEF = standardDailyHeatingEnergy_kJ / dailyUsedEnergy_kJ; // find the "Annual Energy Consumption" (6.4.5) - double annualEnergyConsumption_kJ = 0.; + dailyTestSummary.annualEnergyConsumption_kJ = 0.; if (dailyTestSummary.UEF > 0.) { - constexpr double day_per_year = 365.; + constexpr double days_per_year = 365.; const double nominalDifferenceT_C = F_TO_C(67.); - annualEnergyConsumption_kJ = dailyHeatCapacity_kJperC * nominalDifferenceT_C / dailyTestSummary.UEF; + dailyTestSummary.annualEnergyConsumption_kJ = days_per_year * dailyHeatCapacity_kJperC * nominalDifferenceT_C / dailyTestSummary.UEF; } // find the "Annual Electrical Energy Consumption" (6.4.6) dailyTestSummary.annualElectricalEnergyConsumption_kJ = 0.; if (dailyUsedEnergy_kJ > 0.) { - dailyTestSummary.annualElectricalEnergyConsumption_kJ = (dailyUsedElectricalEnergy_kJ / dailyUsedEnergy_kJ) * annualEnergyConsumption_kJ; + dailyTestSummary.annualElectricalEnergyConsumption_kJ = (dailyUsedElectricalEnergy_kJ / dailyUsedEnergy_kJ) * dailyTestSummary.annualEnergyConsumption_kJ; } return true; diff --git a/test/testCalcUEF.cc b/test/testCalcUEF.cc index 0274a33c..a9e60f99 100644 --- a/test/testCalcUEF.cc +++ b/test/testCalcUEF.cc @@ -18,8 +18,10 @@ static bool testCalcUEF(const std::string& sModelName, double& UEF) } HPWH::DailyTestSummary dailyTestSummary; - return hpwh.runDailyTest(hpwh.findUsageFromMaximumGPM_Rating(), dailyTestSummary); + bool result = hpwh.runDailyTest(hpwh.findUsageFromMaximumGPM_Rating(), dailyTestSummary); UEF = dailyTestSummary.UEF; + + return result; } int main(int argc, char* argv[]) @@ -51,11 +53,12 @@ int main(int argc, char* argv[]) if (runUnitTests) { double UEF; - ASSERTTRUE(testCalcUEF("AOSmithHPTS50", UEF)); - ASSERTTRUE(cmpd(UEF, 4.4091)); - + ASSERTTRUE(testCalcUEF("AquaThermAire", UEF)); - ASSERTTRUE(cmpd(UEF, 3.5848)); + ASSERTTRUE(cmpd(UEF, 2.8442)); + + ASSERTTRUE(testCalcUEF("AOSmithHPTS50", UEF)); + ASSERTTRUE(cmpd(UEF, 3.4366)); return 0; } From bff4b12e0c4a7e35f93a30e3f6afeaca55a728ae Mon Sep 17 00:00:00 2001 From: Phil Ahrenkiel Date: Sat, 6 Jan 2024 15:51:37 -0700 Subject: [PATCH 06/37] Enforce DOE defn's. --- src/HPWH.cc | 254 ++++++++++++++++++++++++++++++++------------ src/HPWH.hh | 13 ++- test/testCalcUEF.cc | 42 ++++---- 3 files changed, 217 insertions(+), 92 deletions(-) diff --git a/src/HPWH.cc b/src/HPWH.cc index 798bd4c0..ff6a74d4 100644 --- a/src/HPWH.cc +++ b/src/HPWH.cc @@ -2904,20 +2904,21 @@ double HPWH::getStandbyLosses(UNITS units /*=UNITS_KWH*/) const } } -double HPWH::getTankHeatContent_kJ() const +double HPWH::getTankTemp_C() const { - // returns tank heat content relative to 0 C using kJ - // get average tank temperature - double avgTemp = 0.0; - for (int i = 0; i < getNumNodes(); i++) + double totalT_C = 0.; + for (auto& T_C : tankTemps_C) { - avgTemp += tankTemps_C[i]; + totalT_C += T_C; } - avgTemp /= getNumNodes(); + return totalT_C / static_cast(getNumNodes()); +} - double totalHeat = avgTemp * DENSITYWATER_kgperL * CPWATER_kJperkgC * tankVolume_L; - return totalHeat; +double HPWH::getTankHeatContent_kJ() const +{ + // returns tank heat content relative to 0 C using kJ + return DENSITYWATER_kgperL * tankVolume_L * CPWATER_kJperkgC * getTankTemp_C(); } double HPWH::getLocationTemp_C() const { return locationTemperature_C; } @@ -5432,7 +5433,7 @@ HPWH::Usage HPWH::findUsageFromMaximumGPM_Rating() /// @param[out] UEF Result of calculation /// @return true (success), false (failure). //----------------------------------------------------------------------------- -bool HPWH::runDailyTest(const Usage usage, DailyTestSummary &dailyTestSummary) +bool HPWH::runDailyTest(const Usage usage, DailyTestSummary& dailyTestSummary) { // select the draw pattern based on usage DrawPattern* drawPattern = nullptr; @@ -5464,14 +5465,11 @@ bool HPWH::runDailyTest(const Usage usage, DailyTestSummary &dailyTestSummary) return false; } - const double inletT_C = 14.4; // p. 40433 - const double ambientT_C = 19.7; // p. 40435 + const double inletT_C = 14.4; // p. 40433 + const double ambientT_C = 19.7; // p. 40435 const double externalT_C = 19.7; const DRMODES drMode = DR_ALLOW; - double dailyRemovedVolume_L = 0.; - double dailyUsedEnergy_kJ = 0.; - /* constexpr double setpointT_C = 51.7; // if (!isSetpointFixed()) @@ -5483,22 +5481,61 @@ bool HPWH::runDailyTest(const Usage usage, DailyTestSummary &dailyTestSummary) } */ - // first-recovery info - bool isFirstRecoveryPeriod = true; + int preTime_min = 0; + bool heatersAreOn = false; + // 1-hr initiation + while ((preTime_min < 60) || heatersAreOn) + { + if (runOneStep(inletT_C, // inlet water temperature (C) + 0, // draw volume (L) + ambientT_C, // ambient Temp (C) + externalT_C, // external Temp (C) + drMode, // DDR Status + 0., // inlet-2 volume (L) + inletT_C, // inlet-2 Temp (C) + NULL) // no extra heat + == HPWH_ABORT) + { + return false; + } - double dailyHeatingEnergy_kJ = 0.; // total energy added to water over 24-hr test + heatersAreOn = false; + for (auto& heatSource : heatSources) + { + heatersAreOn |= heatSource.isEngaged(); + } + + // std::cout << preTime_min << ": " << getTankTemp_C() << ", " << (heatersAreOn? "On": + // "Off") << "\n"; + + ++preTime_min; + } + + double tankT_C = getTankTemp_C(); + double initialTankT_C = tankT_C; + + double dailyRemovedVolume_L = 0.; + double dailyUsedEnergy_kJ = 0.; + double dailyHeatingEnergy_kJ = 0.; // total energy added to water over 24-hr test double dailyUsedElectricalEnergy_kJ = 0.; // total electrical energy consumed over 24-hr test - double dailyUsedFossilFuelEnergy_kJ = 0.; // total "fossil-fuel" energy consumed over 24-hr test + + // first-recovery info + bool isFirstRecoveryPeriod = true; + double firstRecoveryUsedEnergy_kJ = 0.; + double recoveryHeatingEnergy_kJ = 0.; int runTime_min = 0; for (auto& draw : *drawPattern) { - double drawnVolume_L = 0.; + double drawVolume_L = 0.; + double drawVolumeTemperature_LC = 0.; + double drawHeatingEnergy_kJ = 0.; + double drawUsedElectricalEnergy_kJ = 0.; + double drawUsedFossilFuelEnergy_kJ = 0.; - double recoveryVolume_L = 0.; - double recoveryVolumeTemperature_LC = 0.; - double recoveryUsedElectricalEnergy_kJ = 0.; - double recoveryUsedFossilFuelEnergy_kJ = 0.; + double drawSumOutletVolumeT_LC = 0.; + double drawSumInletVolumeT_LC = 0.; + int drawSumTimeT_minC = 0; // limit draw-volume increment to tank volume double incrementalDrawVolume_L = draw.flowRate_Lper_min * (1.); @@ -5507,13 +5544,16 @@ bool HPWH::runDailyTest(const Usage usage, DailyTestSummary &dailyTestSummary) incrementalDrawVolume_L = tankVolume_L; } + bool includedInFirstRecoveryPeriod = isFirstRecoveryPeriod; + bool isDrawComplete = false; // iterate until 1) specified draw volume has been reached and 2) next draw has started - while ((drawnVolume_L < draw.volume_L) || (runTime_min < draw.startTime_min)) + while ((drawVolume_L < draw.volume_L) || (runTime_min < draw.startTime_min)) { // do not exceed specified draw volume - if (drawnVolume_L + incrementalDrawVolume_L > draw.volume_L) + if (drawVolume_L + incrementalDrawVolume_L > draw.volume_L) { - incrementalDrawVolume_L = draw.volume_L - drawnVolume_L; + incrementalDrawVolume_L = draw.volume_L - drawVolume_L; + isDrawComplete = true; } // run a step @@ -5531,70 +5571,143 @@ bool HPWH::runDailyTest(const Usage usage, DailyTestSummary &dailyTestSummary) return false; } - // collect consumed electrical-energy info + tankT_C = getTankTemp_C(); + + drawSumOutletVolumeT_LC += incrementalDrawVolume_L * outletTemp_C; + drawSumInletVolumeT_LC += incrementalDrawVolume_L * inletT_C; + ++drawSumTimeT_minC; + + // collect heating energy + double incrementalDrawMass_kg = DENSITYWATER_kgperL * incrementalDrawVolume_L; + double incrementalDrawHeatCapacity_kJperC = CPWATER_kJperkgC * incrementalDrawMass_kg; + drawHeatingEnergy_kJ += incrementalDrawHeatCapacity_kJperC * (outletTemp_C - inletT_C); + + // collect used-energy info double usedFossilFuelEnergy_kJ = 0.; double usedElectricalEnergy_kJ = 0.; for (int iHS = 0; iHS < getNumHeatSources(); ++iHS) { usedElectricalEnergy_kJ += getNthHeatSourceEnergyInput(iHS, HPWH::UNITS_KJ); } + drawUsedFossilFuelEnergy_kJ += usedFossilFuelEnergy_kJ; + drawUsedElectricalEnergy_kJ += usedElectricalEnergy_kJ; // collect recovery info - recoveryVolume_L += incrementalDrawVolume_L; - recoveryVolumeTemperature_LC += incrementalDrawVolume_L * outletTemp_C; - recoveryUsedElectricalEnergy_kJ += usedElectricalEnergy_kJ; - recoveryUsedFossilFuelEnergy_kJ += usedFossilFuelEnergy_kJ; + if (isFirstRecoveryPeriod) + { + firstRecoveryUsedEnergy_kJ += usedFossilFuelEnergy_kJ + usedElectricalEnergy_kJ; + if (isDrawComplete) // check for cut-off + { + heatersAreOn = false; + for (auto& heatSource : heatSources) + { + heatersAreOn |= heatSource.isEngaged(); + } + if (!heatersAreOn) + { + isFirstRecoveryPeriod = false; - drawnVolume_L += incrementalDrawVolume_L; + double tankContentMass_kg = DENSITYWATER_kgperL * tankVolume_L; + double tankHeatCapacity_kJperC = CPWATER_kJperkgC * tankContentMass_kg; + recoveryHeatingEnergy_kJ += + tankHeatCapacity_kJperC * (tankT_C - initialTankT_C); + } + } + } + + drawVolume_L += incrementalDrawVolume_L; ++runTime_min; } - // collect end-of-draw info - double recoveryUsedEnergy_kJ = recoveryUsedElectricalEnergy_kJ + recoveryUsedFossilFuelEnergy_kJ; // see 6.4.3 - - double recoveryOutletT_C = 0.; - if (recoveryVolume_L > 0.) + if (includedInFirstRecoveryPeriod) { - recoveryOutletT_C = recoveryVolumeTemperature_LC / recoveryVolume_L; - } - double recoveryMassRemoved_kg = HPWH::DENSITYWATER_kgperL * drawnVolume_L; - double recoveryHeatCapacity_kJperC = HPWH::CPWATER_kJperkgC * recoveryMassRemoved_kg; - double recoveryHeatingEnergy_kJ = recoveryHeatCapacity_kJperC * (recoveryOutletT_C - inletT_C); + double meanDrawOutletT_C = drawSumOutletVolumeT_LC / drawVolume_L; + double meanDrawInletT_C = drawSumInletVolumeT_LC / drawVolume_L; - if (isFirstRecoveryPeriod) - { - // find the "Recovery Efficiency" (6.4.2) - if (recoveryUsedEnergy_kJ > 0.) - { - dailyTestSummary.recoveryEfficiency = recoveryHeatingEnergy_kJ / recoveryUsedEnergy_kJ; - } - isFirstRecoveryPeriod = false; - } + double drawMass_kg = DENSITYWATER_kgperL * drawVolume_L; + double drawHeatCapacity_kJperC = CPWATER_kJperkgC * drawMass_kg; - dailyHeatingEnergy_kJ += recoveryHeatingEnergy_kJ; + recoveryHeatingEnergy_kJ += + drawHeatCapacity_kJperC * (meanDrawOutletT_C - meanDrawInletT_C); + } // collect 24-hr test info - dailyRemovedVolume_L += drawnVolume_L; - dailyUsedElectricalEnergy_kJ += recoveryUsedElectricalEnergy_kJ; - dailyUsedFossilFuelEnergy_kJ += recoveryUsedFossilFuelEnergy_kJ; - dailyUsedEnergy_kJ += recoveryUsedEnergy_kJ; + dailyRemovedVolume_L += drawVolume_L; + dailyHeatingEnergy_kJ += drawHeatingEnergy_kJ; + dailyUsedElectricalEnergy_kJ += drawUsedElectricalEnergy_kJ; + dailyUsedEnergy_kJ += drawUsedFossilFuelEnergy_kJ + drawUsedElectricalEnergy_kJ; } - // find the "Adjusted Daily Water Heating Energy Consumption" (6.3.6) - dailyTestSummary.adjustedDailyWaterHeatingEnergy_kJ = 0.; - if (dailyTestSummary.recoveryEfficiency > 0.) + // find the "Recovery Efficiency" (6.3.3) + dailyTestSummary.recoveryEfficiency = 0.; + if (firstRecoveryUsedEnergy_kJ > 0.) { - dailyTestSummary.adjustedDailyWaterHeatingEnergy_kJ = dailyHeatingEnergy_kJ / dailyTestSummary.recoveryEfficiency; + dailyTestSummary.recoveryEfficiency = recoveryHeatingEnergy_kJ / firstRecoveryUsedEnergy_kJ; } - // find the "Uniform Energy Factor" (6.4.4) - const double standardSetpointT_C = 51.7; // - const double standardInletT_C = 14.4; // - + // find the standard daily heating energy + constexpr double standardSetpointT_C = 51.7; + constexpr double standardInletT_C = 14.4; double dailyMassRemoved_kg = HPWH::DENSITYWATER_kgperL * dailyRemovedVolume_L; double dailyHeatCapacity_kJperC = HPWH::CPWATER_kJperkgC * dailyMassRemoved_kg; - double standardDailyHeatingEnergy_kJ = dailyHeatCapacity_kJperC * (standardSetpointT_C - standardInletT_C); - dailyTestSummary.UEF = standardDailyHeatingEnergy_kJ / dailyUsedEnergy_kJ; + double standardDailyHeatingEnergy_kJ = + dailyHeatCapacity_kJperC * (standardSetpointT_C - standardInletT_C); + + // find the "Daily Water Heating Energy Consumption (Qd)" (6.3.5) + dailyTestSummary.dailyHeatingEnergyConsumption_kJ = dailyUsedEnergy_kJ; + if (dailyTestSummary.recoveryEfficiency > 0.) + { + double tankContentMass_kg = DENSITYWATER_kgperL * tankVolume_L; + double tankHeatCapacity_kJperC = CPWATER_kJperkgC * tankContentMass_kg; + dailyTestSummary.dailyHeatingEnergyConsumption_kJ += tankHeatCapacity_kJperC * + (tankT_C - initialTankT_C) / + dailyTestSummary.recoveryEfficiency; + } + + // find the "Adjusted Daily Water Heating Energy Consumption (Qda)" (6.3.6a) + // same as above, because no change in ambient temperature + dailyTestSummary.adjustedDailyWaterHeatingEnergyConsumption_kJ = + dailyTestSummary.dailyHeatingEnergyConsumption_kJ; + + // find the "Energy Used to Heat Water (Q_HW)" (6.3.6a) + dailyTestSummary.energyUsedToHeatWater_kJ = 0.; + if (dailyTestSummary.recoveryEfficiency > 0.) + { + dailyTestSummary.energyUsedToHeatWater_kJ = + dailyHeatingEnergy_kJ / dailyTestSummary.recoveryEfficiency; + } + + // find the "Standard Energy Used to Heat Water (Q_HW,T)" (6.3.6b) + dailyTestSummary.standardEnergyUsedToHeatWater_kJ = 0.; + if (dailyTestSummary.recoveryEfficiency > 0.) + { + double removedMass_kg = DENSITYWATER_kgperL * dailyRemovedVolume_L; + double removedHeatCapacity_kJperC = CPWATER_kJperkgC * removedMass_kg; + double standardRemovedEnergy_kJ = + removedHeatCapacity_kJperC * (standardSetpointT_C - standardInletT_C); + dailyTestSummary.standardEnergyUsedToHeatWater_kJ = + standardRemovedEnergy_kJ / dailyTestSummary.recoveryEfficiency; + } + + // add to the adjusted daily water heating energy consumption (p. 40487) + double energyUsedToHeatWaterDifference_kJ = dailyTestSummary.standardEnergyUsedToHeatWater_kJ - + dailyTestSummary.energyUsedToHeatWater_kJ; + dailyTestSummary.adjustedDailyWaterHeatingEnergyConsumption_kJ += + energyUsedToHeatWaterDifference_kJ; + + // find the "Modified Daily Water Heating Energy Consumption (Qdm = Qda - QHWD) (p. 40487) + // note: same as Q_HW,T + dailyTestSummary.modifiedDailyWaterHeatingEnergyConsumption_kJ = + dailyTestSummary.adjustedDailyWaterHeatingEnergyConsumption_kJ - + energyUsedToHeatWaterDifference_kJ; + + // find the "Uniform Energy Factor" (6.4.4) + dailyTestSummary.UEF = 0.; + if (dailyTestSummary.modifiedDailyWaterHeatingEnergyConsumption_kJ > 0.) + { + dailyTestSummary.UEF = standardDailyHeatingEnergy_kJ / + dailyTestSummary.modifiedDailyWaterHeatingEnergyConsumption_kJ; + } // find the "Annual Energy Consumption" (6.4.5) dailyTestSummary.annualEnergyConsumption_kJ = 0.; @@ -5602,14 +5715,17 @@ bool HPWH::runDailyTest(const Usage usage, DailyTestSummary &dailyTestSummary) { constexpr double days_per_year = 365.; const double nominalDifferenceT_C = F_TO_C(67.); - dailyTestSummary.annualEnergyConsumption_kJ = days_per_year * dailyHeatCapacity_kJperC * nominalDifferenceT_C / dailyTestSummary.UEF; + dailyTestSummary.annualEnergyConsumption_kJ = + days_per_year * dailyHeatCapacity_kJperC * nominalDifferenceT_C / dailyTestSummary.UEF; } // find the "Annual Electrical Energy Consumption" (6.4.6) dailyTestSummary.annualElectricalEnergyConsumption_kJ = 0.; if (dailyUsedEnergy_kJ > 0.) { - dailyTestSummary.annualElectricalEnergyConsumption_kJ = (dailyUsedElectricalEnergy_kJ / dailyUsedEnergy_kJ) * dailyTestSummary.annualEnergyConsumption_kJ; + dailyTestSummary.annualElectricalEnergyConsumption_kJ = + (dailyUsedElectricalEnergy_kJ / dailyUsedEnergy_kJ) * + dailyTestSummary.annualEnergyConsumption_kJ; } return true; diff --git a/src/HPWH.hh b/src/HPWH.hh index d9f51d0c..8fd10a73 100644 --- a/src/HPWH.hh +++ b/src/HPWH.hh @@ -898,6 +898,9 @@ class HPWH void resetTopOffTimer(); /**< resets variables for timer associated with the DR_TOT call */ + /// returns the average tank temperature + double getTankTemp_C() const; + double getLocationTemp_C() const; int setMaxTempDepression(double maxDepression, UNITS units = UNITS_C); @@ -959,17 +962,21 @@ class HPWH /// Determine usage using the maximum GPM rating method Usage findUsageFromMaximumGPM_Rating(); - struct DailyTestSummary + struct DailyTestSummary { double UEF; double recoveryEfficiency; - double adjustedDailyWaterHeatingEnergy_kJ; + double dailyHeatingEnergyConsumption_kJ; + double adjustedDailyWaterHeatingEnergyConsumption_kJ; + double modifiedDailyWaterHeatingEnergyConsumption_kJ; + double energyUsedToHeatWater_kJ; + double standardEnergyUsedToHeatWater_kJ; double annualElectricalEnergyConsumption_kJ; double annualEnergyConsumption_kJ; }; /// run 24-hr draw pattern - bool runDailyTest(const Usage usage, DailyTestSummary &dailyTestSummary); + bool runDailyTest(const Usage usage, DailyTestSummary& dailyTestSummary); struct Draw { diff --git a/test/testCalcUEF.cc b/test/testCalcUEF.cc index a9e60f99..1269ba59 100644 --- a/test/testCalcUEF.cc +++ b/test/testCalcUEF.cc @@ -7,7 +7,7 @@ #include /* Evaluate UEF based on simulations using standard profiles */ -static bool testCalcUEF(const std::string& sModelName, double& UEF) +static bool testCalcMetrics(const std::string& sModelName, HPWH::DailyTestSummary& dailyTestSummary) { HPWH hpwh; @@ -17,11 +17,7 @@ static bool testCalcUEF(const std::string& sModelName, double& UEF) return false; } - HPWH::DailyTestSummary dailyTestSummary; - bool result = hpwh.runDailyTest(hpwh.findUsageFromMaximumGPM_Rating(), dailyTestSummary); - UEF = dailyTestSummary.UEF; - - return result; + return hpwh.runDailyTest(hpwh.findUsageFromMaximumGPM_Rating(), dailyTestSummary); } int main(int argc, char* argv[]) @@ -52,18 +48,19 @@ int main(int argc, char* argv[]) if (runUnitTests) { - double UEF; - - ASSERTTRUE(testCalcUEF("AquaThermAire", UEF)); - ASSERTTRUE(cmpd(UEF, 2.8442)); + HPWH::DailyTestSummary dailyTestSummary; + + ASSERTTRUE(testCalcMetrics("AquaThermAire", dailyTestSummary)); + ASSERTTRUE(cmpd(dailyTestSummary.UEF, 2.8442)); - ASSERTTRUE(testCalcUEF("AOSmithHPTS50", UEF)); - ASSERTTRUE(cmpd(UEF, 3.4366)); + ASSERTTRUE(testCalcMetrics("AOSmithHPTS50", dailyTestSummary)); + ASSERTTRUE(cmpd(dailyTestSummary.UEF, 3.4366)); return 0; } - if (!validNumArgs) { + if (!validNumArgs) + { cout << "Invalid input:\n\ To run all unit tests, provide ZERO arguments.\n\ To determine the UEF for a particular model spec, provide ONE or TWO arguments:\n\ @@ -78,8 +75,8 @@ int main(int argc, char* argv[]) } HPWH hpwh; - bool validModel = false; - if (sPresetOrFile == "preset") + bool validModel = false; + if (sPresetOrFile == "preset") { HPWH::MODELS model = mapStringToPreset(sModelName); if (hpwh.HPWHinit_presets(model) == 0) @@ -102,18 +99,23 @@ int main(int argc, char* argv[]) exit(1); } - sPresetOrFile[0] = static_cast(std::toupper(static_cast(sPresetOrFile[0]))); + sPresetOrFile[0] = + static_cast(std::toupper(static_cast(sPresetOrFile[0]))); std::cout << "Spec type: " << sPresetOrFile << "\n"; std::cout << "Model name: " << sModelName << "\n"; HPWH::DailyTestSummary dailyTestSummary; - if(hpwh.runDailyTest(hpwh.findUsageFromMaximumGPM_Rating(), dailyTestSummary)) + if (hpwh.runDailyTest(hpwh.findUsageFromMaximumGPM_Rating(), dailyTestSummary)) { - std::cout << "UEF: " << dailyTestSummary.UEF << "\n"; - } + std::cout << "\tRecovery Efficiency: " << dailyTestSummary.recoveryEfficiency << "\n"; + std::cout << "\tAdjusted Daily Water Heating Energy Consumption (kJ): " << dailyTestSummary.adjustedDailyWaterHeatingEnergyConsumption_kJ << "\n"; + std::cout << "\tUEF: " << dailyTestSummary.UEF << "\n"; + std::cout << "\tAnnual Electrical Energy Consumption (kJ): " << dailyTestSummary.annualElectricalEnergyConsumption_kJ << "\n"; + std::cout << "\tAnnual Energy Consumption (kJ): " << dailyTestSummary.annualEnergyConsumption_kJ << "\n"; + } else { - std::cout << "Unable to determine UEF.\n"; + std::cout << "Unable to determine efficiency metrics.\n"; } return 0; From 8bd55e37e8027da04d91845938ab9edf49902928 Mon Sep 17 00:00:00 2001 From: Phil Ahrenkiel Date: Sat, 6 Jan 2024 15:53:30 -0700 Subject: [PATCH 07/37] Format. --- test/testCalcUEF.cc | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/test/testCalcUEF.cc b/test/testCalcUEF.cc index 1269ba59..e63094b7 100644 --- a/test/testCalcUEF.cc +++ b/test/testCalcUEF.cc @@ -108,11 +108,14 @@ int main(int argc, char* argv[]) if (hpwh.runDailyTest(hpwh.findUsageFromMaximumGPM_Rating(), dailyTestSummary)) { std::cout << "\tRecovery Efficiency: " << dailyTestSummary.recoveryEfficiency << "\n"; - std::cout << "\tAdjusted Daily Water Heating Energy Consumption (kJ): " << dailyTestSummary.adjustedDailyWaterHeatingEnergyConsumption_kJ << "\n"; + std::cout << "\tAdjusted Daily Water Heating Energy Consumption (kJ): " + << dailyTestSummary.adjustedDailyWaterHeatingEnergyConsumption_kJ << "\n"; std::cout << "\tUEF: " << dailyTestSummary.UEF << "\n"; - std::cout << "\tAnnual Electrical Energy Consumption (kJ): " << dailyTestSummary.annualElectricalEnergyConsumption_kJ << "\n"; - std::cout << "\tAnnual Energy Consumption (kJ): " << dailyTestSummary.annualEnergyConsumption_kJ << "\n"; - } + std::cout << "\tAnnual Electrical Energy Consumption (kJ): " + << dailyTestSummary.annualElectricalEnergyConsumption_kJ << "\n"; + std::cout << "\tAnnual Energy Consumption (kJ): " + << dailyTestSummary.annualEnergyConsumption_kJ << "\n"; + } else { std::cout << "Unable to determine efficiency metrics.\n"; From 748761e95772f1e7ac203bd475507536fe955f53 Mon Sep 17 00:00:00 2001 From: Phil Ahrenkiel Date: Sat, 6 Jan 2024 15:55:36 -0700 Subject: [PATCH 08/37] Fix test results. --- test/testCalcUEF.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/testCalcUEF.cc b/test/testCalcUEF.cc index e63094b7..19af2353 100644 --- a/test/testCalcUEF.cc +++ b/test/testCalcUEF.cc @@ -51,10 +51,10 @@ int main(int argc, char* argv[]) HPWH::DailyTestSummary dailyTestSummary; ASSERTTRUE(testCalcMetrics("AquaThermAire", dailyTestSummary)); - ASSERTTRUE(cmpd(dailyTestSummary.UEF, 2.8442)); + ASSERTTRUE(cmpd(dailyTestSummary.UEF, 2.8258)); ASSERTTRUE(testCalcMetrics("AOSmithHPTS50", dailyTestSummary)); - ASSERTTRUE(cmpd(dailyTestSummary.UEF, 3.4366)); + ASSERTTRUE(cmpd(dailyTestSummary.UEF, 4.8021)); return 0; } From 6d38643a4e08a88a0ee27cf3b1f4ba953d0e1a1f Mon Sep 17 00:00:00 2001 From: Phil Ahrenkiel Date: Sat, 6 Jan 2024 16:56:04 -0700 Subject: [PATCH 09/37] Remove variable. --- src/HPWH.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/src/HPWH.cc b/src/HPWH.cc index ff6a74d4..a1dd2a81 100644 --- a/src/HPWH.cc +++ b/src/HPWH.cc @@ -5528,7 +5528,6 @@ bool HPWH::runDailyTest(const Usage usage, DailyTestSummary& dailyTestSummary) for (auto& draw : *drawPattern) { double drawVolume_L = 0.; - double drawVolumeTemperature_LC = 0.; double drawHeatingEnergy_kJ = 0.; double drawUsedElectricalEnergy_kJ = 0.; double drawUsedFossilFuelEnergy_kJ = 0.; From 8a1c2511a0e8facdb4b9db5186aebd7941a582bd Mon Sep 17 00:00:00 2001 From: Phil Ahrenkiel Date: Mon, 8 Jan 2024 13:04:15 -0700 Subject: [PATCH 10/37] Eval first-hour rating. --- src/HPWH.cc | 203 +++++++++++++++++++++++++++++++++++++++----- src/HPWH.hh | 7 +- test/testCalcUEF.cc | 77 ++++++++++++----- 3 files changed, 240 insertions(+), 47 deletions(-) diff --git a/src/HPWH.cc b/src/HPWH.cc index a1dd2a81..730bcc16 100644 --- a/src/HPWH.cc +++ b/src/HPWH.cc @@ -5400,30 +5400,186 @@ int HPWH::HPWHinit_file(string configFile) } #endif -HPWH::Usage HPWH::findUsageFromFirstHourRating() { return Usage::Medium; } - -HPWH::Usage HPWH::findUsageFromMaximumGPM_Rating() +bool HPWH::findUsageFromFirstHourRating(HPWH::Usage& usage, const double setpointT_C /* = 51.7 */) { - // Assume flow rate unlimited for heat-exchange models - if (hasHeatExchanger) + double flowRate_Lper_min = GAL_TO_L(3.); + if (tankVolume_L < GAL_TO_L(20.)) + flowRate_Lper_min = GAL_TO_L(1.5); + + constexpr double inletT_C = 14.4; // p. 40433 + constexpr double ambientT_C = 19.7; // p. 40435 + constexpr double externalT_C = 19.7; + constexpr DRMODES drMode = DR_ALLOW; + if (!isSetpointFixed()) + { + if (setSetpoint(setpointT_C, UNITS_C) == HPWH_ABORT) + { + return false; + } + } + + double maxT_C = getTankTemp_C(); + double prevMinT_C = getTankTemp_C(); + double tolT_C = dF_TO_dC(0.); // tolerance + + double drawVolume_L = 0.; + double lastPassDrawVolume_L = 0.; + int testTime_min = 0; + int drawOnTime = 0; + int prevDrawOffTime_min = 0; + bool heatersAreOn = false; + bool isDrawing = false; + bool testIsRunning = true; + int testStage = 1; + bool lastDrawSucceeded = false; + while (testIsRunning) + { + heatersAreOn = false; + for (auto& heatSource : heatSources) + { + heatersAreOn |= heatSource.isEngaged(); + } + double tankT_C = getTankTemp_C(); + + switch (testStage) + { + case 1: + { + if (!heatersAreOn) + { + isDrawing = true; + drawOnTime = testTime_min; + testStage = 2; + } + break; + } + + case 2: + { + if (heatersAreOn) + { + isDrawing = false; + prevDrawOffTime_min = testTime_min; + maxT_C = tankT_C; + testStage = 3; + } + break; + } + + case 3: + { + if (isDrawing) + { + double targetT_C = maxT_C - dF_TO_dC(15.) - tolT_C; + if (outletTemp_C < targetT_C) // outletT has dropped by 15 degF below max T + { + prevMinT_C = outletTemp_C; + maxT_C = tankT_C; // initialize for next pass + isDrawing = false; + prevDrawOffTime_min = testTime_min; + } + } + else + { + if (tankT_C > maxT_C) // has not reached max T + { + maxT_C = tankT_C + tolT_C; + if (testTime_min >= 60) // start a final draw + { + isDrawing = true; + drawOnTime = testTime_min; + testStage = 4; + } + } + else { + if (testTime_min >= 60) + { + testIsRunning = false; + } + else + { + isDrawing = true; + drawOnTime = testTime_min; + } + } + } + break; + } + + case 4: + { + if (testTime_min > drawOnTime) + { + if (outletTemp_C > prevMinT_C - tolT_C) + { + lastDrawSucceeded = true; + } + } + if (outletTemp_C <= prevMinT_C + tolT_C) + { + testIsRunning = false; + } + } + } + + // limit draw-volume increment to tank volume + double incrementalDrawVolume_L = isDrawing ? flowRate_Lper_min * (1.) : 0.; + if (incrementalDrawVolume_L > tankVolume_L) + { + incrementalDrawVolume_L = tankVolume_L; + } + + if (runOneStep(inletT_C, // inlet water temperature (C) + incrementalDrawVolume_L, // draw volume (L) + ambientT_C, // ambient Temp (C) + externalT_C, // external Temp (C) + drMode, // DDR Status + 0., // inlet-2 volume (L) + inletT_C, // inlet-2 Temp (C) + NULL) // no extra heat + == HPWH_ABORT) + { + return false; + } + + // std::cout << preTime_min << ": " << getTankTemp_C() << ", " << (heatersAreOn? "On": + // "Off") << "\n"; + if (testStage == 4) + { + lastPassDrawVolume_L += incrementalDrawVolume_L; + } + else + { + drawVolume_L += incrementalDrawVolume_L; + } + + ++testTime_min; + } + + if (lastDrawSucceeded) { - return Usage::High; + drawVolume_L += lastPassDrawVolume_L; } - // Assume max. flow rate = tankVolume / (1 min) - else if (tankVolume_L < L_TO_GAL(1.7)) + // + if (drawVolume_L < GAL_TO_L(18.)) { - return Usage::VerySmall; + usage = Usage::VerySmall; } - else if (tankVolume_L < L_TO_GAL(2.8)) + else if (drawVolume_L < GAL_TO_L(51.)) { - return Usage::Low; + usage = Usage::Low; } - else if (tankVolume_L < L_TO_GAL(4.)) + else if (drawVolume_L < GAL_TO_L(75.)) { - return Usage::Medium; + usage = Usage::Medium; } - return Usage::High; + else + { + usage = Usage::High; + } + + return true; } //----------------------------------------------------------------------------- @@ -5433,7 +5589,9 @@ HPWH::Usage HPWH::findUsageFromMaximumGPM_Rating() /// @param[out] UEF Result of calculation /// @return true (success), false (failure). //----------------------------------------------------------------------------- -bool HPWH::runDailyTest(const Usage usage, DailyTestSummary& dailyTestSummary) +bool HPWH::runDailyTest(const Usage usage, + DailyTestSummary& dailyTestSummary, + const double setpointT_C /* = 51.7 */) { // select the draw pattern based on usage DrawPattern* drawPattern = nullptr; @@ -5465,13 +5623,11 @@ bool HPWH::runDailyTest(const Usage usage, DailyTestSummary& dailyTestSummary) return false; } - const double inletT_C = 14.4; // p. 40433 - const double ambientT_C = 19.7; // p. 40435 - const double externalT_C = 19.7; - const DRMODES drMode = DR_ALLOW; + constexpr double inletT_C = 14.4; // p. 40433 + constexpr double ambientT_C = 19.7; // p. 40435 + constexpr double externalT_C = 19.7; + constexpr DRMODES drMode = DR_ALLOW; - /* - constexpr double setpointT_C = 51.7; // if (!isSetpointFixed()) { if (setSetpoint(setpointT_C, UNITS_C) == HPWH_ABORT) @@ -5479,7 +5635,6 @@ bool HPWH::runDailyTest(const Usage usage, DailyTestSummary& dailyTestSummary) return false; } } - */ int preTime_min = 0; bool heatersAreOn = false; @@ -5523,6 +5678,7 @@ bool HPWH::runDailyTest(const Usage usage, DailyTestSummary& dailyTestSummary) bool isFirstRecoveryPeriod = true; double firstRecoveryUsedEnergy_kJ = 0.; double recoveryHeatingEnergy_kJ = 0.; + bool hasHeated = false; int runTime_min = 0; for (auto& draw : *drawPattern) @@ -5602,7 +5758,8 @@ bool HPWH::runDailyTest(const Usage usage, DailyTestSummary& dailyTestSummary) { heatersAreOn |= heatSource.isEngaged(); } - if (!heatersAreOn) + hasHeated |= heatersAreOn; + if (hasHeated && (!heatersAreOn)) { isFirstRecoveryPeriod = false; diff --git a/src/HPWH.hh b/src/HPWH.hh index 8fd10a73..2a67abc2 100644 --- a/src/HPWH.hh +++ b/src/HPWH.hh @@ -957,10 +957,7 @@ class HPWH }; /// Determine usage using the first-hour rating method - Usage findUsageFromFirstHourRating(); - - /// Determine usage using the maximum GPM rating method - Usage findUsageFromMaximumGPM_Rating(); + bool findUsageFromFirstHourRating(HPWH::Usage &usage,const double setpointT_C = 51.7); struct DailyTestSummary { @@ -976,7 +973,7 @@ class HPWH }; /// run 24-hr draw pattern - bool runDailyTest(const Usage usage, DailyTestSummary& dailyTestSummary); + bool runDailyTest(const Usage usage, DailyTestSummary& dailyTestSummary, const double setpointT_C = 51.7); struct Draw { diff --git a/test/testCalcUEF.cc b/test/testCalcUEF.cc index 19af2353..9a77da6f 100644 --- a/test/testCalcUEF.cc +++ b/test/testCalcUEF.cc @@ -7,7 +7,9 @@ #include /* Evaluate UEF based on simulations using standard profiles */ -static bool testCalcMetrics(const std::string& sModelName, HPWH::DailyTestSummary& dailyTestSummary) +static bool testCalcMetrics(const std::string& sModelName, + HPWH::Usage& usage, + HPWH::DailyTestSummary& dailyTestSummary) { HPWH hpwh; @@ -17,11 +19,16 @@ static bool testCalcMetrics(const std::string& sModelName, HPWH::DailyTestSummar return false; } - return hpwh.runDailyTest(hpwh.findUsageFromMaximumGPM_Rating(), dailyTestSummary); + if (!hpwh.findUsageFromFirstHourRating(usage)) + return false; + + return hpwh.runDailyTest(usage, dailyTestSummary); } int main(int argc, char* argv[]) { + HPWH::Usage usage; + HPWH::DailyTestSummary dailyTestSummary; bool validNumArgs = false; bool runUnitTests = false; @@ -48,13 +55,13 @@ int main(int argc, char* argv[]) if (runUnitTests) { - HPWH::DailyTestSummary dailyTestSummary; + ASSERTTRUE(testCalcMetrics("AquaThermAire", usage, dailyTestSummary)); + ASSERTTRUE(usage == HPWH::Usage::High); + ASSERTTRUE(cmpd(dailyTestSummary.UEF, 3.2797)); - ASSERTTRUE(testCalcMetrics("AquaThermAire", dailyTestSummary)); - ASSERTTRUE(cmpd(dailyTestSummary.UEF, 2.8258)); - - ASSERTTRUE(testCalcMetrics("AOSmithHPTS50", dailyTestSummary)); - ASSERTTRUE(cmpd(dailyTestSummary.UEF, 4.8021)); + ASSERTTRUE(testCalcMetrics("AOSmithHPTS50", usage, dailyTestSummary)); + ASSERTTRUE(usage == HPWH::Usage::Medium); + ASSERTTRUE(cmpd(dailyTestSummary.UEF, 4.8246)); return 0; } @@ -104,21 +111,53 @@ int main(int argc, char* argv[]) std::cout << "Spec type: " << sPresetOrFile << "\n"; std::cout << "Model name: " << sModelName << "\n"; - HPWH::DailyTestSummary dailyTestSummary; - if (hpwh.runDailyTest(hpwh.findUsageFromMaximumGPM_Rating(), dailyTestSummary)) + if (hpwh.findUsageFromFirstHourRating(usage)) { - std::cout << "\tRecovery Efficiency: " << dailyTestSummary.recoveryEfficiency << "\n"; - std::cout << "\tAdjusted Daily Water Heating Energy Consumption (kJ): " - << dailyTestSummary.adjustedDailyWaterHeatingEnergyConsumption_kJ << "\n"; - std::cout << "\tUEF: " << dailyTestSummary.UEF << "\n"; - std::cout << "\tAnnual Electrical Energy Consumption (kJ): " - << dailyTestSummary.annualElectricalEnergyConsumption_kJ << "\n"; - std::cout << "\tAnnual Energy Consumption (kJ): " - << dailyTestSummary.annualEnergyConsumption_kJ << "\n"; + std::string sUsage = ""; + switch (usage) + { + case HPWH::Usage::VerySmall: + { + sUsage = "Very Small"; + break; + } + case HPWH::Usage::Low: + { + sUsage = "Low"; + break; + } + case HPWH::Usage::Medium: + { + sUsage = "Medium"; + break; + } + case HPWH::Usage::High: + { + sUsage = "High"; + break; + } + } + std::cout << "\tUsage: " << sUsage << "\n"; + + if (hpwh.runDailyTest(usage, dailyTestSummary)) + { + std::cout << "\tRecovery Efficiency: " << dailyTestSummary.recoveryEfficiency << "\n"; + std::cout << "\tUEF: " << dailyTestSummary.UEF << "\n"; + std::cout << "\tAdjusted Daily Water Heating Energy Consumption (kWh): " + << KJ_TO_KWH(dailyTestSummary.adjustedDailyWaterHeatingEnergyConsumption_kJ) << "\n"; + std::cout << "\tAnnual Electrical Energy Consumption (kWh): " + << KJ_TO_KWH(dailyTestSummary.annualElectricalEnergyConsumption_kJ) << "\n"; + std::cout << "\tAnnual Energy Consumption (kWh): " + << KJ_TO_KWH(dailyTestSummary.annualEnergyConsumption_kJ) << "\n"; + } + else + { + std::cout << "Unable to determine efficiency metrics.\n"; + } } else { - std::cout << "Unable to determine efficiency metrics.\n"; + std::cout << "Unable to determine first-hour rating.\n"; } return 0; From 6f831fb962406177698317d83b129dbee8256ef2 Mon Sep 17 00:00:00 2001 From: Phil Ahrenkiel Date: Tue, 9 Jan 2024 12:19:01 -0700 Subject: [PATCH 11/37] Modify 1st-hr rating. --- src/HPWH.cc | 252 +++++++++++++++++++++++++------------------- src/HPWH.hh | 3 + test/testCalcUEF.cc | 4 +- 3 files changed, 148 insertions(+), 111 deletions(-) diff --git a/src/HPWH.cc b/src/HPWH.cc index 730bcc16..e8b7a91a 100644 --- a/src/HPWH.cc +++ b/src/HPWH.cc @@ -5400,7 +5400,7 @@ int HPWH::HPWHinit_file(string configFile) } #endif -bool HPWH::findUsageFromFirstHourRating(HPWH::Usage& usage, const double setpointT_C /* = 51.7 */) +bool HPWH::prepForTest() { double flowRate_Lper_min = GAL_TO_L(3.); if (tankVolume_L < GAL_TO_L(20.)) @@ -5409,118 +5409,115 @@ bool HPWH::findUsageFromFirstHourRating(HPWH::Usage& usage, const double setpoin constexpr double inletT_C = 14.4; // p. 40433 constexpr double ambientT_C = 19.7; // p. 40435 constexpr double externalT_C = 19.7; - constexpr DRMODES drMode = DR_ALLOW; - if (!isSetpointFixed()) - { - if (setSetpoint(setpointT_C, UNITS_C) == HPWH_ABORT) - { - return false; - } - } - double maxT_C = getTankTemp_C(); - double prevMinT_C = getTankTemp_C(); - double tolT_C = dF_TO_dC(0.); // tolerance + double tankT_C = getTankTemp_C(); - double drawVolume_L = 0.; - double lastPassDrawVolume_L = 0.; - int testTime_min = 0; - int drawOnTime = 0; - int prevDrawOffTime_min = 0; - bool heatersAreOn = false; + DRMODES drMode = DR_ALLOW; bool isDrawing = false; - bool testIsRunning = true; - int testStage = 1; - bool lastDrawSucceeded = false; - while (testIsRunning) + bool done = false; + int step = 0; + int time_min = 0; + while (!done) { - heatersAreOn = false; - for (auto& heatSource : heatSources) - { - heatersAreOn |= heatSource.isEngaged(); - } - double tankT_C = getTankTemp_C(); - - switch (testStage) + switch (step) { - case 1: + case 0: // start with heat off { - if (!heatersAreOn) + if (!isHeating) { isDrawing = true; - drawOnTime = testTime_min; - testStage = 2; + ++step; } break; } - case 2: + case 1: // draw until heat turns on { - if (heatersAreOn) + if (isHeating) { isDrawing = false; - prevDrawOffTime_min = testTime_min; - maxT_C = tankT_C; - testStage = 3; + ++step; } break; } - case 3: + case 2: // wait for heat to turn on { - if (isDrawing) + if (!isHeating) { - double targetT_C = maxT_C - dF_TO_dC(15.) - tolT_C; - if (outletTemp_C < targetT_C) // outletT has dropped by 15 degF below max T - { - prevMinT_C = outletTemp_C; - maxT_C = tankT_C; // initialize for next pass - isDrawing = false; - prevDrawOffTime_min = testTime_min; - } - } - else - { - if (tankT_C > maxT_C) // has not reached max T - { - maxT_C = tankT_C + tolT_C; - if (testTime_min >= 60) // start a final draw - { - isDrawing = true; - drawOnTime = testTime_min; - testStage = 4; - } - } - else { - if (testTime_min >= 60) - { - testIsRunning = false; - } - else - { - isDrawing = true; - drawOnTime = testTime_min; - } - } + isDrawing = false; + done = true; } break; } + } - case 4: + // limit draw-volume increment to tank volume + double incrementalDrawVolume_L = isDrawing ? flowRate_Lper_min * (1.) : 0.; + if (incrementalDrawVolume_L > tankVolume_L) { - if (testTime_min > drawOnTime) - { - if (outletTemp_C > prevMinT_C - tolT_C) - { - lastDrawSucceeded = true; - } - } - if (outletTemp_C <= prevMinT_C + tolT_C) - { - testIsRunning = false; - } + incrementalDrawVolume_L = tankVolume_L; } + + if (runOneStep(inletT_C, // inlet water temperature (C) + incrementalDrawVolume_L, // draw volume (L) + ambientT_C, // ambient Temp (C) + externalT_C, // external Temp (C) + drMode, // DDR Status + 0., // inlet-2 volume (L) + inletT_C, // inlet-2 Temp (C) + NULL) // no extra heat + == HPWH_ABORT) + { + return false; } + tankT_C = getTankTemp_C(); + ++time_min; + } + return true; +} + +bool HPWH::findUsageFromFirstHourRating(HPWH::Usage& usage, const double setpointT_C /* = 51.7 */) +{ + double flowRate_Lper_min = GAL_TO_L(3.); + if (tankVolume_L < GAL_TO_L(20.)) + flowRate_Lper_min = GAL_TO_L(1.5); + + constexpr double inletT_C = 14.4; // p. 40433 + constexpr double ambientT_C = 19.7; // p. 40435 + constexpr double externalT_C = 19.7; + + if (!isSetpointFixed()) + { + if (setSetpoint(setpointT_C, UNITS_C) == HPWH_ABORT) + { + return false; + } + } + + double tankT_C = getTankTemp_C(); + double maxTankT_C = tankT_C; + double maxOutletT_C = 0.; + + DRMODES drMode = DR_ALLOW; + double drawVolume_L = 0.; + int elapsedTime_min = 0; + int totalDrawTime_min = 0; + int totalHeatingTime_min = 0; + bool isDrawing = false; + bool done = false; + int step = 0; + int numCompletedCycles = 0; + constexpr int numCycles = 10; + + prepForTest(); + + isDrawing = true; + maxOutletT_C = 0.; + drMode = DR_LOC; + + while (!done) + { // limit draw-volume increment to tank volume double incrementalDrawVolume_L = isDrawing ? flowRate_Lper_min * (1.) : 0.; @@ -5541,36 +5538,77 @@ bool HPWH::findUsageFromFirstHourRating(HPWH::Usage& usage, const double setpoin { return false; } + tankT_C = getTankTemp_C(); - // std::cout << preTime_min << ": " << getTankTemp_C() << ", " << (heatersAreOn? "On": - // "Off") << "\n"; - if (testStage == 4) + switch (step) + { + case 0: { - lastPassDrawVolume_L += incrementalDrawVolume_L; + ++totalDrawTime_min; + maxOutletT_C = std::max(outletTemp_C, maxOutletT_C); + if (outletTemp_C < maxOutletT_C - dF_TO_dC(15.)) // outletT has dropped by 15 degF below max T + { + isDrawing = false; + drMode = DR_ALLOW; + maxTankT_C = tankT_C; // initialize for next pass + maxOutletT_C = outletTemp_C; // initialize for next pass + ++step; + + ++numCompletedCycles; + if (numCompletedCycles >= numCycles) + { + done = true; // end with a draw + } + } + break; } - else + + case 1: { - drawVolume_L += incrementalDrawVolume_L; + ++totalHeatingTime_min; + if (isHeating) // ensure heat on before proceeding + { + ++step; + } + break; } - ++testTime_min; + case 2: + { + ++totalHeatingTime_min; + if ((tankT_C > maxTankT_C) && + isHeating) // has not reached maxTankT and heat is on + { + maxTankT_C = std::max(tankT_C, maxTankT_C); + } + else // has reached maxTankT + { + isDrawing = true; + drMode = DR_LOC; + step = 0; // repeat + } + } + } + drawVolume_L += incrementalDrawVolume_L; + ++elapsedTime_min; } - if (lastDrawSucceeded) - { - drawVolume_L += lastPassDrawVolume_L; - } + double avgCyleDrawVolume_L = drawVolume_L / static_cast(numCycles); + double avgCyleTime_min = elapsedTime_min / static_cast(numCycles); + double avgDrawTime_min = totalDrawTime_min / static_cast(numCycles); + double avgHeatingTime_min = totalHeatingTime_min / static_cast(numCycles); + double hourlyDrawVolume_L = (60. / avgCyleTime_min) * avgCyleDrawVolume_L; // - if (drawVolume_L < GAL_TO_L(18.)) + if (hourlyDrawVolume_L < GAL_TO_L(18.)) { usage = Usage::VerySmall; } - else if (drawVolume_L < GAL_TO_L(51.)) + else if (hourlyDrawVolume_L < GAL_TO_L(51.)) { usage = Usage::Low; } - else if (drawVolume_L < GAL_TO_L(75.)) + else if (hourlyDrawVolume_L < GAL_TO_L(75.)) { usage = Usage::Medium; } @@ -5727,6 +5765,7 @@ bool HPWH::runDailyTest(const Usage usage, } tankT_C = getTankTemp_C(); + hasHeated |= isHeating; drawSumOutletVolumeT_LC += incrementalDrawVolume_L * outletTemp_C; drawSumInletVolumeT_LC += incrementalDrawVolume_L * inletT_C; @@ -5753,13 +5792,7 @@ bool HPWH::runDailyTest(const Usage usage, firstRecoveryUsedEnergy_kJ += usedFossilFuelEnergy_kJ + usedElectricalEnergy_kJ; if (isDrawComplete) // check for cut-off { - heatersAreOn = false; - for (auto& heatSource : heatSources) - { - heatersAreOn |= heatSource.isEngaged(); - } - hasHeated |= heatersAreOn; - if (hasHeated && (!heatersAreOn)) + if (hasHeated && (!isHeating)) { isFirstRecoveryPeriod = false; @@ -5815,13 +5848,14 @@ bool HPWH::runDailyTest(const Usage usage, { double tankContentMass_kg = DENSITYWATER_kgperL * tankVolume_L; double tankHeatCapacity_kJperC = CPWATER_kJperkgC * tankContentMass_kg; - dailyTestSummary.dailyHeatingEnergyConsumption_kJ += tankHeatCapacity_kJperC * - (tankT_C - initialTankT_C) / + double finalTankT_C = tankT_C; + dailyTestSummary.dailyHeatingEnergyConsumption_kJ -= tankHeatCapacity_kJperC * + (finalTankT_C - initialTankT_C) / dailyTestSummary.recoveryEfficiency; } // find the "Adjusted Daily Water Heating Energy Consumption (Qda)" (6.3.6a) - // same as above, because no change in ambient temperature + // same as above, because simulation induces no change in ambient temperature dailyTestSummary.adjustedDailyWaterHeatingEnergyConsumption_kJ = dailyTestSummary.dailyHeatingEnergyConsumption_kJ; diff --git a/src/HPWH.hh b/src/HPWH.hh index 2a67abc2..0c81cef3 100644 --- a/src/HPWH.hh +++ b/src/HPWH.hh @@ -956,6 +956,9 @@ class HPWH High }; + + bool prepForTest(); + /// Determine usage using the first-hour rating method bool findUsageFromFirstHourRating(HPWH::Usage &usage,const double setpointT_C = 51.7); diff --git a/test/testCalcUEF.cc b/test/testCalcUEF.cc index 9a77da6f..0aa70c3a 100644 --- a/test/testCalcUEF.cc +++ b/test/testCalcUEF.cc @@ -57,11 +57,11 @@ int main(int argc, char* argv[]) { ASSERTTRUE(testCalcMetrics("AquaThermAire", usage, dailyTestSummary)); ASSERTTRUE(usage == HPWH::Usage::High); - ASSERTTRUE(cmpd(dailyTestSummary.UEF, 3.2797)); + ASSERTTRUE(cmpd(dailyTestSummary.UEF, 2.7540)); ASSERTTRUE(testCalcMetrics("AOSmithHPTS50", usage, dailyTestSummary)); ASSERTTRUE(usage == HPWH::Usage::Medium); - ASSERTTRUE(cmpd(dailyTestSummary.UEF, 4.8246)); + ASSERTTRUE(cmpd(dailyTestSummary.UEF, 2.6290)); return 0; } From c6e32250e71da937c4e4e8d0318579af6a69149d Mon Sep 17 00:00:00 2001 From: Phil Ahrenkiel Date: Wed, 10 Jan 2024 12:19:54 -0700 Subject: [PATCH 12/37] Refine test. --- src/HPWH.cc | 235 +++++++++++++++++++++++++++----------------- src/HPWH.hh | 26 +++-- test/testCalcUEF.cc | 102 ++++++++++--------- 3 files changed, 222 insertions(+), 141 deletions(-) diff --git a/src/HPWH.cc b/src/HPWH.cc index e8b7a91a..732904ca 100644 --- a/src/HPWH.cc +++ b/src/HPWH.cc @@ -64,6 +64,8 @@ const double HPWH::MAXOUTLET_R410A = F_TO_C(140.); const double HPWH::MAXOUTLET_R744 = F_TO_C(190.); const double HPWH::MINSINGLEPASSLIFT = dF_TO_dC(15.); +double HPWH::StandardTestSummary::consumerHPWH_maxPower_kW = 6.; // EERE–2019–BT–TP–0032, p. 40415 + HPWH::DrawPattern HPWH::verySmallUsage = { {HM_TO_MIN(0, 00), 7.6, 3.8}, {HM_TO_MIN(1, 00), 3.8, 3.8}, @@ -5400,7 +5402,13 @@ int HPWH::HPWHinit_file(string configFile) } #endif -bool HPWH::prepForTest() +//----------------------------------------------------------------------------- +/// @brief Performs a draw/heat cycle to prep for test +/// @note Flags if model is not qualified for test +/// @param[in/out] standardTestSummary contains usage on output +/// @return true (success), false (failure). +//----------------------------------------------------------------------------- +bool HPWH::prepForTest(StandardTestSummary& standardTestSummary) { double flowRate_Lper_min = GAL_TO_L(3.); if (tankVolume_L < GAL_TO_L(20.)) @@ -5410,8 +5418,6 @@ bool HPWH::prepForTest() constexpr double ambientT_C = 19.7; // p. 40435 constexpr double externalT_C = 19.7; - double tankT_C = getTankTemp_C(); - DRMODES drMode = DR_ALLOW; bool isDrawing = false; bool done = false; @@ -5471,13 +5477,34 @@ bool HPWH::prepForTest() { return false; } - tankT_C = getTankTemp_C(); + + if (isHeating) // check whether power is below limit for consumer HPWH + { + double qInElectrical_kJ = 0.; + for (int iHS = 0; iHS < getNumHeatSources(); iHS++) + { + qInElectrical_kJ += getNthHeatSourceEnergyInput(iHS, UNITS_KJ); + } + double electricalPower_kW = qInElectrical_kJ / sec_per_min; + if (electricalPower_kW > StandardTestSummary::consumerHPWH_maxPower_kW) + { + standardTestSummary.qualifies = false; + } + } + ++time_min; } return true; } -bool HPWH::findUsageFromFirstHourRating(HPWH::Usage& usage, const double setpointT_C /* = 51.7 */) +//----------------------------------------------------------------------------- +/// @brief Finds usage prior to 24-hr test +/// @note Determines usage; flags if model is not qualified +/// @param[in/out] standardTestSummary contains usage on output +/// @param[in] setpointT_C setpoint temperature (optional) +/// @return true (success), false (failure). +//----------------------------------------------------------------------------- +bool HPWH::findUsageFromFirstHourRating(StandardTestSummary& standardTestSummary, const double setpointT_C /* = 51.7 */) { double flowRate_Lper_min = GAL_TO_L(3.); if (tankVolume_L < GAL_TO_L(20.)) @@ -5501,24 +5528,31 @@ bool HPWH::findUsageFromFirstHourRating(HPWH::Usage& usage, const double setpoin DRMODES drMode = DR_ALLOW; double drawVolume_L = 0.; - int elapsedTime_min = 0; - int totalDrawTime_min = 0; - int totalHeatingTime_min = 0; + double totalDrawVolume_L = 0.; + + double sumOutletVolumeT_LC = 0; + double sumOutletVolume_L = 0; + + double avgOutletT_C = 0; + double minOutletT_C = 0; + double prevAvgOutletT_C = 0.; + double prevMinOutletT_C = 0.; + bool isDrawing = false; bool done = false; int step = 0; - int numCompletedCycles = 0; - constexpr int numCycles = 10; - - prepForTest(); + if (!prepForTest(standardTestSummary)) + { + return false; + } + bool firstDraw = true; isDrawing = true; maxOutletT_C = 0.; drMode = DR_LOC; - + int elapsedTime_min = 0; while (!done) { - // limit draw-volume increment to tank volume double incrementalDrawVolume_L = isDrawing ? flowRate_Lper_min * (1.) : 0.; if (incrementalDrawVolume_L > tankVolume_L) @@ -5542,98 +5576,122 @@ bool HPWH::findUsageFromFirstHourRating(HPWH::Usage& usage, const double setpoin switch (step) { - case 0: + case 0: // drawing { - ++totalDrawTime_min; + sumOutletVolume_L += incrementalDrawVolume_L; + sumOutletVolumeT_LC += incrementalDrawVolume_L * outletTemp_C; + maxOutletT_C = std::max(outletTemp_C, maxOutletT_C); if (outletTemp_C < maxOutletT_C - dF_TO_dC(15.)) // outletT has dropped by 15 degF below max T { - isDrawing = false; - drMode = DR_ALLOW; - maxTankT_C = tankT_C; // initialize for next pass - maxOutletT_C = outletTemp_C; // initialize for next pass - ++step; - - ++numCompletedCycles; - if (numCompletedCycles >= numCycles) + avgOutletT_C = sumOutletVolumeT_LC / sumOutletVolume_L; + minOutletT_C = outletTemp_C; + if(elapsedTime_min >= 60) + { + double fac = 1; + if (!firstDraw) + { + fac = (avgOutletT_C - prevMinOutletT_C) / (prevAvgOutletT_C - prevMinOutletT_C); + } + totalDrawVolume_L += fac * drawVolume_L; + done = true; + } + else { - done = true; // end with a draw + totalDrawVolume_L += drawVolume_L; + drawVolume_L = 0.; + isDrawing = false; + drMode = DR_ALLOW; + maxTankT_C = tankT_C; // initialize for next pass + maxOutletT_C = outletTemp_C; // initialize for next pass + prevAvgOutletT_C = avgOutletT_C; + prevMinOutletT_C = minOutletT_C; + ++step; } - } + + } break; } case 1: { - ++totalHeatingTime_min; - if (isHeating) // ensure heat on before proceeding + if (isHeating) // ensure heat is on before proceeding { - ++step; + ++step; } break; } - case 2: + case 2: // heating { - ++totalHeatingTime_min; if ((tankT_C > maxTankT_C) && - isHeating) // has not reached maxTankT and heat is on + isHeating && (elapsedTime_min < 60)) // has not reached maxTankT, heat is on, and has not reached 1 hr { maxTankT_C = std::max(tankT_C, maxTankT_C); } - else // has reached maxTankT + else // start another draw { + firstDraw = false; isDrawing = true; + drawVolume_L = 0.; drMode = DR_LOC; step = 0; // repeat } } } + + if (isHeating) // check whether power is below limit for consumer HPWH + { + double qInElectrical_kJ = 0.; + for (int iHS = 0; iHS < getNumHeatSources(); iHS++) + { + qInElectrical_kJ += getNthHeatSourceEnergyInput(iHS, UNITS_KJ); + } + double electricalPower_kW = qInElectrical_kJ / sec_per_min; + if (electricalPower_kW > StandardTestSummary::consumerHPWH_maxPower_kW) + { + standardTestSummary.qualifies = false; + } + } + drawVolume_L += incrementalDrawVolume_L; ++elapsedTime_min; } - double avgCyleDrawVolume_L = drawVolume_L / static_cast(numCycles); - double avgCyleTime_min = elapsedTime_min / static_cast(numCycles); - double avgDrawTime_min = totalDrawTime_min / static_cast(numCycles); - double avgHeatingTime_min = totalHeatingTime_min / static_cast(numCycles); - double hourlyDrawVolume_L = (60. / avgCyleTime_min) * avgCyleDrawVolume_L; - // - if (hourlyDrawVolume_L < GAL_TO_L(18.)) + if (totalDrawVolume_L < GAL_TO_L(18.)) { - usage = Usage::VerySmall; + standardTestSummary.usage = Usage::VerySmall; } - else if (hourlyDrawVolume_L < GAL_TO_L(51.)) + else if (totalDrawVolume_L < GAL_TO_L(51.)) { - usage = Usage::Low; + standardTestSummary.usage = Usage::Low; } - else if (hourlyDrawVolume_L < GAL_TO_L(75.)) + else if (totalDrawVolume_L < GAL_TO_L(75.)) { - usage = Usage::Medium; + standardTestSummary.usage = Usage::Medium; } else { - usage = Usage::High; + standardTestSummary.usage = Usage::High; } return true; } //----------------------------------------------------------------------------- -/// @brief Calculates the uniform energy factor (UEF) +/// @brief Performs standard 24-hr test /// @note see https://www.regulations.gov/document/EERE-2019-BT-TP-0032-0058 -/// @param[in] usage Specification of draw pattern -/// @param[out] UEF Result of calculation +/// @param[in/out] standardTestSummary specifies usage on input, test metrics on output +/// @param[in] setpointT_C setpoint temperature (optional) /// @return true (success), false (failure). //----------------------------------------------------------------------------- -bool HPWH::runDailyTest(const Usage usage, - DailyTestSummary& dailyTestSummary, +bool HPWH::run24hrTest(StandardTestSummary& standardTestSummary, const double setpointT_C /* = 51.7 */) { // select the draw pattern based on usage DrawPattern* drawPattern = nullptr; - switch (usage) + switch (standardTestSummary.usage) { case Usage::VerySmall: { @@ -5674,9 +5732,13 @@ bool HPWH::runDailyTest(const Usage usage, } } + if (!prepForTest(standardTestSummary)) + { + return false; + } + // idle for 1 hr int preTime_min = 0; bool heatersAreOn = false; - // 1-hr initiation while ((preTime_min < 60) || heatersAreOn) { if (runOneStep(inletT_C, // inlet water temperature (C) @@ -5698,9 +5760,6 @@ bool HPWH::runDailyTest(const Usage usage, heatersAreOn |= heatSource.isEngaged(); } - // std::cout << preTime_min << ": " << getTankTemp_C() << ", " << (heatersAreOn? "On": - // "Off") << "\n"; - ++preTime_min; } @@ -5828,10 +5887,10 @@ bool HPWH::runDailyTest(const Usage usage, } // find the "Recovery Efficiency" (6.3.3) - dailyTestSummary.recoveryEfficiency = 0.; + standardTestSummary.recoveryEfficiency = 0.; if (firstRecoveryUsedEnergy_kJ > 0.) { - dailyTestSummary.recoveryEfficiency = recoveryHeatingEnergy_kJ / firstRecoveryUsedEnergy_kJ; + standardTestSummary.recoveryEfficiency = recoveryHeatingEnergy_kJ / firstRecoveryUsedEnergy_kJ; } // find the standard daily heating energy @@ -5843,79 +5902,79 @@ bool HPWH::runDailyTest(const Usage usage, dailyHeatCapacity_kJperC * (standardSetpointT_C - standardInletT_C); // find the "Daily Water Heating Energy Consumption (Qd)" (6.3.5) - dailyTestSummary.dailyHeatingEnergyConsumption_kJ = dailyUsedEnergy_kJ; - if (dailyTestSummary.recoveryEfficiency > 0.) + standardTestSummary.dailyHeatingEnergyConsumption_kJ = dailyUsedEnergy_kJ; + if (standardTestSummary.recoveryEfficiency > 0.) { double tankContentMass_kg = DENSITYWATER_kgperL * tankVolume_L; double tankHeatCapacity_kJperC = CPWATER_kJperkgC * tankContentMass_kg; double finalTankT_C = tankT_C; - dailyTestSummary.dailyHeatingEnergyConsumption_kJ -= tankHeatCapacity_kJperC * + standardTestSummary.dailyHeatingEnergyConsumption_kJ -= tankHeatCapacity_kJperC * (finalTankT_C - initialTankT_C) / - dailyTestSummary.recoveryEfficiency; + standardTestSummary.recoveryEfficiency; } // find the "Adjusted Daily Water Heating Energy Consumption (Qda)" (6.3.6a) // same as above, because simulation induces no change in ambient temperature - dailyTestSummary.adjustedDailyWaterHeatingEnergyConsumption_kJ = - dailyTestSummary.dailyHeatingEnergyConsumption_kJ; + standardTestSummary.adjustedDailyWaterHeatingEnergyConsumption_kJ = + standardTestSummary.dailyHeatingEnergyConsumption_kJ; // find the "Energy Used to Heat Water (Q_HW)" (6.3.6a) - dailyTestSummary.energyUsedToHeatWater_kJ = 0.; - if (dailyTestSummary.recoveryEfficiency > 0.) + standardTestSummary.energyUsedToHeatWater_kJ = 0.; + if (standardTestSummary.recoveryEfficiency > 0.) { - dailyTestSummary.energyUsedToHeatWater_kJ = - dailyHeatingEnergy_kJ / dailyTestSummary.recoveryEfficiency; + standardTestSummary.energyUsedToHeatWater_kJ = + dailyHeatingEnergy_kJ / standardTestSummary.recoveryEfficiency; } // find the "Standard Energy Used to Heat Water (Q_HW,T)" (6.3.6b) - dailyTestSummary.standardEnergyUsedToHeatWater_kJ = 0.; - if (dailyTestSummary.recoveryEfficiency > 0.) + standardTestSummary.standardEnergyUsedToHeatWater_kJ = 0.; + if (standardTestSummary.recoveryEfficiency > 0.) { double removedMass_kg = DENSITYWATER_kgperL * dailyRemovedVolume_L; double removedHeatCapacity_kJperC = CPWATER_kJperkgC * removedMass_kg; double standardRemovedEnergy_kJ = removedHeatCapacity_kJperC * (standardSetpointT_C - standardInletT_C); - dailyTestSummary.standardEnergyUsedToHeatWater_kJ = - standardRemovedEnergy_kJ / dailyTestSummary.recoveryEfficiency; + standardTestSummary.standardEnergyUsedToHeatWater_kJ = + standardRemovedEnergy_kJ / standardTestSummary.recoveryEfficiency; } // add to the adjusted daily water heating energy consumption (p. 40487) - double energyUsedToHeatWaterDifference_kJ = dailyTestSummary.standardEnergyUsedToHeatWater_kJ - - dailyTestSummary.energyUsedToHeatWater_kJ; - dailyTestSummary.adjustedDailyWaterHeatingEnergyConsumption_kJ += + double energyUsedToHeatWaterDifference_kJ = standardTestSummary.standardEnergyUsedToHeatWater_kJ - + standardTestSummary.energyUsedToHeatWater_kJ; + standardTestSummary.adjustedDailyWaterHeatingEnergyConsumption_kJ += energyUsedToHeatWaterDifference_kJ; // find the "Modified Daily Water Heating Energy Consumption (Qdm = Qda - QHWD) (p. 40487) // note: same as Q_HW,T - dailyTestSummary.modifiedDailyWaterHeatingEnergyConsumption_kJ = - dailyTestSummary.adjustedDailyWaterHeatingEnergyConsumption_kJ - + standardTestSummary.modifiedDailyWaterHeatingEnergyConsumption_kJ = + standardTestSummary.adjustedDailyWaterHeatingEnergyConsumption_kJ - energyUsedToHeatWaterDifference_kJ; // find the "Uniform Energy Factor" (6.4.4) - dailyTestSummary.UEF = 0.; - if (dailyTestSummary.modifiedDailyWaterHeatingEnergyConsumption_kJ > 0.) + standardTestSummary.UEF = 0.; + if (standardTestSummary.modifiedDailyWaterHeatingEnergyConsumption_kJ > 0.) { - dailyTestSummary.UEF = standardDailyHeatingEnergy_kJ / - dailyTestSummary.modifiedDailyWaterHeatingEnergyConsumption_kJ; + standardTestSummary.UEF = standardDailyHeatingEnergy_kJ / + standardTestSummary.modifiedDailyWaterHeatingEnergyConsumption_kJ; } // find the "Annual Energy Consumption" (6.4.5) - dailyTestSummary.annualEnergyConsumption_kJ = 0.; - if (dailyTestSummary.UEF > 0.) + standardTestSummary.annualEnergyConsumption_kJ = 0.; + if (standardTestSummary.UEF > 0.) { constexpr double days_per_year = 365.; const double nominalDifferenceT_C = F_TO_C(67.); - dailyTestSummary.annualEnergyConsumption_kJ = - days_per_year * dailyHeatCapacity_kJperC * nominalDifferenceT_C / dailyTestSummary.UEF; + standardTestSummary.annualEnergyConsumption_kJ = + days_per_year * dailyHeatCapacity_kJperC * nominalDifferenceT_C / standardTestSummary.UEF; } // find the "Annual Electrical Energy Consumption" (6.4.6) - dailyTestSummary.annualElectricalEnergyConsumption_kJ = 0.; + standardTestSummary.annualElectricalEnergyConsumption_kJ = 0.; if (dailyUsedEnergy_kJ > 0.) { - dailyTestSummary.annualElectricalEnergyConsumption_kJ = + standardTestSummary.annualElectricalEnergyConsumption_kJ = (dailyUsedElectricalEnergy_kJ / dailyUsedEnergy_kJ) * - dailyTestSummary.annualEnergyConsumption_kJ; + standardTestSummary.annualEnergyConsumption_kJ; } return true; diff --git a/src/HPWH.hh b/src/HPWH.hh index 0c81cef3..96734805 100644 --- a/src/HPWH.hh +++ b/src/HPWH.hh @@ -947,7 +947,7 @@ class HPWH /// Addition of extra heat handled separately from normal heat sources void addExtraHeatAboveNode(double qAdd_kJ, const int nodeNum); - /// Draw patterns corresponding to ratings for UEF calculation + /// designations to determine draw pattern in 24-hr test enum class Usage { VerySmall, @@ -956,13 +956,8 @@ class HPWH High }; - - bool prepForTest(); - - /// Determine usage using the first-hour rating method - bool findUsageFromFirstHourRating(HPWH::Usage &usage,const double setpointT_C = 51.7); - - struct DailyTestSummary + /// collection of information derived from standard test + struct StandardTestSummary { double UEF; double recoveryEfficiency; @@ -973,11 +968,22 @@ class HPWH double standardEnergyUsedToHeatWater_kJ; double annualElectricalEnergyConsumption_kJ; double annualEnergyConsumption_kJ; + Usage usage; + bool qualifies = true; + + static double consumerHPWH_maxPower_kW; }; + /// perform a draw/heat cycle to prepare for test + bool prepForTest(StandardTestSummary& standardTestSummary); + + /// determine usage using the first-hour rating method + bool findUsageFromFirstHourRating(StandardTestSummary& standardTestSummary,const double setpointT_C = 51.7); + /// run 24-hr draw pattern - bool runDailyTest(const Usage usage, DailyTestSummary& dailyTestSummary, const double setpointT_C = 51.7); + bool run24hrTest(StandardTestSummary& standardTestSummary, const double setpointT_C = 51.7); + /// specific information for a single draw struct Draw { double startTime_min; @@ -994,8 +1000,10 @@ class HPWH } }; + /// sequence of draws in pattern typedef std::vector DrawPattern; + /// standard draw patterns static DrawPattern verySmallUsage; static DrawPattern lowUsage; static DrawPattern mediumUsage; diff --git a/test/testCalcUEF.cc b/test/testCalcUEF.cc index 0aa70c3a..fd15bcaa 100644 --- a/test/testCalcUEF.cc +++ b/test/testCalcUEF.cc @@ -6,10 +6,9 @@ #include -/* Evaluate UEF based on simulations using standard profiles */ -static bool testCalcMetrics(const std::string& sModelName, - HPWH::Usage& usage, - HPWH::DailyTestSummary& dailyTestSummary) +/* Measure metrics based on simulations using standard profiles */ +static bool testMeasureMetrics(const std::string& sModelName, + HPWH::StandardTestSummary& standardTestSummary) { HPWH hpwh; @@ -19,16 +18,17 @@ static bool testCalcMetrics(const std::string& sModelName, return false; } - if (!hpwh.findUsageFromFirstHourRating(usage)) + if (!hpwh.findUsageFromFirstHourRating(standardTestSummary)) + { return false; + } - return hpwh.runDailyTest(usage, dailyTestSummary); + return hpwh.run24hrTest(standardTestSummary); } int main(int argc, char* argv[]) { - HPWH::Usage usage; - HPWH::DailyTestSummary dailyTestSummary; + HPWH::StandardTestSummary standardTestSummary; bool validNumArgs = false; bool runUnitTests = false; @@ -55,13 +55,15 @@ int main(int argc, char* argv[]) if (runUnitTests) { - ASSERTTRUE(testCalcMetrics("AquaThermAire", usage, dailyTestSummary)); - ASSERTTRUE(usage == HPWH::Usage::High); - ASSERTTRUE(cmpd(dailyTestSummary.UEF, 2.7540)); + ASSERTTRUE(testMeasureMetrics("AquaThermAire", standardTestSummary)); + ASSERTTRUE(standardTestSummary.qualifies ); + ASSERTTRUE(standardTestSummary.usage == HPWH::Usage::Medium); + ASSERTTRUE(cmpd(standardTestSummary.UEF, 2.6326)); - ASSERTTRUE(testCalcMetrics("AOSmithHPTS50", usage, dailyTestSummary)); - ASSERTTRUE(usage == HPWH::Usage::Medium); - ASSERTTRUE(cmpd(dailyTestSummary.UEF, 2.6290)); + ASSERTTRUE(testMeasureMetrics("AOSmithHPTS50", standardTestSummary)); + ASSERTTRUE(standardTestSummary.qualifies ); + ASSERTTRUE(standardTestSummary.usage == HPWH::Usage::Low); + ASSERTTRUE(cmpd(standardTestSummary.UEF, 4.4914)); return 0; } @@ -111,53 +113,65 @@ int main(int argc, char* argv[]) std::cout << "Spec type: " << sPresetOrFile << "\n"; std::cout << "Model name: " << sModelName << "\n"; - if (hpwh.findUsageFromFirstHourRating(usage)) + if (hpwh.findUsageFromFirstHourRating(standardTestSummary)) { - std::string sUsage = ""; - switch (usage) - { - case HPWH::Usage::VerySmall: - { - sUsage = "Very Small"; - break; - } - case HPWH::Usage::Low: + if (standardTestSummary.qualifies) { - sUsage = "Low"; - break; + std::string sUsage = ""; + switch (standardTestSummary.usage) + { + case HPWH::Usage::VerySmall: + { + sUsage = "Very Small"; + break; + } + case HPWH::Usage::Low: + { + sUsage = "Low"; + break; + } + case HPWH::Usage::Medium: + { + sUsage = "Medium"; + break; + } + case HPWH::Usage::High: + { + sUsage = "High"; + break; + } + } + std::cout << "\tUsage: " << sUsage << "\n"; } - case HPWH::Usage::Medium: - { - sUsage = "Medium"; - break; - } - case HPWH::Usage::High: + else { - sUsage = "High"; - break; + std::cout << "\tDoes not qualify as consumer water heater.\n"; } - } - std::cout << "\tUsage: " << sUsage << "\n"; - if (hpwh.runDailyTest(usage, dailyTestSummary)) + if (hpwh.run24hrTest(standardTestSummary)) { - std::cout << "\tRecovery Efficiency: " << dailyTestSummary.recoveryEfficiency << "\n"; - std::cout << "\tUEF: " << dailyTestSummary.UEF << "\n"; + + std::cout << "\tRecovery Efficiency: " << standardTestSummary.recoveryEfficiency + << "\n"; + std::cout << "\tUEF: " << standardTestSummary.UEF << "\n"; std::cout << "\tAdjusted Daily Water Heating Energy Consumption (kWh): " - << KJ_TO_KWH(dailyTestSummary.adjustedDailyWaterHeatingEnergyConsumption_kJ) << "\n"; + << KJ_TO_KWH( + standardTestSummary.adjustedDailyWaterHeatingEnergyConsumption_kJ) + << "\n"; std::cout << "\tAnnual Electrical Energy Consumption (kWh): " - << KJ_TO_KWH(dailyTestSummary.annualElectricalEnergyConsumption_kJ) << "\n"; + << KJ_TO_KWH(standardTestSummary.annualElectricalEnergyConsumption_kJ) + << "\n"; std::cout << "\tAnnual Energy Consumption (kWh): " - << KJ_TO_KWH(dailyTestSummary.annualEnergyConsumption_kJ) << "\n"; + << KJ_TO_KWH(standardTestSummary.annualEnergyConsumption_kJ) << "\n"; } else { - std::cout << "Unable to determine efficiency metrics.\n"; + std::cout << "Unable to complete 24-hr test.\n"; } } else { - std::cout << "Unable to determine first-hour rating.\n"; + std::cout << "Unable to complete first-hour rating test.\n"; } return 0; From a045e8c102ba559704e38087434e974c75bc1044 Mon Sep 17 00:00:00 2001 From: Phil Ahrenkiel Date: Wed, 10 Jan 2024 13:40:43 -0700 Subject: [PATCH 13/37] Format. --- src/HPWH.cc | 42 ++++++++++++++++++++++++------------------ src/HPWH.hh | 9 +++++---- test/testCalcUEF.cc | 11 ++++++++--- 3 files changed, 37 insertions(+), 25 deletions(-) diff --git a/src/HPWH.cc b/src/HPWH.cc index 732904ca..87aeaffe 100644 --- a/src/HPWH.cc +++ b/src/HPWH.cc @@ -5504,7 +5504,8 @@ bool HPWH::prepForTest(StandardTestSummary& standardTestSummary) /// @param[in] setpointT_C setpoint temperature (optional) /// @return true (success), false (failure). //----------------------------------------------------------------------------- -bool HPWH::findUsageFromFirstHourRating(StandardTestSummary& standardTestSummary, const double setpointT_C /* = 51.7 */) +bool HPWH::findUsageFromFirstHourRating(StandardTestSummary& standardTestSummary, + const double setpointT_C /* = 51.7 */) { double flowRate_Lper_min = GAL_TO_L(3.); if (tankVolume_L < GAL_TO_L(20.)) @@ -5582,16 +5583,18 @@ bool HPWH::findUsageFromFirstHourRating(StandardTestSummary& standardTestSummary sumOutletVolumeT_LC += incrementalDrawVolume_L * outletTemp_C; maxOutletT_C = std::max(outletTemp_C, maxOutletT_C); - if (outletTemp_C < maxOutletT_C - dF_TO_dC(15.)) // outletT has dropped by 15 degF below max T + if (outletTemp_C < + maxOutletT_C - dF_TO_dC(15.)) // outletT has dropped by 15 degF below max T { avgOutletT_C = sumOutletVolumeT_LC / sumOutletVolume_L; minOutletT_C = outletTemp_C; - if(elapsedTime_min >= 60) + if (elapsedTime_min >= 60) { double fac = 1; if (!firstDraw) { - fac = (avgOutletT_C - prevMinOutletT_C) / (prevAvgOutletT_C - prevMinOutletT_C); + fac = (avgOutletT_C - prevMinOutletT_C) / + (prevAvgOutletT_C - prevMinOutletT_C); } totalDrawVolume_L += fac * drawVolume_L; done = true; @@ -5608,8 +5611,7 @@ bool HPWH::findUsageFromFirstHourRating(StandardTestSummary& standardTestSummary prevMinOutletT_C = minOutletT_C; ++step; } - - } + } break; } @@ -5624,8 +5626,9 @@ bool HPWH::findUsageFromFirstHourRating(StandardTestSummary& standardTestSummary case 2: // heating { - if ((tankT_C > maxTankT_C) && - isHeating && (elapsedTime_min < 60)) // has not reached maxTankT, heat is on, and has not reached 1 hr + if ((tankT_C > maxTankT_C) && isHeating && + (elapsedTime_min < + 60)) // has not reached maxTankT, heat is on, and has not reached 1 hr { maxTankT_C = std::max(tankT_C, maxTankT_C); } @@ -5687,7 +5690,7 @@ bool HPWH::findUsageFromFirstHourRating(StandardTestSummary& standardTestSummary /// @return true (success), false (failure). //----------------------------------------------------------------------------- bool HPWH::run24hrTest(StandardTestSummary& standardTestSummary, - const double setpointT_C /* = 51.7 */) + const double setpointT_C /* = 51.7 */) { // select the draw pattern based on usage DrawPattern* drawPattern = nullptr; @@ -5890,7 +5893,8 @@ bool HPWH::run24hrTest(StandardTestSummary& standardTestSummary, standardTestSummary.recoveryEfficiency = 0.; if (firstRecoveryUsedEnergy_kJ > 0.) { - standardTestSummary.recoveryEfficiency = recoveryHeatingEnergy_kJ / firstRecoveryUsedEnergy_kJ; + standardTestSummary.recoveryEfficiency = + recoveryHeatingEnergy_kJ / firstRecoveryUsedEnergy_kJ; } // find the standard daily heating energy @@ -5908,9 +5912,9 @@ bool HPWH::run24hrTest(StandardTestSummary& standardTestSummary, double tankContentMass_kg = DENSITYWATER_kgperL * tankVolume_L; double tankHeatCapacity_kJperC = CPWATER_kJperkgC * tankContentMass_kg; double finalTankT_C = tankT_C; - standardTestSummary.dailyHeatingEnergyConsumption_kJ -= tankHeatCapacity_kJperC * - (finalTankT_C - initialTankT_C) / - standardTestSummary.recoveryEfficiency; + standardTestSummary.dailyHeatingEnergyConsumption_kJ -= + tankHeatCapacity_kJperC * (finalTankT_C - initialTankT_C) / + standardTestSummary.recoveryEfficiency; } // find the "Adjusted Daily Water Heating Energy Consumption (Qda)" (6.3.6a) @@ -5939,8 +5943,9 @@ bool HPWH::run24hrTest(StandardTestSummary& standardTestSummary, } // add to the adjusted daily water heating energy consumption (p. 40487) - double energyUsedToHeatWaterDifference_kJ = standardTestSummary.standardEnergyUsedToHeatWater_kJ - - standardTestSummary.energyUsedToHeatWater_kJ; + double energyUsedToHeatWaterDifference_kJ = + standardTestSummary.standardEnergyUsedToHeatWater_kJ - + standardTestSummary.energyUsedToHeatWater_kJ; standardTestSummary.adjustedDailyWaterHeatingEnergyConsumption_kJ += energyUsedToHeatWaterDifference_kJ; @@ -5955,7 +5960,7 @@ bool HPWH::run24hrTest(StandardTestSummary& standardTestSummary, if (standardTestSummary.modifiedDailyWaterHeatingEnergyConsumption_kJ > 0.) { standardTestSummary.UEF = standardDailyHeatingEnergy_kJ / - standardTestSummary.modifiedDailyWaterHeatingEnergyConsumption_kJ; + standardTestSummary.modifiedDailyWaterHeatingEnergyConsumption_kJ; } // find the "Annual Energy Consumption" (6.4.5) @@ -5964,8 +5969,9 @@ bool HPWH::run24hrTest(StandardTestSummary& standardTestSummary, { constexpr double days_per_year = 365.; const double nominalDifferenceT_C = F_TO_C(67.); - standardTestSummary.annualEnergyConsumption_kJ = - days_per_year * dailyHeatCapacity_kJperC * nominalDifferenceT_C / standardTestSummary.UEF; + standardTestSummary.annualEnergyConsumption_kJ = days_per_year * dailyHeatCapacity_kJperC * + nominalDifferenceT_C / + standardTestSummary.UEF; } // find the "Annual Electrical Energy Consumption" (6.4.6) diff --git a/src/HPWH.hh b/src/HPWH.hh index 96734805..f047492d 100644 --- a/src/HPWH.hh +++ b/src/HPWH.hh @@ -974,11 +974,12 @@ class HPWH static double consumerHPWH_maxPower_kW; }; - /// perform a draw/heat cycle to prepare for test - bool prepForTest(StandardTestSummary& standardTestSummary); + /// perform a draw/heat cycle to prepare for test + bool prepForTest(StandardTestSummary& standardTestSummary); - /// determine usage using the first-hour rating method - bool findUsageFromFirstHourRating(StandardTestSummary& standardTestSummary,const double setpointT_C = 51.7); + /// determine usage using the first-hour rating method + bool findUsageFromFirstHourRating(StandardTestSummary& standardTestSummary, + const double setpointT_C = 51.7); /// run 24-hr draw pattern bool run24hrTest(StandardTestSummary& standardTestSummary, const double setpointT_C = 51.7); diff --git a/test/testCalcUEF.cc b/test/testCalcUEF.cc index fd15bcaa..569b9b37 100644 --- a/test/testCalcUEF.cc +++ b/test/testCalcUEF.cc @@ -8,7 +8,7 @@ /* Measure metrics based on simulations using standard profiles */ static bool testMeasureMetrics(const std::string& sModelName, - HPWH::StandardTestSummary& standardTestSummary) + HPWH::StandardTestSummary& standardTestSummary) { HPWH hpwh; @@ -56,15 +56,20 @@ int main(int argc, char* argv[]) if (runUnitTests) { ASSERTTRUE(testMeasureMetrics("AquaThermAire", standardTestSummary)); - ASSERTTRUE(standardTestSummary.qualifies ); + ASSERTTRUE(standardTestSummary.qualifies); ASSERTTRUE(standardTestSummary.usage == HPWH::Usage::Medium); ASSERTTRUE(cmpd(standardTestSummary.UEF, 2.6326)); ASSERTTRUE(testMeasureMetrics("AOSmithHPTS50", standardTestSummary)); - ASSERTTRUE(standardTestSummary.qualifies ); + ASSERTTRUE(standardTestSummary.qualifies); ASSERTTRUE(standardTestSummary.usage == HPWH::Usage::Low); ASSERTTRUE(cmpd(standardTestSummary.UEF, 4.4914)); + ASSERTTRUE(testMeasureMetrics("AOSmithHPTS80", standardTestSummary)); + ASSERTTRUE(standardTestSummary.qualifies); + ASSERTTRUE(standardTestSummary.usage == HPWH::Usage::High); + ASSERTTRUE(cmpd(standardTestSummary.UEF, 3.5230)); + return 0; } From 5178988afd97f43e7622ef1bfff9f4457e14df25 Mon Sep 17 00:00:00 2001 From: Phil Ahrenkiel Date: Wed, 10 Jan 2024 14:39:28 -0700 Subject: [PATCH 14/37] Check if qualified. --- src/HPWH.cc | 78 ++++++----------- src/HPWH.hh | 18 ++-- test/CMakeLists.txt | 6 +- .../{testCalcUEF.cc => testMeasureMetrics.cc} | 87 ++++++++++--------- 4 files changed, 81 insertions(+), 108 deletions(-) rename test/{testCalcUEF.cc => testMeasureMetrics.cc} (66%) diff --git a/src/HPWH.cc b/src/HPWH.cc index 87aeaffe..db4cda3d 100644 --- a/src/HPWH.cc +++ b/src/HPWH.cc @@ -64,8 +64,6 @@ const double HPWH::MAXOUTLET_R410A = F_TO_C(140.); const double HPWH::MAXOUTLET_R744 = F_TO_C(190.); const double HPWH::MINSINGLEPASSLIFT = dF_TO_dC(15.); -double HPWH::StandardTestSummary::consumerHPWH_maxPower_kW = 6.; // EERE–2019–BT–TP–0032, p. 40415 - HPWH::DrawPattern HPWH::verySmallUsage = { {HM_TO_MIN(0, 00), 7.6, 3.8}, {HM_TO_MIN(1, 00), 3.8, 3.8}, @@ -5404,18 +5402,16 @@ int HPWH::HPWHinit_file(string configFile) //----------------------------------------------------------------------------- /// @brief Performs a draw/heat cycle to prep for test -/// @note Flags if model is not qualified for test -/// @param[in/out] standardTestSummary contains usage on output /// @return true (success), false (failure). //----------------------------------------------------------------------------- -bool HPWH::prepForTest(StandardTestSummary& standardTestSummary) +bool HPWH::prepForTest() { double flowRate_Lper_min = GAL_TO_L(3.); if (tankVolume_L < GAL_TO_L(20.)) flowRate_Lper_min = GAL_TO_L(1.5); - constexpr double inletT_C = 14.4; // p. 40433 - constexpr double ambientT_C = 19.7; // p. 40435 + constexpr double inletT_C = 14.4; // EERE-2019-BT-TP-0032-0058, p. 40433 + constexpr double ambientT_C = 19.7; // EERE-2019-BT-TP-0032-0058, p. 40435 constexpr double externalT_C = 19.7; DRMODES drMode = DR_ALLOW; @@ -5478,41 +5474,27 @@ bool HPWH::prepForTest(StandardTestSummary& standardTestSummary) return false; } - if (isHeating) // check whether power is below limit for consumer HPWH - { - double qInElectrical_kJ = 0.; - for (int iHS = 0; iHS < getNumHeatSources(); iHS++) - { - qInElectrical_kJ += getNthHeatSourceEnergyInput(iHS, UNITS_KJ); - } - double electricalPower_kW = qInElectrical_kJ / sec_per_min; - if (electricalPower_kW > StandardTestSummary::consumerHPWH_maxPower_kW) - { - standardTestSummary.qualifies = false; - } - } - ++time_min; } return true; } //----------------------------------------------------------------------------- -/// @brief Finds usage prior to 24-hr test -/// @note Determines usage; flags if model is not qualified +/// @brief Find usage category prior to 24-hr test +/// @note Determines usage category for 24-hr test /// @param[in/out] standardTestSummary contains usage on output /// @param[in] setpointT_C setpoint temperature (optional) /// @return true (success), false (failure). //----------------------------------------------------------------------------- -bool HPWH::findUsageFromFirstHourRating(StandardTestSummary& standardTestSummary, +bool HPWH::findUsageFromFirstHourRating(Usage &usage, const double setpointT_C /* = 51.7 */) { double flowRate_Lper_min = GAL_TO_L(3.); if (tankVolume_L < GAL_TO_L(20.)) flowRate_Lper_min = GAL_TO_L(1.5); - constexpr double inletT_C = 14.4; // p. 40433 - constexpr double ambientT_C = 19.7; // p. 40435 + constexpr double inletT_C = 14.4; // EERE-2019-BT-TP-0032-0058, p. 40433 + constexpr double ambientT_C = 19.7; // EERE-2019-BT-TP-0032-0058, p. 40435 constexpr double externalT_C = 19.7; if (!isSetpointFixed()) @@ -5543,10 +5525,11 @@ bool HPWH::findUsageFromFirstHourRating(StandardTestSummary& standardTestSummary bool done = false; int step = 0; - if (!prepForTest(standardTestSummary)) + if (!prepForTest()) { return false; } + bool firstDraw = true; isDrawing = true; maxOutletT_C = 0.; @@ -5628,7 +5611,7 @@ bool HPWH::findUsageFromFirstHourRating(StandardTestSummary& standardTestSummary { if ((tankT_C > maxTankT_C) && isHeating && (elapsedTime_min < - 60)) // has not reached maxTankT, heat is on, and has not reached 1 hr + 60)) // has not reached maxTankT, heat is on, and less than 1 hr has elpased { maxTankT_C = std::max(tankT_C, maxTankT_C); } @@ -5643,20 +5626,6 @@ bool HPWH::findUsageFromFirstHourRating(StandardTestSummary& standardTestSummary } } - if (isHeating) // check whether power is below limit for consumer HPWH - { - double qInElectrical_kJ = 0.; - for (int iHS = 0; iHS < getNumHeatSources(); iHS++) - { - qInElectrical_kJ += getNthHeatSourceEnergyInput(iHS, UNITS_KJ); - } - double electricalPower_kW = qInElectrical_kJ / sec_per_min; - if (electricalPower_kW > StandardTestSummary::consumerHPWH_maxPower_kW) - { - standardTestSummary.qualifies = false; - } - } - drawVolume_L += incrementalDrawVolume_L; ++elapsedTime_min; } @@ -5664,19 +5633,19 @@ bool HPWH::findUsageFromFirstHourRating(StandardTestSummary& standardTestSummary // if (totalDrawVolume_L < GAL_TO_L(18.)) { - standardTestSummary.usage = Usage::VerySmall; + usage = Usage::VerySmall; } else if (totalDrawVolume_L < GAL_TO_L(51.)) { - standardTestSummary.usage = Usage::Low; + usage = Usage::Low; } else if (totalDrawVolume_L < GAL_TO_L(75.)) { - standardTestSummary.usage = Usage::Medium; + usage = Usage::Medium; } else { - standardTestSummary.usage = Usage::High; + usage = Usage::High; } return true; @@ -5689,12 +5658,12 @@ bool HPWH::findUsageFromFirstHourRating(StandardTestSummary& standardTestSummary /// @param[in] setpointT_C setpoint temperature (optional) /// @return true (success), false (failure). //----------------------------------------------------------------------------- -bool HPWH::run24hrTest(StandardTestSummary& standardTestSummary, +bool HPWH::run24hrTest(const Usage &usage, StandardTestSummary& standardTestSummary, const double setpointT_C /* = 51.7 */) { // select the draw pattern based on usage DrawPattern* drawPattern = nullptr; - switch (standardTestSummary.usage) + switch (usage) { case Usage::VerySmall: { @@ -5722,8 +5691,8 @@ bool HPWH::run24hrTest(StandardTestSummary& standardTestSummary, return false; } - constexpr double inletT_C = 14.4; // p. 40433 - constexpr double ambientT_C = 19.7; // p. 40435 + constexpr double inletT_C = 14.4; // EERE-2019-BT-TP-0032-0058, p. 40433 + constexpr double ambientT_C = 19.7; // EERE-2019-BT-TP-0032-0058, p. 40435 constexpr double externalT_C = 19.7; constexpr DRMODES drMode = DR_ALLOW; @@ -5735,10 +5704,11 @@ bool HPWH::run24hrTest(StandardTestSummary& standardTestSummary, } } - if (!prepForTest(standardTestSummary)) + if (!prepForTest()) { return false; } + // idle for 1 hr int preTime_min = 0; bool heatersAreOn = false; @@ -5889,6 +5859,12 @@ bool HPWH::run24hrTest(StandardTestSummary& standardTestSummary, dailyUsedEnergy_kJ += drawUsedFossilFuelEnergy_kJ + drawUsedElectricalEnergy_kJ; } + // require heating during 24-hr test for unit to qualify as consumer water heater + if (hasHeated) + { + standardTestSummary.qualifies = true; + } + // find the "Recovery Efficiency" (6.3.3) standardTestSummary.recoveryEfficiency = 0.; if (firstRecoveryUsedEnergy_kJ > 0.) diff --git a/src/HPWH.hh b/src/HPWH.hh index f047492d..daee53d3 100644 --- a/src/HPWH.hh +++ b/src/HPWH.hh @@ -947,7 +947,7 @@ class HPWH /// Addition of extra heat handled separately from normal heat sources void addExtraHeatAboveNode(double qAdd_kJ, const int nodeNum); - /// designations to determine draw pattern in 24-hr test + /// draw-pattern designations for 24-hr test enum class Usage { VerySmall, @@ -968,21 +968,17 @@ class HPWH double standardEnergyUsedToHeatWater_kJ; double annualElectricalEnergyConsumption_kJ; double annualEnergyConsumption_kJ; - Usage usage; - bool qualifies = true; - - static double consumerHPWH_maxPower_kW; + bool qualifies = false; }; /// perform a draw/heat cycle to prepare for test - bool prepForTest(StandardTestSummary& standardTestSummary); + bool prepForTest(); - /// determine usage using the first-hour rating method - bool findUsageFromFirstHourRating(StandardTestSummary& standardTestSummary, - const double setpointT_C = 51.7); + /// determine usage based on the first-hour rating method + bool findUsageFromFirstHourRating(Usage &usage, const double setpointT_C = 51.7); - /// run 24-hr draw pattern - bool run24hrTest(StandardTestSummary& standardTestSummary, const double setpointT_C = 51.7); + /// run 24-hr draw pattern and compute metrics + bool run24hrTest(const Usage &usage, StandardTestSummary& standardTestSummary, const double setpointT_C = 51.7); /// specific information for a single draw struct Draw diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 9518fc25..30495733 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -12,7 +12,7 @@ add_executable(testPerformanceMaps testPerformanceMaps.cc) add_executable(testStateOfChargeFcts testStateOfChargeFcts.cc) add_executable(testHeatingLogics testHeatingLogics.cc) add_executable(testEnergyBalance testEnergyBalance.cc) -add_executable(testCalcUEF testCalcUEF.cc) +add_executable(testMeasureMetrics testMeasureMetrics.cc) set(libs libHPWHsim ${PROJECT_NAME}_common_interface) @@ -27,7 +27,7 @@ target_link_libraries(testPerformanceMaps PRIVATE ${libs}) target_link_libraries(testStateOfChargeFcts PRIVATE ${libs}) target_link_libraries(testHeatingLogics PRIVATE ${libs}) target_link_libraries(testEnergyBalance PRIVATE ${libs}) -target_link_libraries(testCalcUEF PRIVATE ${libs}) +target_link_libraries(testMeasureMetrics PRIVATE ${libs}) target_compile_features(testTool PRIVATE cxx_std_17) @@ -48,7 +48,7 @@ add_test(NAME "testPerformanceMaps" COMMAND $ $ add_test(NAME "testStateOfChargeFcts" COMMAND $ ${testArgs} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) add_test(NAME "testHeatingLogics" COMMAND $ ${testArgs} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) add_test(NAME "testEnergyBalance" COMMAND $ ${testArgs} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) -add_test(NAME "testCalcUEF" COMMAND $ ${testArgs} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) +add_test(NAME "testMeasureMetrics" COMMAND $ ${testArgs} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) #add_test(NAME "testREGoesTo99C.AOSmithCAHP120" COMMAND $ "Preset" "AOSmithCAHP120" "testREGoesTo99C" #"${CMAKE_CURRENT_BINARY_DIR}/output" WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/test/testCalcUEF.cc b/test/testMeasureMetrics.cc similarity index 66% rename from test/testCalcUEF.cc rename to test/testMeasureMetrics.cc index 569b9b37..c8228014 100644 --- a/test/testCalcUEF.cc +++ b/test/testMeasureMetrics.cc @@ -1,13 +1,14 @@ /* - * test UEF calculation + * test measure performance metrics */ #include "HPWH.hh" #include "testUtilityFcts.cc" #include -/* Measure metrics based on simulations using standard profiles */ +/* Measure metrics using 24-hr test based on model name (preset only) */ static bool testMeasureMetrics(const std::string& sModelName, + HPWH::Usage& usage, HPWH::StandardTestSummary& standardTestSummary) { HPWH hpwh; @@ -18,12 +19,12 @@ static bool testMeasureMetrics(const std::string& sModelName, return false; } - if (!hpwh.findUsageFromFirstHourRating(standardTestSummary)) + if (!hpwh.findUsageFromFirstHourRating(usage)) { return false; } - return hpwh.run24hrTest(standardTestSummary); + return hpwh.run24hrTest(usage, standardTestSummary); } int main(int argc, char* argv[]) @@ -55,19 +56,20 @@ int main(int argc, char* argv[]) if (runUnitTests) { - ASSERTTRUE(testMeasureMetrics("AquaThermAire", standardTestSummary)); + HPWH::Usage usage; + ASSERTTRUE(testMeasureMetrics("AquaThermAire", usage, standardTestSummary)); ASSERTTRUE(standardTestSummary.qualifies); - ASSERTTRUE(standardTestSummary.usage == HPWH::Usage::Medium); + ASSERTTRUE(usage == HPWH::Usage::Medium); ASSERTTRUE(cmpd(standardTestSummary.UEF, 2.6326)); - ASSERTTRUE(testMeasureMetrics("AOSmithHPTS50", standardTestSummary)); + ASSERTTRUE(testMeasureMetrics("AOSmithHPTS50", usage, standardTestSummary)); ASSERTTRUE(standardTestSummary.qualifies); - ASSERTTRUE(standardTestSummary.usage == HPWH::Usage::Low); + ASSERTTRUE(usage == HPWH::Usage::Low); ASSERTTRUE(cmpd(standardTestSummary.UEF, 4.4914)); - ASSERTTRUE(testMeasureMetrics("AOSmithHPTS80", standardTestSummary)); + ASSERTTRUE(testMeasureMetrics("AOSmithHPTS80", usage, standardTestSummary)); ASSERTTRUE(standardTestSummary.qualifies); - ASSERTTRUE(standardTestSummary.usage == HPWH::Usage::High); + ASSERTTRUE(usage == HPWH::Usage::High); ASSERTTRUE(cmpd(standardTestSummary.UEF, 3.5230)); return 0; @@ -77,9 +79,9 @@ int main(int argc, char* argv[]) { cout << "Invalid input:\n\ To run all unit tests, provide ZERO arguments.\n\ - To determine the UEF for a particular model spec, provide ONE or TWO arguments:\n\ - \t[model spec Type (i.e., Preset (default) or File)]\n\ - \t[model spec Name (i.e., Sanden80)]\n"; + To determine performance metrics for a particular model spec, provide ONE or TWO arguments:\n\ + \t[model spec Type, i.e., Preset (default) or File]\n\ + \t[model spec Name, i.e., Sanden80]\n"; exit(1); } @@ -118,44 +120,43 @@ int main(int argc, char* argv[]) std::cout << "Spec type: " << sPresetOrFile << "\n"; std::cout << "Model name: " << sModelName << "\n"; - if (hpwh.findUsageFromFirstHourRating(standardTestSummary)) + HPWH::Usage usage; + if (hpwh.findUsageFromFirstHourRating(usage)) { - if (standardTestSummary.qualifies) + std::string sUsage = ""; + switch (usage) { - std::string sUsage = ""; - switch (standardTestSummary.usage) - { - case HPWH::Usage::VerySmall: - { - sUsage = "Very Small"; - break; - } - case HPWH::Usage::Low: - { - sUsage = "Low"; - break; - } - case HPWH::Usage::Medium: - { - sUsage = "Medium"; - break; - } - case HPWH::Usage::High: - { - sUsage = "High"; - break; - } - } - std::cout << "\tUsage: " << sUsage << "\n"; + case HPWH::Usage::VerySmall: + { + sUsage = "Very Small"; + break; } - else + case HPWH::Usage::Low: + { + sUsage = "Low"; + break; + } + case HPWH::Usage::Medium: + { + sUsage = "Medium"; + break; + } + case HPWH::Usage::High: { - std::cout << "\tDoes not qualify as consumer water heater.\n"; + sUsage = "High"; + break; + } } + std::cout << "\tUsage: " << sUsage << "\n"; - if (hpwh.run24hrTest(standardTestSummary)) + if (hpwh.run24hrTest(usage, standardTestSummary)) { + if (!standardTestSummary.qualifies) + { + std::cout << "\tDoes not qualify as consumer water heater.\n"; + } + std::cout << "\tRecovery Efficiency: " << standardTestSummary.recoveryEfficiency << "\n"; std::cout << "\tUEF: " << standardTestSummary.UEF << "\n"; From bedc69c72810b12fc0e4bd57613d6d019a2826e4 Mon Sep 17 00:00:00 2001 From: Phil Ahrenkiel Date: Wed, 10 Jan 2024 15:56:13 -0700 Subject: [PATCH 15/37] Format. --- src/HPWH.cc | 6 +++--- src/HPWH.hh | 6 ++++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/HPWH.cc b/src/HPWH.cc index db4cda3d..a52271e6 100644 --- a/src/HPWH.cc +++ b/src/HPWH.cc @@ -5486,8 +5486,7 @@ bool HPWH::prepForTest() /// @param[in] setpointT_C setpoint temperature (optional) /// @return true (success), false (failure). //----------------------------------------------------------------------------- -bool HPWH::findUsageFromFirstHourRating(Usage &usage, - const double setpointT_C /* = 51.7 */) +bool HPWH::findUsageFromFirstHourRating(Usage& usage, const double setpointT_C /* = 51.7 */) { double flowRate_Lper_min = GAL_TO_L(3.); if (tankVolume_L < GAL_TO_L(20.)) @@ -5658,7 +5657,8 @@ bool HPWH::findUsageFromFirstHourRating(Usage &usage, /// @param[in] setpointT_C setpoint temperature (optional) /// @return true (success), false (failure). //----------------------------------------------------------------------------- -bool HPWH::run24hrTest(const Usage &usage, StandardTestSummary& standardTestSummary, +bool HPWH::run24hrTest(const Usage& usage, + StandardTestSummary& standardTestSummary, const double setpointT_C /* = 51.7 */) { // select the draw pattern based on usage diff --git a/src/HPWH.hh b/src/HPWH.hh index daee53d3..6c7bd39a 100644 --- a/src/HPWH.hh +++ b/src/HPWH.hh @@ -975,10 +975,12 @@ class HPWH bool prepForTest(); /// determine usage based on the first-hour rating method - bool findUsageFromFirstHourRating(Usage &usage, const double setpointT_C = 51.7); + bool findUsageFromFirstHourRating(Usage& usage, const double setpointT_C = 51.7); /// run 24-hr draw pattern and compute metrics - bool run24hrTest(const Usage &usage, StandardTestSummary& standardTestSummary, const double setpointT_C = 51.7); + bool run24hrTest(const Usage& usage, + StandardTestSummary& standardTestSummary, + const double setpointT_C = 51.7); /// specific information for a single draw struct Draw From f3bf0fed2782654a444104a3c9d0bfe9932ac2eb Mon Sep 17 00:00:00 2001 From: Phil Ahrenkiel Date: Wed, 10 Jan 2024 16:07:20 -0700 Subject: [PATCH 16/37] Small changes. --- src/HPWH.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/HPWH.cc b/src/HPWH.cc index a52271e6..b40e05f5 100644 --- a/src/HPWH.cc +++ b/src/HPWH.cc @@ -5512,11 +5512,11 @@ bool HPWH::findUsageFromFirstHourRating(Usage& usage, const double setpointT_C / double drawVolume_L = 0.; double totalDrawVolume_L = 0.; - double sumOutletVolumeT_LC = 0; - double sumOutletVolume_L = 0; + double sumOutletVolumeT_LC = 0.; + double sumOutletVolume_L = 0.; - double avgOutletT_C = 0; - double minOutletT_C = 0; + double avgOutletT_C = 0.; + double minOutletT_C = 0.; double prevAvgOutletT_C = 0.; double prevMinOutletT_C = 0.; From 5125ff4ec7be275dc7ecc39e801b2747b737feca Mon Sep 17 00:00:00 2001 From: Phil Ahrenkiel Date: Fri, 12 Jan 2024 11:21:48 -0700 Subject: [PATCH 17/37] Improve naming. --- src/HPWH.cc | 430 ++++++++++++++++++++----------------- src/HPWH.hh | 71 +++--- src/HPWHHeatSources.cc | 21 +- src/HPWHHeatingLogics.cc | 2 +- test/testMeasureMetrics.cc | 48 ++--- 5 files changed, 302 insertions(+), 270 deletions(-) diff --git a/src/HPWH.cc b/src/HPWH.cc index 3d2ed227..77224572 100644 --- a/src/HPWH.cc +++ b/src/HPWH.cc @@ -1500,51 +1500,6 @@ double HPWH::getMinOperatingTemp(UNITS units /*=UNITS_C*/) const } } -int HPWH::resetTankToSetpoint() { return setTankToTemperature(setpoint_C); } - -int HPWH::setTankToTemperature(double temp_C) { return setTankLayerTemperatures({temp_C}); } - -//----------------------------------------------------------------------------- -/// @brief Assigns new temps provided from a std::vector to tankTemps_C. -/// @param[in] setTankTemps new tank temps (arbitrary non-zero size) -/// @param[in] units temp units in setTankTemps (default = UNITS_C) -/// @return Success: 0; Failure: HPWH_ABORT -//----------------------------------------------------------------------------- -int HPWH::setTankLayerTemperatures(std::vector setTankTemps, const UNITS units) -{ - if ((units != UNITS_C) && (units != UNITS_F)) - { - if (hpwhVerbosity >= VRB_reluctant) - { - msg("Incorrect unit specification for setSetpoint. \n"); - } - return HPWH_ABORT; - } - - std::size_t numSetNodes = setTankTemps.size(); - if (numSetNodes == 0) - { - if (hpwhVerbosity >= VRB_reluctant) - { - msg("No temperatures provided.\n"); - } - return HPWH_ABORT; - } - - // convert setTankTemps to �C, if necessary - if (units == UNITS_F) - for (auto& T : setTankTemps) - T = F_TO_C(T); - - // set node temps - if (!resampleIntensive(tankTemps_C, setTankTemps)) - return HPWH_ABORT; - - return 0; -} - -void HPWH::getTankTemps(std::vector& tankTemps) { tankTemps = tankTemps_C; } - int HPWH::setAirFlowFreedom(double fanFraction) { if (fanFraction < 0 || fanFraction > 1) @@ -2464,74 +2419,6 @@ int HPWH::getNumNodes() const { return static_cast(tankTemps_C.size()); } int HPWH::getIndexTopNode() const { return getNumNodes() - 1; } -double HPWH::getTankNodeTemp(int nodeNum, UNITS units /*=UNITS_C*/) const -{ - if (tankTemps_C.empty()) - { - if (hpwhVerbosity >= VRB_reluctant) - { - msg("You have attempted to access the temperature of a tank node that does not exist. " - "\n"); - } - return double(HPWH_ABORT); - } - else - { - double result = tankTemps_C[nodeNum]; - // if (result == double(HPWH_ABORT)) { can't happen? - // return result; - // } - if (units == UNITS_C) - { - return result; - } - else if (units == UNITS_F) - { - return C_TO_F(result); - } - else - { - if (hpwhVerbosity >= VRB_reluctant) - { - msg("Incorrect unit specification for getTankNodeTemp. \n"); - } - return double(HPWH_ABORT); - } - } -} - -double HPWH::getNthSimTcouple(int iTCouple, int nTCouple, UNITS units /*=UNITS_C*/) const -{ - if (iTCouple > nTCouple || iTCouple < 1) - { - if (hpwhVerbosity >= VRB_reluctant) - { - msg("You have attempted to access a simulated thermocouple that does not exist. \n"); - } - return double(HPWH_ABORT); - } - double beginFraction = static_cast(iTCouple - 1.) / static_cast(nTCouple); - double endFraction = static_cast(iTCouple) / static_cast(nTCouple); - - double simTcoupleTemp_C = getResampledValue(tankTemps_C, beginFraction, endFraction); - if (units == UNITS_C) - { - return simTcoupleTemp_C; - } - else if (units == UNITS_F) - { - return C_TO_F(simTcoupleTemp_C); - } - else - { - if (hpwhVerbosity >= VRB_reluctant) - { - msg("Incorrect unit specification for getNthSimTcouple. \n"); - } - return double(HPWH_ABORT); - } -} - int HPWH::getNumHeatSources() const { return static_cast(heatSources.size()); } int HPWH::getCompressorIndex() const { return compressorIndex; } @@ -2775,6 +2662,78 @@ double HPWH::getTankSize(UNITS units /*=UNITS_L*/) const } } +double HPWH::getExternalVolumeHeated(UNITS units /*=UNITS_L*/) const +{ + if (units == UNITS_L) + { + return externalVolumeHeated_L; + } + else if (units == UNITS_GAL) + { + return L_TO_GAL(externalVolumeHeated_L); + } + else + { + if (hpwhVerbosity >= VRB_reluctant) + { + msg("Incorrect unit specification for getExternalVolumeHeated. \n"); + } + return double(HPWH_ABORT); + } +} + +double HPWH::getEnergyRemovedFromEnvironment(UNITS units /*=UNITS_KWH*/) const +{ + // moving heat from the space to the water is the positive direction + if (units == UNITS_KWH) + { + return energyRemovedFromEnvironment_kWh; + } + else if (units == UNITS_BTU) + { + return KWH_TO_BTU(energyRemovedFromEnvironment_kWh); + } + else if (units == UNITS_KJ) + { + return KWH_TO_KJ(energyRemovedFromEnvironment_kWh); + } + else + { + if (hpwhVerbosity >= VRB_reluctant) + { + msg("Incorrect unit specification for getEnergyRemovedFromEnvironment. \n"); + } + return double(HPWH_ABORT); + } +} + +double HPWH::getStandbyLosses(UNITS units /*=UNITS_KWH*/) const +{ + // moving heat from the water to the space is the positive direction + if (units == UNITS_KWH) + { + return standbyLosses_kWh; + } + else if (units == UNITS_BTU) + { + return KWH_TO_BTU(standbyLosses_kWh); + } + else if (units == UNITS_KJ) + { + return KWH_TO_KJ(standbyLosses_kWh); + } + else + { + if (hpwhVerbosity >= VRB_reluctant) + { + msg("Incorrect unit specification for getStandbyLosses. \n"); + } + return double(HPWH_ABORT); + } +} + +/////////////////////////////////////////////////////////////////////////////////// + double HPWH::getOutletTemp(UNITS units /*=UNITS_C*/) const { if (units == UNITS_C) @@ -2835,96 +2794,207 @@ double HPWH::getCondenserWaterOutletTemp(UNITS units /*=UNITS_C*/) const } } -double HPWH::getExternalVolumeHeated(UNITS units /*=UNITS_L*/) const +double HPWH::getTankNodeTemp(int nodeNum, UNITS units /*=UNITS_C*/) const { - if (units == UNITS_L) - { - return externalVolumeHeated_L; - } - else if (units == UNITS_GAL) + if (tankTemps_C.empty()) { - return L_TO_GAL(externalVolumeHeated_L); + if (hpwhVerbosity >= VRB_reluctant) + { + msg("You have attempted to access the temperature of a tank node that does not exist. " + "\n"); + } + return double(HPWH_ABORT); } else { - if (hpwhVerbosity >= VRB_reluctant) + double result = tankTemps_C[nodeNum]; + // if (result == double(HPWH_ABORT)) { can't happen? + // return result; + // } + if (units == UNITS_C) { - msg("Incorrect unit specification for getExternalVolumeHeated. \n"); + return result; + } + else if (units == UNITS_F) + { + return C_TO_F(result); + } + else + { + if (hpwhVerbosity >= VRB_reluctant) + { + msg("Incorrect unit specification for getTankNodeTemp. \n"); + } + return double(HPWH_ABORT); } - return double(HPWH_ABORT); } } -double HPWH::getEnergyRemovedFromEnvironment(UNITS units /*=UNITS_KWH*/) const +double HPWH::getNthSimTcouple(int iTCouple, int nTCouple, UNITS units /*=UNITS_C*/) const { - // moving heat from the space to the water is the positive direction - if (units == UNITS_KWH) + if (iTCouple > nTCouple || iTCouple < 1) { - return energyRemovedFromEnvironment_kWh; + if (hpwhVerbosity >= VRB_reluctant) + { + msg("You have attempted to access a simulated thermocouple that does not exist. \n"); + } + return double(HPWH_ABORT); } - else if (units == UNITS_BTU) + double beginFraction = static_cast(iTCouple - 1.) / static_cast(nTCouple); + double endFraction = static_cast(iTCouple) / static_cast(nTCouple); + + double simTcoupleTemp_C = getResampledValue(tankTemps_C, beginFraction, endFraction); + if (units == UNITS_C) { - return KWH_TO_BTU(energyRemovedFromEnvironment_kWh); + return simTcoupleTemp_C; } - else if (units == UNITS_KJ) + else if (units == UNITS_F) { - return KWH_TO_KJ(energyRemovedFromEnvironment_kWh); + return C_TO_F(simTcoupleTemp_C); } else { if (hpwhVerbosity >= VRB_reluctant) { - msg("Incorrect unit specification for getEnergyRemovedFromEnvironment. \n"); + msg("Incorrect unit specification for getNthSimTcouple. \n"); } return double(HPWH_ABORT); } } -double HPWH::getStandbyLosses(UNITS units /*=UNITS_KWH*/) const +double HPWH::getLocationTemp_C() const { return locationTemperature_C; } + +void HPWH::getTankTemps(std::vector& tankTemps) { tankTemps = tankTemps_C; } + +//----------------------------------------------------------------------------- +/// @brief Evaluates the tank temperature averaged uniformly +/// @param[in] nodeWeights Discrete set of weighted nodes +/// @return Tank temperature (C) +//----------------------------------------------------------------------------- +double HPWH::getTankTemp_C() const { - // moving heat from the water to the space is the positive direction - if (units == UNITS_KWH) + double totalT_C = 0.; + for (auto& T_C : tankTemps_C) { - return standbyLosses_kWh; + totalT_C += T_C; } - else if (units == UNITS_BTU) + return totalT_C / static_cast(getNumNodes()); +} + +//----------------------------------------------------------------------------- +/// @brief Evaluates the average tank temperature based on distribution. +/// @note Distribution must have positive size and be normalized. +/// @param[in] dist Discrete set of distribution values +//----------------------------------------------------------------------------- +double HPWH::getTankTemp_C(const std::vector &dist) const +{ + std::vector resampledTankTemps_C(dist.size()); + resample(resampledTankTemps_C, tankTemps_C); + + double tankT_C = 0.; + + std::size_t j = 0; + for (auto& nodeT_C : resampledTankTemps_C) { - return KWH_TO_BTU(standbyLosses_kWh); + tankT_C += dist[j] * nodeT_C; + ++j; } - else if (units == UNITS_KJ) + return tankT_C; +} + +//----------------------------------------------------------------------------- +/// @brief Evaluates the average tank temperature based on weighted logic nodes. +/// @note Logic nodes must be normalizable and are referred to the fixed size LOGIC_NODE_SIZE. +/// Node indices as associated with tank nodes as follows: +/// node # 0: bottom tank node only; +/// node # LOGIC_NODE_SIZE + 1: top node only; +/// nodes # 1..LOGIC_NODE_SIZE: resampled tank nodes. +/// @param[in] nodeWeights Discrete set of weighted nodes +/// @return Tank temperature (C) +//----------------------------------------------------------------------------- +double HPWH::getTankTemp_C(const std::vector &nodeWeights) const +{ + double sum = 0; + double totWeight = 0; + + std::vector resampledTankTemps(LOGIC_NODE_SIZE); + resample(resampledTankTemps, tankTemps_C); + + for (auto& nodeWeight : nodeWeights) { - return KWH_TO_KJ(standbyLosses_kWh); + if (nodeWeight.nodeNum == 0) + { // bottom node only + sum += tankTemps_C.front() * nodeWeight.weight; + totWeight += nodeWeight.weight; + } + else if (nodeWeight.nodeNum > LOGIC_NODE_SIZE) + { // top node only + sum += tankTemps_C.back() * nodeWeight.weight; + totWeight += nodeWeight.weight; + } + else + { // general case; sum over all weighted nodes + sum += resampledTankTemps[static_cast(nodeWeight.nodeNum - 1)] * + nodeWeight.weight; + totWeight += nodeWeight.weight; + } } - else + return sum / totWeight; +} + +//----------------------------------------------------------------------------- +/// @brief Assigns new temps provided from a std::vector to tankTemps_C. +/// @param[in] setTankTemps new tank temps (arbitrary non-zero size) +/// @param[in] units temp units in setTankTemps (default = UNITS_C) +/// @return Success: 0; Failure: HPWH_ABORT +//----------------------------------------------------------------------------- +int HPWH::setTankLayerTemperatures(std::vector setTankTemps, const UNITS units) +{ + if ((units != UNITS_C) && (units != UNITS_F)) { if (hpwhVerbosity >= VRB_reluctant) { - msg("Incorrect unit specification for getStandbyLosses. \n"); + msg("Incorrect unit specification for setSetpoint. \n"); } - return double(HPWH_ABORT); + return HPWH_ABORT; } -} -double HPWH::getTankTemp_C() const -{ - // get average tank temperature - double totalT_C = 0.; - for (auto& T_C : tankTemps_C) + std::size_t numSetNodes = setTankTemps.size(); + if (numSetNodes == 0) { - totalT_C += T_C; + if (hpwhVerbosity >= VRB_reluctant) + { + msg("No temperatures provided.\n"); + } + return HPWH_ABORT; } - return totalT_C / static_cast(getNumNodes()); + + // convert setTankTemps to �C, if necessary + if (units == UNITS_F) + for (auto& T : setTankTemps) + T = F_TO_C(T); + + // set node temps + if (!resampleIntensive(tankTemps_C, setTankTemps)) + return HPWH_ABORT; + + return 0; } +int HPWH::resetTankToSetpoint() { return setTankToTemperature(setpoint_C); } + +int HPWH::setTankToTemperature(double temp_C) { return setTankLayerTemperatures({temp_C}); } + +/////////////////////////////////////////////////////////////////////////////////// + double HPWH::getTankHeatContent_kJ() const { // returns tank heat content relative to 0 C using kJ return DENSITYWATER_kgperL * tankVolume_L * CPWATER_kJperkgC * getTankTemp_C(); } -double HPWH::getLocationTemp_C() const { return locationTemperature_C; } - int HPWH::getHPWHModel() const { return hpwhModel; } + int HPWH::getCompressorCoilConfig() const { if (!hasACompressor()) @@ -3885,36 +3955,6 @@ bool HPWH::areAllHeatSourcesOff() const return allOff; } -double HPWH::tankAvg_C(const std::vector nodeWeights) const -{ - double sum = 0; - double totWeight = 0; - - std::vector resampledTankTemps(LOGIC_NODE_SIZE); - resample(resampledTankTemps, tankTemps_C); - - for (auto& nodeWeight : nodeWeights) - { - if (nodeWeight.nodeNum == 0) - { // bottom node only - sum += tankTemps_C.front() * nodeWeight.weight; - totWeight += nodeWeight.weight; - } - else if (nodeWeight.nodeNum > LOGIC_NODE_SIZE) - { // top node only - sum += tankTemps_C.back() * nodeWeight.weight; - totWeight += nodeWeight.weight; - } - else - { // general case; sum over all weighted nodes - sum += resampledTankTemps[static_cast(nodeWeight.nodeNum - 1)] * - nodeWeight.weight; - totWeight += nodeWeight.weight; - } - } - return sum / totWeight; -} - void HPWH::mixTankNodes(int mixedAboveNode, int mixedBelowNode, double mixFactor) { double ave = 0.; @@ -5459,13 +5499,13 @@ bool HPWH::prepForTest() } //----------------------------------------------------------------------------- -/// @brief Find usage category prior to 24-hr test +/// @brief Find usage designation prior to 24-hr test /// @note Determines usage category for 24-hr test /// @param[in/out] standardTestSummary contains usage on output /// @param[in] setpointT_C setpoint temperature (optional) /// @return true (success), false (failure). //----------------------------------------------------------------------------- -bool HPWH::findUsageFromFirstHourRating(Usage& usage, const double setpointT_C /* = 51.7 */) +bool HPWH::findFirstHourRating(FirstHourRating& firstHourRating, const double setpointT_C /* = 51.7 */) { double flowRate_Lper_min = GAL_TO_L(3.); if (tankVolume_L < GAL_TO_L(20.)) @@ -5611,19 +5651,19 @@ bool HPWH::findUsageFromFirstHourRating(Usage& usage, const double setpointT_C / // if (totalDrawVolume_L < GAL_TO_L(18.)) { - usage = Usage::VerySmall; + firstHourRating = FirstHourRating::VerySmall; } else if (totalDrawVolume_L < GAL_TO_L(51.)) { - usage = Usage::Low; + firstHourRating = FirstHourRating::Low; } else if (totalDrawVolume_L < GAL_TO_L(75.)) { - usage = Usage::Medium; + firstHourRating = FirstHourRating::Medium; } else { - usage = Usage::High; + firstHourRating = FirstHourRating::High; } return true; @@ -5636,30 +5676,30 @@ bool HPWH::findUsageFromFirstHourRating(Usage& usage, const double setpointT_C / /// @param[in] setpointT_C setpoint temperature (optional) /// @return true (success), false (failure). //----------------------------------------------------------------------------- -bool HPWH::run24hrTest(const Usage& usage, +bool HPWH::run24hrTest(const FirstHourRating firstHourRating, StandardTestSummary& standardTestSummary, const double setpointT_C /* = 51.7 */) { // select the draw pattern based on usage DrawPattern* drawPattern = nullptr; - switch (usage) + switch (firstHourRating) { - case Usage::VerySmall: + case FirstHourRating::VerySmall: { drawPattern = &verySmallUsage; break; } - case Usage::Low: + case FirstHourRating::Low: { drawPattern = &lowUsage; break; } - case Usage::Medium: + case FirstHourRating::Medium: { drawPattern = &mediumUsage; break; } - case Usage::High: + case FirstHourRating::High: { drawPattern = &highUsage; break; diff --git a/src/HPWH.hh b/src/HPWH.hh index 9808212e..056f1b90 100644 --- a/src/HPWH.hh +++ b/src/HPWH.hh @@ -604,7 +604,6 @@ class HPWH /**< Sets the tank node temps based on the provided vector of temps, which are mapped onto the existing nodes, regardless of numNodes. */ int setTankLayerTemperatures(std::vector setTemps, const UNITS units = UNITS_C); - void getTankTemps(std::vector& tankTemps); bool isSetpointFixed() const; /**< is the setpoint allowed to be changed */ int setSetpoint(double newSetpoint, UNITS units = UNITS_C); /** nTCouple, or incorrect units */ - int getNumHeatSources() const; /**< returns the number of heat sources */ @@ -835,17 +824,6 @@ class HPWH HEATSOURCE_TYPE getNthHeatSourceType(int N) const; /**< returns the enum value for what type of heat source the Nth heat source is */ - double getOutletTemp(UNITS units = UNITS_C) const; - /**< returns the outlet temperature in the specified units - returns 0 when no draw occurs, or HPWH_ABORT for incorrect unit specifier */ - double getCondenserWaterInletTemp(UNITS units = UNITS_C) const; - /**< returns the condenser inlet temperature in the specified units - returns 0 when no HP not running occurs, or HPWH_ABORT for incorrect unit specifier */ - - double getCondenserWaterOutletTemp(UNITS units = UNITS_C) const; - /**< returns the condenser outlet temperature in the specified units - returns 0 when no HP not running occurs, or HPWH_ABORT for incorrect unit specifier */ - double getExternalVolumeHeated(UNITS units = UNITS_L) const; /**< returns the volume of water heated in an external in the specified units returns 0 when no external heat source is running */ @@ -900,10 +878,42 @@ class HPWH void resetTopOffTimer(); /**< resets variables for timer associated with the DR_TOT call */ - /// returns the average tank temperature + double getLocationTemp_C() const; + + + void getTankTemps(std::vector& tankTemps); + + double getOutletTemp(UNITS units = UNITS_C) const; + /**< returns the outlet temperature in the specified units + returns 0 when no draw occurs, or HPWH_ABORT for incorrect unit specifier */ + + double getCondenserWaterInletTemp(UNITS units = UNITS_C) const; + /**< returns the condenser inlet temperature in the specified units + returns 0 when no HP not running occurs, or HPWH_ABORT for incorrect unit specifier */ + + double getCondenserWaterOutletTemp(UNITS units = UNITS_C) const; + /**< returns the condenser outlet temperature in the specified units + returns 0 when no HP not running occurs, or HPWH_ABORT for incorrect unit specifier */ + + double getTankNodeTemp(int nodeNum, UNITS units = UNITS_C) const; + /**< returns the temperature of the water at the specified node - with specified units + or HPWH_ABORT for incorrect node number or unit failure */ + + double getNthSimTcouple(int iTCouple, int nTCouple, UNITS units = UNITS_C) const; + /**< returns the temperature from a set number of virtual "thermocouples" specified by nTCouple, + which are constructed from the node temperature array. Specify iTCouple from 1-nTCouple, + 1 at the bottom using specified units + returns HPWH_ABORT for iTCouple < 0, > nTCouple, or incorrect units */ + + /// returns the tank temperature averaged uniformly double getTankTemp_C() const; - double getLocationTemp_C() const; + /// returns the tank temperature averaged over a distribution. + double getTankTemp_C(const std::vector &dist) const; + + /// returns the average tank temperature based on weighted logic nodes. + double getTankTemp_C(const std::vector &nodeWeights) const; + int setMaxTempDepression(double maxDepression, UNITS units = UNITS_C); bool hasEnteringWaterHighTempShutOff(int heatSourceIndex); @@ -949,8 +959,8 @@ class HPWH /// Addition of extra heat handled separately from normal heat sources void addExtraHeatAboveNode(double qAdd_kJ, const int nodeNum); - /// draw-pattern designations for 24-hr test - enum class Usage + /// usage designations to determine draw pattern for 24-hr test + enum class FirstHourRating { VerySmall, Low, @@ -976,11 +986,11 @@ class HPWH /// perform a draw/heat cycle to prepare for test bool prepForTest(); - /// determine usage based on the first-hour rating method - bool findUsageFromFirstHourRating(Usage& usage, const double setpointT_C = 51.7); + /// determine usage designation based on the first-hour rating method + bool findFirstHourRating(FirstHourRating& firstHourRating, const double setpointT_C = 51.7); /// run 24-hr draw pattern and compute metrics - bool run24hrTest(const Usage& usage, + bool run24hrTest(const FirstHourRating firstHourRating, StandardTestSummary& standardTestSummary, const double setpointT_C = 51.7); @@ -1036,9 +1046,6 @@ class HPWH /// "extra" heat added during a simulation step double extraEnergyInput_kWh; - double tankAvg_C(const std::vector nodeWeights) const; - /**< functions to calculate what the temperature in a portion of the tank is */ - void mixTankNodes(int mixedAboveNode, int mixedBelowNode, double mixFactor); /**< function to average the nodes in a tank together bewtween the mixed abovenode and mixed * below node. */ diff --git a/src/HPWHHeatSources.cc b/src/HPWHHeatSources.cc index b70572b0..5a9c13ac 100644 --- a/src/HPWHHeatSources.cc +++ b/src/HPWHHeatSources.cc @@ -464,12 +464,9 @@ double HPWH::HeatSource::fractToMeetComparisonExternal() const { hpwh->msg("\tshutsOff logic: %s ", shutOffLogicSet[i]->description.c_str()); } - fracTemp = shutOffLogicSet[i]->getFractToMeetComparisonExternal(); - frac = fracTemp < frac ? fracTemp : frac; } - return frac; } @@ -564,24 +561,12 @@ void HPWH::HeatSource::sortPerformanceMap() double HPWH::HeatSource::getTankTemp() const { - - std::vector resampledTankTemps(getCondensitySize()); - resample(resampledTankTemps, hpwh->tankTemps_C); - - double tankTemp_C = 0.; - - std::size_t j = 0; - for (auto& resampledNodeTemp : resampledTankTemps) - { - tankTemp_C += condensity[j] * resampledNodeTemp; - // Note that condensity is normalized. - ++j; - } + double tankT_C = hpwh->getTankTemp_C(condensity); if (hpwh->hpwhVerbosity >= VRB_typical) { - hpwh->msg("tank temp %.2lf \n", tankTemp_C); + hpwh->msg("tank temp %.2lf \n", tankT_C); } - return tankTemp_C; + return tankT_C; } void HPWH::HeatSource::getCapacity(double externalT_C, diff --git a/src/HPWHHeatingLogics.cc b/src/HPWHHeatingLogics.cc index 65e43227..7ca98e0c 100644 --- a/src/HPWHHeatingLogics.cc +++ b/src/HPWHHeatingLogics.cc @@ -176,7 +176,7 @@ double HPWH::TempBasedHeatingLogic::getComparisonValue() } } -double HPWH::TempBasedHeatingLogic::getTankValue() { return hpwh->tankAvg_C(nodeWeights); } +double HPWH::TempBasedHeatingLogic::getTankValue() { return hpwh->getTankTemp_C(nodeWeights); } int HPWH::TempBasedHeatingLogic::setDecisionPoint(double value) { diff --git a/test/testMeasureMetrics.cc b/test/testMeasureMetrics.cc index e137c44c..99e05421 100644 --- a/test/testMeasureMetrics.cc +++ b/test/testMeasureMetrics.cc @@ -8,7 +8,7 @@ /* Measure metrics using 24-hr test based on model name (preset only) */ static bool testMeasureMetrics(const std::string& sModelName, - HPWH::Usage& usage, + HPWH::FirstHourRating& firstHourRating, HPWH::StandardTestSummary& standardTestSummary) { HPWH hpwh; @@ -19,12 +19,12 @@ static bool testMeasureMetrics(const std::string& sModelName, return false; } - if (!hpwh.findUsageFromFirstHourRating(usage)) + if (!hpwh.findFirstHourRating(firstHourRating)) { return false; } - return hpwh.run24hrTest(usage, standardTestSummary); + return hpwh.run24hrTest(firstHourRating, standardTestSummary); } int main(int argc, char* argv[]) @@ -56,20 +56,20 @@ int main(int argc, char* argv[]) if (runUnitTests) { - HPWH::Usage usage; - ASSERTTRUE(testMeasureMetrics("AquaThermAire", usage, standardTestSummary)); + HPWH::FirstHourRating firstHourRating; + ASSERTTRUE(testMeasureMetrics("AquaThermAire", firstHourRating, standardTestSummary)); ASSERTTRUE(standardTestSummary.qualifies); - ASSERTTRUE(usage == HPWH::Usage::Medium); + ASSERTTRUE(firstHourRating == HPWH::FirstHourRating::Medium); ASSERTTRUE(cmpd(standardTestSummary.UEF, 3.2212)); - ASSERTTRUE(testMeasureMetrics("AOSmithHPTS50", usage, standardTestSummary)); + ASSERTTRUE(testMeasureMetrics("AOSmithHPTS50", firstHourRating, standardTestSummary)); ASSERTTRUE(standardTestSummary.qualifies); - ASSERTTRUE(usage == HPWH::Usage::Low); + ASSERTTRUE(firstHourRating == HPWH::FirstHourRating::Low); ASSERTTRUE(cmpd(standardTestSummary.UEF, 4.4914)); - ASSERTTRUE(testMeasureMetrics("AOSmithHPTS80", usage, standardTestSummary)); + ASSERTTRUE(testMeasureMetrics("AOSmithHPTS80", firstHourRating, standardTestSummary)); ASSERTTRUE(standardTestSummary.qualifies); - ASSERTTRUE(usage == HPWH::Usage::High); + ASSERTTRUE(firstHourRating == HPWH::FirstHourRating::High); ASSERTTRUE(cmpd(standardTestSummary.UEF, 3.5230)); return 0; @@ -120,36 +120,36 @@ int main(int argc, char* argv[]) std::cout << "Spec type: " << sPresetOrFile << "\n"; std::cout << "Model name: " << sModelName << "\n"; - HPWH::Usage usage; - if (hpwh.findUsageFromFirstHourRating(usage)) + HPWH::FirstHourRating firstHourRating; + if (hpwh.findFirstHourRating(firstHourRating)) { - std::string sUsage = ""; - switch (usage) + std::string sFirstHourRating = ""; + switch (firstHourRating) { - case HPWH::Usage::VerySmall: + case HPWH::FirstHourRating::VerySmall: { - sUsage = "Very Small"; + sFirstHourRating = "Very Small"; break; } - case HPWH::Usage::Low: + case HPWH::FirstHourRating::Low: { - sUsage = "Low"; + sFirstHourRating = "Low"; break; } - case HPWH::Usage::Medium: + case HPWH::FirstHourRating::Medium: { - sUsage = "Medium"; + sFirstHourRating = "Medium"; break; } - case HPWH::Usage::High: + case HPWH::FirstHourRating::High: { - sUsage = "High"; + sFirstHourRating = "High"; break; } } - std::cout << "\tUsage: " << sUsage << "\n"; + std::cout << "\tFirst-Hour Rating: " << sFirstHourRating << "\n"; - if (hpwh.run24hrTest(usage, standardTestSummary)) + if (hpwh.run24hrTest(firstHourRating, standardTestSummary)) { if (!standardTestSummary.qualifies) From f84912f1e370c19a19def784d1c92696f7ad0f75 Mon Sep 17 00:00:00 2001 From: Phil Ahrenkiel Date: Fri, 12 Jan 2024 11:41:44 -0700 Subject: [PATCH 18/37] Use unordered_map. --- src/HPWH.cc | 143 ++++++++++++++++++++++------------------------------ src/HPWH.hh | 10 ++-- 2 files changed, 66 insertions(+), 87 deletions(-) diff --git a/src/HPWH.cc b/src/HPWH.cc index 77224572..6de83288 100644 --- a/src/HPWH.cc +++ b/src/HPWH.cc @@ -65,57 +65,60 @@ const double HPWH::MAXOUTLET_R410A = F_TO_C(140.); const double HPWH::MAXOUTLET_R744 = F_TO_C(190.); const double HPWH::MINSINGLEPASSLIFT = dF_TO_dC(15.); -HPWH::DrawPattern HPWH::verySmallUsage = { - {HM_TO_MIN(0, 00), 7.6, 3.8}, - {HM_TO_MIN(1, 00), 3.8, 3.8}, - {HM_TO_MIN(1, 05), 1.9, 3.8}, - {HM_TO_MIN(1, 10), 1.9, 3.8}, - {HM_TO_MIN(1, 15), 1.9, 3.8}, - {HM_TO_MIN(8, 00), 3.8, 3.8}, - {HM_TO_MIN(8, 15), 7.6, 3.8}, - {HM_TO_MIN(9, 00), 5.7, 3.8}, - {HM_TO_MIN(9, 15), 3.8, 3.8}, -}; - -HPWH::DrawPattern HPWH::lowUsage = {{HM_TO_MIN(0, 00), 56.8, 6.4}, - {HM_TO_MIN(0, 30), 7.6, 3.8}, - {HM_TO_MIN(1, 00), 3.8, 3.8}, - {HM_TO_MIN(10, 30), 22.7, 6.4}, - {HM_TO_MIN(11, 30), 15.1, 6.4}, - {HM_TO_MIN(12, 00), 3.8, 3.8}, - {HM_TO_MIN(12, 45), 3.8, 3.8}, - {HM_TO_MIN(12, 50), 3.8, 3.8}, - {HM_TO_MIN(16, 15), 7.6, 3.8}, - {HM_TO_MIN(16, 45), 7.6, 6.4}, - {HM_TO_MIN(17, 00), 11.4, 6.4}}; - -HPWH::DrawPattern HPWH::mediumUsage = {{HM_TO_MIN(0, 00), 56.8, 6.4}, - {HM_TO_MIN(0, 30), 7.6, 3.8}, - {HM_TO_MIN(1, 40), 34.1, 6.4}, - {HM_TO_MIN(10, 30), 34.1, 6.4}, - {HM_TO_MIN(11, 30), 18.9, 6.4}, - {HM_TO_MIN(12, 00), 3.8, 3.8}, - {HM_TO_MIN(12, 45), 3.8, 3.8}, - {HM_TO_MIN(12, 50), 3.8, 3.8}, - {HM_TO_MIN(16, 00), 3.8, 3.8}, - {HM_TO_MIN(16, 15), 7.6, 3.8}, - {HM_TO_MIN(16, 45), 7.6, 6.4}, - {HM_TO_MIN(17, 00), 26.5, 6.4}}; - -HPWH::DrawPattern HPWH::highUsage = {{HM_TO_MIN(0, 00), 102, 11.4}, - {HM_TO_MIN(0, 30), 7.6, 3.8}, - {HM_TO_MIN(0, 40), 3.8, 3.8}, - {HM_TO_MIN(1, 40), 34.1, 6.4}, - {HM_TO_MIN(10, 30), 56.8, 11.4}, - {HM_TO_MIN(11, 30), 18.9, 6.4}, - {HM_TO_MIN(12, 00), 3.8, 3.8}, - {HM_TO_MIN(12, 45), 3.8, 3.8}, - {HM_TO_MIN(12, 50), 3.8, 3.8}, - {HM_TO_MIN(16, 00), 7.6, 3.8}, - {HM_TO_MIN(16, 15), 7.6, 3.8}, - {HM_TO_MIN(16, 30), 7.6, 6.4}, - {HM_TO_MIN(16, 45), 7.6, 6.4}, - {HM_TO_MIN(17, 00), 53.0, 11.4}}; +std::unordered_map HPWH::drawPatterns = { + {HPWH::FirstHourRating::VerySmall, + {{HM_TO_MIN(0, 00), 7.6, 3.8}, + {HM_TO_MIN(1, 00), 3.8, 3.8}, + {HM_TO_MIN(1, 05), 1.9, 3.8}, + {HM_TO_MIN(1, 10), 1.9, 3.8}, + {HM_TO_MIN(1, 15), 1.9, 3.8}, + {HM_TO_MIN(8, 00), 3.8, 3.8}, + {HM_TO_MIN(8, 15), 7.6, 3.8}, + {HM_TO_MIN(9, 00), 5.7, 3.8}, + {HM_TO_MIN(9, 15), 3.8, 3.8}}}, + + {HPWH::FirstHourRating::Low, + {{HM_TO_MIN(0, 00), 56.8, 6.4}, + {HM_TO_MIN(0, 30), 7.6, 3.8}, + {HM_TO_MIN(1, 00), 3.8, 3.8}, + {HM_TO_MIN(10, 30), 22.7, 6.4}, + {HM_TO_MIN(11, 30), 15.1, 6.4}, + {HM_TO_MIN(12, 00), 3.8, 3.8}, + {HM_TO_MIN(12, 45), 3.8, 3.8}, + {HM_TO_MIN(12, 50), 3.8, 3.8}, + {HM_TO_MIN(16, 15), 7.6, 3.8}, + {HM_TO_MIN(16, 45), 7.6, 6.4}, + {HM_TO_MIN(17, 00), 11.4, 6.4}}}, + + {HPWH::FirstHourRating::Medium, + {{HM_TO_MIN(0, 00), 56.8, 6.4}, + {HM_TO_MIN(0, 30), 7.6, 3.8}, + {HM_TO_MIN(1, 40), 34.1, 6.4}, + {HM_TO_MIN(10, 30), 34.1, 6.4}, + {HM_TO_MIN(11, 30), 18.9, 6.4}, + {HM_TO_MIN(12, 00), 3.8, 3.8}, + {HM_TO_MIN(12, 45), 3.8, 3.8}, + {HM_TO_MIN(12, 50), 3.8, 3.8}, + {HM_TO_MIN(16, 00), 3.8, 3.8}, + {HM_TO_MIN(16, 15), 7.6, 3.8}, + {HM_TO_MIN(16, 45), 7.6, 6.4}, + {HM_TO_MIN(17, 00), 26.5, 6.4}}}, + + {HPWH::FirstHourRating::High, + {{HM_TO_MIN(0, 00), 102, 11.4}, + {HM_TO_MIN(0, 30), 7.6, 3.8}, + {HM_TO_MIN(0, 40), 3.8, 3.8}, + {HM_TO_MIN(1, 40), 34.1, 6.4}, + {HM_TO_MIN(10, 30), 56.8, 11.4}, + {HM_TO_MIN(11, 30), 18.9, 6.4}, + {HM_TO_MIN(12, 00), 3.8, 3.8}, + {HM_TO_MIN(12, 45), 3.8, 3.8}, + {HM_TO_MIN(12, 50), 3.8, 3.8}, + {HM_TO_MIN(16, 00), 7.6, 3.8}, + {HM_TO_MIN(16, 15), 7.6, 3.8}, + {HM_TO_MIN(16, 30), 7.6, 6.4}, + {HM_TO_MIN(16, 45), 7.6, 6.4}, + {HM_TO_MIN(17, 00), 53.0, 11.4}}}}; //----------------------------------------------------------------------------- /// @brief Samples a std::vector to extract a single value spanning the fractional @@ -2886,7 +2889,7 @@ double HPWH::getTankTemp_C() const /// @note Distribution must have positive size and be normalized. /// @param[in] dist Discrete set of distribution values //----------------------------------------------------------------------------- -double HPWH::getTankTemp_C(const std::vector &dist) const +double HPWH::getTankTemp_C(const std::vector& dist) const { std::vector resampledTankTemps_C(dist.size()); resample(resampledTankTemps_C, tankTemps_C); @@ -2912,7 +2915,7 @@ double HPWH::getTankTemp_C(const std::vector &dist) const /// @param[in] nodeWeights Discrete set of weighted nodes /// @return Tank temperature (C) //----------------------------------------------------------------------------- -double HPWH::getTankTemp_C(const std::vector &nodeWeights) const +double HPWH::getTankTemp_C(const std::vector& nodeWeights) const { double sum = 0; double totWeight = 0; @@ -5505,7 +5508,8 @@ bool HPWH::prepForTest() /// @param[in] setpointT_C setpoint temperature (optional) /// @return true (success), false (failure). //----------------------------------------------------------------------------- -bool HPWH::findFirstHourRating(FirstHourRating& firstHourRating, const double setpointT_C /* = 51.7 */) +bool HPWH::findFirstHourRating(FirstHourRating& firstHourRating, + const double setpointT_C /* = 51.7 */) { double flowRate_Lper_min = GAL_TO_L(3.); if (tankVolume_L < GAL_TO_L(20.)) @@ -5681,34 +5685,7 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, const double setpointT_C /* = 51.7 */) { // select the draw pattern based on usage - DrawPattern* drawPattern = nullptr; - switch (firstHourRating) - { - case FirstHourRating::VerySmall: - { - drawPattern = &verySmallUsage; - break; - } - case FirstHourRating::Low: - { - drawPattern = &lowUsage; - break; - } - case FirstHourRating::Medium: - { - drawPattern = &mediumUsage; - break; - } - case FirstHourRating::High: - { - drawPattern = &highUsage; - break; - } - } - if (drawPattern == nullptr) - { - return false; - } + DrawPattern &drawPattern = drawPatterns[firstHourRating]; constexpr double inletT_C = 14.4; // EERE-2019-BT-TP-0032-0058, p. 40433 constexpr double ambientT_C = 19.7; // EERE-2019-BT-TP-0032-0058, p. 40435 @@ -5770,7 +5747,7 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, bool hasHeated = false; int runTime_min = 0; - for (auto& draw : *drawPattern) + for (auto& draw : drawPattern) { double drawVolume_L = 0.; double drawHeatingEnergy_kJ = 0.; diff --git a/src/HPWH.hh b/src/HPWH.hh index 056f1b90..66601736 100644 --- a/src/HPWH.hh +++ b/src/HPWH.hh @@ -12,6 +12,7 @@ #include #include //for exit #include +#include namespace Btwxt { @@ -1015,10 +1016,11 @@ class HPWH typedef std::vector DrawPattern; /// standard draw patterns - static DrawPattern verySmallUsage; - static DrawPattern lowUsage; - static DrawPattern mediumUsage; - static DrawPattern highUsage; + static std::unordered_map drawPatterns; + //static DrawPattern verySmallUsage; + //static DrawPattern lowUsage; + //static DrawPattern mediumUsage; + //static DrawPattern highUsage; private: class HeatSource; From dcc08c1b6f4dccf393570221c9d8b9e5239f977e Mon Sep 17 00:00:00 2001 From: Phil Ahrenkiel Date: Fri, 12 Jan 2024 14:02:27 -0700 Subject: [PATCH 19/37] Improve names. --- src/HPWH.cc | 16 ++++++++-------- src/HPWH.hh | 23 +++++++++-------------- 2 files changed, 17 insertions(+), 22 deletions(-) diff --git a/src/HPWH.cc b/src/HPWH.cc index 6de83288..74afd367 100644 --- a/src/HPWH.cc +++ b/src/HPWH.cc @@ -5502,10 +5502,9 @@ bool HPWH::prepForTest() } //----------------------------------------------------------------------------- -/// @brief Find usage designation prior to 24-hr test -/// @note Determines usage category for 24-hr test -/// @param[in/out] standardTestSummary contains usage on output -/// @param[in] setpointT_C setpoint temperature (optional) +/// @brief Find first-hour rating designation for 24-hr test +/// @param[out] firstHourRating contains first-hour rating designation +/// @param[in] setpointT_C setpoint temperature (optional) /// @return true (success), false (failure). //----------------------------------------------------------------------------- bool HPWH::findFirstHourRating(FirstHourRating& firstHourRating, @@ -5676,16 +5675,17 @@ bool HPWH::findFirstHourRating(FirstHourRating& firstHourRating, //----------------------------------------------------------------------------- /// @brief Performs standard 24-hr test /// @note see https://www.regulations.gov/document/EERE-2019-BT-TP-0032-0058 -/// @param[in/out] standardTestSummary specifies usage on input, test metrics on output -/// @param[in] setpointT_C setpoint temperature (optional) +/// @param[in] firstHourRating specifies first-hour rating +/// @param[out] standardTestSummary contains test metrics on output +/// @param[in] setpointT_C setpoint temperature (optional) /// @return true (success), false (failure). //----------------------------------------------------------------------------- bool HPWH::run24hrTest(const FirstHourRating firstHourRating, StandardTestSummary& standardTestSummary, const double setpointT_C /* = 51.7 */) { - // select the draw pattern based on usage - DrawPattern &drawPattern = drawPatterns[firstHourRating]; + // select the draw pattern + DrawPattern& drawPattern = drawPatterns[firstHourRating]; constexpr double inletT_C = 14.4; // EERE-2019-BT-TP-0032-0058, p. 40433 constexpr double ambientT_C = 19.7; // EERE-2019-BT-TP-0032-0058, p. 40435 diff --git a/src/HPWH.hh b/src/HPWH.hh index 66601736..d0c7449e 100644 --- a/src/HPWH.hh +++ b/src/HPWH.hh @@ -879,9 +879,8 @@ class HPWH void resetTopOffTimer(); /**< resets variables for timer associated with the DR_TOT call */ - double getLocationTemp_C() const; + double getLocationTemp_C() const; - void getTankTemps(std::vector& tankTemps); double getOutletTemp(UNITS units = UNITS_C) const; @@ -905,16 +904,16 @@ class HPWH which are constructed from the node temperature array. Specify iTCouple from 1-nTCouple, 1 at the bottom using specified units returns HPWH_ABORT for iTCouple < 0, > nTCouple, or incorrect units */ - + /// returns the tank temperature averaged uniformly double getTankTemp_C() const; /// returns the tank temperature averaged over a distribution. - double getTankTemp_C(const std::vector &dist) const; + double getTankTemp_C(const std::vector& dist) const; /// returns the average tank temperature based on weighted logic nodes. - double getTankTemp_C(const std::vector &nodeWeights) const; - + double getTankTemp_C(const std::vector& nodeWeights) const; + int setMaxTempDepression(double maxDepression, UNITS units = UNITS_C); bool hasEnteringWaterHighTempShutOff(int heatSourceIndex); @@ -960,7 +959,7 @@ class HPWH /// Addition of extra heat handled separately from normal heat sources void addExtraHeatAboveNode(double qAdd_kJ, const int nodeNum); - /// usage designations to determine draw pattern for 24-hr test + /// first-hour rating designations to determine draw pattern for 24-hr test enum class FirstHourRating { VerySmall, @@ -987,7 +986,7 @@ class HPWH /// perform a draw/heat cycle to prepare for test bool prepForTest(); - /// determine usage designation based on the first-hour rating method + /// determine first-hour rating bool findFirstHourRating(FirstHourRating& firstHourRating, const double setpointT_C = 51.7); /// run 24-hr draw pattern and compute metrics @@ -1015,12 +1014,8 @@ class HPWH /// sequence of draws in pattern typedef std::vector DrawPattern; - /// standard draw patterns - static std::unordered_map drawPatterns; - //static DrawPattern verySmallUsage; - //static DrawPattern lowUsage; - //static DrawPattern mediumUsage; - //static DrawPattern highUsage; + /// collection of standard draw patterns + static std::unordered_map drawPatterns; private: class HeatSource; From b191059182fdec6ca5d73718f1355b0d132b08aa Mon Sep 17 00:00:00 2001 From: Phil Ahrenkiel Date: Fri, 12 Jan 2024 16:08:06 -0700 Subject: [PATCH 20/37] Rename fncs Average. --- src/HPWH.cc | 16 ++++++++-------- src/HPWH.hh | 10 +++++----- src/HPWHHeatSources.cc | 2 +- src/HPWHHeatingLogics.cc | 2 +- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/HPWH.cc b/src/HPWH.cc index 74afd367..d5a087e5 100644 --- a/src/HPWH.cc +++ b/src/HPWH.cc @@ -2874,7 +2874,7 @@ void HPWH::getTankTemps(std::vector& tankTemps) { tankTemps = tankTemps_ /// @param[in] nodeWeights Discrete set of weighted nodes /// @return Tank temperature (C) //----------------------------------------------------------------------------- -double HPWH::getTankTemp_C() const +double HPWH::getAverageTankTemp_C() const { double totalT_C = 0.; for (auto& T_C : tankTemps_C) @@ -2889,7 +2889,7 @@ double HPWH::getTankTemp_C() const /// @note Distribution must have positive size and be normalized. /// @param[in] dist Discrete set of distribution values //----------------------------------------------------------------------------- -double HPWH::getTankTemp_C(const std::vector& dist) const +double HPWH::getAverageTankTemp_C(const std::vector& dist) const { std::vector resampledTankTemps_C(dist.size()); resample(resampledTankTemps_C, tankTemps_C); @@ -2915,7 +2915,7 @@ double HPWH::getTankTemp_C(const std::vector& dist) const /// @param[in] nodeWeights Discrete set of weighted nodes /// @return Tank temperature (C) //----------------------------------------------------------------------------- -double HPWH::getTankTemp_C(const std::vector& nodeWeights) const +double HPWH::getAverageTankTemp_C(const std::vector& nodeWeights) const { double sum = 0; double totWeight = 0; @@ -2993,7 +2993,7 @@ int HPWH::setTankToTemperature(double temp_C) { return setTankLayerTemperatures( double HPWH::getTankHeatContent_kJ() const { // returns tank heat content relative to 0 C using kJ - return DENSITYWATER_kgperL * tankVolume_L * CPWATER_kJperkgC * getTankTemp_C(); + return DENSITYWATER_kgperL * tankVolume_L * CPWATER_kJperkgC * getAverageTankTemp_C(); } int HPWH::getHPWHModel() const { return hpwhModel; } @@ -5526,7 +5526,7 @@ bool HPWH::findFirstHourRating(FirstHourRating& firstHourRating, } } - double tankT_C = getTankTemp_C(); + double tankT_C = getAverageTankTemp_C(); double maxTankT_C = tankT_C; double maxOutletT_C = 0.; @@ -5577,7 +5577,7 @@ bool HPWH::findFirstHourRating(FirstHourRating& firstHourRating, { return false; } - tankT_C = getTankTemp_C(); + tankT_C = getAverageTankTemp_C(); switch (step) { @@ -5732,7 +5732,7 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, ++preTime_min; } - double tankT_C = getTankTemp_C(); + double tankT_C = getAverageTankTemp_C(); double initialTankT_C = tankT_C; double dailyRemovedVolume_L = 0.; @@ -5792,7 +5792,7 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, return false; } - tankT_C = getTankTemp_C(); + tankT_C = getAverageTankTemp_C(); hasHeated |= isHeating; drawSumOutletVolumeT_LC += incrementalDrawVolume_L * outletTemp_C; diff --git a/src/HPWH.hh b/src/HPWH.hh index 24237a60..b405d587 100644 --- a/src/HPWH.hh +++ b/src/HPWH.hh @@ -906,13 +906,13 @@ class HPWH returns HPWH_ABORT for iTCouple < 0, > nTCouple, or incorrect units */ /// returns the tank temperature averaged uniformly - double getTankTemp_C() const; + double getAverageTankTemp_C() const; - /// returns the tank temperature averaged over a distribution. - double getTankTemp_C(const std::vector& dist) const; + /// returns the tank temperature averaged over a distribution + double getAverageTankTemp_C(const std::vector& dist) const; - /// returns the average tank temperature based on weighted logic nodes. - double getTankTemp_C(const std::vector& nodeWeights) const; + /// returns the tank temperature averaged using weighted logic nodes + double getAverageTankTemp_C(const std::vector& nodeWeights) const; int setMaxTempDepression(double maxDepression, UNITS units = UNITS_C); diff --git a/src/HPWHHeatSources.cc b/src/HPWHHeatSources.cc index 5a9c13ac..0cb357d9 100644 --- a/src/HPWHHeatSources.cc +++ b/src/HPWHHeatSources.cc @@ -561,7 +561,7 @@ void HPWH::HeatSource::sortPerformanceMap() double HPWH::HeatSource::getTankTemp() const { - double tankT_C = hpwh->getTankTemp_C(condensity); + double tankT_C = hpwh->getAverageTankTemp_C(condensity); if (hpwh->hpwhVerbosity >= VRB_typical) { hpwh->msg("tank temp %.2lf \n", tankT_C); diff --git a/src/HPWHHeatingLogics.cc b/src/HPWHHeatingLogics.cc index 7ca98e0c..5a300f35 100644 --- a/src/HPWHHeatingLogics.cc +++ b/src/HPWHHeatingLogics.cc @@ -176,7 +176,7 @@ double HPWH::TempBasedHeatingLogic::getComparisonValue() } } -double HPWH::TempBasedHeatingLogic::getTankValue() { return hpwh->getTankTemp_C(nodeWeights); } +double HPWH::TempBasedHeatingLogic::getTankValue() { return hpwh->getAverageTankTemp_C(nodeWeights); } int HPWH::TempBasedHeatingLogic::setDecisionPoint(double value) { From 985261d2014ee3b07f12bccb2a5c82b28c7f7917 Mon Sep 17 00:00:00 2001 From: Phil Ahrenkiel Date: Fri, 12 Jan 2024 16:11:14 -0700 Subject: [PATCH 21/37] Format. --- src/HPWHHeatingLogics.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/HPWHHeatingLogics.cc b/src/HPWHHeatingLogics.cc index 5a300f35..a890e409 100644 --- a/src/HPWHHeatingLogics.cc +++ b/src/HPWHHeatingLogics.cc @@ -176,7 +176,10 @@ double HPWH::TempBasedHeatingLogic::getComparisonValue() } } -double HPWH::TempBasedHeatingLogic::getTankValue() { return hpwh->getAverageTankTemp_C(nodeWeights); } +double HPWH::TempBasedHeatingLogic::getTankValue() +{ + return hpwh->getAverageTankTemp_C(nodeWeights); +} int HPWH::TempBasedHeatingLogic::setDecisionPoint(double value) { From 7dd5db57eb67bfe57b3b960f7a899ffc721cdc26 Mon Sep 17 00:00:00 2001 From: Phil Ahrenkiel Date: Mon, 5 Feb 2024 11:19:31 -0700 Subject: [PATCH 22/37] Retain draw volume. --- src/HPWH.cc | 33 +++++++++++++++++---------------- src/HPWH.hh | 10 ++++++++-- test/testMeasureMetrics.cc | 33 +++++++++++++++++++-------------- 3 files changed, 44 insertions(+), 32 deletions(-) diff --git a/src/HPWH.cc b/src/HPWH.cc index d5a087e5..2f1af3b2 100644 --- a/src/HPWH.cc +++ b/src/HPWH.cc @@ -65,8 +65,8 @@ const double HPWH::MAXOUTLET_R410A = F_TO_C(140.); const double HPWH::MAXOUTLET_R744 = F_TO_C(190.); const double HPWH::MINSINGLEPASSLIFT = dF_TO_dC(15.); -std::unordered_map HPWH::drawPatterns = { - {HPWH::FirstHourRating::VerySmall, +std::unordered_map HPWH::drawPatterns = { + {HPWH::FirstHourRatingDesig::VerySmall, {{HM_TO_MIN(0, 00), 7.6, 3.8}, {HM_TO_MIN(1, 00), 3.8, 3.8}, {HM_TO_MIN(1, 05), 1.9, 3.8}, @@ -77,7 +77,7 @@ std::unordered_map HPWH::drawPatterns {HM_TO_MIN(9, 00), 5.7, 3.8}, {HM_TO_MIN(9, 15), 3.8, 3.8}}}, - {HPWH::FirstHourRating::Low, + {HPWH::FirstHourRatingDesig::Low, {{HM_TO_MIN(0, 00), 56.8, 6.4}, {HM_TO_MIN(0, 30), 7.6, 3.8}, {HM_TO_MIN(1, 00), 3.8, 3.8}, @@ -90,7 +90,7 @@ std::unordered_map HPWH::drawPatterns {HM_TO_MIN(16, 45), 7.6, 6.4}, {HM_TO_MIN(17, 00), 11.4, 6.4}}}, - {HPWH::FirstHourRating::Medium, + {HPWH::FirstHourRatingDesig::Medium, {{HM_TO_MIN(0, 00), 56.8, 6.4}, {HM_TO_MIN(0, 30), 7.6, 3.8}, {HM_TO_MIN(1, 40), 34.1, 6.4}, @@ -104,7 +104,7 @@ std::unordered_map HPWH::drawPatterns {HM_TO_MIN(16, 45), 7.6, 6.4}, {HM_TO_MIN(17, 00), 26.5, 6.4}}}, - {HPWH::FirstHourRating::High, + {HPWH::FirstHourRatingDesig::High, {{HM_TO_MIN(0, 00), 102, 11.4}, {HM_TO_MIN(0, 30), 7.6, 3.8}, {HM_TO_MIN(0, 40), 3.8, 3.8}, @@ -5532,7 +5532,8 @@ bool HPWH::findFirstHourRating(FirstHourRating& firstHourRating, DRMODES drMode = DR_ALLOW; double drawVolume_L = 0.; - double totalDrawVolume_L = 0.; + + firstHourRating.drawVolume_L = 0.; double sumOutletVolumeT_LC = 0.; double sumOutletVolume_L = 0.; @@ -5600,12 +5601,12 @@ bool HPWH::findFirstHourRating(FirstHourRating& firstHourRating, fac = (avgOutletT_C - prevMinOutletT_C) / (prevAvgOutletT_C - prevMinOutletT_C); } - totalDrawVolume_L += fac * drawVolume_L; + firstHourRating.drawVolume_L += fac * drawVolume_L; done = true; } else { - totalDrawVolume_L += drawVolume_L; + firstHourRating.drawVolume_L += drawVolume_L; drawVolume_L = 0.; isDrawing = false; drMode = DR_ALLOW; @@ -5652,21 +5653,21 @@ bool HPWH::findFirstHourRating(FirstHourRating& firstHourRating, } // - if (totalDrawVolume_L < GAL_TO_L(18.)) + if (firstHourRating.drawVolume_L < GAL_TO_L(18.)) { - firstHourRating = FirstHourRating::VerySmall; + firstHourRating.desig = FirstHourRatingDesig::VerySmall; } - else if (totalDrawVolume_L < GAL_TO_L(51.)) + else if (firstHourRating.drawVolume_L < GAL_TO_L(51.)) { - firstHourRating = FirstHourRating::Low; + firstHourRating.desig = FirstHourRatingDesig::Low; } - else if (totalDrawVolume_L < GAL_TO_L(75.)) + else if (firstHourRating.drawVolume_L < GAL_TO_L(75.)) { - firstHourRating = FirstHourRating::Medium; + firstHourRating.desig = FirstHourRatingDesig::Medium; } else { - firstHourRating = FirstHourRating::High; + firstHourRating.desig = FirstHourRatingDesig::High; } return true; @@ -5685,7 +5686,7 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, const double setpointT_C /* = 51.7 */) { // select the draw pattern - DrawPattern& drawPattern = drawPatterns[firstHourRating]; + DrawPattern& drawPattern = drawPatterns[firstHourRating.desig]; constexpr double inletT_C = 14.4; // EERE-2019-BT-TP-0032-0058, p. 40433 constexpr double ambientT_C = 19.7; // EERE-2019-BT-TP-0032-0058, p. 40435 diff --git a/src/HPWH.hh b/src/HPWH.hh index b405d587..a0a1ef1d 100644 --- a/src/HPWH.hh +++ b/src/HPWH.hh @@ -960,7 +960,7 @@ class HPWH void addExtraHeatAboveNode(double qAdd_kJ, const int nodeNum); /// first-hour rating designations to determine draw pattern for 24-hr test - enum class FirstHourRating + enum class FirstHourRatingDesig { VerySmall, Low, @@ -968,6 +968,12 @@ class HPWH High }; + struct FirstHourRating + { + FirstHourRatingDesig desig; + double drawVolume_L; + }; + /// collection of information derived from standard test struct StandardTestSummary { @@ -1015,7 +1021,7 @@ class HPWH typedef std::vector DrawPattern; /// collection of standard draw patterns - static std::unordered_map drawPatterns; + static std::unordered_map drawPatterns; private: class HeatSource; diff --git a/test/testMeasureMetrics.cc b/test/testMeasureMetrics.cc index 99e05421..fc4ddc96 100644 --- a/test/testMeasureMetrics.cc +++ b/test/testMeasureMetrics.cc @@ -59,17 +59,20 @@ int main(int argc, char* argv[]) HPWH::FirstHourRating firstHourRating; ASSERTTRUE(testMeasureMetrics("AquaThermAire", firstHourRating, standardTestSummary)); ASSERTTRUE(standardTestSummary.qualifies); - ASSERTTRUE(firstHourRating == HPWH::FirstHourRating::Medium); + ASSERTTRUE(cmpd(firstHourRating.drawVolume_L, 272.5659)); + ASSERTTRUE(firstHourRating.desig == HPWH::FirstHourRatingDesig::Medium); ASSERTTRUE(cmpd(standardTestSummary.UEF, 3.2212)); ASSERTTRUE(testMeasureMetrics("AOSmithHPTS50", firstHourRating, standardTestSummary)); ASSERTTRUE(standardTestSummary.qualifies); - ASSERTTRUE(firstHourRating == HPWH::FirstHourRating::Low); + ASSERTTRUE(cmpd(firstHourRating.drawVolume_L, 188.0432)); + ASSERTTRUE(firstHourRating.desig == HPWH::FirstHourRatingDesig::Low); ASSERTTRUE(cmpd(standardTestSummary.UEF, 4.4914)); ASSERTTRUE(testMeasureMetrics("AOSmithHPTS80", firstHourRating, standardTestSummary)); ASSERTTRUE(standardTestSummary.qualifies); - ASSERTTRUE(firstHourRating == HPWH::FirstHourRating::High); + ASSERTTRUE(cmpd(firstHourRating.drawVolume_L, 310.9384)); + ASSERTTRUE(firstHourRating.desig == HPWH::FirstHourRatingDesig::High); ASSERTTRUE(cmpd(standardTestSummary.UEF, 3.5230)); return 0; @@ -123,31 +126,33 @@ int main(int argc, char* argv[]) HPWH::FirstHourRating firstHourRating; if (hpwh.findFirstHourRating(firstHourRating)) { - std::string sFirstHourRating = ""; - switch (firstHourRating) + std::string sFirstHourRatingDesig = ""; + switch (firstHourRating.desig) { - case HPWH::FirstHourRating::VerySmall: + case HPWH::FirstHourRatingDesig::VerySmall: { - sFirstHourRating = "Very Small"; + sFirstHourRatingDesig = "Very Small"; break; } - case HPWH::FirstHourRating::Low: + case HPWH::FirstHourRatingDesig::Low: { - sFirstHourRating = "Low"; + sFirstHourRatingDesig = "Low"; break; } - case HPWH::FirstHourRating::Medium: + case HPWH::FirstHourRatingDesig::Medium: { - sFirstHourRating = "Medium"; + sFirstHourRatingDesig = "Medium"; break; } - case HPWH::FirstHourRating::High: + case HPWH::FirstHourRatingDesig::High: { - sFirstHourRating = "High"; + sFirstHourRatingDesig = "High"; break; } } - std::cout << "\tFirst-Hour Rating: " << sFirstHourRating << "\n"; + std::cout << "\tFirst-Hour Rating:\n"; + std::cout << "\t\tVolume Drawn (L): " << firstHourRating.drawVolume_L << "\n"; + std::cout << "\t\tDesignation: " << sFirstHourRatingDesig << "\n"; if (hpwh.run24hrTest(firstHourRating, standardTestSummary)) { From ef495ea560e118e9e99a11b812fd5c5d8f19a9bb Mon Sep 17 00:00:00 2001 From: Phil Ahrenkiel Date: Mon, 5 Feb 2024 15:34:23 -0700 Subject: [PATCH 23/37] Enable writing output. --- src/HPWH.cc | 57 +++++++++++++++++++++++++------ src/HPWH.hh | 35 ++++++++++++------- test/testMeasureMetrics.cc | 70 ++++++++++++++++++++++++++++++++------ 3 files changed, 129 insertions(+), 33 deletions(-) diff --git a/src/HPWH.cc b/src/HPWH.cc index 2f1af3b2..d7c34b70 100644 --- a/src/HPWH.cc +++ b/src/HPWH.cc @@ -5426,7 +5426,7 @@ int HPWH::HPWHinit_file(string configFile) /// @brief Performs a draw/heat cycle to prep for test /// @return true (success), false (failure). //----------------------------------------------------------------------------- -bool HPWH::prepForTest() +bool HPWH::prepForTest(StandardTestOptions& standardTestOptions) { double flowRate_Lper_min = GAL_TO_L(3.); if (tankVolume_L < GAL_TO_L(20.)) @@ -5436,6 +5436,17 @@ bool HPWH::prepForTest() constexpr double ambientT_C = 19.7; // EERE-2019-BT-TP-0032-0058, p. 40435 constexpr double externalT_C = 19.7; + if (standardTestOptions.changeSetpoint) + { + if (!isSetpointFixed()) + { + if (setSetpoint(standardTestOptions.setpointT_C, UNITS_C) == HPWH_ABORT) + { + return false; + } + } + } + DRMODES drMode = DR_ALLOW; bool isDrawing = false; bool done = false; @@ -5508,7 +5519,7 @@ bool HPWH::prepForTest() /// @return true (success), false (failure). //----------------------------------------------------------------------------- bool HPWH::findFirstHourRating(FirstHourRating& firstHourRating, - const double setpointT_C /* = 51.7 */) + StandardTestOptions& standardTestOptions) { double flowRate_Lper_min = GAL_TO_L(3.); if (tankVolume_L < GAL_TO_L(20.)) @@ -5518,11 +5529,14 @@ bool HPWH::findFirstHourRating(FirstHourRating& firstHourRating, constexpr double ambientT_C = 19.7; // EERE-2019-BT-TP-0032-0058, p. 40435 constexpr double externalT_C = 19.7; - if (!isSetpointFixed()) + if (standardTestOptions.changeSetpoint) { - if (setSetpoint(setpointT_C, UNITS_C) == HPWH_ABORT) + if (!isSetpointFixed()) { - return false; + if (setSetpoint(standardTestOptions.setpointT_C, UNITS_C) == HPWH_ABORT) + { + return false; + } } } @@ -5547,7 +5561,7 @@ bool HPWH::findFirstHourRating(FirstHourRating& firstHourRating, bool done = false; int step = 0; - if (!prepForTest()) + if (!prepForTest(standardTestOptions)) { return false; } @@ -5683,7 +5697,7 @@ bool HPWH::findFirstHourRating(FirstHourRating& firstHourRating, //----------------------------------------------------------------------------- bool HPWH::run24hrTest(const FirstHourRating firstHourRating, StandardTestSummary& standardTestSummary, - const double setpointT_C /* = 51.7 */) + StandardTestOptions& standardTestOptions) { // select the draw pattern DrawPattern& drawPattern = drawPatterns[firstHourRating.desig]; @@ -5693,15 +5707,18 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, constexpr double externalT_C = 19.7; constexpr DRMODES drMode = DR_ALLOW; - if (!isSetpointFixed()) + if (standardTestOptions.changeSetpoint) { - if (setSetpoint(setpointT_C, UNITS_C) == HPWH_ABORT) + if (!isSetpointFixed()) { - return false; + if (setSetpoint(standardTestOptions.setpointT_C, UNITS_C) == HPWH_ABORT) + { + return false; + } } } - if (!prepForTest()) + if (!prepForTest(standardTestOptions)) { return false; } @@ -5833,6 +5850,24 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, } } + if (standardTestOptions.saveOutput) + { + std::string sPreamble = + std::to_string(runTime_min) + ", " + std::to_string(ambientT_C) + ", " + + std::to_string(getSetpoint()) + ", " + std::to_string(inletT_C) + ", " + + std::to_string(incrementalDrawVolume_L) + ", "; + + int csvOptions = HPWH::CSVOPT_NONE; + if (incrementalDrawVolume_L > 0.) + { + csvOptions |= HPWH::CSVOPT_IS_DRAWING; + } + WriteCSVRow(standardTestOptions.outputFile, + sPreamble.c_str(), + standardTestOptions.nTestTCouples, + csvOptions); + } + drawVolume_L += incrementalDrawVolume_L; ++runTime_min; } diff --git a/src/HPWH.hh b/src/HPWH.hh index a0a1ef1d..ded8441e 100644 --- a/src/HPWH.hh +++ b/src/HPWH.hh @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -977,28 +978,38 @@ class HPWH /// collection of information derived from standard test struct StandardTestSummary { - double UEF; - double recoveryEfficiency; - double dailyHeatingEnergyConsumption_kJ; - double adjustedDailyWaterHeatingEnergyConsumption_kJ; - double modifiedDailyWaterHeatingEnergyConsumption_kJ; - double energyUsedToHeatWater_kJ; - double standardEnergyUsedToHeatWater_kJ; - double annualElectricalEnergyConsumption_kJ; - double annualEnergyConsumption_kJ; + double UEF = 0.; + double recoveryEfficiency = 0.; + double dailyHeatingEnergyConsumption_kJ = 0.; + double adjustedDailyWaterHeatingEnergyConsumption_kJ = 0.; + double modifiedDailyWaterHeatingEnergyConsumption_kJ = 0.; + double energyUsedToHeatWater_kJ = 0.; + double standardEnergyUsedToHeatWater_kJ = 0.; + double annualElectricalEnergyConsumption_kJ = 0.; + double annualEnergyConsumption_kJ = 0.; bool qualifies = false; }; + struct StandardTestOptions + { + bool saveOutput = false; + bool changeSetpoint = false; + std::ofstream outputFile; + int nTestTCouples = 6; + double setpointT_C = 51.7; + }; + /// perform a draw/heat cycle to prepare for test - bool prepForTest(); + bool prepForTest(StandardTestOptions& standardTestOptions); /// determine first-hour rating - bool findFirstHourRating(FirstHourRating& firstHourRating, const double setpointT_C = 51.7); + bool findFirstHourRating(FirstHourRating& firstHourRating, + StandardTestOptions& standardTestOptions); /// run 24-hr draw pattern and compute metrics bool run24hrTest(const FirstHourRating firstHourRating, StandardTestSummary& standardTestSummary, - const double setpointT_C = 51.7); + StandardTestOptions& standardTestOptions); /// specific information for a single draw struct Draw diff --git a/test/testMeasureMetrics.cc b/test/testMeasureMetrics.cc index fc4ddc96..93b7620e 100644 --- a/test/testMeasureMetrics.cc +++ b/test/testMeasureMetrics.cc @@ -4,12 +4,14 @@ #include "HPWH.hh" #include "testUtilityFcts.cc" +#include #include /* Measure metrics using 24-hr test based on model name (preset only) */ static bool testMeasureMetrics(const std::string& sModelName, HPWH::FirstHourRating& firstHourRating, - HPWH::StandardTestSummary& standardTestSummary) + HPWH::StandardTestSummary& standardTestSummary, + HPWH::StandardTestOptions& standardTestOptions) { HPWH hpwh; @@ -19,12 +21,12 @@ static bool testMeasureMetrics(const std::string& sModelName, return false; } - if (!hpwh.findFirstHourRating(firstHourRating)) + if (!hpwh.findFirstHourRating(firstHourRating, standardTestOptions)) { return false; } - return hpwh.run24hrTest(firstHourRating, standardTestSummary); + return hpwh.run24hrTest(firstHourRating, standardTestSummary, standardTestOptions); } int main(int argc, char* argv[]) @@ -33,9 +35,16 @@ int main(int argc, char* argv[]) bool validNumArgs = false; bool runUnitTests = false; + HPWH::StandardTestOptions standardTestOptions; + standardTestOptions.saveOutput = false; + standardTestOptions.changeSetpoint = true; + standardTestOptions.nTestTCouples = 6; + standardTestOptions.setpointT_C = 51.7; + // process command line arguments std::string sPresetOrFile = "Preset"; std::string sModelName; + std::string sOutputDirectory; if (argc == 1) { runUnitTests = true; @@ -53,23 +62,35 @@ int main(int argc, char* argv[]) validNumArgs = true; runUnitTests = false; } + else if (argc == 4) + { + sPresetOrFile = argv[1]; + sModelName = argv[2]; + sOutputDirectory = argv[3]; + validNumArgs = true; + runUnitTests = false; + standardTestOptions.saveOutput = true; + } if (runUnitTests) { HPWH::FirstHourRating firstHourRating; - ASSERTTRUE(testMeasureMetrics("AquaThermAire", firstHourRating, standardTestSummary)); + ASSERTTRUE(testMeasureMetrics( + "AquaThermAire", firstHourRating, standardTestSummary, standardTestOptions)); ASSERTTRUE(standardTestSummary.qualifies); ASSERTTRUE(cmpd(firstHourRating.drawVolume_L, 272.5659)); ASSERTTRUE(firstHourRating.desig == HPWH::FirstHourRatingDesig::Medium); ASSERTTRUE(cmpd(standardTestSummary.UEF, 3.2212)); - ASSERTTRUE(testMeasureMetrics("AOSmithHPTS50", firstHourRating, standardTestSummary)); + ASSERTTRUE(testMeasureMetrics( + "AOSmithHPTS50", firstHourRating, standardTestSummary, standardTestOptions)); ASSERTTRUE(standardTestSummary.qualifies); ASSERTTRUE(cmpd(firstHourRating.drawVolume_L, 188.0432)); ASSERTTRUE(firstHourRating.desig == HPWH::FirstHourRatingDesig::Low); ASSERTTRUE(cmpd(standardTestSummary.UEF, 4.4914)); - ASSERTTRUE(testMeasureMetrics("AOSmithHPTS80", firstHourRating, standardTestSummary)); + ASSERTTRUE(testMeasureMetrics( + "AOSmithHPTS80", firstHourRating, standardTestSummary, standardTestOptions)); ASSERTTRUE(standardTestSummary.qualifies); ASSERTTRUE(cmpd(firstHourRating.drawVolume_L, 310.9384)); ASSERTTRUE(firstHourRating.desig == HPWH::FirstHourRatingDesig::High); @@ -82,9 +103,10 @@ int main(int argc, char* argv[]) { cout << "Invalid input:\n\ To run all unit tests, provide ZERO arguments.\n\ - To determine performance metrics for a particular model spec, provide ONE or TWO arguments:\n\ + To determine performance metrics for a particular model spec, provide ONE, TWO, or THREE arguments:\n\ \t[model spec Type, i.e., Preset (default) or File]\n\ - \t[model spec Name, i.e., Sanden80]\n"; + \t[model spec Name, i.e., Sanden80]\n\ + \t[output Directory, i.e., ..\\build\\test\\output]\n"; exit(1); } @@ -123,8 +145,31 @@ int main(int argc, char* argv[]) std::cout << "Spec type: " << sPresetOrFile << "\n"; std::cout << "Model name: " << sModelName << "\n"; + if (standardTestOptions.saveOutput) + { + std::string sOutputFilename = "test24hr_" + sPresetOrFile + "_" + sModelName + ".csv"; + + std::string sFullOutputFilename = sOutputDirectory + "/" + sOutputFilename; + standardTestOptions.outputFile.open(sFullOutputFilename.c_str(), std::ifstream::out); + if (!standardTestOptions.outputFile.is_open()) + { + cout << "Could not open output file " << sFullOutputFilename << "\n"; + exit(1); + } + std::cout << "Output file: " << sFullOutputFilename << "\n"; + + string strPreamble; + string sHeader = "minutes,Ta,Tsetpoint,inletT,draw,"; + + int csvOptions = HPWH::CSVOPT_NONE; + hpwh.WriteCSVHeading(standardTestOptions.outputFile, + sHeader.c_str(), + standardTestOptions.nTestTCouples, + csvOptions); + } + HPWH::FirstHourRating firstHourRating; - if (hpwh.findFirstHourRating(firstHourRating)) + if (hpwh.findFirstHourRating(firstHourRating, standardTestOptions)) { std::string sFirstHourRatingDesig = ""; switch (firstHourRating.desig) @@ -154,7 +199,7 @@ int main(int argc, char* argv[]) std::cout << "\t\tVolume Drawn (L): " << firstHourRating.drawVolume_L << "\n"; std::cout << "\t\tDesignation: " << sFirstHourRatingDesig << "\n"; - if (hpwh.run24hrTest(firstHourRating, standardTestSummary)) + if (hpwh.run24hrTest(firstHourRating, standardTestSummary, standardTestOptions)) { if (!standardTestSummary.qualifies) @@ -185,5 +230,10 @@ int main(int argc, char* argv[]) std::cout << "Unable to complete first-hour rating test.\n"; } + if (standardTestOptions.saveOutput) + { + standardTestOptions.outputFile.close(); + } + return 0; } From 5c0890f1d3f936c93fb26ecd4167f82f2f3093c4 Mon Sep 17 00:00:00 2001 From: Phil Ahrenkiel Date: Tue, 6 Feb 2024 12:00:59 -0700 Subject: [PATCH 24/37] Has calc issue. --- src/HPWH.cc | 236 +++++++++++++++++++++++++++++----------------------- 1 file changed, 134 insertions(+), 102 deletions(-) diff --git a/src/HPWH.cc b/src/HPWH.cc index d7c34b70..8d614bba 100644 --- a/src/HPWH.cc +++ b/src/HPWH.cc @@ -5755,7 +5755,7 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, double dailyRemovedVolume_L = 0.; double dailyUsedEnergy_kJ = 0.; - double dailyHeatingEnergy_kJ = 0.; // total energy added to water over 24-hr test + double dailyUsedHeatingEnergy_kJ = 0.; // total energy added to water over 24-hr test double dailyUsedElectricalEnergy_kJ = 0.; // total electrical energy consumed over 24-hr test // first-recovery info @@ -5764,135 +5764,167 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, double recoveryHeatingEnergy_kJ = 0.; bool hasHeated = false; - int runTime_min = 0; - for (auto& draw : drawPattern) - { - double drawVolume_L = 0.; - double drawHeatingEnergy_kJ = 0.; - double drawUsedElectricalEnergy_kJ = 0.; - double drawUsedFossilFuelEnergy_kJ = 0.; + int endTime_min = 24 * min_per_hr; + std::size_t iDraw = 0; + double remainingDrawVolume_L = 0.; + double drawVolume_L = 0.; + bool nextDraw = true; + bool isDrawComplete = false; + bool needCalc = false; + bool isFirstDraw = true; - double drawSumOutletVolumeT_LC = 0.; - double drawSumInletVolumeT_LC = 0.; - int drawSumTimeT_minC = 0; + double drawHeatingEnergy_kJ = 0.; + double drawUsedElectricalEnergy_kJ = 0.; + double drawUsedFossilFuelEnergy_kJ = 0.; - // limit draw-volume increment to tank volume - double incrementalDrawVolume_L = draw.flowRate_Lper_min * (1.); - if (incrementalDrawVolume_L > tankVolume_L) + double drawSumOutletVolumeT_LC = 0.; + double drawSumInletVolumeT_LC = 0.; + int drawSumTimeT_minC = 0; + + double stepDrawVolume_L = 0.; + for (int runTime_min = 0; runTime_min < endTime_min; ++runTime_min) + { + if (nextDraw) { - incrementalDrawVolume_L = tankVolume_L; + auto& draw = drawPattern[iDraw]; + if (runTime_min >= draw.startTime_min) + { + // limit draw-volume step to tank volume + stepDrawVolume_L = draw.flowRate_Lper_min * (1.); + if (stepDrawVolume_L > tankVolume_L) + { + stepDrawVolume_L = tankVolume_L; + } + + remainingDrawVolume_L = drawVolume_L = draw.volume_L; + + nextDraw = false; + isDrawComplete = false; + needCalc = false; + + drawHeatingEnergy_kJ = 0.; + drawUsedElectricalEnergy_kJ = 0.; + drawUsedFossilFuelEnergy_kJ = 0.; + + drawSumOutletVolumeT_LC = 0.; + drawSumInletVolumeT_LC = 0.; + drawSumTimeT_minC = 0; + } } - bool includedInFirstRecoveryPeriod = isFirstRecoveryPeriod; - bool isDrawComplete = false; // iterate until 1) specified draw volume has been reached and 2) next draw has started - while ((drawVolume_L < draw.volume_L) || (runTime_min < draw.startTime_min)) + // do not exceed specified draw volume + if ((!isDrawComplete) && (stepDrawVolume_L >= remainingDrawVolume_L)) { - // do not exceed specified draw volume - if (drawVolume_L + incrementalDrawVolume_L > draw.volume_L) - { - incrementalDrawVolume_L = draw.volume_L - drawVolume_L; - isDrawComplete = true; - } + stepDrawVolume_L = remainingDrawVolume_L; + remainingDrawVolume_L = 0.; + isDrawComplete = true; + needCalc = true; + } + + // run a step + int runResult = runOneStep(inletT_C, // inlet water temperature (C) + stepDrawVolume_L, // draw volume (L) + ambientT_C, // ambient Temp (C) + externalT_C, // external Temp (C) + drMode, // DDR Status + 0., // inlet-2 volume (L) + inletT_C, // inlet-2 Temp (C) + NULL); // no extra heat + + if (runResult == HPWH_ABORT) + { + return false; + } + + if (standardTestOptions.saveOutput) + { + std::string sPreamble = + std::to_string(runTime_min) + ", " + std::to_string(ambientT_C) + ", " + + std::to_string(getSetpoint()) + ", " + std::to_string(inletT_C) + ", " + + std::to_string(stepDrawVolume_L) + ", "; - // run a step - int runResult = runOneStep(inletT_C, // inlet water temperature (C) - incrementalDrawVolume_L, // draw volume (L) - ambientT_C, // ambient Temp (C) - externalT_C, // external Temp (C) - drMode, // DDR Status - 0., // inlet-2 volume (L) - inletT_C, // inlet-2 Temp (C) - NULL); // no extra heat - - if (runResult == HPWH_ABORT) + int csvOptions = HPWH::CSVOPT_NONE; + if (stepDrawVolume_L > 0.) { - return false; + csvOptions |= HPWH::CSVOPT_IS_DRAWING; } + WriteCSVRow(standardTestOptions.outputFile, + sPreamble.c_str(), + standardTestOptions.nTestTCouples, + csvOptions); + } - tankT_C = getAverageTankTemp_C(); - hasHeated |= isHeating; + remainingDrawVolume_L -= stepDrawVolume_L; - drawSumOutletVolumeT_LC += incrementalDrawVolume_L * outletTemp_C; - drawSumInletVolumeT_LC += incrementalDrawVolume_L * inletT_C; - ++drawSumTimeT_minC; + tankT_C = getAverageTankTemp_C(); + hasHeated |= isHeating; - // collect heating energy - double incrementalDrawMass_kg = DENSITYWATER_kgperL * incrementalDrawVolume_L; - double incrementalDrawHeatCapacity_kJperC = CPWATER_kJperkgC * incrementalDrawMass_kg; - drawHeatingEnergy_kJ += incrementalDrawHeatCapacity_kJperC * (outletTemp_C - inletT_C); + drawSumOutletVolumeT_LC += stepDrawVolume_L * outletTemp_C; + drawSumInletVolumeT_LC += stepDrawVolume_L * inletT_C; + ++drawSumTimeT_minC; - // collect used-energy info - double usedFossilFuelEnergy_kJ = 0.; - double usedElectricalEnergy_kJ = 0.; - for (int iHS = 0; iHS < getNumHeatSources(); ++iHS) - { - usedElectricalEnergy_kJ += getNthHeatSourceEnergyInput(iHS, HPWH::UNITS_KJ); - } - drawUsedFossilFuelEnergy_kJ += usedFossilFuelEnergy_kJ; - drawUsedElectricalEnergy_kJ += usedElectricalEnergy_kJ; + // collect heating energy + double stepDrawMass_kg = DENSITYWATER_kgperL * stepDrawVolume_L; + double stepDrawHeatCapacity_kJperC = CPWATER_kJperkgC * stepDrawMass_kg; + drawHeatingEnergy_kJ += stepDrawHeatCapacity_kJperC * (outletTemp_C - inletT_C); - // collect recovery info + // collect used-energy info + double usedFossilFuelEnergy_kJ = 0.; + double usedElectricalEnergy_kJ = 0.; + for (int iHS = 0; iHS < getNumHeatSources(); ++iHS) + { + usedElectricalEnergy_kJ += getNthHeatSourceEnergyInput(iHS, HPWH::UNITS_KJ); + } + drawUsedFossilFuelEnergy_kJ += usedFossilFuelEnergy_kJ; + drawUsedElectricalEnergy_kJ += usedElectricalEnergy_kJ; + + if (isDrawComplete && needCalc) + { if (isFirstRecoveryPeriod) { - firstRecoveryUsedEnergy_kJ += usedFossilFuelEnergy_kJ + usedElectricalEnergy_kJ; - if (isDrawComplete) // check for cut-off + if (hasHeated && (!isHeating)) { - if (hasHeated && (!isHeating)) - { - isFirstRecoveryPeriod = false; - - double tankContentMass_kg = DENSITYWATER_kgperL * tankVolume_L; - double tankHeatCapacity_kJperC = CPWATER_kJperkgC * tankContentMass_kg; - recoveryHeatingEnergy_kJ += - tankHeatCapacity_kJperC * (tankT_C - initialTankT_C); - } + // collect recovery info + isFirstRecoveryPeriod = false; + + double tankContentMass_kg = DENSITYWATER_kgperL * tankVolume_L; + double tankHeatCapacity_kJperC = CPWATER_kJperkgC * tankContentMass_kg; + recoveryHeatingEnergy_kJ += + tankHeatCapacity_kJperC * (tankT_C - initialTankT_C); + isFirstDraw = false; } - } - if (standardTestOptions.saveOutput) - { - std::string sPreamble = - std::to_string(runTime_min) + ", " + std::to_string(ambientT_C) + ", " + - std::to_string(getSetpoint()) + ", " + std::to_string(inletT_C) + ", " + - std::to_string(incrementalDrawVolume_L) + ", "; + double meanDrawOutletT_C = drawSumOutletVolumeT_LC / drawVolume_L; + double meanDrawInletT_C = drawSumInletVolumeT_LC / drawVolume_L; - int csvOptions = HPWH::CSVOPT_NONE; - if (incrementalDrawVolume_L > 0.) - { - csvOptions |= HPWH::CSVOPT_IS_DRAWING; - } - WriteCSVRow(standardTestOptions.outputFile, - sPreamble.c_str(), - standardTestOptions.nTestTCouples, - csvOptions); - } + double drawMass_kg = DENSITYWATER_kgperL * drawVolume_L; + double drawHeatCapacity_kJperC = CPWATER_kJperkgC * drawMass_kg; - drawVolume_L += incrementalDrawVolume_L; - ++runTime_min; - } + recoveryHeatingEnergy_kJ += + drawHeatCapacity_kJperC * (meanDrawOutletT_C - meanDrawInletT_C); - if (includedInFirstRecoveryPeriod) - { - double meanDrawOutletT_C = drawSumOutletVolumeT_LC / drawVolume_L; - double meanDrawInletT_C = drawSumInletVolumeT_LC / drawVolume_L; + firstRecoveryUsedEnergy_kJ += + drawUsedFossilFuelEnergy_kJ + drawUsedElectricalEnergy_kJ; + } - double drawMass_kg = DENSITYWATER_kgperL * drawVolume_L; - double drawHeatCapacity_kJperC = CPWATER_kJperkgC * drawMass_kg; + // collect 24-hr test info + dailyRemovedVolume_L += drawVolume_L; + dailyUsedHeatingEnergy_kJ += drawHeatingEnergy_kJ; + dailyUsedElectricalEnergy_kJ += drawUsedElectricalEnergy_kJ; + dailyUsedEnergy_kJ += drawUsedFossilFuelEnergy_kJ + drawUsedElectricalEnergy_kJ; - recoveryHeatingEnergy_kJ += - drawHeatCapacity_kJperC * (meanDrawOutletT_C - meanDrawInletT_C); + ++iDraw; + if (iDraw < drawPattern.size()) + { + nextDraw = true; + } + needCalc = false; } - - // collect 24-hr test info - dailyRemovedVolume_L += drawVolume_L; - dailyHeatingEnergy_kJ += drawHeatingEnergy_kJ; - dailyUsedElectricalEnergy_kJ += drawUsedElectricalEnergy_kJ; - dailyUsedEnergy_kJ += drawUsedFossilFuelEnergy_kJ + drawUsedElectricalEnergy_kJ; } // require heating during 24-hr test for unit to qualify as consumer water heater - if (hasHeated) + if (hasHeated && isDrawComplete) { standardTestSummary.qualifies = true; } @@ -5935,7 +5967,7 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, if (standardTestSummary.recoveryEfficiency > 0.) { standardTestSummary.energyUsedToHeatWater_kJ = - dailyHeatingEnergy_kJ / standardTestSummary.recoveryEfficiency; + dailyUsedHeatingEnergy_kJ / standardTestSummary.recoveryEfficiency; } // find the "Standard Energy Used to Heat Water (Q_HW,T)" (6.3.6b) From cda3c137b9a3904319b95537511fb5c24f920e29 Mon Sep 17 00:00:00 2001 From: Phil Ahrenkiel Date: Tue, 6 Feb 2024 15:16:11 -0700 Subject: [PATCH 25/37] In progress. --- src/HPWH.cc | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/HPWH.cc b/src/HPWH.cc index 8d614bba..567d5819 100644 --- a/src/HPWH.cc +++ b/src/HPWH.cc @@ -5814,12 +5814,9 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, // iterate until 1) specified draw volume has been reached and 2) next draw has started // do not exceed specified draw volume - if ((!isDrawComplete) && (stepDrawVolume_L >= remainingDrawVolume_L)) + if (stepDrawVolume_L >= remainingDrawVolume_L) { stepDrawVolume_L = remainingDrawVolume_L; - remainingDrawVolume_L = 0.; - isDrawComplete = true; - needCalc = true; } // run a step @@ -5857,6 +5854,12 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, remainingDrawVolume_L -= stepDrawVolume_L; + if (remainingDrawVolume_L <= 0.) + { + isDrawComplete = true; + needCalc = true; + } + tankT_C = getAverageTankTemp_C(); hasHeated |= isHeating; From 158d1d5260236bd28e0a328e3bcc27fa92e844c9 Mon Sep 17 00:00:00 2001 From: Phil Ahrenkiel Date: Wed, 7 Feb 2024 09:29:43 -0700 Subject: [PATCH 26/37] For comparison. --- src/HPWH.cc | 72 ++++++++++++++++++++++++----------------------------- 1 file changed, 33 insertions(+), 39 deletions(-) diff --git a/src/HPWH.cc b/src/HPWH.cc index 567d5819..dc5da599 100644 --- a/src/HPWH.cc +++ b/src/HPWH.cc @@ -5768,21 +5768,18 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, std::size_t iDraw = 0; double remainingDrawVolume_L = 0.; double drawVolume_L = 0.; + bool nextDraw = true; bool isDrawComplete = false; bool needCalc = false; bool isFirstDraw = true; - double drawHeatingEnergy_kJ = 0.; - double drawUsedElectricalEnergy_kJ = 0.; - double drawUsedFossilFuelEnergy_kJ = 0.; - double drawSumOutletVolumeT_LC = 0.; double drawSumInletVolumeT_LC = 0.; int drawSumTimeT_minC = 0; double stepDrawVolume_L = 0.; - for (int runTime_min = 0; runTime_min < endTime_min; ++runTime_min) + for (int runTime_min = 0; runTime_min <= endTime_min; ++runTime_min) { if (nextDraw) { @@ -5802,10 +5799,6 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, isDrawComplete = false; needCalc = false; - drawHeatingEnergy_kJ = 0.; - drawUsedElectricalEnergy_kJ = 0.; - drawUsedFossilFuelEnergy_kJ = 0.; - drawSumOutletVolumeT_LC = 0.; drawSumInletVolumeT_LC = 0.; drawSumTimeT_minC = 0; @@ -5817,6 +5810,9 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, if (stepDrawVolume_L >= remainingDrawVolume_L) { stepDrawVolume_L = remainingDrawVolume_L; + + isDrawComplete = true; + needCalc = true; } // run a step @@ -5854,12 +5850,6 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, remainingDrawVolume_L -= stepDrawVolume_L; - if (remainingDrawVolume_L <= 0.) - { - isDrawComplete = true; - needCalc = true; - } - tankT_C = getAverageTankTemp_C(); hasHeated |= isHeating; @@ -5870,7 +5860,7 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, // collect heating energy double stepDrawMass_kg = DENSITYWATER_kgperL * stepDrawVolume_L; double stepDrawHeatCapacity_kJperC = CPWATER_kJperkgC * stepDrawMass_kg; - drawHeatingEnergy_kJ += stepDrawHeatCapacity_kJperC * (outletTemp_C - inletT_C); + double usedHeatingEnergy_kJ = stepDrawHeatCapacity_kJperC * (outletTemp_C - inletT_C); // collect used-energy info double usedFossilFuelEnergy_kJ = 0.; @@ -5879,10 +5869,19 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, { usedElectricalEnergy_kJ += getNthHeatSourceEnergyInput(iHS, HPWH::UNITS_KJ); } - drawUsedFossilFuelEnergy_kJ += usedFossilFuelEnergy_kJ; - drawUsedElectricalEnergy_kJ += usedElectricalEnergy_kJ; - if (isDrawComplete && needCalc) + // collect 24-hr test info + dailyRemovedVolume_L += stepDrawVolume_L; + dailyUsedHeatingEnergy_kJ += usedHeatingEnergy_kJ; + dailyUsedElectricalEnergy_kJ += usedElectricalEnergy_kJ; + dailyUsedEnergy_kJ += usedFossilFuelEnergy_kJ + usedElectricalEnergy_kJ; + + if (isFirstRecoveryPeriod) + { + firstRecoveryUsedEnergy_kJ += usedFossilFuelEnergy_kJ + usedElectricalEnergy_kJ; + } + + if (isDrawComplete) { if (isFirstRecoveryPeriod) { @@ -5895,34 +5894,29 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, double tankHeatCapacity_kJperC = CPWATER_kJperkgC * tankContentMass_kg; recoveryHeatingEnergy_kJ += tankHeatCapacity_kJperC * (tankT_C - initialTankT_C); - isFirstDraw = false; } - double meanDrawOutletT_C = drawSumOutletVolumeT_LC / drawVolume_L; - double meanDrawInletT_C = drawSumInletVolumeT_LC / drawVolume_L; - - double drawMass_kg = DENSITYWATER_kgperL * drawVolume_L; - double drawHeatCapacity_kJperC = CPWATER_kJperkgC * drawMass_kg; + if (!nextDraw) + { + double meanDrawOutletT_C = drawSumOutletVolumeT_LC / drawVolume_L; + double meanDrawInletT_C = drawSumInletVolumeT_LC / drawVolume_L; - recoveryHeatingEnergy_kJ += - drawHeatCapacity_kJperC * (meanDrawOutletT_C - meanDrawInletT_C); + double drawMass_kg = DENSITYWATER_kgperL * drawVolume_L; + double drawHeatCapacity_kJperC = CPWATER_kJperkgC * drawMass_kg; - firstRecoveryUsedEnergy_kJ += - drawUsedFossilFuelEnergy_kJ + drawUsedElectricalEnergy_kJ; + recoveryHeatingEnergy_kJ += + drawHeatCapacity_kJperC * (meanDrawOutletT_C - meanDrawInletT_C); + } } - // collect 24-hr test info - dailyRemovedVolume_L += drawVolume_L; - dailyUsedHeatingEnergy_kJ += drawHeatingEnergy_kJ; - dailyUsedElectricalEnergy_kJ += drawUsedElectricalEnergy_kJ; - dailyUsedEnergy_kJ += drawUsedFossilFuelEnergy_kJ + drawUsedElectricalEnergy_kJ; - - ++iDraw; - if (iDraw < drawPattern.size()) + if (!nextDraw) { - nextDraw = true; + ++iDraw; + if (iDraw < drawPattern.size()) + { + nextDraw = true; + } } - needCalc = false; } } From 2c09e4f5bfa0931c5152ec2a9ac298f638c9ae96 Mon Sep 17 00:00:00 2001 From: Phil Ahrenkiel Date: Wed, 7 Feb 2024 12:18:35 -0700 Subject: [PATCH 27/37] Record pre-test minutes. --- src/HPWH.cc | 120 ++++++++++++++++++++++++++++++++++++++++++++++------ src/HPWH.hh | 19 +++++++++ 2 files changed, 127 insertions(+), 12 deletions(-) diff --git a/src/HPWH.cc b/src/HPWH.cc index dc5da599..32059089 100644 --- a/src/HPWH.cc +++ b/src/HPWH.cc @@ -1236,6 +1236,52 @@ int HPWH::WriteCSVRow(std::ofstream& outFILE, return 0; } +int HPWH::writeRowAsCSV(std::ofstream& outFILE, + OutputData& outputData, + const CSVOPTIONS& options /* = CSVOPTIONS::CSVOPT_NONE */) const +{ + bool doIP = (options & CSVOPT_IPUNITS) != 0; + + // + outFILE << fmt::format("{}", outputData.time_min); + outFILE << fmt::format(",{:0.2f}", + doIP ? C_TO_F(outputData.ambientT_C) : outputData.ambientT_C); + outFILE << fmt::format(",{:0.2f}", + doIP ? C_TO_F(outputData.setpointT_C) : outputData.setpointT_C); + outFILE << fmt::format(",{:0.2f}", doIP ? C_TO_F(outputData.inletT_C) : outputData.inletT_C); + outFILE << fmt::format(",{:0.2f}", + doIP ? L_TO_GAL(outputData.drawVolume_L) : outputData.drawVolume_L); + outFILE << fmt::format(",{}", outputData.drMode); + + // + for (int iHS = 0; iHS < getNumHeatSources(); iHS++) + { + outFILE << fmt::format(",{:0.2f},{:0.2f}", + outputData.h_srcIn_kWh[iHS] * 1000., + outputData.h_srcOut_kWh[iHS] * 1000.); + } + + // + for (auto thermocoupleT_C : outputData.thermocoupleT_C) + { + outFILE << fmt::format(",{:0.2f}", doIP ? C_TO_F(thermocoupleT_C) : thermocoupleT_C); + } + + // + if (outputData.drawVolume_L > 0.) + { + outFILE << fmt::format(",{:0.2f}", + doIP ? C_TO_F(outputData.outletT_C) : outputData.outletT_C); + } + else + { + outFILE << ","; + } + + outFILE << std::endl; + return 0; +} + bool HPWH::isSetpointFixed() const { return setpointFixed; } int HPWH::setSetpoint(double newSetpoint, UNITS units /*=UNITS_C*/) @@ -5723,6 +5769,8 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, return false; } + std::vector outputDataSet; + // idle for 1 hr int preTime_min = 0; bool heatersAreOn = false; @@ -5747,9 +5795,41 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, heatersAreOn |= heatSource.isEngaged(); } + { + OutputData outputData; + outputData.time_min = preTime_min; + outputData.ambientT_C = ambientT_C; + outputData.setpointT_C = getSetpoint(); + outputData.inletT_C = inletT_C; + outputData.drawVolume_L = 0.; + outputData.drMode = drMode; + + for (int iHS = 0; iHS < getNumHeatSources(); ++iHS) + { + outputData.h_srcIn_kWh.push_back(getNthHeatSourceEnergyInput(iHS, HPWH::UNITS_KWH)); + outputData.h_srcOut_kWh.push_back( + getNthHeatSourceEnergyOutput(iHS, HPWH::UNITS_KWH)); + } + + for (int iTC = 0; iTC < standardTestOptions.nTestTCouples; ++iTC) + { + outputData.thermocoupleT_C.push_back( + getNthSimTcouple(iTC + 1, standardTestOptions.nTestTCouples, UNITS_C)); + } + outputData.outletT_C = 0.; + + outputDataSet.push_back(outputData); + } + ++preTime_min; } + // correct time to start test at 0 min + for (auto& outputData : outputDataSet) + { + outputData.time_min -= preTime_min; + } + double tankT_C = getAverageTankTemp_C(); double initialTankT_C = tankT_C; @@ -5830,22 +5910,30 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, return false; } - if (standardTestOptions.saveOutput) { - std::string sPreamble = - std::to_string(runTime_min) + ", " + std::to_string(ambientT_C) + ", " + - std::to_string(getSetpoint()) + ", " + std::to_string(inletT_C) + ", " + - std::to_string(stepDrawVolume_L) + ", "; + OutputData outputData; + outputData.time_min = runTime_min; + outputData.ambientT_C = ambientT_C; + outputData.setpointT_C = getSetpoint(); + outputData.inletT_C = inletT_C; + outputData.drawVolume_L = stepDrawVolume_L; + outputData.drMode = drMode; + + for (int iHS = 0; iHS < getNumHeatSources(); ++iHS) + { + outputData.h_srcIn_kWh.push_back(getNthHeatSourceEnergyInput(iHS, HPWH::UNITS_KWH)); + outputData.h_srcOut_kWh.push_back( + getNthHeatSourceEnergyOutput(iHS, HPWH::UNITS_KWH)); + } - int csvOptions = HPWH::CSVOPT_NONE; - if (stepDrawVolume_L > 0.) + for (int iTC = 0; iTC < standardTestOptions.nTestTCouples; ++iTC) { - csvOptions |= HPWH::CSVOPT_IS_DRAWING; + outputData.thermocoupleT_C.push_back( + getNthSimTcouple(iTC + 1, standardTestOptions.nTestTCouples, UNITS_C)); } - WriteCSVRow(standardTestOptions.outputFile, - sPreamble.c_str(), - standardTestOptions.nTestTCouples, - csvOptions); + outputData.outletT_C = outletTemp_C; + + outputDataSet.push_back(outputData); } remainingDrawVolume_L -= stepDrawVolume_L; @@ -5920,6 +6008,14 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, } } + if (standardTestOptions.saveOutput) + { + for (auto& outputData : outputDataSet) + { + writeRowAsCSV(standardTestOptions.outputFile, outputData); + } + } + // require heating during 24-hr test for unit to qualify as consumer water heater if (hasHeated && isDrawComplete) { diff --git a/src/HPWH.hh b/src/HPWH.hh index ded8441e..df23d013 100644 --- a/src/HPWH.hh +++ b/src/HPWH.hh @@ -1034,6 +1034,25 @@ class HPWH /// collection of standard draw patterns static std::unordered_map drawPatterns; + /// fields for test output to csv + struct OutputData + { + int time_min; + double ambientT_C; + double setpointT_C; + double inletT_C; + double drawVolume_L; + DRMODES drMode; + std::vector h_srcIn_kWh; + std::vector h_srcOut_kWh; + std::vector thermocoupleT_C; + double outletT_C; + }; + + int writeRowAsCSV(std::ofstream& outFILE, + OutputData& outputData, + const CSVOPTIONS& options = CSVOPTIONS::CSVOPT_NONE) const; + private: class HeatSource; From e70b057db29da5d804698f60f84f10dc121f400f Mon Sep 17 00:00:00 2001 From: Phil Ahrenkiel Date: Thu, 8 Feb 2024 13:21:34 -0700 Subject: [PATCH 28/37] Improved calc. --- src/HPWH.cc | 196 +++++++++++++++++++------------------ src/HPWH.hh | 32 ++++-- test/testMeasureMetrics.cc | 10 +- 3 files changed, 132 insertions(+), 106 deletions(-) diff --git a/src/HPWH.cc b/src/HPWH.cc index 32059089..5f3a11f8 100644 --- a/src/HPWH.cc +++ b/src/HPWH.cc @@ -65,6 +65,12 @@ const double HPWH::MAXOUTLET_R410A = F_TO_C(140.); const double HPWH::MAXOUTLET_R744 = F_TO_C(190.); const double HPWH::MINSINGLEPASSLIFT = dF_TO_dC(15.); +std::unordered_map HPWH::firstDrawClusterSizes = { + {HPWH::FirstHourRatingDesig::VerySmall, 5}, + {HPWH::FirstHourRatingDesig::Low, 3}, + {HPWH::FirstHourRatingDesig::Medium, 3}, + {HPWH::FirstHourRatingDesig::High, 4}}; + std::unordered_map HPWH::drawPatterns = { {HPWH::FirstHourRatingDesig::VerySmall, {{HM_TO_MIN(0, 00), 7.6, 3.8}, @@ -5472,7 +5478,7 @@ int HPWH::HPWHinit_file(string configFile) /// @brief Performs a draw/heat cycle to prep for test /// @return true (success), false (failure). //----------------------------------------------------------------------------- -bool HPWH::prepForTest(StandardTestOptions& standardTestOptions) +bool HPWH::prepForTest(StandardTestOptions& testOptions) { double flowRate_Lper_min = GAL_TO_L(3.); if (tankVolume_L < GAL_TO_L(20.)) @@ -5482,11 +5488,11 @@ bool HPWH::prepForTest(StandardTestOptions& standardTestOptions) constexpr double ambientT_C = 19.7; // EERE-2019-BT-TP-0032-0058, p. 40435 constexpr double externalT_C = 19.7; - if (standardTestOptions.changeSetpoint) + if (testOptions.changeSetpoint) { if (!isSetpointFixed()) { - if (setSetpoint(standardTestOptions.setpointT_C, UNITS_C) == HPWH_ABORT) + if (setSetpoint(testOptions.setpointT_C, UNITS_C) == HPWH_ABORT) { return false; } @@ -5564,8 +5570,7 @@ bool HPWH::prepForTest(StandardTestOptions& standardTestOptions) /// @param[in] setpointT_C setpoint temperature (optional) /// @return true (success), false (failure). //----------------------------------------------------------------------------- -bool HPWH::findFirstHourRating(FirstHourRating& firstHourRating, - StandardTestOptions& standardTestOptions) +bool HPWH::findFirstHourRating(FirstHourRating& firstHourRating, StandardTestOptions& testOptions) { double flowRate_Lper_min = GAL_TO_L(3.); if (tankVolume_L < GAL_TO_L(20.)) @@ -5575,11 +5580,11 @@ bool HPWH::findFirstHourRating(FirstHourRating& firstHourRating, constexpr double ambientT_C = 19.7; // EERE-2019-BT-TP-0032-0058, p. 40435 constexpr double externalT_C = 19.7; - if (standardTestOptions.changeSetpoint) + if (testOptions.changeSetpoint) { if (!isSetpointFixed()) { - if (setSetpoint(standardTestOptions.setpointT_C, UNITS_C) == HPWH_ABORT) + if (setSetpoint(testOptions.setpointT_C, UNITS_C) == HPWH_ABORT) { return false; } @@ -5607,7 +5612,7 @@ bool HPWH::findFirstHourRating(FirstHourRating& firstHourRating, bool done = false; int step = 0; - if (!prepForTest(standardTestOptions)) + if (!prepForTest(testOptions)) { return false; } @@ -5737,34 +5742,35 @@ bool HPWH::findFirstHourRating(FirstHourRating& firstHourRating, /// @brief Performs standard 24-hr test /// @note see https://www.regulations.gov/document/EERE-2019-BT-TP-0032-0058 /// @param[in] firstHourRating specifies first-hour rating -/// @param[out] standardTestSummary contains test metrics on output +/// @param[out] testSummary contains test metrics on output /// @param[in] setpointT_C setpoint temperature (optional) /// @return true (success), false (failure). //----------------------------------------------------------------------------- bool HPWH::run24hrTest(const FirstHourRating firstHourRating, - StandardTestSummary& standardTestSummary, - StandardTestOptions& standardTestOptions) + StandardTestSummary& testSummary, + StandardTestOptions& testOptions) { - // select the draw pattern + // select the first draw cluster size and pattern + int firstDrawClusterSize = firstDrawClusterSizes[firstHourRating.desig]; DrawPattern& drawPattern = drawPatterns[firstHourRating.desig]; constexpr double inletT_C = 14.4; // EERE-2019-BT-TP-0032-0058, p. 40433 constexpr double ambientT_C = 19.7; // EERE-2019-BT-TP-0032-0058, p. 40435 constexpr double externalT_C = 19.7; - constexpr DRMODES drMode = DR_ALLOW; + DRMODES drMode = DR_ALLOW; - if (standardTestOptions.changeSetpoint) + if (testOptions.changeSetpoint) { if (!isSetpointFixed()) { - if (setSetpoint(standardTestOptions.setpointT_C, UNITS_C) == HPWH_ABORT) + if (setSetpoint(testOptions.setpointT_C, UNITS_C) == HPWH_ABORT) { return false; } } } - if (!prepForTest(standardTestOptions)) + if (!prepForTest(testOptions)) { return false; } @@ -5811,10 +5817,10 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, getNthHeatSourceEnergyOutput(iHS, HPWH::UNITS_KWH)); } - for (int iTC = 0; iTC < standardTestOptions.nTestTCouples; ++iTC) + for (int iTC = 0; iTC < testOptions.nTestTCouples; ++iTC) { outputData.thermocoupleT_C.push_back( - getNthSimTcouple(iTC + 1, standardTestOptions.nTestTCouples, UNITS_C)); + getNthSimTcouple(iTC + 1, testOptions.nTestTCouples, UNITS_C)); } outputData.outletT_C = 0.; @@ -5833,18 +5839,22 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, double tankT_C = getAverageTankTemp_C(); double initialTankT_C = tankT_C; - double dailyRemovedVolume_L = 0.; - double dailyUsedEnergy_kJ = 0.; - double dailyUsedHeatingEnergy_kJ = 0.; // total energy added to water over 24-hr test - double dailyUsedElectricalEnergy_kJ = 0.; // total electrical energy consumed over 24-hr test + double deliveredEnergy_kJ = 0.; // total energy delivered to water + testSummary.removedVolume_L = 0.; + testSummary.usedEnergy_kJ = 0.; // Q + testSummary.usedFossilFuelEnergy_kJ = 0.; // total fossil-fuel energy consumed, Qf + testSummary.usedElectricalEnergy_kJ = 0.; // total electrical energy consumed, Qe // first-recovery info bool isFirstRecoveryPeriod = true; - double firstRecoveryUsedEnergy_kJ = 0.; - double recoveryHeatingEnergy_kJ = 0.; + testSummary.recoveryStoredEnergy_kJ = 0.; + testSummary.recoveryDeliveredEnergy_kJ = 0.; + testSummary.recoveryUsedEnergy_kJ = 0.; + bool hasHeated = false; int endTime_min = 24 * min_per_hr; + int standbyStartTime_min = 23 * min_per_hr; std::size_t iDraw = 0; double remainingDrawVolume_L = 0.; double drawVolume_L = 0.; @@ -5858,9 +5868,16 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, double drawSumInletVolumeT_LC = 0.; int drawSumTimeT_minC = 0; + bool inLastHour = false; double stepDrawVolume_L = 0.; for (int runTime_min = 0; runTime_min <= endTime_min; ++runTime_min) { + if ((runTime_min >= standbyStartTime_min) && (!inLastHour)) + { + inLastHour = true; + drMode = DR_LOC | DR_LOR; + } + if (nextDraw) { auto& draw = drawPattern[iDraw]; @@ -5926,10 +5943,10 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, getNthHeatSourceEnergyOutput(iHS, HPWH::UNITS_KWH)); } - for (int iTC = 0; iTC < standardTestOptions.nTestTCouples; ++iTC) + for (int iTC = 0; iTC < testOptions.nTestTCouples; ++iTC) { outputData.thermocoupleT_C.push_back( - getNthSimTcouple(iTC + 1, standardTestOptions.nTestTCouples, UNITS_C)); + getNthSimTcouple(iTC + 1, testOptions.nTestTCouples, UNITS_C)); } outputData.outletT_C = outletTemp_C; @@ -5945,10 +5962,10 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, drawSumInletVolumeT_LC += stepDrawVolume_L * inletT_C; ++drawSumTimeT_minC; - // collect heating energy + // collect energy added to water double stepDrawMass_kg = DENSITYWATER_kgperL * stepDrawVolume_L; double stepDrawHeatCapacity_kJperC = CPWATER_kJperkgC * stepDrawMass_kg; - double usedHeatingEnergy_kJ = stepDrawHeatCapacity_kJperC * (outletTemp_C - inletT_C); + deliveredEnergy_kJ += stepDrawHeatCapacity_kJperC * (outletTemp_C - inletT_C); // collect used-energy info double usedFossilFuelEnergy_kJ = 0.; @@ -5959,14 +5976,14 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, } // collect 24-hr test info - dailyRemovedVolume_L += stepDrawVolume_L; - dailyUsedHeatingEnergy_kJ += usedHeatingEnergy_kJ; - dailyUsedElectricalEnergy_kJ += usedElectricalEnergy_kJ; - dailyUsedEnergy_kJ += usedFossilFuelEnergy_kJ + usedElectricalEnergy_kJ; + testSummary.removedVolume_L += stepDrawVolume_L; + testSummary.usedFossilFuelEnergy_kJ += usedFossilFuelEnergy_kJ; + testSummary.usedElectricalEnergy_kJ += usedElectricalEnergy_kJ; + testSummary.usedEnergy_kJ += usedFossilFuelEnergy_kJ + usedElectricalEnergy_kJ; if (isFirstRecoveryPeriod) { - firstRecoveryUsedEnergy_kJ += usedFossilFuelEnergy_kJ + usedElectricalEnergy_kJ; + testSummary.recoveryUsedEnergy_kJ += usedFossilFuelEnergy_kJ + usedElectricalEnergy_kJ; } if (isDrawComplete) @@ -5980,7 +5997,7 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, double tankContentMass_kg = DENSITYWATER_kgperL * tankVolume_L; double tankHeatCapacity_kJperC = CPWATER_kJperkgC * tankContentMass_kg; - recoveryHeatingEnergy_kJ += + testSummary.recoveryStoredEnergy_kJ = tankHeatCapacity_kJperC * (tankT_C - initialTankT_C); } @@ -5992,7 +6009,7 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, double drawMass_kg = DENSITYWATER_kgperL * drawVolume_L; double drawHeatCapacity_kJperC = CPWATER_kJperkgC * drawMass_kg; - recoveryHeatingEnergy_kJ += + testSummary.recoveryDeliveredEnergy_kJ += drawHeatCapacity_kJperC * (meanDrawOutletT_C - meanDrawInletT_C); } } @@ -6008,112 +6025,105 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, } } - if (standardTestOptions.saveOutput) + double finalTankT_C = tankT_C; + + if (testOptions.saveOutput) { for (auto& outputData : outputDataSet) { - writeRowAsCSV(standardTestOptions.outputFile, outputData); + writeRowAsCSV(testOptions.outputFile, outputData); } } // require heating during 24-hr test for unit to qualify as consumer water heater if (hasHeated && isDrawComplete) { - standardTestSummary.qualifies = true; + testSummary.qualifies = true; } // find the "Recovery Efficiency" (6.3.3) - standardTestSummary.recoveryEfficiency = 0.; - if (firstRecoveryUsedEnergy_kJ > 0.) + testSummary.recoveryEfficiency = 0.; + if (testSummary.recoveryUsedEnergy_kJ > 0.) { - standardTestSummary.recoveryEfficiency = - recoveryHeatingEnergy_kJ / firstRecoveryUsedEnergy_kJ; + testSummary.recoveryEfficiency = + (testSummary.recoveryStoredEnergy_kJ + testSummary.recoveryDeliveredEnergy_kJ) / + testSummary.recoveryUsedEnergy_kJ; } - // find the standard daily heating energy + // find the standard delivered daily energy constexpr double standardSetpointT_C = 51.7; constexpr double standardInletT_C = 14.4; - double dailyMassRemoved_kg = HPWH::DENSITYWATER_kgperL * dailyRemovedVolume_L; - double dailyHeatCapacity_kJperC = HPWH::CPWATER_kJperkgC * dailyMassRemoved_kg; - double standardDailyHeatingEnergy_kJ = - dailyHeatCapacity_kJperC * (standardSetpointT_C - standardInletT_C); + double removedMass_kg = HPWH::DENSITYWATER_kgperL * testSummary.removedVolume_L; + double removedHeatCapacity_kJperC = HPWH::CPWATER_kJperkgC * removedMass_kg; + double standardDeliveredEnergy_kJ = + removedHeatCapacity_kJperC * (standardSetpointT_C - standardInletT_C); - // find the "Daily Water Heating Energy Consumption (Qd)" (6.3.5) - standardTestSummary.dailyHeatingEnergyConsumption_kJ = dailyUsedEnergy_kJ; - if (standardTestSummary.recoveryEfficiency > 0.) + // find the "Daily Water Heating Energy Consumption (Q_d)" (6.3.5) + testSummary.consumedHeatingEnergy_kJ = testSummary.usedEnergy_kJ; + if (testSummary.recoveryEfficiency > 0.) { double tankContentMass_kg = DENSITYWATER_kgperL * tankVolume_L; double tankHeatCapacity_kJperC = CPWATER_kJperkgC * tankContentMass_kg; - double finalTankT_C = tankT_C; - standardTestSummary.dailyHeatingEnergyConsumption_kJ -= - tankHeatCapacity_kJperC * (finalTankT_C - initialTankT_C) / - standardTestSummary.recoveryEfficiency; + testSummary.consumedHeatingEnergy_kJ -= tankHeatCapacity_kJperC * + (finalTankT_C - initialTankT_C) / + testSummary.recoveryEfficiency; } - // find the "Adjusted Daily Water Heating Energy Consumption (Qda)" (6.3.6a) + // find the "Adjusted Daily Water Heating Energy Consumption (Q_da)" (6.3.6) // same as above, because simulation induces no change in ambient temperature - standardTestSummary.adjustedDailyWaterHeatingEnergyConsumption_kJ = - standardTestSummary.dailyHeatingEnergyConsumption_kJ; + testSummary.adjustedConsumedWaterHeatingEnergy_kJ = testSummary.consumedHeatingEnergy_kJ; - // find the "Energy Used to Heat Water (Q_HW)" (6.3.6a) - standardTestSummary.energyUsedToHeatWater_kJ = 0.; - if (standardTestSummary.recoveryEfficiency > 0.) + // find the "Energy Used to Heat Water (Q_HW)" (6.3.6) + testSummary.waterHeatingEnergy_kJ = 0.; + if (testSummary.recoveryEfficiency > 0.) { - standardTestSummary.energyUsedToHeatWater_kJ = - dailyUsedHeatingEnergy_kJ / standardTestSummary.recoveryEfficiency; + testSummary.waterHeatingEnergy_kJ = deliveredEnergy_kJ / testSummary.recoveryEfficiency; } - // find the "Standard Energy Used to Heat Water (Q_HW,T)" (6.3.6b) - standardTestSummary.standardEnergyUsedToHeatWater_kJ = 0.; - if (standardTestSummary.recoveryEfficiency > 0.) + // find the "Standard Energy Used to Heat Water (Q_HW,T)" (6.3.6) + testSummary.standardWaterHeatingEnergy_kJ = 0.; + if (testSummary.recoveryEfficiency > 0.) { - double removedMass_kg = DENSITYWATER_kgperL * dailyRemovedVolume_L; + double removedMass_kg = DENSITYWATER_kgperL * testSummary.removedVolume_L; double removedHeatCapacity_kJperC = CPWATER_kJperkgC * removedMass_kg; double standardRemovedEnergy_kJ = removedHeatCapacity_kJperC * (standardSetpointT_C - standardInletT_C); - standardTestSummary.standardEnergyUsedToHeatWater_kJ = - standardRemovedEnergy_kJ / standardTestSummary.recoveryEfficiency; + testSummary.standardWaterHeatingEnergy_kJ = + standardRemovedEnergy_kJ / testSummary.recoveryEfficiency; } - // add to the adjusted daily water heating energy consumption (p. 40487) - double energyUsedToHeatWaterDifference_kJ = - standardTestSummary.standardEnergyUsedToHeatWater_kJ - - standardTestSummary.energyUsedToHeatWater_kJ; - standardTestSummary.adjustedDailyWaterHeatingEnergyConsumption_kJ += - energyUsedToHeatWaterDifference_kJ; - - // find the "Modified Daily Water Heating Energy Consumption (Qdm = Qda - QHWD) (p. 40487) + // find the "Modified Daily Water Heating Energy Consumption (Q_dm = Q_da - Q_HWD) (p. 40487) // note: same as Q_HW,T - standardTestSummary.modifiedDailyWaterHeatingEnergyConsumption_kJ = - standardTestSummary.adjustedDailyWaterHeatingEnergyConsumption_kJ - - energyUsedToHeatWaterDifference_kJ; + double waterHeatingDifferenceEnergy_kJ = + testSummary.standardWaterHeatingEnergy_kJ - testSummary.waterHeatingEnergy_kJ; // Q_HWD + testSummary.modifiedConsumedWaterHeatingEnergy_kJ = + testSummary.adjustedConsumedWaterHeatingEnergy_kJ + waterHeatingDifferenceEnergy_kJ; // find the "Uniform Energy Factor" (6.4.4) - standardTestSummary.UEF = 0.; - if (standardTestSummary.modifiedDailyWaterHeatingEnergyConsumption_kJ > 0.) + testSummary.UEF = 0.; + if (testSummary.modifiedConsumedWaterHeatingEnergy_kJ > 0.) { - standardTestSummary.UEF = standardDailyHeatingEnergy_kJ / - standardTestSummary.modifiedDailyWaterHeatingEnergyConsumption_kJ; + testSummary.UEF = + standardDeliveredEnergy_kJ / testSummary.modifiedConsumedWaterHeatingEnergy_kJ; } // find the "Annual Energy Consumption" (6.4.5) - standardTestSummary.annualEnergyConsumption_kJ = 0.; - if (standardTestSummary.UEF > 0.) + testSummary.annualConsumedEnergy_kJ = 0.; + if (testSummary.UEF > 0.) { constexpr double days_per_year = 365.; const double nominalDifferenceT_C = F_TO_C(67.); - standardTestSummary.annualEnergyConsumption_kJ = days_per_year * dailyHeatCapacity_kJperC * - nominalDifferenceT_C / - standardTestSummary.UEF; + testSummary.annualConsumedEnergy_kJ = + days_per_year * removedHeatCapacity_kJperC * nominalDifferenceT_C / testSummary.UEF; } // find the "Annual Electrical Energy Consumption" (6.4.6) - standardTestSummary.annualElectricalEnergyConsumption_kJ = 0.; - if (dailyUsedEnergy_kJ > 0.) + testSummary.annualConsumedElectricalEnergy_kJ = 0.; + if (testSummary.usedEnergy_kJ > 0.) { - standardTestSummary.annualElectricalEnergyConsumption_kJ = - (dailyUsedElectricalEnergy_kJ / dailyUsedEnergy_kJ) * - standardTestSummary.annualEnergyConsumption_kJ; + testSummary.annualConsumedElectricalEnergy_kJ = + (testSummary.usedElectricalEnergy_kJ / testSummary.usedEnergy_kJ) * + testSummary.annualConsumedEnergy_kJ; } return true; diff --git a/src/HPWH.hh b/src/HPWH.hh index df23d013..17256211 100644 --- a/src/HPWH.hh +++ b/src/HPWH.hh @@ -978,15 +978,29 @@ class HPWH /// collection of information derived from standard test struct StandardTestSummary { + // first recovery values + double recoveryEfficiency = 0.; // eta_r + double recoveryDeliveredEnergy_kJ = 0.; + double recoveryStoredEnergy_kJ = 0.; + double recoveryUsedEnergy_kJ = 0.; // Q_r + + double standardWaterHeatingEnergy_kJ = 0.; // Q_HW,T + + // 24-hr values + double removedVolume_L = 0.; + double waterHeatingEnergy_kJ = 0.; // Q_HW + double usedFossilFuelEnergy_kJ = 0.; // Q_f + double usedElectricalEnergy_kJ = 0.; // Q_e + double usedEnergy_kJ = 0.; // Q + double consumedHeatingEnergy_kJ = 0.; // Q_d + double adjustedConsumedWaterHeatingEnergy_kJ = 0.; // Q_da + double modifiedConsumedWaterHeatingEnergy_kJ = 0.; // Q_dm double UEF = 0.; - double recoveryEfficiency = 0.; - double dailyHeatingEnergyConsumption_kJ = 0.; - double adjustedDailyWaterHeatingEnergyConsumption_kJ = 0.; - double modifiedDailyWaterHeatingEnergyConsumption_kJ = 0.; - double energyUsedToHeatWater_kJ = 0.; - double standardEnergyUsedToHeatWater_kJ = 0.; - double annualElectricalEnergyConsumption_kJ = 0.; - double annualEnergyConsumption_kJ = 0.; + + // (calculated) annual totals + double annualConsumedElectricalEnergy_kJ = 0.; // E_annual,e + double annualConsumedEnergy_kJ = 0.; // E_annual + bool qualifies = false; }; @@ -1031,6 +1045,8 @@ class HPWH /// sequence of draws in pattern typedef std::vector DrawPattern; + static std::unordered_map firstDrawClusterSizes; + /// collection of standard draw patterns static std::unordered_map drawPatterns; diff --git a/test/testMeasureMetrics.cc b/test/testMeasureMetrics.cc index 93b7620e..56d7c709 100644 --- a/test/testMeasureMetrics.cc +++ b/test/testMeasureMetrics.cc @@ -210,15 +210,15 @@ int main(int argc, char* argv[]) std::cout << "\tRecovery Efficiency: " << standardTestSummary.recoveryEfficiency << "\n"; std::cout << "\tUEF: " << standardTestSummary.UEF << "\n"; + std::cout << "\tDaily Water Heating Energy Consumption (kWh): " + << standardTestSummary.waterHeatingEnergy_kJ << "\n"; std::cout << "\tAdjusted Daily Water Heating Energy Consumption (kWh): " - << KJ_TO_KWH( - standardTestSummary.adjustedDailyWaterHeatingEnergyConsumption_kJ) + << KJ_TO_KWH(standardTestSummary.adjustedConsumedWaterHeatingEnergy_kJ) << "\n"; std::cout << "\tAnnual Electrical Energy Consumption (kWh): " - << KJ_TO_KWH(standardTestSummary.annualElectricalEnergyConsumption_kJ) - << "\n"; + << KJ_TO_KWH(standardTestSummary.annualConsumedElectricalEnergy_kJ) << "\n"; std::cout << "\tAnnual Energy Consumption (kWh): " - << KJ_TO_KWH(standardTestSummary.annualEnergyConsumption_kJ) << "\n"; + << KJ_TO_KWH(standardTestSummary.annualConsumedEnergy_kJ) << "\n"; } else { From 2d054fb7934fa3b6b35797e3b59eb2ae3f9e3ee3 Mon Sep 17 00:00:00 2001 From: Phil Ahrenkiel Date: Thu, 8 Feb 2024 15:25:52 -0700 Subject: [PATCH 29/37] Clean up. --- src/HPWH.cc | 30 +++++++++++++++++++----------- src/HPWH.hh | 5 ++++- test/testMeasureMetrics.cc | 38 ++++++++++++++++++++++++++++++-------- 3 files changed, 53 insertions(+), 20 deletions(-) diff --git a/src/HPWH.cc b/src/HPWH.cc index 5f3a11f8..cc45adc9 100644 --- a/src/HPWH.cc +++ b/src/HPWH.cc @@ -5839,11 +5839,13 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, double tankT_C = getAverageTankTemp_C(); double initialTankT_C = tankT_C; - double deliveredEnergy_kJ = 0.; // total energy delivered to water - testSummary.removedVolume_L = 0.; - testSummary.usedEnergy_kJ = 0.; // Q - testSummary.usedFossilFuelEnergy_kJ = 0.; // total fossil-fuel energy consumed, Qf - testSummary.usedElectricalEnergy_kJ = 0.; // total electrical energy consumed, Qe + // used to find average draw temperatures + double drawSumOutletVolumeT_LC = 0.; + double drawSumInletVolumeT_LC = 0.; + + // used to find average 24-hr test temperatures + double sumOutletVolumeT_LC = 0.; + double sumInletVolumeT_LC = 0.; // first-recovery info bool isFirstRecoveryPeriod = true; @@ -5851,6 +5853,12 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, testSummary.recoveryDeliveredEnergy_kJ = 0.; testSummary.recoveryUsedEnergy_kJ = 0.; + double deliveredEnergy_kJ = 0.; // total energy delivered to water + testSummary.removedVolume_L = 0.; + testSummary.usedEnergy_kJ = 0.; // Q + testSummary.usedFossilFuelEnergy_kJ = 0.; // total fossil-fuel energy consumed, Qf + testSummary.usedElectricalEnergy_kJ = 0.; // total electrical energy consumed, Qe + bool hasHeated = false; int endTime_min = 24 * min_per_hr; @@ -5864,10 +5872,6 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, bool needCalc = false; bool isFirstDraw = true; - double drawSumOutletVolumeT_LC = 0.; - double drawSumInletVolumeT_LC = 0.; - int drawSumTimeT_minC = 0; - bool inLastHour = false; double stepDrawVolume_L = 0.; for (int runTime_min = 0; runTime_min <= endTime_min; ++runTime_min) @@ -5898,7 +5902,6 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, drawSumOutletVolumeT_LC = 0.; drawSumInletVolumeT_LC = 0.; - drawSumTimeT_minC = 0; } } @@ -5960,7 +5963,9 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, drawSumOutletVolumeT_LC += stepDrawVolume_L * outletTemp_C; drawSumInletVolumeT_LC += stepDrawVolume_L * inletT_C; - ++drawSumTimeT_minC; + + sumOutletVolumeT_LC += stepDrawVolume_L * outletTemp_C; + sumInletVolumeT_LC += stepDrawVolume_L * inletT_C; // collect energy added to water double stepDrawMass_kg = DENSITYWATER_kgperL * stepDrawVolume_L; @@ -6027,6 +6032,9 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, double finalTankT_C = tankT_C; + testSummary.avgOutletT_C = sumOutletVolumeT_LC / testSummary.removedVolume_L; + testSummary.avgInletT_C = sumInletVolumeT_LC / testSummary.removedVolume_L; + if (testOptions.saveOutput) { for (auto& outputData : outputDataSet) diff --git a/src/HPWH.hh b/src/HPWH.hh index 17256211..997f5e6f 100644 --- a/src/HPWH.hh +++ b/src/HPWH.hh @@ -988,7 +988,10 @@ class HPWH // 24-hr values double removedVolume_L = 0.; - double waterHeatingEnergy_kJ = 0.; // Q_HW + double waterHeatingEnergy_kJ = 0.; // Q_HW + double avgOutletT_C = 0.; // + double avgInletT_C = 0.; // + double usedFossilFuelEnergy_kJ = 0.; // Q_f double usedElectricalEnergy_kJ = 0.; // Q_e double usedEnergy_kJ = 0.; // Q diff --git a/test/testMeasureMetrics.cc b/test/testMeasureMetrics.cc index 56d7c709..6d4ca375 100644 --- a/test/testMeasureMetrics.cc +++ b/test/testMeasureMetrics.cc @@ -168,6 +168,8 @@ int main(int argc, char* argv[]) csvOptions); } + const std::string sDeg = "\370"; + HPWH::FirstHourRating firstHourRating; if (hpwh.findFirstHourRating(firstHourRating, standardTestOptions)) { @@ -202,22 +204,42 @@ int main(int argc, char* argv[]) if (hpwh.run24hrTest(firstHourRating, standardTestSummary, standardTestOptions)) { + std::cout << "\t24-Hour Test Results:\n"; if (!standardTestSummary.qualifies) { - std::cout << "\tDoes not qualify as consumer water heater.\n"; + std::cout << "\t\tDoes not qualify as consumer water heater.\n"; } - std::cout << "\tRecovery Efficiency: " << standardTestSummary.recoveryEfficiency + std::cout << "\t\tRecovery Efficiency: " << standardTestSummary.recoveryEfficiency + << "\n"; + + std::cout << "\t\tUEF: " << standardTestSummary.UEF << "\n"; + + std::cout << "\t\tAverage Inlet Temperature (" << sDeg + << "C): " << standardTestSummary.avgInletT_C << "\n"; + + std::cout << "\t\tAverage Outlet Temperature (" << sDeg + << "C): " << standardTestSummary.avgOutletT_C << "\n"; + + std::cout << "\t\tTotal Volume Drawn (L): " << standardTestSummary.removedVolume_L << "\n"; - std::cout << "\tUEF: " << standardTestSummary.UEF << "\n"; - std::cout << "\tDaily Water Heating Energy Consumption (kWh): " - << standardTestSummary.waterHeatingEnergy_kJ << "\n"; - std::cout << "\tAdjusted Daily Water Heating Energy Consumption (kWh): " + + std::cout << "\t\tDaily Water-Heating Energy Consumption (kWh): " + << KJ_TO_KWH(standardTestSummary.waterHeatingEnergy_kJ) << "\n"; + + std::cout << "\t\tAdjusted Daily Water-Heating Energy Consumption (kWh): " << KJ_TO_KWH(standardTestSummary.adjustedConsumedWaterHeatingEnergy_kJ) << "\n"; - std::cout << "\tAnnual Electrical Energy Consumption (kWh): " + + std::cout << "\t\tModified Daily Water-Heating Energy Consumption (kWh): " + << KJ_TO_KWH(standardTestSummary.modifiedConsumedWaterHeatingEnergy_kJ) + << "\n"; + + std::cout << "\tAnnual Values:\n"; + std::cout << "\t\tAnnual Electrical Energy Consumption (kWh): " << KJ_TO_KWH(standardTestSummary.annualConsumedElectricalEnergy_kJ) << "\n"; - std::cout << "\tAnnual Energy Consumption (kWh): " + + std::cout << "\t\tAnnual Energy Consumption (kWh): " << KJ_TO_KWH(standardTestSummary.annualConsumedEnergy_kJ) << "\n"; } else From 505bdcb716b416ed4f492c0be51bcb16adcf2dbc Mon Sep 17 00:00:00 2001 From: Phil Ahrenkiel Date: Thu, 8 Feb 2024 15:32:38 -0700 Subject: [PATCH 30/37] Change test results. --- test/testMeasureMetrics.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/testMeasureMetrics.cc b/test/testMeasureMetrics.cc index 6d4ca375..22c52d98 100644 --- a/test/testMeasureMetrics.cc +++ b/test/testMeasureMetrics.cc @@ -80,21 +80,21 @@ int main(int argc, char* argv[]) ASSERTTRUE(standardTestSummary.qualifies); ASSERTTRUE(cmpd(firstHourRating.drawVolume_L, 272.5659)); ASSERTTRUE(firstHourRating.desig == HPWH::FirstHourRatingDesig::Medium); - ASSERTTRUE(cmpd(standardTestSummary.UEF, 3.2212)); + ASSERTTRUE(cmpd(standardTestSummary.UEF, 2.6493)); ASSERTTRUE(testMeasureMetrics( "AOSmithHPTS50", firstHourRating, standardTestSummary, standardTestOptions)); ASSERTTRUE(standardTestSummary.qualifies); ASSERTTRUE(cmpd(firstHourRating.drawVolume_L, 188.0432)); ASSERTTRUE(firstHourRating.desig == HPWH::FirstHourRatingDesig::Low); - ASSERTTRUE(cmpd(standardTestSummary.UEF, 4.4914)); + ASSERTTRUE(cmpd(standardTestSummary.UEF, 4.0018)); ASSERTTRUE(testMeasureMetrics( "AOSmithHPTS80", firstHourRating, standardTestSummary, standardTestOptions)); ASSERTTRUE(standardTestSummary.qualifies); ASSERTTRUE(cmpd(firstHourRating.drawVolume_L, 310.9384)); ASSERTTRUE(firstHourRating.desig == HPWH::FirstHourRatingDesig::High); - ASSERTTRUE(cmpd(standardTestSummary.UEF, 3.5230)); + ASSERTTRUE(cmpd(standardTestSummary.UEF, 4.3272)); return 0; } From 105d0101a85172da38f4a739403ea7078ea2dd8e Mon Sep 17 00:00:00 2001 From: Phil Ahrenkiel Date: Sat, 10 Feb 2024 10:13:45 -0700 Subject: [PATCH 31/37] Correct UA. --- src/HPWH.cc | 183 +++++++++++++++++++++++++++++++------ src/HPWH.hh | 17 +++- test/testMeasureMetrics.cc | 3 + 3 files changed, 174 insertions(+), 29 deletions(-) diff --git a/src/HPWH.cc b/src/HPWH.cc index cc45adc9..ff39299f 100644 --- a/src/HPWH.cc +++ b/src/HPWH.cc @@ -5848,7 +5848,6 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, double sumInletVolumeT_LC = 0.; // first-recovery info - bool isFirstRecoveryPeriod = true; testSummary.recoveryStoredEnergy_kJ = 0.; testSummary.recoveryDeliveredEnergy_kJ = 0.; testSummary.recoveryUsedEnergy_kJ = 0.; @@ -5862,23 +5861,39 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, bool hasHeated = false; int endTime_min = 24 * min_per_hr; - int standbyStartTime_min = 23 * min_per_hr; std::size_t iDraw = 0; double remainingDrawVolume_L = 0.; double drawVolume_L = 0.; + double prevDrawEndTime_min = 0.; + bool isFirstRecoveryPeriod = true; + bool isInFirstDrawCluster = true; + bool hasStandbyPeriodStarted = false; + bool hasStandbyPeriodEnded = false; bool nextDraw = true; - bool isDrawComplete = false; - bool needCalc = false; - bool isFirstDraw = true; + bool isDrawing = false; + bool isDrawPatternComplete = false; + + int recoveryEndTime_min = 0; + + int standbyStartTime_min = 0; + int standbyEndTime_min = 0; + double standbyStartT_C = 0; + double standbyEndT_C = 0; + double standbyStartTankEnergy_kJ = 0.; + double standbyEndTankEnergy_kJ = 0.; + double standbySumTimeTankT_minC = 0.; + double standbySumTimeAmbientT_minC = 0.; + + int noDrawTotalTime_min = 0.; + double noDrawSumTimeAmbientT_minC = 0.; bool inLastHour = false; double stepDrawVolume_L = 0.; for (int runTime_min = 0; runTime_min <= endTime_min; ++runTime_min) { - if ((runTime_min >= standbyStartTime_min) && (!inLastHour)) + if (inLastHour) { - inLastHour = true; drMode = DR_LOC | DR_LOR; } @@ -5897,22 +5912,42 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, remainingDrawVolume_L = drawVolume_L = draw.volume_L; nextDraw = false; - isDrawComplete = false; - needCalc = false; + isDrawing = true; drawSumOutletVolumeT_LC = 0.; drawSumInletVolumeT_LC = 0.; + + if (hasStandbyPeriodStarted && (!hasStandbyPeriodEnded)) + { + hasStandbyPeriodEnded = true; + standbyEndTankEnergy_kJ = testSummary.usedEnergy_kJ; // Qsu,0 + standbyEndT_C = tankT_C; // Tsu,0 + standbyEndTime_min = runTime_min; + } } } // iterate until 1) specified draw volume has been reached and 2) next draw has started // do not exceed specified draw volume - if (stepDrawVolume_L >= remainingDrawVolume_L) + if (isDrawing) { - stepDrawVolume_L = remainingDrawVolume_L; - - isDrawComplete = true; - needCalc = true; + if (stepDrawVolume_L >= remainingDrawVolume_L) + { + stepDrawVolume_L = remainingDrawVolume_L; + remainingDrawVolume_L = 0.; + isDrawing = false; + prevDrawEndTime_min = runTime_min; + } + else + { + remainingDrawVolume_L -= stepDrawVolume_L; + } + } + else + { + remainingDrawVolume_L = stepDrawVolume_L = 0.; + noDrawSumTimeAmbientT_minC += (1.) * ambientT_C; + ++noDrawTotalTime_min; } // run a step @@ -5956,8 +5991,6 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, outputDataSet.push_back(outputData); } - remainingDrawVolume_L -= stepDrawVolume_L; - tankT_C = getAverageTankTemp_C(); hasHeated |= isHeating; @@ -5991,7 +6024,7 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, testSummary.recoveryUsedEnergy_kJ += usedFossilFuelEnergy_kJ + usedElectricalEnergy_kJ; } - if (isDrawComplete) + if (!isDrawing) { if (isFirstRecoveryPeriod) { @@ -6019,12 +6052,61 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, } } + if (!hasStandbyPeriodEnded) + { + if (hasStandbyPeriodStarted) + { + standbySumTimeTankT_minC += (1.) * tankT_C; + standbySumTimeAmbientT_minC += (1.) * ambientT_C; + + if (runTime_min >= standbyStartTime_min + 8 * min_per_hr) + { + hasStandbyPeriodEnded = true; + standbyEndTankEnergy_kJ = testSummary.usedEnergy_kJ; // Qsu,0 + standbyEndT_C = tankT_C; // Tsu,0 + standbyEndTime_min = runTime_min; + } + } + else + { + if (isHeating) + { + recoveryEndTime_min = runTime_min; + } + else + { + if ((!isInFirstDrawCluster) || isDrawPatternComplete) + { + if ((runTime_min > prevDrawEndTime_min + 5) && + (runTime_min > recoveryEndTime_min + 5)) + { + hasStandbyPeriodStarted = true; + standbyStartTime_min = runTime_min; + standbyStartTankEnergy_kJ = testSummary.usedEnergy_kJ; // Qsu,0 + standbyStartT_C = tankT_C; // Tsu,0 + + if (isDrawPatternComplete && + (runTime_min + 8 * min_per_hr > endTime_min)) + { + endTime_min = runTime_min + 8 * min_per_hr; + } + } + } + } + } + } + if (!nextDraw) { ++iDraw; if (iDraw < drawPattern.size()) { nextDraw = true; + isInFirstDrawCluster = (iDraw < firstDrawClusterSize); + } + else + { + isDrawPatternComplete = true; } } } @@ -6032,8 +6114,13 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, double finalTankT_C = tankT_C; - testSummary.avgOutletT_C = sumOutletVolumeT_LC / testSummary.removedVolume_L; - testSummary.avgInletT_C = sumInletVolumeT_LC / testSummary.removedVolume_L; + if (!hasStandbyPeriodEnded) + { + hasStandbyPeriodEnded = true; + standbyEndTime_min = endTime_min; + standbyEndTankEnergy_kJ = testSummary.usedEnergy_kJ; // Qsu,0 + standbyEndT_C = tankT_C; // Tsu,0 + } if (testOptions.saveOutput) { @@ -6043,8 +6130,18 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, } } + testSummary.avgOutletT_C = sumOutletVolumeT_LC / testSummary.removedVolume_L; + testSummary.avgInletT_C = sumInletVolumeT_LC / testSummary.removedVolume_L; + + constexpr double standardSetpointT_C = 51.7; + constexpr double standardInletT_C = 14.4; + constexpr double standardAmbientT_C = 19.7; + + double tankContentMass_kg = DENSITYWATER_kgperL * tankVolume_L; + double tankHeatCapacity_kJperC = CPWATER_kJperkgC * tankContentMass_kg; + // require heating during 24-hr test for unit to qualify as consumer water heater - if (hasHeated && isDrawComplete) + if (hasHeated && !isDrawing) { testSummary.qualifies = true; } @@ -6058,9 +6155,39 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, testSummary.recoveryUsedEnergy_kJ; } + // find the energy consumed during the standby-loss test, Qstdby + testSummary.standbyUsedEnergy_kJ = standbyEndTankEnergy_kJ - standbyStartTankEnergy_kJ; + + int standbyPeriodTime_min = standbyEndTime_min - standbyStartTime_min - 1; + testSummary.standbyPeriodTime_h = standbyPeriodTime_min / min_per_hr; // tau_stby,1 + if ((testSummary.standbyPeriodTime_h > 0) && (testSummary.recoveryEfficiency > 0.)) + { + double standardTankEnergy_kJ = tankHeatCapacity_kJperC * (standbyEndT_C - standbyStartT_C) / + testSummary.recoveryEfficiency; + testSummary.standbyHourlyLossEnergy_kJperh = + (testSummary.standbyUsedEnergy_kJ - standardTankEnergy_kJ) / + testSummary.standbyPeriodTime_h; + + double standbyAverageTankT_C = standbySumTimeTankT_minC / standbyPeriodTime_min; + double standbyAverageAmbientT_C = standbySumTimeAmbientT_minC / standbyPeriodTime_min; + + double dT_C = standbyAverageTankT_C - standbyAverageAmbientT_C; + if (dT_C > 0.) + { + testSummary.standbyLossCoefficient_kJperhC = + testSummary.standbyHourlyLossEnergy_kJperh / dT_C; // UA + } + } + + // + testSummary.noDrawTotalTime_h = noDrawTotalTime_min / min_per_hr; // tau_stby,2 + if (noDrawTotalTime_min > 0) + { + testSummary.noDrawAverageAmbientT_C = + noDrawSumTimeAmbientT_minC / noDrawTotalTime_min; // + } + // find the standard delivered daily energy - constexpr double standardSetpointT_C = 51.7; - constexpr double standardInletT_C = 14.4; double removedMass_kg = HPWH::DENSITYWATER_kgperL * testSummary.removedVolume_L; double removedHeatCapacity_kJperC = HPWH::CPWATER_kJperkgC * removedMass_kg; double standardDeliveredEnergy_kJ = @@ -6070,16 +6197,16 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, testSummary.consumedHeatingEnergy_kJ = testSummary.usedEnergy_kJ; if (testSummary.recoveryEfficiency > 0.) { - double tankContentMass_kg = DENSITYWATER_kgperL * tankVolume_L; - double tankHeatCapacity_kJperC = CPWATER_kJperkgC * tankContentMass_kg; testSummary.consumedHeatingEnergy_kJ -= tankHeatCapacity_kJperC * (finalTankT_C - initialTankT_C) / testSummary.recoveryEfficiency; } // find the "Adjusted Daily Water Heating Energy Consumption (Q_da)" (6.3.6) - // same as above, because simulation induces no change in ambient temperature - testSummary.adjustedConsumedWaterHeatingEnergy_kJ = testSummary.consumedHeatingEnergy_kJ; + testSummary.adjustedConsumedWaterHeatingEnergy_kJ = + testSummary.consumedHeatingEnergy_kJ - + (standardAmbientT_C - testSummary.noDrawAverageAmbientT_C) * + testSummary.standbyLossCoefficient_kJperhC * testSummary.noDrawTotalTime_h; // find the "Energy Used to Heat Water (Q_HW)" (6.3.6) testSummary.waterHeatingEnergy_kJ = 0.; @@ -6100,8 +6227,8 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, standardRemovedEnergy_kJ / testSummary.recoveryEfficiency; } - // find the "Modified Daily Water Heating Energy Consumption (Q_dm = Q_da - Q_HWD) (p. 40487) - // note: same as Q_HW,T + // find the "Modified Daily Water Heating Energy Consumption (Q_dm = Q_da - Q_HWD) (p. + // 40487) note: same as Q_HW,T double waterHeatingDifferenceEnergy_kJ = testSummary.standardWaterHeatingEnergy_kJ - testSummary.waterHeatingEnergy_kJ; // Q_HWD testSummary.modifiedConsumedWaterHeatingEnergy_kJ = diff --git a/src/HPWH.hh b/src/HPWH.hh index 997f5e6f..1c6cf031 100644 --- a/src/HPWH.hh +++ b/src/HPWH.hh @@ -984,7 +984,21 @@ class HPWH double recoveryStoredEnergy_kJ = 0.; double recoveryUsedEnergy_kJ = 0.; // Q_r - double standardWaterHeatingEnergy_kJ = 0.; // Q_HW,T + // + double standbyPeriodTime_h = 0; // tau_stby,1 + + double standbyStartTankT_C = 0.; // T_su,0 + double standbyEndTankT_C = 0.; // T_su,f + + double standbyStartEnergy_kJ = 0.; // Q_su,0 + double standbyEndEnergy_kJ = 0.; // Q_su,f + double standbyUsedEnergy_kJ = 0.; // Q_stby + + double standbyHourlyLossEnergy_kJperh = 0.; // Q_hr + double standbyLossCoefficient_kJperhC = 0.; // UA + + double noDrawTotalTime_h = 0; // tau_stby,2 + double noDrawAverageAmbientT_C = 0.; // // 24-hr values double removedVolume_L = 0.; @@ -996,6 +1010,7 @@ class HPWH double usedElectricalEnergy_kJ = 0.; // Q_e double usedEnergy_kJ = 0.; // Q double consumedHeatingEnergy_kJ = 0.; // Q_d + double standardWaterHeatingEnergy_kJ = 0.; // Q_HW,T double adjustedConsumedWaterHeatingEnergy_kJ = 0.; // Q_da double modifiedConsumedWaterHeatingEnergy_kJ = 0.; // Q_dm double UEF = 0.; diff --git a/test/testMeasureMetrics.cc b/test/testMeasureMetrics.cc index 22c52d98..87760fcc 100644 --- a/test/testMeasureMetrics.cc +++ b/test/testMeasureMetrics.cc @@ -213,6 +213,9 @@ int main(int argc, char* argv[]) std::cout << "\t\tRecovery Efficiency: " << standardTestSummary.recoveryEfficiency << "\n"; + std::cout << "\t\tStandby Loss Coefficient (kJ/h" << sDeg + << "C): " << standardTestSummary.standbyLossCoefficient_kJperhC << "\n"; + std::cout << "\t\tUEF: " << standardTestSummary.UEF << "\n"; std::cout << "\t\tAverage Inlet Temperature (" << sDeg From 2d3dbbe65b83acda2c7007efe90b4419489a13f9 Mon Sep 17 00:00:00 2001 From: Phil Ahrenkiel Date: Sat, 10 Feb 2024 10:31:22 -0700 Subject: [PATCH 32/37] Fix naming and types. --- src/HPWH.cc | 27 +++++++++++++-------------- src/HPWH.hh | 20 ++++++++++---------- src/HPWHHeatSources.cc | 14 +++++++------- 3 files changed, 30 insertions(+), 31 deletions(-) diff --git a/src/HPWH.cc b/src/HPWH.cc index ff39299f..038b9b08 100644 --- a/src/HPWH.cc +++ b/src/HPWH.cc @@ -380,7 +380,7 @@ void HPWH::setMinutesPerStep(const double minutesPerStep_in) { minutesPerStep = minutesPerStep_in; secondsPerStep = sec_per_min * minutesPerStep; - hoursPerStep = minutesPerStep / min_per_hr; + hoursPerStep = minutesPerStep / min_per_h; } // public HPWH functions @@ -3977,13 +3977,13 @@ void HPWH::addExtraHeat(std::vector& extraHeatDist_W) if (heatDistribution_W[i] != 0) { double qAdd_BTUperHr = KWH_TO_BTU(heatDistribution_W[i] / 1000.); - double qAdd_KJ = BTU_TO_KJ(qAdd_BTUperHr * minutesPerStep / min_per_hr); + double qAdd_KJ = BTU_TO_KJ(qAdd_BTUperHr * minutesPerStep / min_per_h); addExtraHeatAboveNode(qAdd_KJ, i); tot_qAdded_BTUperHr += qAdd_BTUperHr; } } // Write the input & output energy - extraEnergyInput_kWh = BTU_TO_KWH(tot_qAdded_BTUperHr * minutesPerStep / min_per_hr); + extraEnergyInput_kWh = BTU_TO_KWH(tot_qAdded_BTUperHr * minutesPerStep / min_per_h); } /////////////////////////////////////////////////////////////////////////////////// @@ -5860,7 +5860,7 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, bool hasHeated = false; - int endTime_min = 24 * min_per_hr; + int endTime_min = 24 * static_cast(min_per_h); std::size_t iDraw = 0; double remainingDrawVolume_L = 0.; double drawVolume_L = 0.; @@ -5885,7 +5885,7 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, double standbySumTimeTankT_minC = 0.; double standbySumTimeAmbientT_minC = 0.; - int noDrawTotalTime_min = 0.; + int noDrawTotalTime_min = 0; double noDrawSumTimeAmbientT_minC = 0.; bool inLastHour = false; @@ -6059,7 +6059,7 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, standbySumTimeTankT_minC += (1.) * tankT_C; standbySumTimeAmbientT_minC += (1.) * ambientT_C; - if (runTime_min >= standbyStartTime_min + 8 * min_per_hr) + if (runTime_min >= standbyStartTime_min + 8 * min_per_h) { hasStandbyPeriodEnded = true; standbyEndTankEnergy_kJ = testSummary.usedEnergy_kJ; // Qsu,0 @@ -6086,9 +6086,9 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, standbyStartT_C = tankT_C; // Tsu,0 if (isDrawPatternComplete && - (runTime_min + 8 * min_per_hr > endTime_min)) + (runTime_min + 8 * min_per_h > endTime_min)) { - endTime_min = runTime_min + 8 * min_per_hr; + endTime_min = runTime_min + 8 * static_cast(min_per_h); } } } @@ -6140,6 +6140,9 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, double tankContentMass_kg = DENSITYWATER_kgperL * tankVolume_L; double tankHeatCapacity_kJperC = CPWATER_kJperkgC * tankContentMass_kg; + double removedMass_kg = DENSITYWATER_kgperL * testSummary.removedVolume_L; + double removedHeatCapacity_kJperC = CPWATER_kJperkgC * removedMass_kg; + // require heating during 24-hr test for unit to qualify as consumer water heater if (hasHeated && !isDrawing) { @@ -6159,7 +6162,7 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, testSummary.standbyUsedEnergy_kJ = standbyEndTankEnergy_kJ - standbyStartTankEnergy_kJ; int standbyPeriodTime_min = standbyEndTime_min - standbyStartTime_min - 1; - testSummary.standbyPeriodTime_h = standbyPeriodTime_min / min_per_hr; // tau_stby,1 + testSummary.standbyPeriodTime_h = standbyPeriodTime_min / min_per_h; // tau_stby,1 if ((testSummary.standbyPeriodTime_h > 0) && (testSummary.recoveryEfficiency > 0.)) { double standardTankEnergy_kJ = tankHeatCapacity_kJperC * (standbyEndT_C - standbyStartT_C) / @@ -6180,7 +6183,7 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, } // - testSummary.noDrawTotalTime_h = noDrawTotalTime_min / min_per_hr; // tau_stby,2 + testSummary.noDrawTotalTime_h = noDrawTotalTime_min / min_per_h; // tau_stby,2 if (noDrawTotalTime_min > 0) { testSummary.noDrawAverageAmbientT_C = @@ -6188,8 +6191,6 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, } // find the standard delivered daily energy - double removedMass_kg = HPWH::DENSITYWATER_kgperL * testSummary.removedVolume_L; - double removedHeatCapacity_kJperC = HPWH::CPWATER_kJperkgC * removedMass_kg; double standardDeliveredEnergy_kJ = removedHeatCapacity_kJperC * (standardSetpointT_C - standardInletT_C); @@ -6219,8 +6220,6 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, testSummary.standardWaterHeatingEnergy_kJ = 0.; if (testSummary.recoveryEfficiency > 0.) { - double removedMass_kg = DENSITYWATER_kgperL * testSummary.removedVolume_L; - double removedHeatCapacity_kJperC = CPWATER_kJperkgC * removedMass_kg; double standardRemovedEnergy_kJ = removedHeatCapacity_kJperC * (standardSetpointT_C - standardInletT_C); testSummary.standardWaterHeatingEnergy_kJ = diff --git a/src/HPWH.hh b/src/HPWH.hh index 1c6cf031..1369b24e 100644 --- a/src/HPWH.hh +++ b/src/HPWH.hh @@ -1637,24 +1637,24 @@ constexpr double BTUperKWH = constexpr double FperC = 9. / 5.; // degF / degC constexpr double offsetF = 32.; // degF offset constexpr double sec_per_min = 60.; // seconds / min -constexpr double min_per_hr = 60.; // min / hr -constexpr double sec_per_hr = sec_per_min * min_per_hr; // seconds / hr -constexpr double L_per_gal = 3.78541; // liters / gal -constexpr double ft_per_m = 3.2808; // feet / meter -constexpr double ft2_per_m2 = ft_per_m * ft_per_m; // feet / meter +constexpr double min_per_h = 60.; // min / h +constexpr double sec_per_h = sec_per_min * min_per_h; // seconds / hr +constexpr double L_per_gal = 3.78541; // liters / gal +constexpr double ft_per_m = 3.2808; // feet / meter +constexpr double ft2_per_m2 = ft_per_m * ft_per_m; // feet / meter // a few extra functions for unit conversion inline double dF_TO_dC(double temperature) { return (temperature / FperC); } inline double F_TO_C(double temperature) { return ((temperature - offsetF) / FperC); } inline double C_TO_F(double temperature) { return ((FperC * temperature) + offsetF); } inline double KWH_TO_BTU(double kwh) { return (BTUperKWH * kwh); } -inline double KWH_TO_KJ(double kwh) { return (kwh * sec_per_hr); } +inline double KWH_TO_KJ(double kwh) { return (kwh * sec_per_h); } inline double BTU_TO_KWH(double btu) { return (btu / BTUperKWH); } inline double BTUperH_TO_KW(double btu) { return (btu / BTUperKWH); } inline double KW_TO_BTUperH(double kw) { return (kw * BTUperKWH); } inline double W_TO_BTUperH(double w) { return (w * BTUperKWH / 1000.); } -inline double KJ_TO_KWH(double kj) { return (kj / sec_per_hr); } -inline double BTU_TO_KJ(double btu) { return (btu * sec_per_hr / BTUperKWH); } +inline double KJ_TO_KWH(double kj) { return (kj / sec_per_h); } +inline double BTU_TO_KJ(double btu) { return (btu * sec_per_h / BTUperKWH); } inline double GAL_TO_L(double gallons) { return (gallons * L_per_gal); } inline double L_TO_GAL(double liters) { return (liters / L_per_gal); } inline double L_TO_FT3(double liters) { return (liters / 28.31685); } @@ -1666,11 +1666,11 @@ inline double FT_TO_M(double feet) { return (feet / ft_per_m); } inline double FT2_TO_M2(double feet2) { return (feet2 / ft2_per_m2); } inline double MIN_TO_SEC(double minute) { return minute * sec_per_min; } -inline double MIN_TO_HR(double minute) { return minute / min_per_hr; } +inline double MIN_TO_HR(double minute) { return minute / min_per_h; } inline double HM_TO_MIN(const double hours, const double minutes) { - return min_per_hr * hours + minutes; + return min_per_h * hours + minutes; } inline HPWH::DRMODES operator|(HPWH::DRMODES a, HPWH::DRMODES b) diff --git a/src/HPWHHeatSources.cc b/src/HPWHHeatSources.cc index 0cb357d9..357c9af6 100644 --- a/src/HPWHHeatSources.cc +++ b/src/HPWHHeatSources.cc @@ -498,7 +498,7 @@ void HPWH::HeatSource::addHeat(double externalT_C, double minutesToRun) if (hpwh->hpwhVerbosity >= VRB_typical) { hpwh->msg("capacity_kWh %.2lf \t\t cap_BTUperHr %.2lf \n", - BTU_TO_KWH(cap_BTUperHr) * (minutesToRun) / min_per_hr, + BTU_TO_KWH(cap_BTUperHr) * (minutesToRun) / min_per_h, cap_BTUperHr); } @@ -512,7 +512,7 @@ void HPWH::HeatSource::addHeat(double externalT_C, double minutesToRun) { // for(int i = 0; i < hpwh->numNodes; i++){ double nodeCap_kJ = - BTU_TO_KJ(cap_BTUperHr * minutesToRun / min_per_hr * heatDistribution[i]); + BTU_TO_KJ(cap_BTUperHr * minutesToRun / min_per_h * heatDistribution[i]); if (nodeCap_kJ != 0.) { double heatToAdd_kJ = nodeCap_kJ + leftoverCap_kJ; @@ -527,7 +527,7 @@ void HPWH::HeatSource::addHeat(double externalT_C, double minutesToRun) } // after you've done everything, any leftover capacity is time that didn't run - double cap_kJ = BTU_TO_KJ(cap_BTUperHr * minutesToRun / min_per_hr); + double cap_kJ = BTU_TO_KJ(cap_BTUperHr * minutesToRun / min_per_h); runtime_min = (1. - (leftoverCap_kJ / cap_kJ)) * minutesToRun; #if 1 // error check, 1-22-2017; updated 12-6-2023 if (runtime_min < -TOL_MINVALUE) @@ -546,8 +546,8 @@ void HPWH::HeatSource::addHeat(double externalT_C, double minutesToRun) } // Write the input & output energy - energyInput_kWh += BTU_TO_KWH(input_BTUperHr * runtime_min / min_per_hr); - energyOutput_kWh += BTU_TO_KWH(cap_BTUperHr * runtime_min / min_per_hr); + energyInput_kWh += BTU_TO_KWH(input_BTUperHr * runtime_min / min_per_h); + energyOutput_kWh += BTU_TO_KWH(cap_BTUperHr * runtime_min / min_per_h); } // private HPWH::HeatSource functions @@ -960,7 +960,7 @@ double HPWH::HeatSource::addHeatExternal(double externalT_C, tempInput_BTUperHr, tempCap_BTUperHr, temp_cop); - heatingCapacity_kJ = BTU_TO_KJ(tempCap_BTUperHr * (timeRemaining_min / min_per_hr)); + heatingCapacity_kJ = BTU_TO_KJ(tempCap_BTUperHr * (timeRemaining_min / min_per_h)); targetT_C = calcMPOutletTemperature(BTUperH_TO_KW(tempCap_BTUperHr)); } else @@ -971,7 +971,7 @@ double HPWH::HeatSource::addHeatExternal(double externalT_C, tempInput_BTUperHr, tempCap_BTUperHr, temp_cop); - heatingCapacity_kJ = BTU_TO_KJ(tempCap_BTUperHr * (minutesToRun / min_per_hr)); + heatingCapacity_kJ = BTU_TO_KJ(tempCap_BTUperHr * (minutesToRun / min_per_h)); if (hpwh->hpwhVerbosity >= VRB_emetic) { hpwh->msg("\theatingCapacity_kJ stepwise: %.2lf \n", heatingCapacity_kJ); From c8896b77fc6faaa98979ce83e9c19d024cbc953d Mon Sep 17 00:00:00 2001 From: Phil Ahrenkiel Date: Sat, 10 Feb 2024 10:51:55 -0700 Subject: [PATCH 33/37] Cast DRmode as int. --- src/HPWH.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/HPWH.cc b/src/HPWH.cc index 038b9b08..ec05d64e 100644 --- a/src/HPWH.cc +++ b/src/HPWH.cc @@ -1257,7 +1257,7 @@ int HPWH::writeRowAsCSV(std::ofstream& outFILE, outFILE << fmt::format(",{:0.2f}", doIP ? C_TO_F(outputData.inletT_C) : outputData.inletT_C); outFILE << fmt::format(",{:0.2f}", doIP ? L_TO_GAL(outputData.drawVolume_L) : outputData.drawVolume_L); - outFILE << fmt::format(",{}", outputData.drMode); + outFILE << fmt::format(",{}", static_cast(outputData.drMode)); // for (int iHS = 0; iHS < getNumHeatSources(); iHS++) From 795439a06fabc1fcf8c5caa87d23948cd29bd639 Mon Sep 17 00:00:00 2001 From: Phil Ahrenkiel Date: Sat, 10 Feb 2024 11:05:57 -0700 Subject: [PATCH 34/37] Use size_t. --- src/HPWH.cc | 4 ++-- src/HPWH.hh | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/HPWH.cc b/src/HPWH.cc index ec05d64e..033199e6 100644 --- a/src/HPWH.cc +++ b/src/HPWH.cc @@ -65,7 +65,7 @@ const double HPWH::MAXOUTLET_R410A = F_TO_C(140.); const double HPWH::MAXOUTLET_R744 = F_TO_C(190.); const double HPWH::MINSINGLEPASSLIFT = dF_TO_dC(15.); -std::unordered_map HPWH::firstDrawClusterSizes = { +std::unordered_map HPWH::firstDrawClusterSizes = { {HPWH::FirstHourRatingDesig::VerySmall, 5}, {HPWH::FirstHourRatingDesig::Low, 3}, {HPWH::FirstHourRatingDesig::Medium, 3}, @@ -5751,7 +5751,7 @@ bool HPWH::run24hrTest(const FirstHourRating firstHourRating, StandardTestOptions& testOptions) { // select the first draw cluster size and pattern - int firstDrawClusterSize = firstDrawClusterSizes[firstHourRating.desig]; + auto firstDrawClusterSize = firstDrawClusterSizes[firstHourRating.desig]; DrawPattern& drawPattern = drawPatterns[firstHourRating.desig]; constexpr double inletT_C = 14.4; // EERE-2019-BT-TP-0032-0058, p. 40433 diff --git a/src/HPWH.hh b/src/HPWH.hh index 1369b24e..d0059e07 100644 --- a/src/HPWH.hh +++ b/src/HPWH.hh @@ -1063,7 +1063,7 @@ class HPWH /// sequence of draws in pattern typedef std::vector DrawPattern; - static std::unordered_map firstDrawClusterSizes; + static std::unordered_map firstDrawClusterSizes; /// collection of standard draw patterns static std::unordered_map drawPatterns; From c1d5950feaf39a8c37d8607871e1246b62f6b7e5 Mon Sep 17 00:00:00 2001 From: Phil Ahrenkiel Date: Mon, 12 Feb 2024 10:54:44 -0700 Subject: [PATCH 35/37] Remove special chars. --- test/testMeasureMetrics.cc | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/test/testMeasureMetrics.cc b/test/testMeasureMetrics.cc index 87760fcc..b2d1a090 100644 --- a/test/testMeasureMetrics.cc +++ b/test/testMeasureMetrics.cc @@ -168,8 +168,6 @@ int main(int argc, char* argv[]) csvOptions); } - const std::string sDeg = "\370"; - HPWH::FirstHourRating firstHourRating; if (hpwh.findFirstHourRating(firstHourRating, standardTestOptions)) { @@ -213,16 +211,16 @@ int main(int argc, char* argv[]) std::cout << "\t\tRecovery Efficiency: " << standardTestSummary.recoveryEfficiency << "\n"; - std::cout << "\t\tStandby Loss Coefficient (kJ/h" << sDeg - << "C): " << standardTestSummary.standbyLossCoefficient_kJperhC << "\n"; + std::cout << "\t\tStandby Loss Coefficient (kJ/h degC): " + << standardTestSummary.standbyLossCoefficient_kJperhC << "\n"; std::cout << "\t\tUEF: " << standardTestSummary.UEF << "\n"; - std::cout << "\t\tAverage Inlet Temperature (" << sDeg - << "C): " << standardTestSummary.avgInletT_C << "\n"; + std::cout << "\t\tAverage Inlet Temperature (degC): " << standardTestSummary.avgInletT_C + << "\n"; - std::cout << "\t\tAverage Outlet Temperature (" << sDeg - << "C): " << standardTestSummary.avgOutletT_C << "\n"; + std::cout << "\t\tAverage Outlet Temperature (degC): " + << standardTestSummary.avgOutletT_C << "\n"; std::cout << "\t\tTotal Volume Drawn (L): " << standardTestSummary.removedVolume_L << "\n"; From d7371d2a825f308275a53d68a56a53bd7cd80576 Mon Sep 17 00:00:00 2001 From: Phil Ahrenkiel Date: Mon, 26 Feb 2024 13:10:32 -0700 Subject: [PATCH 36/37] Add mesaureMetrics exe. --- test/CMakeLists.txt | 5 + test/measureMetrics.cc | 204 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 209 insertions(+) create mode 100644 test/measureMetrics.cc diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 65867831..4da009be 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -343,3 +343,8 @@ add_test(NAME "RegressionTest.YearRuns" COMMAND ${CMAKE_COMMAND} -E compare_file # Add unit tests add_subdirectory(unit_tests) + +# Build measureMetrics +add_executable(measureMetrics measureMetrics.cc) +target_link_libraries(measureMetrics PRIVATE ${libs}) +target_compile_features(measureMetrics PRIVATE cxx_std_17) diff --git a/test/measureMetrics.cc b/test/measureMetrics.cc new file mode 100644 index 00000000..f2964eaf --- /dev/null +++ b/test/measureMetrics.cc @@ -0,0 +1,204 @@ +/* + * Ultiltiy to measure HPWH performance metrics + */ + +#include "HPWH.hh" + +int main(int argc, char* argv[]) +{ + HPWH::StandardTestSummary standardTestSummary; + bool validNumArgs = false; + bool runUnitTests = false; + + HPWH::StandardTestOptions standardTestOptions; + standardTestOptions.saveOutput = false; + standardTestOptions.changeSetpoint = true; + standardTestOptions.nTestTCouples = 6; + standardTestOptions.setpointT_C = 51.7; + + // process command line arguments + std::string sPresetOrFile = "Preset"; + std::string sModelName; + std::string sOutputDirectory; + if (argc == 2) + { + sModelName = argv[1]; + validNumArgs = true; + runUnitTests = false; + } + else if (argc == 3) + { + sPresetOrFile = argv[1]; + sModelName = argv[2]; + validNumArgs = true; + runUnitTests = false; + } + else if (argc == 4) + { + sPresetOrFile = argv[1]; + sModelName = argv[2]; + sOutputDirectory = argv[3]; + validNumArgs = true; + runUnitTests = false; + standardTestOptions.saveOutput = true; + } + + if (!validNumArgs) + { + std::cout << "Invalid input:\n\ + To determine performance metrics for a particular model spec, provide ONE, TWO, or THREE arguments:\n\ + \t[model spec Type, i.e., Preset (default) or File]\n\ + \t[model spec Name, i.e., Sanden80]\n\ + \t[output Directory, i.e., .\\output]\n"; + exit(1); + } + + for (auto& c : sPresetOrFile) + { + c = static_cast(std::tolower(static_cast(c))); + } + + HPWH hpwh; + bool validModel = false; + if (sPresetOrFile == "preset") + { + if (hpwh.initPreset(sModelName) == 0) + { + validModel = true; + } + } + else + { + std::string inputFile = sModelName + ".txt"; + if (hpwh.initFromFile(inputFile) == 0) + { + validModel = true; + } + } + + if (!validModel) + { + std::cout << "Invalid input: Model name not found.\n"; + exit(1); + } + + sPresetOrFile[0] = + static_cast(std::toupper(static_cast(sPresetOrFile[0]))); + std::cout << "Spec type: " << sPresetOrFile << "\n"; + std::cout << "Model name: " << sModelName << "\n"; + + if (standardTestOptions.saveOutput) + { + std::string sOutputFilename = "test24hr_" + sPresetOrFile + "_" + sModelName + ".csv"; + + std::string sFullOutputFilename = sOutputDirectory + "/" + sOutputFilename; + standardTestOptions.outputFile.open(sFullOutputFilename.c_str(), std::ifstream::out); + if (!standardTestOptions.outputFile.is_open()) + { + std::cout << "Could not open output file " << sFullOutputFilename << "\n"; + exit(1); + } + std::cout << "Output file: " << sFullOutputFilename << "\n"; + + std::string strPreamble; + std::string sHeader = "minutes,Ta,Tsetpoint,inletT,draw,"; + + int csvOptions = HPWH::CSVOPT_NONE; + hpwh.WriteCSVHeading(standardTestOptions.outputFile, + sHeader.c_str(), + standardTestOptions.nTestTCouples, + csvOptions); + } + + HPWH::FirstHourRating firstHourRating; + if (hpwh.findFirstHourRating(firstHourRating, standardTestOptions)) + { + std::string sFirstHourRatingDesig = ""; + switch (firstHourRating.desig) + { + case HPWH::FirstHourRatingDesig::VerySmall: + { + sFirstHourRatingDesig = "Very Small"; + break; + } + case HPWH::FirstHourRatingDesig::Low: + { + sFirstHourRatingDesig = "Low"; + break; + } + case HPWH::FirstHourRatingDesig::Medium: + { + sFirstHourRatingDesig = "Medium"; + break; + } + case HPWH::FirstHourRatingDesig::High: + { + sFirstHourRatingDesig = "High"; + break; + } + } + std::cout << "\tFirst-Hour Rating:\n"; + std::cout << "\t\tVolume Drawn (L): " << firstHourRating.drawVolume_L << "\n"; + std::cout << "\t\tDesignation: " << sFirstHourRatingDesig << "\n"; + + if (hpwh.run24hrTest(firstHourRating, standardTestSummary, standardTestOptions)) + { + + std::cout << "\t24-Hour Test Results:\n"; + if (!standardTestSummary.qualifies) + { + std::cout << "\t\tDoes not qualify as consumer water heater.\n"; + } + + std::cout << "\t\tRecovery Efficiency: " << standardTestSummary.recoveryEfficiency + << "\n"; + + std::cout << "\t\tStandby Loss Coefficient (kJ/h degC): " + << standardTestSummary.standbyLossCoefficient_kJperhC << "\n"; + + std::cout << "\t\tUEF: " << standardTestSummary.UEF << "\n"; + + std::cout << "\t\tAverage Inlet Temperature (degC): " << standardTestSummary.avgInletT_C + << "\n"; + + std::cout << "\t\tAverage Outlet Temperature (degC): " + << standardTestSummary.avgOutletT_C << "\n"; + + std::cout << "\t\tTotal Volume Drawn (L): " << standardTestSummary.removedVolume_L + << "\n"; + + std::cout << "\t\tDaily Water-Heating Energy Consumption (kWh): " + << KJ_TO_KWH(standardTestSummary.waterHeatingEnergy_kJ) << "\n"; + + std::cout << "\t\tAdjusted Daily Water-Heating Energy Consumption (kWh): " + << KJ_TO_KWH(standardTestSummary.adjustedConsumedWaterHeatingEnergy_kJ) + << "\n"; + + std::cout << "\t\tModified Daily Water-Heating Energy Consumption (kWh): " + << KJ_TO_KWH(standardTestSummary.modifiedConsumedWaterHeatingEnergy_kJ) + << "\n"; + + std::cout << "\tAnnual Values:\n"; + std::cout << "\t\tAnnual Electrical Energy Consumption (kWh): " + << KJ_TO_KWH(standardTestSummary.annualConsumedElectricalEnergy_kJ) << "\n"; + + std::cout << "\t\tAnnual Energy Consumption (kWh): " + << KJ_TO_KWH(standardTestSummary.annualConsumedEnergy_kJ) << "\n"; + } + else + { + std::cout << "Unable to complete 24-hr test.\n"; + } + } + else + { + std::cout << "Unable to complete first-hour rating test.\n"; + } + + if (standardTestOptions.saveOutput) + { + standardTestOptions.outputFile.close(); + } + + return 0; +} From e2418c85fe564ff619b20659899028dffa9d6ed7 Mon Sep 17 00:00:00 2001 From: Phil Ahrenkiel Date: Mon, 26 Feb 2024 13:24:53 -0700 Subject: [PATCH 37/37] Remove unused var. --- test/measureMetrics.cc | 4 ---- 1 file changed, 4 deletions(-) diff --git a/test/measureMetrics.cc b/test/measureMetrics.cc index f2964eaf..0cab4e3f 100644 --- a/test/measureMetrics.cc +++ b/test/measureMetrics.cc @@ -8,7 +8,6 @@ int main(int argc, char* argv[]) { HPWH::StandardTestSummary standardTestSummary; bool validNumArgs = false; - bool runUnitTests = false; HPWH::StandardTestOptions standardTestOptions; standardTestOptions.saveOutput = false; @@ -24,14 +23,12 @@ int main(int argc, char* argv[]) { sModelName = argv[1]; validNumArgs = true; - runUnitTests = false; } else if (argc == 3) { sPresetOrFile = argv[1]; sModelName = argv[2]; validNumArgs = true; - runUnitTests = false; } else if (argc == 4) { @@ -39,7 +36,6 @@ int main(int argc, char* argv[]) sModelName = argv[2]; sOutputDirectory = argv[3]; validNumArgs = true; - runUnitTests = false; standardTestOptions.saveOutput = true; }