diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0be9497d..1e9214e3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -22,6 +22,7 @@ set(source HPWHHeatSources.cc HPWHHeatingLogics.cc HPWHpresets.cc + HPWHSimulator.cc ) add_library(libHPWHsim ${source} ${headers}) diff --git a/src/HPWH.cc b/src/HPWH.cc index b615ffeb..5e8d4f61 100644 --- a/src/HPWH.cc +++ b/src/HPWH.cc @@ -63,6 +63,10 @@ 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.); +/* static */ void (*HPWH::messageCallback)(const std::string message, void* contextPtr) = nullptr; + +/* static */ void* HPWH::messageCallbackContextPtr = nullptr; + //----------------------------------------------------------------------------- /// @brief Samples a std::vector to extract a single value spanning the fractional /// coordinate range from frac_begin to frac_end. @@ -321,10 +325,7 @@ void HPWH::setMinutesPerStep(const double minutesPerStep_in) }; // public HPWH functions -HPWH::HPWH() : messageCallback(NULL), messageCallbackContextPtr(NULL), hpwhVerbosity(VRB_silent) -{ - setAllDefaults(); -}; +HPWH::HPWH() : verbosity(VRB_silent) { setAllDefaults(); }; void HPWH::setAllDefaults() { @@ -352,7 +353,6 @@ void HPWH::setAllDefaults() timerTOT = 0.; usesSoCLogic = false; setMinutesPerStep(1.0); - hpwhVerbosity = VRB_minuteOut; hasHeatExchanger = false; heatExchangerEffectiveness = 0.9; } @@ -368,7 +368,7 @@ HPWH& HPWH::operator=(const HPWH& hpwh) simHasFailed = hpwh.simHasFailed; - hpwhVerbosity = hpwh.hpwhVerbosity; + verbosity = hpwh.verbosity; // these should actually be the same pointers messageCallback = hpwh.messageCallback; @@ -451,14 +451,14 @@ int HPWH::runOneStep(double drawVolume_L, if ((DRstatus & (DR_TOO | DR_TOT))) { - if (hpwhVerbosity >= VRB_typical) + if (verbosity >= VRB_typical) { msg("DR_TOO | DR_TOT use conflicting logic sets. The logic will follow a DR_TOT scheme " " \n"); } } - if (hpwhVerbosity >= VRB_typical) + if (verbosity >= VRB_typical) { msg("Beginning runOneStep. \nTank Temps: "); printTankTemps(); @@ -474,7 +474,7 @@ int HPWH::runOneStep(double drawVolume_L, // is the failure flag is set, don't run if (simHasFailed) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("simHasFailed is set, aborting. \n"); } @@ -521,7 +521,7 @@ int HPWH::runOneStep(double drawVolume_L, if ((DRstatus & DR_LOC) != 0 && (DRstatus & DR_LOR) != 0) { turnAllHeatSourcesOff(); // turns off isheating - if (hpwhVerbosity >= VRB_emetic) + if (verbosity >= VRB_emetic) { msg("DR_LOC | DR_LOC everything off, DRstatus = %i \n", DRstatus); } @@ -541,7 +541,7 @@ int HPWH::runOneStep(double drawVolume_L, heatSources[lowestElementIndex].engageHeatSource(DRstatus); } - if (hpwhVerbosity >= VRB_emetic) + if (verbosity >= VRB_emetic) { msg("TURNED ON DR_TOO engaged compressor and lowest resistance element, DRstatus = " "%i \n", @@ -552,7 +552,7 @@ int HPWH::runOneStep(double drawVolume_L, // do HeatSource choice for (int i = 0; i < getNumHeatSources(); i++) { - if (hpwhVerbosity >= VRB_emetic) + if (verbosity >= VRB_emetic) { msg("Heat source choice:\theatsource %d can choose from %lu turn on logics and %lu " "shut off logics\n", @@ -580,7 +580,7 @@ int HPWH::runOneStep(double drawVolume_L, // come on, then turn off and start it up if (heatSources[i].isVIP) { - if (hpwhVerbosity >= VRB_emetic) + if (verbosity >= VRB_emetic) { msg("\tVIP check"); } @@ -616,7 +616,7 @@ int HPWH::runOneStep(double drawVolume_L, } // end loop over heat sources - if (hpwhVerbosity >= VRB_emetic) + if (verbosity >= VRB_emetic) { msg("after heat source choosing: "); for (int i = 0; i < getNumHeatSources(); i++) @@ -631,14 +631,14 @@ int HPWH::runOneStep(double drawVolume_L, for (int i = 0; i < getNumHeatSources(); i++) { // check/apply lock-outs - if (hpwhVerbosity >= VRB_emetic) + if (verbosity >= VRB_emetic) { msg("Checking lock-out logic for heat source %d:\n", i); } if (shouldDRLockOut(heatSources[i].typeOfHeatSource, DRstatus)) { heatSources[i].lockOutHeatSource(); - if (hpwhVerbosity >= VRB_emetic) + if (verbosity >= VRB_emetic) { msg("Locked out heat source, DRstatus = %i\n", DRstatus); } @@ -651,7 +651,7 @@ int HPWH::runOneStep(double drawVolume_L, if (heatSources[i].isLockedOut() && heatSources[i].backupHeatSource == NULL) { heatSources[i].disengageHeatSource(); - if (hpwhVerbosity >= HPWH::VRB_emetic) + if (verbosity >= HPWH::VRB_emetic) { msg("\nWARNING: lock-out triggered, but no backupHeatSource defined. " "Simulation will continue will lock out the heat source."); @@ -680,7 +680,7 @@ int HPWH::runOneStep(double drawVolume_L, else if (VIPIndex >= 0 && heatSources[VIPIndex].isOn && heatSources[i].backupHeatSource->isAResistance()) { - if (hpwhVerbosity >= VRB_typical) + if (verbosity >= VRB_typical) { msg("Locked out back up heat source AND the engaged heat source %i, " "DRstatus = %i\n", @@ -706,7 +706,7 @@ int HPWH::runOneStep(double drawVolume_L, if (heatSourcePtr->runtime_min < minutesToRun) { // debugging message handling - if (hpwhVerbosity >= VRB_emetic) + if (verbosity >= VRB_emetic) { msg("done heating! runtime_min minutesToRun %.2lf %.2lf\n", heatSourcePtr->runtime_min, @@ -812,7 +812,7 @@ int HPWH::runOneStep(double drawVolume_L, // cursory check for inverted temperature profile if (tankTemps_C[getNumNodes() - 1] < tankTemps_C[0]) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("The top of the tank is cooler than the bottom. \n"); } @@ -834,14 +834,14 @@ int HPWH::runOneStep(double drawVolume_L, if (simHasFailed) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("The simulation has encountered an error. \n"); } return HPWH_ABORT; } - if (hpwhVerbosity >= VRB_typical) + if (verbosity >= VRB_typical) { msg("Ending runOneStep. \n\n\n\n"); } @@ -867,7 +867,7 @@ int HPWH::runNSteps(int N, std::vector heatSources_energyInputs_SUM(getNumHeatSources()); std::vector heatSources_energyOutputs_SUM(getNumHeatSources()); - if (hpwhVerbosity >= VRB_typical) + if (verbosity >= VRB_typical) { msg("Begin runNSteps. \n"); } @@ -879,7 +879,7 @@ int HPWH::runNSteps(int N, if (simHasFailed) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("RunNSteps has encountered an error on step %d of N and has ceased running. " "\n", @@ -902,7 +902,7 @@ int HPWH::runNSteps(int N, } // print minutely output - if (hpwhVerbosity == VRB_minuteOut) + if (verbosity == VRB_minuteOut) { msg("%f,%f,%f,", tankAmbientT_C[i], drawVolume_L[i], inletT_C[i]); for (int j = 0; j < getNumHeatSources(); j++) @@ -951,7 +951,7 @@ int HPWH::runNSteps(int N, heatSources[i].energyOutput_kWh = heatSources_energyOutputs_SUM[i]; } - if (hpwhVerbosity >= VRB_typical) + if (verbosity >= VRB_typical) { msg("Ending runNSteps. \n\n\n\n"); } @@ -986,51 +986,6 @@ void HPWH::addHeatParent(HeatSource* heatSourcePtr, } } -void HPWH::setVerbosity(VERBOSITY hpwhVrb) { hpwhVerbosity = hpwhVrb; } -void HPWH::setMessageCallback(void (*callbackFunc)(const string message, void* contextPtr), - void* contextPtr) -{ - messageCallback = callbackFunc; - messageCallbackContextPtr = contextPtr; -} -void HPWH::sayMessage(const string message) const -{ - if (messageCallback != NULL) - { - (*messageCallback)(message, messageCallbackContextPtr); - } - else - { - std::cout << message; - } -} -void HPWH::msg(const char* fmt, ...) const -{ - va_list ap; - va_start(ap, fmt); - msgV(fmt, ap); -} -void HPWH::msgV(const char* fmt, va_list ap /*=NULL*/) const -{ - char outputString[MAXOUTSTRING]; - - const char* p; - if (ap) - { -#if defined(_MSC_VER) - vsprintf_s(outputString, fmt, ap); -#else - vsnprintf(outputString, MAXOUTSTRING, fmt, ap); -#endif - p = outputString; - } - else - { - p = fmt; - } - sayMessage(p); -} // HPWH::msgV - void HPWH::printHeatSourceInfo() { std::stringstream ss; @@ -1192,7 +1147,7 @@ int HPWH::setSetpoint(double newSetpoint, UNITS units /*=UNITS_C*/) } else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Incorrect unit specification for setSetpoint. \n"); } @@ -1200,7 +1155,7 @@ int HPWH::setSetpoint(double newSetpoint, UNITS units /*=UNITS_C*/) } if (!isNewSetpointPossible(newSetpoint_C, temp, why)) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Unwilling to set this setpoint for the currently selected model, max setpoint is " "%f C. %s\n", @@ -1227,7 +1182,7 @@ double HPWH::getSetpoint(UNITS units /*=UNITS_C*/) const } else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Incorrect unit specification for getSetpoint. \n"); } @@ -1240,7 +1195,7 @@ double HPWH::getMaxCompressorSetpoint(UNITS units /*=UNITS_C*/) const if (!hasACompressor()) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Unit does not have a compressor \n"); } @@ -1258,7 +1213,7 @@ double HPWH::getMaxCompressorSetpoint(UNITS units /*=UNITS_C*/) const } else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Incorrect unit specification for getMaxCompressorSetpoint. \n"); } @@ -1284,7 +1239,7 @@ bool HPWH::isNewSetpointPossible(double newSetpoint, } else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Incorrect unit specification for isNewSetpointPossible. \n"); } @@ -1370,7 +1325,7 @@ double HPWH::calcSoCFraction(double tMains_C, double tMinUseful_C, double tMax_C // fractional equation if (tMains_C >= tMinUseful_C) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("tMains_C is greater than or equal tMinUseful_C. \n"); } @@ -1378,7 +1333,7 @@ double HPWH::calcSoCFraction(double tMains_C, double tMinUseful_C, double tMax_C } if (tMinUseful_C > tMax_C) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("tMinUseful_C is greater tMax_C. \n"); } @@ -1421,7 +1376,7 @@ double HPWH::getMinOperatingTemp(UNITS units /*=UNITS_C*/) const { if (!hasACompressor()) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("No compressor found in this HPWH. \n"); } @@ -1437,7 +1392,7 @@ double HPWH::getMinOperatingTemp(UNITS units /*=UNITS_C*/) const } else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Incorrect unit specification for getMinOperatingTemp.\n"); } @@ -1459,7 +1414,7 @@ int HPWH::setTankLayerTemperatures(std::vector setTankTemps, const UNITS { if ((units != UNITS_C) && (units != UNITS_F)) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Incorrect unit specification for setSetpoint. \n"); } @@ -1469,14 +1424,14 @@ int HPWH::setTankLayerTemperatures(std::vector setTankTemps, const UNITS std::size_t numSetNodes = setTankTemps.size(); if (numSetNodes == 0) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("No temperatures provided.\n"); } return HPWH_ABORT; } - // convert setTankTemps to �C, if necessary + // convert setTankTemps to °C, if necessary if (units == UNITS_F) for (auto& T : setTankTemps) T = F_TO_C(T); @@ -1494,7 +1449,7 @@ int HPWH::setAirFlowFreedom(double fanFraction) { if (fanFraction < 0 || fanFraction > 1) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("You have attempted to set the fan fraction outside of bounds. \n"); } @@ -1539,7 +1494,7 @@ int HPWH::setTankSize_adjustUA(double HPWH_size, } else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Incorrect unit specification for setTankSize_adjustUA. \n"); } @@ -1580,7 +1535,7 @@ double HPWH::getTankSurfaceArea(UNITS units /*=UNITS_FT2*/) const double value = getTankSurfaceArea(tankVolume_L, UNITS_L, units); if (value < 0.) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) msg("Incorrect unit specification for getTankSurfaceArea. \n"); value = HPWH_ABORT; } @@ -1620,7 +1575,7 @@ double HPWH::getTankRadius(UNITS units /*=UNITS_FT*/) const if (value < 0.) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) msg("Incorrect unit specification for getTankRadius. \n"); value = HPWH_ABORT; } @@ -1633,7 +1588,7 @@ int HPWH::setTankSize(double HPWH_size, UNITS units /*=UNITS_L*/, bool forceChan { if (isTankSizeFixed() && !forceChange) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Can not change the tank size for your currently selected model. \n"); } @@ -1641,7 +1596,7 @@ int HPWH::setTankSize(double HPWH_size, UNITS units /*=UNITS_L*/, bool forceChan } if (HPWH_size <= 0) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("You have attempted to set the tank volume outside of bounds. \n"); } @@ -1660,7 +1615,7 @@ int HPWH::setTankSize(double HPWH_size, UNITS units /*=UNITS_L*/, bool forceChan } else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Incorrect unit specification for setTankSize. \n"); } @@ -1672,14 +1627,14 @@ int HPWH::setTankSize(double HPWH_size, UNITS units /*=UNITS_L*/, bool forceChan return 0; } -int HPWH::setDoInversionMixing(bool doInvMix) +int HPWH::setDoInversionMixing(bool doInversionMixing_in) { - this->doInversionMixing = doInvMix; + doInversionMixing = doInversionMixing_in; return 0; } -int HPWH::setDoConduction(bool doCondu) +int HPWH::setDoConduction(bool doConduction_in) { - this->doConduction = doCondu; + doConduction = doConduction_in; return 0; } @@ -1695,7 +1650,7 @@ int HPWH::setUA(double UA, UNITS units /*=UNITS_kJperHrC*/) } else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Incorrect unit specification for setUA. \n"); } @@ -1717,7 +1672,7 @@ int HPWH::getUA(double& UA, UNITS units /*=UNITS_kJperHrC*/) const } else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Incorrect unit specification for getUA. \n"); } @@ -1739,7 +1694,7 @@ int HPWH::setFittingsUA(double UA, UNITS units /*=UNITS_kJperHrC*/) } else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Incorrect unit specification for setFittingsUA. \n"); } @@ -1760,7 +1715,7 @@ int HPWH::getFittingsUA(double& UA, UNITS units /*=UNITS_kJperHrC*/) const } else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Incorrect unit specification for getUA. \n"); } @@ -1792,7 +1747,7 @@ int HPWH::setExternalPortHeightByFraction(double fractionalHeight, int whichExte { if (!hasExternalHeatSource()) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Does not have an external heat source \n"); } @@ -1828,7 +1783,7 @@ int HPWH::setNodeNumFromFractionalHeight(double fractionalHeight, int& inletNum) { if (fractionalHeight > 1. || fractionalHeight < 0.) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Out of bounds fraction for setInletByFraction \n"); } @@ -1845,7 +1800,7 @@ int HPWH::getExternalInletHeight() const { if (!hasExternalHeatSource()) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Does not have an external heat source \n"); } @@ -1865,7 +1820,7 @@ int HPWH::getExternalOutletHeight() const { if (!hasExternalHeatSource()) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Does not have an external heat source \n"); } @@ -1886,7 +1841,7 @@ int HPWH::setTimerLimitTOT(double limit_min) { if (limit_min > 24. * 60. || limit_min < 0.) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Out of bounds time limit for setTimerLimitTOT \n"); } @@ -1912,7 +1867,7 @@ int HPWH::getInletHeight(int whichInlet) const } else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Invalid inlet chosen in getInletHeight \n"); } @@ -1924,15 +1879,15 @@ int HPWH::setMaxTempDepression(double maxDepression, UNITS units /*=UNITS_C*/) { if (units == UNITS_C) { - this->maxDepression_C = maxDepression; + maxDepression_C = maxDepression; } else if (units == UNITS_F) { - this->maxDepression_C = F_TO_C(maxDepression); + maxDepression_C = F_TO_C(maxDepression); } else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Incorrect unit specification for max Temp Depression. \n"); } @@ -1971,7 +1926,7 @@ int HPWH::setEnteringWaterHighTempShutOff(double highTemp, { if (!hasEnteringWaterHighTempShutOff(heatSourceIndex)) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("You have attempted to acess a heating logic that does not exist. \n"); } @@ -1989,7 +1944,7 @@ int HPWH::setEnteringWaterHighTempShutOff(double highTemp, } else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Incorrect unit specification for set Entering Water High Temp Shut Off. \n"); } @@ -2014,7 +1969,7 @@ int HPWH::setEnteringWaterHighTempShutOff(double highTemp, } if (highTempIsNotValid) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("High temperature shut off is too close to the setpoint, excpected a minimum " "difference of %.2lf.\n", @@ -2039,7 +1994,7 @@ int HPWH::setTargetSoCFraction(double target) { if (!isSoCControlled()) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Can not set target state of charge if HPWH is not using state of charge " "controls."); @@ -2048,7 +2003,7 @@ int HPWH::setTargetSoCFraction(double target) } if (target < 0) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Can not set a negative target state of charge."); } @@ -2093,7 +2048,7 @@ int HPWH::switchToSoCControls(double targetSoC, { if (!canUseSoCControls()) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Cannot set up state of charge controls for integrated or wrapped HPWHs.\n"); } @@ -2113,7 +2068,7 @@ int HPWH::switchToSoCControls(double targetSoC, } else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Incorrect unit specification for set Enterinh Water High Temp Shut Off.\n"); } @@ -2122,7 +2077,7 @@ int HPWH::switchToSoCControls(double targetSoC, if (mainsT_C >= tempMinUseful_C) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("The mains temperature can't be equal to or greater than the minimum useful " "temperature.\n"); @@ -2413,7 +2368,7 @@ double HPWH::getTankNodeTemp(int nodeNum, UNITS units /*=UNITS_C*/) const { if (tankTemps_C.empty()) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("You have attempted to access the temperature of a tank node that does not exist. " "\n"); @@ -2436,7 +2391,7 @@ double HPWH::getTankNodeTemp(int nodeNum, UNITS units /*=UNITS_C*/) const } else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Incorrect unit specification for getTankNodeTemp. \n"); } @@ -2449,7 +2404,7 @@ double HPWH::getNthSimTcouple(int iTCouple, int nTCouple, UNITS units /*=UNITS_C { if (iTCouple > nTCouple || iTCouple < 1) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("You have attempted to access a simulated thermocouple that does not exist. \n"); } @@ -2469,7 +2424,7 @@ double HPWH::getNthSimTcouple(int iTCouple, int nTCouple, UNITS units /*=UNITS_C } else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Incorrect unit specification for getNthSimTcouple. \n"); } @@ -2503,7 +2458,7 @@ double HPWH::getCompressorCapacity(double airTemp /*=19.722*/, if (!hasACompressor()) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Current model does not have a compressor. \n"); } @@ -2524,7 +2479,7 @@ double HPWH::getCompressorCapacity(double airTemp /*=19.722*/, } else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Incorrect unit specification for temperatures in getCompressorCapacity. \n"); } @@ -2534,7 +2489,7 @@ double HPWH::getCompressorCapacity(double airTemp /*=19.722*/, if (airTemp_C < heatSources[compressorIndex].minT || airTemp_C > heatSources[compressorIndex].maxT) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("The compress does not operate at the specified air temperature. \n"); } @@ -2546,7 +2501,7 @@ double HPWH::getCompressorCapacity(double airTemp /*=19.722*/, heatSources[compressorIndex].secondaryHeatExchanger.hotSideTemperatureOffset_dC; if (outTemp_C > maxAllowedSetpoint_C) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Inputted outlet temperature of the compressor is higher than can be produced."); } @@ -2572,7 +2527,7 @@ double HPWH::getCompressorCapacity(double airTemp /*=19.722*/, } else if (pwrUnit != UNITS_BTUperHr) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Incorrect unit specification for capacity in getCompressorCapacity. \n"); } @@ -2587,7 +2542,7 @@ double HPWH::getNthHeatSourceEnergyInput(int N, UNITS units /*=UNITS_KWH*/) cons // energy used by the heat source is positive - this should always be positive if (N >= getNumHeatSources() || N < 0) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("You have attempted to access the energy input of a heat source that does not " "exist. \n"); @@ -2609,7 +2564,7 @@ double HPWH::getNthHeatSourceEnergyInput(int N, UNITS units /*=UNITS_KWH*/) cons } else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Incorrect unit specification for getNthHeatSourceEnergyInput. \n"); } @@ -2622,7 +2577,7 @@ double HPWH::getNthHeatSourceEnergyOutput(int N, UNITS units /*=UNITS_KWH*/) con // returns energy from the heat source into the water - this should always be positive if (N >= getNumHeatSources() || N < 0) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("You have attempted to access the energy output of a heat source that does not " "exist. \n"); @@ -2644,7 +2599,7 @@ double HPWH::getNthHeatSourceEnergyOutput(int N, UNITS units /*=UNITS_KWH*/) con } else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Incorrect unit specification for getNthHeatSourceEnergyInput. \n"); } @@ -2656,7 +2611,7 @@ double HPWH::getNthHeatSourceRunTime(int N) const { if (N >= getNumHeatSources() || N < 0) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("You have attempted to access the run time of a heat source that does not exist. " "\n"); @@ -2670,7 +2625,7 @@ int HPWH::isNthHeatSourceRunning(int N) const { if (N >= getNumHeatSources() || N < 0) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("You have attempted to access the status of a heat source that does not exist. " "\n"); @@ -2691,7 +2646,7 @@ HPWH::HEATSOURCE_TYPE HPWH::getNthHeatSourceType(int N) const { if (N >= getNumHeatSources() || N < 0) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("You have attempted to access the type of a heat source that does not exist. \n"); } @@ -2712,7 +2667,7 @@ double HPWH::getTankSize(UNITS units /*=UNITS_L*/) const } else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Incorrect unit specification for getTankSize. \n"); } @@ -2732,7 +2687,7 @@ double HPWH::getOutletTemp(UNITS units /*=UNITS_C*/) const } else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Incorrect unit specification for getOutletTemp. \n"); } @@ -2752,7 +2707,7 @@ double HPWH::getCondenserWaterInletTemp(UNITS units /*=UNITS_C*/) const } else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Incorrect unit specification for getCondenserWaterInletTemp. \n"); } @@ -2772,7 +2727,7 @@ double HPWH::getCondenserWaterOutletTemp(UNITS units /*=UNITS_C*/) const } else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Incorrect unit specification for getCondenserWaterInletTemp. \n"); } @@ -2792,7 +2747,7 @@ double HPWH::getExternalVolumeHeated(UNITS units /*=UNITS_L*/) const } else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Incorrect unit specification for getExternalVolumeHeated. \n"); } @@ -2817,7 +2772,7 @@ double HPWH::getEnergyRemovedFromEnvironment(UNITS units /*=UNITS_KWH*/) const } else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Incorrect unit specification for getEnergyRemovedFromEnvironment. \n"); } @@ -2842,7 +2797,7 @@ double HPWH::getStandbyLosses(UNITS units /*=UNITS_KWH*/) const } else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Incorrect unit specification for getStandbyLosses. \n"); } @@ -2873,7 +2828,7 @@ int HPWH::getCompressorCoilConfig() const { if (!hasACompressor()) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Current model does not have a compressor. \n"); } @@ -2885,7 +2840,7 @@ bool HPWH::isCompressorMultipass() const { if (!hasACompressor()) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Current model does not have a compressor. \n"); } @@ -2897,7 +2852,7 @@ bool HPWH::isCompressoExternalMultipass() const { if (!hasACompressor()) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Current model does not have a compressor. \n"); } @@ -2924,7 +2879,7 @@ double HPWH::getExternalMPFlowRate(UNITS units /*=UNITS_GPM*/) const { if (!isCompressoExternalMultipass()) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Does not have an external multipass heat source \n"); } @@ -2941,7 +2896,7 @@ double HPWH::getExternalMPFlowRate(UNITS units /*=UNITS_GPM*/) const } else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Incorrect unit specification for getExternalMPFlowRate. \n"); } @@ -2970,7 +2925,7 @@ double HPWH::getCompressorMinRuntime(UNITS units /*=UNITS_MIN*/) const } else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Incorrect unit specification for getCompressorMinRunTime. \n"); } @@ -2979,7 +2934,7 @@ double HPWH::getCompressorMinRuntime(UNITS units /*=UNITS_MIN*/) const } else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("This HPWH has no compressor. \n"); } @@ -2994,7 +2949,7 @@ int HPWH::getSizingFractions(double& aquaFract, double& useableFract) const if (!hasACompressor()) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Current model does not have a compressor. \n"); } @@ -3002,7 +2957,7 @@ int HPWH::getSizingFractions(double& aquaFract, double& useableFract) const } else if (usesSoCLogic) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Current model uses SOC control logic and does not have a definition for sizing " "fractions. \n"); @@ -3015,7 +2970,7 @@ int HPWH::getSizingFractions(double& aquaFract, double& useableFract) const { double tempA; - if (hpwhVerbosity >= VRB_emetic) + if (verbosity >= VRB_emetic) { msg("\tturnon logic: %s ", onLogic->description.c_str()); } @@ -3032,7 +2987,7 @@ int HPWH::getSizingFractions(double& aquaFract, double& useableFract) const double tempUse; - if (hpwhVerbosity >= VRB_emetic) + if (verbosity >= VRB_emetic) { msg("\tshutsOff logic: %s ", offLogic->description.c_str()); } @@ -3053,7 +3008,7 @@ int HPWH::getSizingFractions(double& aquaFract, double& useableFract) const } else { - if (hpwhVerbosity >= VRB_emetic) + if (verbosity >= VRB_emetic) { msg("\no shutoff logics present"); } @@ -3077,7 +3032,7 @@ int HPWH::setScaleHPWHCapacityCOP(double scaleCapacity /*=1.0*/, double scaleCOP { if (!isHPWHScalable()) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Can not scale the HPWH Capacity or COP \n"); } @@ -3085,7 +3040,7 @@ int HPWH::setScaleHPWHCapacityCOP(double scaleCapacity /*=1.0*/, double scaleCOP } if (!hasACompressor()) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Current model does not have a compressor. \n"); } @@ -3093,7 +3048,7 @@ int HPWH::setScaleHPWHCapacityCOP(double scaleCapacity /*=1.0*/, double scaleCOP } if (scaleCapacity <= 0 || scaleCOP <= 0) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Can not scale the HPWH Capacity or COP to 0 or less than 0 \n"); } @@ -3146,7 +3101,7 @@ int HPWH::setResistanceCapacity(double power, int which /*=-1*/, UNITS pwrUnit / // Input checks if (!isHPWHScalable()) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Can not scale the resistance elements \n"); } @@ -3154,7 +3109,7 @@ int HPWH::setResistanceCapacity(double power, int which /*=-1*/, UNITS pwrUnit / } if (getNumResistanceElements() == 0) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("There are no resistance elements to set capacity for \n"); } @@ -3162,7 +3117,7 @@ int HPWH::setResistanceCapacity(double power, int which /*=-1*/, UNITS pwrUnit / } if (which < -1 || which > getNumResistanceElements() - 1) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Out of bounds value for which in setResistanceCapacity()\n"); } @@ -3170,7 +3125,7 @@ int HPWH::setResistanceCapacity(double power, int which /*=-1*/, UNITS pwrUnit / } if (power < 0) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Can not have a negative input power \n"); } @@ -3188,7 +3143,7 @@ int HPWH::setResistanceCapacity(double power, int which /*=-1*/, UNITS pwrUnit / } else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Incorrect unit specification for capacity in setResistanceCapacity. \n"); } @@ -3231,7 +3186,7 @@ double HPWH::getResistanceCapacity(int which /*=-1*/, UNITS pwrUnit /*=UNITS_KW* // Input checks if (getNumResistanceElements() == 0) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("There are no resistance elements to return capacity for \n"); } @@ -3239,7 +3194,7 @@ double HPWH::getResistanceCapacity(int which /*=-1*/, UNITS pwrUnit /*=UNITS_KW* } if (which < -1 || which > getNumResistanceElements() - 1) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Out of bounds value for which in getResistanceCapacity()\n"); } @@ -3287,7 +3242,7 @@ double HPWH::getResistanceCapacity(int which /*=-1*/, UNITS pwrUnit /*=UNITS_KW* } else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Incorrect unit specification for capacity in getResistanceCapacity. \n"); } @@ -3302,7 +3257,7 @@ int HPWH::getResistancePosition(int elementIndex) const if (elementIndex < 0 || elementIndex > getNumHeatSources() - 1) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Out of bounds value for which in getResistancePosition\n"); } @@ -3311,7 +3266,7 @@ int HPWH::getResistancePosition(int elementIndex) const if (!heatSources[elementIndex].isAResistance()) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("This index is not a resistance element\n"); } @@ -3345,7 +3300,7 @@ void HPWH::updateTankTemps(double drawVolume_L, // calculate how many nodes to draw (wholeNodesToDraw), and the remainder (drawFraction) if (inletVol2_L > drawVolume_L) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Volume in inlet 2 is greater than the draw volume. \n"); } @@ -3402,8 +3357,8 @@ void HPWH::updateTankTemps(double drawVolume_L, double drawVolume_N = drawVolume_L / nodeVolume_L; if (drawVolume_L > tankVolume_L) { - // if (hpwhVerbosity >= VRB_reluctant) { - // //msg("WARNING: Drawing more than the tank volume in one step is undefined + // if (verbosity >= VRB_reluctant) { + // msg("WARNING: Drawing more than the tank volume in one step is undefined // behavior. Terminating simulation. \n"); msg("WARNING: Drawing more than the // tank volume in one step is undefined behavior. Continuing simulation at your own // risk. \n"); @@ -3534,7 +3489,7 @@ void HPWH::updateTankTemps(double drawVolume_L, secondsPerStep; if (tau > 0.5) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("The stability condition for conduction has failed, these results are going to " "be interesting!\n"); @@ -3637,7 +3592,7 @@ double HPWH::addHeatAboveNode(double qAdd_kJ, int nodeNum, const double maxT_C) // Do not exceed maxT_C or setpoint double maxHeatToT_C = std::min(maxT_C, setpoint_C); - if (hpwhVerbosity >= VRB_emetic) + if (verbosity >= VRB_emetic) { msg("node %2d cap_kwh %.4lf \n", nodeNum, KJ_TO_KWH(qAdd_kJ)); } @@ -3713,7 +3668,7 @@ double HPWH::addHeatAboveNode(double qAdd_kJ, int nodeNum, const double maxT_C) void HPWH::addExtraHeatAboveNode(double qAdd_kJ, const int nodeNum) { - if (hpwhVerbosity >= VRB_emetic) + if (verbosity >= VRB_emetic) { msg("node %2d cap_kwh %.4lf \n", nodeNum, KJ_TO_KWH(qAdd_kJ)); } @@ -3959,7 +3914,7 @@ void HPWH::calcDerivedHeatingValues() { heatSources[i].Tshrinkage_C = findShrinkageT_C(heatSources[i].condensity); - if (hpwhVerbosity >= VRB_emetic) + if (verbosity >= VRB_emetic) { msg(outputString, "Heat Source %d \n", i); msg(outputString, "shrinkage %.2lf \n\n", heatSources[i].Tshrinkage_C); @@ -3971,7 +3926,7 @@ void HPWH::calcDerivedHeatingValues() { heatSources[i].lowestNode = findLowestNode(heatSources[i].condensity, getNumNodes()); - if (hpwhVerbosity >= VRB_emetic) + if (verbosity >= VRB_emetic) { msg(outputString, "Heat Source %d \n", i); msg(outputString, " lowest : %d \n", heatSources[i].lowestNode); @@ -4003,7 +3958,7 @@ void HPWH::calcDerivedHeatingValues() } else { - if (hpwhVerbosity >= VRB_minuteOut) + if (verbosity >= VRB_minuteOut) { msg("More than one resistance element is assigned to VIP"); }; @@ -4026,13 +3981,13 @@ void HPWH::calcDerivedHeatingValues() } } } - if (hpwhVerbosity >= VRB_emetic) + if (verbosity >= VRB_emetic) { msg(outputString, " compressorIndex : %d \n", compressorIndex); msg(outputString, " lowestElementIndex : %d \n", lowestElementIndex); msg(outputString, " highestElementIndex : %d \n", highestElementIndex); } - if (hpwhVerbosity >= VRB_emetic) + if (verbosity >= VRB_emetic) { msg(outputString, " VIPIndex : %d \n", VIPIndex); } @@ -4081,7 +4036,7 @@ int HPWH::checkInputs() if (getNumHeatSources() <= 0 && hpwhModel != MODELS_StorageTank) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("You must have at least one HeatSource.\n"); } @@ -4095,7 +4050,7 @@ int HPWH::checkInputs() // check the heat source type to make sure it has been set if (heatSources[i].typeOfHeatSource == TYPE_none) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Heat source %d does not have a specified type. Initialization failed.\n", i); } @@ -4106,7 +4061,7 @@ int HPWH::checkInputs() if (heatSources[i].turnOnLogicSet.size() == 0 && (parent == -1 || heatSources[parent].turnOnLogicSet.size() == 0)) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("You must specify at least one logic to turn on the element or the element " "must be set as a backup for another heat source with at least one logic."); @@ -4120,7 +4075,7 @@ int HPWH::checkInputs() if (!logic->isValid()) { returnVal = HPWH_ABORT; - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("On logic at index %i is invalid", i); } @@ -4132,7 +4087,7 @@ int HPWH::checkInputs() if (!logic->isValid()) { returnVal = HPWH_ABORT; - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Off logic at index %i is invalid", i); } @@ -4146,7 +4101,7 @@ int HPWH::checkInputs() condensitySum += heatSources[i].condensity[j]; if (fabs(condensitySum - 1.0) > 1e-6) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("The condensity for heatsource %d does not sum to 1. \n", i); msg("It sums to %f \n", condensitySum); @@ -4156,7 +4111,7 @@ int HPWH::checkInputs() // check that air flows are all set properly if (heatSources[i].airflowFreedom > 1.0 || heatSources[i].airflowFreedom <= 0.0) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("The airflowFreedom must be between 0 and 1 for heatsource %d. \n", i); } @@ -4169,7 +4124,7 @@ int HPWH::checkInputs() { if (heatSources[i].defrostMap.size() < 3) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Defrost logic set to true but no valid defrost map of length 3 or " "greater set. \n"); @@ -4178,7 +4133,7 @@ int HPWH::checkInputs() } if (heatSources[i].configuration != HeatSource::CONFIG_EXTERNAL) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Defrost is only simulated for external compressors. \n"); } @@ -4191,7 +4146,7 @@ int HPWH::checkInputs() if (heatSources[i].shutOffLogicSet.size() != 1) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("External heat sources can only have one shut off logic. \n "); } @@ -4200,7 +4155,7 @@ int HPWH::checkInputs() if (0 > heatSources[i].externalOutletHeight || heatSources[i].externalOutletHeight > getNumNodes() - 1) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("External heat sources need an external outlet height within the bounds " "from from 0 to numNodes-1. \n"); @@ -4210,7 +4165,7 @@ int HPWH::checkInputs() if (0 > heatSources[i].externalInletHeight || heatSources[i].externalInletHeight > getNumNodes() - 1) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("External heat sources need an external inlet height within the bounds " "from from 0 to numNodes-1. \n"); @@ -4223,7 +4178,7 @@ int HPWH::checkInputs() if (heatSources[i].secondaryHeatExchanger.extraPumpPower_W != 0 || heatSources[i].secondaryHeatExchanger.extraPumpPower_W) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Heatsource %d is not an external heat source but has an external " "secondary heat exchanger. \n", @@ -4241,7 +4196,7 @@ int HPWH::checkInputs() // If useBtwxtGrid is true that the perfMap is empty if (heatSources[i].perfMap.size() != 0) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Using the grid lookups but a regression based perforamnce map is given " "\n"); @@ -4254,7 +4209,7 @@ int HPWH::checkInputs() heatSources[i].perfGridValues[1].size() && heatSources[i].perfGridValues[0].size() != 0) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("When using grid lookups for perfmance the vectors in perfGridValues must " "be the same length. \n"); @@ -4271,7 +4226,7 @@ int HPWH::checkInputs() } if (expLength != heatSources[i].perfGridValues[0].size()) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("When using grid lookups for perfmance the vectors in perfGridValues must " "be the same length. \n"); @@ -4284,7 +4239,7 @@ int HPWH::checkInputs() // Check that perfmap only has 1 point if config_external and multipass if (heatSources[i].isExternalMultipass() && heatSources[i].perfMap.size() != 1) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("External multipass heat sources must have a perfMap of only one point " "with regression equations. \n"); @@ -4301,7 +4256,7 @@ int HPWH::checkInputs() getSizingFractions(aquaF, useF); if (aquaF < (1. - useF)) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("The relationship between the on logic and off logic is not supported. The off " "logic is beneath the on logic."); @@ -4315,7 +4270,7 @@ int HPWH::checkInputs() double tempSetpoint = setpoint_C; if (!isNewSetpointPossible(tempSetpoint, maxTemp, why)) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Cannot set new setpoint. %s", why.c_str()); } @@ -4325,7 +4280,7 @@ int HPWH::checkInputs() // Check if the UA is out of bounds if (tankUA_kJperHrC < 0.0) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("The tankUA_kJperHrC is less than 0 for a HPWH, it must be greater than 0, " "tankUA_kJperHrC is: %f \n", @@ -4337,7 +4292,7 @@ int HPWH::checkInputs() // Check single-node heat-exchange effectiveness validity if (heatExchangerEffectiveness > 1.) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Heat-exchanger effectiveness cannot exceed 1.\n"); } @@ -4401,7 +4356,7 @@ bool HPWH::isEnergyBalanced(const double drawVol_L, double fracEnergyDiff = fabs(qBal_kJ) / std::max(prevHeatContent_kJ, 1.); if (fracEnergyDiff > fracEnergyTolerance) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Energy-balance error: %f kJ, %f %% \n", qBal_kJ, 100. * fracEnergyDiff); } @@ -4423,7 +4378,7 @@ int HPWH::HPWHinit_file(string configFile) inputFILE.open(configFile.c_str()); if (!inputFILE.is_open()) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Input file failed to open. \n"); } @@ -4468,7 +4423,7 @@ int HPWH::HPWHinit_file(string configFile) ; // do nothing, lol else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Incorrect units specification for %s. \n", token.c_str()); } @@ -4481,7 +4436,7 @@ int HPWH::HPWHinit_file(string configFile) line_ss >> tempDouble >> units; if (units != "kJperHrC") { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Incorrect units specification for %s. \n", token.c_str()); } @@ -4502,7 +4457,7 @@ int HPWH::HPWHinit_file(string configFile) } else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Improper value for %s\n", token.c_str()); } @@ -4522,7 +4477,7 @@ int HPWH::HPWHinit_file(string configFile) } else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Improper value for %s\n", token.c_str()); } @@ -4534,7 +4489,7 @@ int HPWH::HPWHinit_file(string configFile) line_ss >> tempDouble; if (tempDouble < 0 || tempDouble > 1) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Out of bounds value for %s. Should be between 0 and 1. \n", token.c_str()); } @@ -4551,7 +4506,7 @@ int HPWH::HPWHinit_file(string configFile) ; // do nothing, lol else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Incorrect units specification for %s. \n", token.c_str()); } @@ -4569,7 +4524,7 @@ int HPWH::HPWHinit_file(string configFile) setpointFixed = false; else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Improper value for %s\n", token.c_str()); } @@ -4585,7 +4540,7 @@ int HPWH::HPWHinit_file(string configFile) ; else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Incorrect units specification for %s. \n", token.c_str()); } @@ -4604,7 +4559,7 @@ int HPWH::HPWHinit_file(string configFile) hasHeatExchanger = false; else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Improper value for %s\n", token.c_str()); } @@ -4622,23 +4577,23 @@ int HPWH::HPWHinit_file(string configFile) line_ss >> token; if (token == "silent") { - hpwhVerbosity = VRB_silent; + verbosity = VRB_silent; } else if (token == "reluctant") { - hpwhVerbosity = VRB_reluctant; + verbosity = VRB_reluctant; } else if (token == "typical") { - hpwhVerbosity = VRB_typical; + verbosity = VRB_typical; } else if (token == "emetic") { - hpwhVerbosity = VRB_emetic; + verbosity = VRB_emetic; } else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Incorrect verbosity on input. \n"); } @@ -4673,7 +4628,7 @@ int HPWH::HPWHinit_file(string configFile) heatSources[heatsource].isVIP = false; else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Improper value for %s for heat source %d\n", token.c_str(), @@ -4691,7 +4646,7 @@ int HPWH::HPWHinit_file(string configFile) heatSources[heatsource].isOn = false; else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Improper value for %s for heat source %d\n", token.c_str(), @@ -4709,7 +4664,7 @@ int HPWH::HPWHinit_file(string configFile) ; // do nothing, lol else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Incorrect units specification for %s. \n", token.c_str()); } @@ -4726,7 +4681,7 @@ int HPWH::HPWHinit_file(string configFile) ; // do nothing, lol else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Incorrect units specification for %s. \n", token.c_str()); } @@ -4748,7 +4703,7 @@ int HPWH::HPWHinit_file(string configFile) int nodeNum = std::stoi(nextToken); if (nodeNum > LOGIC_NODE_SIZE + 1 || nodeNum < 0) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Node number for heatsource %d %s must be between 0 and %d. " "\n", @@ -4780,7 +4735,7 @@ int HPWH::HPWHinit_file(string configFile) } if (nodeNums.size() != weights.size()) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Number of weights for heatsource %d %s (%d) does not match number " "of nodes for %s (%d). \n", @@ -4794,7 +4749,7 @@ int HPWH::HPWHinit_file(string configFile) } if (nextToken != "absolute" && nextToken != "relative") { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Improper definition, \"%s\", for heat source %d %s. Should be " "\"relative\" or \"absoute\".\n", @@ -4814,7 +4769,7 @@ int HPWH::HPWHinit_file(string configFile) compare = std::greater(); else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Improper comparison, \"%s\", for heat source %d %s. Should be " "\"<\" or \">\".\n", @@ -4839,7 +4794,7 @@ int HPWH::HPWHinit_file(string configFile) ; // do nothing, lol else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Incorrect units specification for %s from heatsource %d. \n", token.c_str(), @@ -4886,7 +4841,7 @@ int HPWH::HPWHinit_file(string configFile) compare = std::greater(); else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Improper comparison, \"%s\", for heat source %d %s. Should be " "\"<\" or \">\".\n", @@ -4918,7 +4873,7 @@ int HPWH::HPWHinit_file(string configFile) ; // do nothing, lol else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Incorrect units specification for %s from heatsource %d. \n", token.c_str(), @@ -4973,7 +4928,7 @@ int HPWH::HPWHinit_file(string configFile) } else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Improper %s for heat source %d\n", token.c_str(), heatsource); } @@ -4989,7 +4944,7 @@ int HPWH::HPWHinit_file(string configFile) ; // do nothing, lol else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Incorrect units specification for %s from heatsource %d. \n", token.c_str(), @@ -5026,7 +4981,7 @@ int HPWH::HPWHinit_file(string configFile) } else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Improper %s for heat source %d\n", token.c_str(), heatsource); } @@ -5047,7 +5002,7 @@ int HPWH::HPWHinit_file(string configFile) } else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Improper %s for heat source %d\n", token.c_str(), heatsource); } @@ -5071,7 +5026,7 @@ int HPWH::HPWHinit_file(string configFile) } else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Improper %s for heat source %d\n", token.c_str(), heatsource); } @@ -5091,7 +5046,7 @@ int HPWH::HPWHinit_file(string configFile) } else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Improper %s for heat source %d\n", token.c_str(), heatsource); } @@ -5108,7 +5063,7 @@ int HPWH::HPWHinit_file(string configFile) } else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Improper %s for heat source %d\n", token.c_str(), heatsource); } @@ -5124,7 +5079,7 @@ int HPWH::HPWHinit_file(string configFile) } else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Improper %s for heat source %d\n", token.c_str(), heatsource); } @@ -5156,7 +5111,7 @@ int HPWH::HPWHinit_file(string configFile) { if (maxTemps == 0) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("%s specified for heatsource %d before definition of nTemps. \n", token.c_str(), @@ -5166,7 +5121,7 @@ int HPWH::HPWHinit_file(string configFile) } else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Incorrect specification for %s from heatsource %d. nTemps, %d, is " "less than %d. \n", @@ -5187,7 +5142,7 @@ int HPWH::HPWHinit_file(string configFile) tempDouble = C_TO_F(tempDouble); else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Incorrect units specification for %s from heatsource %d. \n", token.c_str(), @@ -5224,7 +5179,7 @@ int HPWH::HPWHinit_file(string configFile) { if (maxTemps == 0) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("%s specified for heatsource %d before definition of nTemps. \n", token.c_str(), @@ -5234,7 +5189,7 @@ int HPWH::HPWHinit_file(string configFile) } else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Incorrect specification for %s from heatsource %d. nTemps, %d, is " "less than %d. \n", @@ -5267,7 +5222,7 @@ int HPWH::HPWHinit_file(string configFile) ; // do nothing, lol else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Incorrect units specification for %s from heatsource %d. \n", token.c_str(), @@ -5294,7 +5249,7 @@ int HPWH::HPWHinit_file(string configFile) } else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Improper specifier (%s) for heat source %d\n", token.c_str(), heatsource); } @@ -5341,3 +5296,51 @@ int HPWH::HPWHinit_file(string configFile) return 0; } #endif + +void HPWH::setVerbosity(VERBOSITY verbosity_in) { verbosity = verbosity_in; } + +// static +void HPWH::setMessageCallback(void (*callbackFunc)(const string message, void* contextPtr), + void* contextPtr) +{ + messageCallback = callbackFunc; + messageCallbackContextPtr = contextPtr; +} + +void HPWH::sayMessage(const string message) +{ + if (messageCallback != NULL) + { + (*messageCallback)(message, messageCallbackContextPtr); + } + else + { + std::cout << message; + } +} +void HPWH::msg(const char* fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + msgV(fmt, ap); +} +void HPWH::msgV(const char* fmt, va_list ap /*=NULL*/) +{ + char outputString[MAXOUTSTRING]; + + const char* p; + if (ap) + { +#if defined(_MSC_VER) + vsprintf_s(outputString, fmt, ap); +#else + vsnprintf(outputString, MAXOUTSTRING, fmt, ap); +#endif + p = outputString; + } + else + { + p = fmt; + } + sayMessage(p); +} // HPWH::msgV diff --git a/src/HPWH.hh b/src/HPWH.hh index ccdae473..95c21247 100644 --- a/src/HPWH.hh +++ b/src/HPWH.hh @@ -244,17 +244,6 @@ class HPWH MODELS_AquaThermAire = 400 // heat exchanger model }; - /// specifies the modes for writing output - /// the specified values are used for >= comparisons, so the numerical order is relevant - enum VERBOSITY - { - VRB_silent = 0, /**< print no outputs */ - VRB_reluctant = 10, /**< print only outputs for fatal errors */ - VRB_minuteOut = 15, /**< print minutely output */ - VRB_typical = 20, /**< print some basic debugging info */ - VRB_emetic = 30 /**< print all the things */ - }; - enum UNITS { UNITS_C, /**< celsius */ @@ -570,10 +559,6 @@ class HPWH void setInletT(double newInletT_C) { member_inletT_C = newInletT_C; }; void setMinutesPerStep(double newMinutesPerStep); - void setVerbosity(VERBOSITY hpwhVrb); - /**< sets the verbosity to the specified level */ - void setMessageCallback(void (*callbackFunc)(const std::string message, void* pContext), - void* pContext); /**< sets the function to be used for message passing */ void printHeatSourceInfo(); /**< this prints out the heat source info, nicely formatted @@ -670,11 +655,11 @@ class HPWH double getTankSize(UNITS units = UNITS_L) const; /**< returns the tank volume in L or GAL */ - int setDoInversionMixing(bool doInvMix); + int setDoInversionMixing(bool doInversionMixing_in); /**< This is a simple setter for the logical for running the inversion mixing method, default is * true */ - int setDoConduction(bool doCondu); + int setDoConduction(bool doConduction_in); /**< This is a simple setter for doing internal conduction and nodal heatloss, default is true*/ int setUA(double UA, UNITS units = UNITS_kJperHrC); @@ -992,13 +977,6 @@ class HPWH void calcAndSetSoCFraction(); - void sayMessage(const std::string message) const; - /**< if the messagePriority is >= the hpwh verbosity, - either pass your message out to the callback function or print it to cout - otherwise do nothing */ - void msg(const char* fmt, ...) const; - void msgV(const char* fmt, va_list ap = NULL) const; - bool simHasFailed; /**< did an internal error cause the simulation to fail? */ @@ -1014,14 +992,6 @@ class HPWH bool canScale; /**< can the HPWH scale capactiy and COP or not */ - VERBOSITY hpwhVerbosity; - /**< an enum to let the sim know how much output to say */ - - void (*messageCallback)(const std::string message, void* contextPtr); - /**< function pointer to indicate an external message processing function */ - void* messageCallbackContextPtr; - /**< caller context pointer for external message processing */ - MODELS hpwhModel; /**< The hpwh should know which preset initialized it, or if it was from a fileget */ @@ -1170,6 +1140,40 @@ class HPWH /// line (derived from heatExchangerEffectiveness). double nodeHeatExchangerEffectiveness; + public: + /// specifies the modes for writing output + /// the specified values are used for >= comparisons, so the numerical order is relevant + enum VERBOSITY + { + VRB_silent = 0, /**< print no outputs */ + VRB_reluctant = 10, /**< print only outputs for fatal errors */ + VRB_minuteOut = 15, /**< print minutely output */ + VRB_typical = 20, /**< print some basic debugging info */ + VRB_emetic = 30 /**< print all the things */ + }; + + VERBOSITY verbosity; + /**< an enum to let the sim know how much output to say */ + + void setVerbosity(VERBOSITY verbosity_in); + + static void (*messageCallback)(const std::string message, void* contextPtr); + /**< function pointer to indicate an external message processing function */ + static void* messageCallbackContextPtr; + /**< caller context pointer for external message processing */ + + static void sayMessage(const std::string message); + /**< if the messagePriority is >= the hpwh verbosity, + either pass your message out to the callback function or print it to cout + otherwise do nothing */ + static void msg(const char* fmt, ...); + static void msgV(const char* fmt, va_list ap = NULL); + + /**< sets the verbosity to the specified level */ + static void setMessageCallback(void (*callbackFunc)(const std::string message, void* pContext), + void* pContext); + class Simulator; + }; // end of HPWH class class HPWH::HeatSource @@ -1492,6 +1496,77 @@ class HPWH::HeatSource }; // end of HeatSource class +class HPWH::Simulator +{ + public: + friend class HPWH; + + VERBOSITY verbosity; + void setVerbosity(VERBOSITY verbosity_in) { verbosity = verbosity_in; } + + Simulator(); + /**< constructor assigns a pointer to the hpwh that owns this heat source */ + Simulator(const Simulator& simulator_in); /// copy constructor + Simulator& operator=(const Simulator& simulator_in); /// assignment operator + + struct ControlInfo + { + long outputCode; + long timeToRun_min; + double setpointT_C; + std::unique_ptr initialTankT_C; + bool doConduction; + bool doInversionMixing; + std::unique_ptr inletH; + std::unique_ptr tankSize_gal; + std::unique_ptr tot_limit; + bool useSoC; + std::string temperatureUnits; + bool recordMinuteData; + bool recordYearData; + bool modifyDraw; + }; + bool openFileText(std::ifstream& fileStream, const std::string& sFilename); + void closeFileText(std::ifstream& fileStream); + + bool openResourceText(std::istream& resourceStream, const std::string& sFilename); + + bool readControlInfo(std::istream& controlStream, ControlInfo& controlInfo); + + typedef std::vector Schedule; + bool readSchedules(const bool isResource, + const std::string& testName, + const ControlInfo& controlInfo, + std::vector& allSchedules); + bool readSchedule(Schedule& schedule, + const std::string& scheduleName, + std::istream& scheduleStream, + long testLength_min); + + struct TestDesc + { + std::string presetOrFile; + std::string modelName; + std::string testName; + }; + + struct TestResults + { + bool passed; + double totalEnergyConsumed_kJ; + double totalVolumeRemoved_L; + }; + + bool run(HPWH& hpwh, + const TestDesc& testDesc, + const std::string& outputDirectory, + const ControlInfo& controlInfo, + std::vector& allSchedules, + double airT_C, + const bool doTempDepress, + TestResults& testResults); +}; + constexpr double BTUperKWH = 3412.14163312794; // https://www.rapidtables.com/convert/energy/kWh_to_BTU.html constexpr double FperC = 9. / 5.; // degF / degC @@ -1563,4 +1638,11 @@ void calcThermalDist(std::vector& thermalDist, const std::vector& nodeTemp_C, const double setpointT_C); +inline bool getBool(const std::string sValue) +{ + if ((sValue == "F") || (sValue == "false") || (sValue == "False") || (stoi(sValue) == 0)) + return false; + return true; +} + #endif diff --git a/src/HPWHHeatSources.cc b/src/HPWHHeatSources.cc index e193e7f7..7d741b7a 100644 --- a/src/HPWHHeatSources.cc +++ b/src/HPWHHeatSources.cc @@ -61,7 +61,7 @@ HPWH::HeatSource& HPWH::HeatSource::operator=(const HeatSource& hSource) hSource.followedByHeatSource != NULL) { hpwh->simHasFailed = true; - if (hpwh->hpwhVerbosity >= VRB_reluctant) + if (hpwh->verbosity >= VRB_reluctant) { hpwh->msg( "HeatSources cannot be copied if they contain pointers to other HeatSources\n"); @@ -160,7 +160,7 @@ bool HPWH::HeatSource::shouldLockOut(double heatSourceAmbientT_C) const if (isEngaged() == true && heatSourceAmbientT_C < minT - hysteresis_dC) { lock = true; - if (hpwh->hpwhVerbosity >= HPWH::VRB_emetic) + if (hpwh->verbosity >= HPWH::VRB_emetic) { hpwh->msg("\tlock-out: running below minT\tambient: %.2f\tminT: %.2f", heatSourceAmbientT_C, @@ -171,7 +171,7 @@ bool HPWH::HeatSource::shouldLockOut(double heatSourceAmbientT_C) const else if (isEngaged() == false && heatSourceAmbientT_C < minT) { lock = true; - if (hpwh->hpwhVerbosity >= HPWH::VRB_emetic) + if (hpwh->verbosity >= HPWH::VRB_emetic) { hpwh->msg("\tlock-out: already below minT\tambient: %.2f\tminT: %.2f", heatSourceAmbientT_C, @@ -184,7 +184,7 @@ bool HPWH::HeatSource::shouldLockOut(double heatSourceAmbientT_C) const if (isEngaged() == true && heatSourceAmbientT_C > maxT + hysteresis_dC) { lock = true; - if (hpwh->hpwhVerbosity >= HPWH::VRB_emetic) + if (hpwh->verbosity >= HPWH::VRB_emetic) { hpwh->msg("\tlock-out: running above maxT\tambient: %.2f\tmaxT: %.2f", heatSourceAmbientT_C, @@ -195,7 +195,7 @@ bool HPWH::HeatSource::shouldLockOut(double heatSourceAmbientT_C) const else if (isEngaged() == false && heatSourceAmbientT_C > maxT) { lock = true; - if (hpwh->hpwhVerbosity >= HPWH::VRB_emetic) + if (hpwh->verbosity >= HPWH::VRB_emetic) { hpwh->msg("\tlock-out: already above maxT\tambient: %.2f\tmaxT: %.2f", heatSourceAmbientT_C, @@ -206,19 +206,19 @@ bool HPWH::HeatSource::shouldLockOut(double heatSourceAmbientT_C) const if (maxedOut()) { lock = true; - if (hpwh->hpwhVerbosity >= HPWH::VRB_emetic) + if (hpwh->verbosity >= HPWH::VRB_emetic) { hpwh->msg("\tlock-out: condenser water temperature above max: %.2f", maxSetpoint_C); } } // if (lock == true && backupHeatSource == NULL) { - // if (hpwh->hpwhVerbosity >= HPWH::VRB_emetic) { + // if (hpwh->verbosity >= HPWH::VRB_emetic) { // hpwh->msg("\nWARNING: lock-out triggered, but no backupHeatSource defined. // Simulation will continue without lock-out"); // } // lock = false; // } - if (hpwh->hpwhVerbosity >= VRB_typical) + if (hpwh->verbosity >= VRB_typical) { hpwh->msg("\n"); } @@ -248,15 +248,13 @@ bool HPWH::HeatSource::shouldUnlock(double heatSourceAmbientT_C) const heatSourceAmbientT_C < maxT - hysteresis_dC) { unlock = true; - if (hpwh->hpwhVerbosity >= HPWH::VRB_emetic && - heatSourceAmbientT_C > minT + hysteresis_dC) + if (hpwh->verbosity >= HPWH::VRB_emetic && heatSourceAmbientT_C > minT + hysteresis_dC) { hpwh->msg("\tunlock: running above minT\tambient: %.2f\tminT: %.2f", heatSourceAmbientT_C, minT); } - if (hpwh->hpwhVerbosity >= HPWH::VRB_emetic && - heatSourceAmbientT_C < maxT - hysteresis_dC) + if (hpwh->verbosity >= HPWH::VRB_emetic && heatSourceAmbientT_C < maxT - hysteresis_dC) { hpwh->msg("\tunlock: running below maxT\tambient: %.2f\tmaxT: %.2f", heatSourceAmbientT_C, @@ -267,20 +265,20 @@ bool HPWH::HeatSource::shouldUnlock(double heatSourceAmbientT_C) const else if (isEngaged() == false && heatSourceAmbientT_C > minT && heatSourceAmbientT_C < maxT) { unlock = true; - if (hpwh->hpwhVerbosity >= HPWH::VRB_emetic && heatSourceAmbientT_C > minT) + if (hpwh->verbosity >= HPWH::VRB_emetic && heatSourceAmbientT_C > minT) { hpwh->msg("\tunlock: already above minT\tambient: %.2f\tminT: %.2f", heatSourceAmbientT_C, minT); } - if (hpwh->hpwhVerbosity >= HPWH::VRB_emetic && heatSourceAmbientT_C < maxT) + if (hpwh->verbosity >= HPWH::VRB_emetic && heatSourceAmbientT_C < maxT) { hpwh->msg("\tunlock: already below maxT\tambient: %.2f\tmaxT: %.2f", heatSourceAmbientT_C, maxT); } } - if (hpwh->hpwhVerbosity >= VRB_typical) + if (hpwh->verbosity >= VRB_typical) { hpwh->msg("\n"); } @@ -325,7 +323,7 @@ bool HPWH::HeatSource::shouldHeat() const for (int i = 0; i < (int)turnOnLogicSet.size(); i++) { - if (hpwh->hpwhVerbosity >= VRB_emetic) + if (hpwh->verbosity >= VRB_emetic) { hpwh->msg("\tshouldHeat logic: %s ", turnOnLogicSet[i]->description.c_str()); } @@ -355,11 +353,11 @@ bool HPWH::HeatSource::shouldHeat() const if (shouldEngage) { // debugging message handling - if (hpwh->hpwhVerbosity >= VRB_typical) + if (hpwh->verbosity >= VRB_typical) { hpwh->msg("engages!\n"); } - if (hpwh->hpwhVerbosity >= VRB_emetic) + if (hpwh->verbosity >= VRB_emetic) { hpwh->msg("average: %.2lf \t setpoint: %.2lf \t decisionPoint: %.2lf \t " "comparison: %2.1f\n", @@ -371,7 +369,7 @@ bool HPWH::HeatSource::shouldHeat() const break; } - if (hpwh->hpwhVerbosity >= VRB_emetic) + if (hpwh->verbosity >= VRB_emetic) { hpwh->msg("returns: %d \t", shouldEngage); } @@ -381,13 +379,13 @@ bool HPWH::HeatSource::shouldHeat() const if (shouldEngage == true && shutsOff() == true) { shouldEngage = false; - if (hpwh->hpwhVerbosity >= VRB_typical) + if (hpwh->verbosity >= VRB_typical) { hpwh->msg("but is denied by shutsOff"); } } - if (hpwh->hpwhVerbosity >= VRB_typical) + if (hpwh->verbosity >= VRB_typical) { hpwh->msg("\n"); } @@ -401,7 +399,7 @@ bool HPWH::HeatSource::shutsOff() const if (hpwh->tankTemps_C[0] >= hpwh->setpoint_C) { shutOff = true; - if (hpwh->hpwhVerbosity >= VRB_emetic) + if (hpwh->verbosity >= VRB_emetic) { hpwh->msg("shutsOff bottom node hot: %.2d C \n returns true", hpwh->tankTemps_C[0]); } @@ -410,7 +408,7 @@ bool HPWH::HeatSource::shutsOff() const for (int i = 0; i < (int)shutOffLogicSet.size(); i++) { - if (hpwh->hpwhVerbosity >= VRB_emetic) + if (hpwh->verbosity >= VRB_emetic) { hpwh->msg("\tshutsOff logic: %s ", shutOffLogicSet[i]->description.c_str()); } @@ -423,14 +421,14 @@ bool HPWH::HeatSource::shutsOff() const shutOff = true; // debugging message handling - if (hpwh->hpwhVerbosity >= VRB_typical) + if (hpwh->verbosity >= VRB_typical) { hpwh->msg("shuts down %s\n", shutOffLogicSet[i]->description.c_str()); } } } - if (hpwh->hpwhVerbosity >= VRB_emetic) + if (hpwh->verbosity >= VRB_emetic) { hpwh->msg("returns: %d \n", shutOff); } @@ -460,7 +458,7 @@ double HPWH::HeatSource::fractToMeetComparisonExternal() const for (int i = 0; i < (int)shutOffLogicSet.size(); i++) { - if (hpwh->hpwhVerbosity >= VRB_emetic) + if (hpwh->verbosity >= VRB_emetic) { hpwh->msg("\tshutsOff logic: %s ", shutOffLogicSet[i]->description.c_str()); } @@ -498,7 +496,7 @@ void HPWH::HeatSource::addHeat(double externalT_C, double minutesToRun) getCapacity(externalT_C, getTankTemp(), input_BTUperHr, cap_BTUperHr, cop); } // some outputs for debugging - if (hpwh->hpwhVerbosity >= VRB_typical) + if (hpwh->verbosity >= VRB_typical) { hpwh->msg("capacity_kWh %.2lf \t\t cap_BTUperHr %.2lf \n", BTU_TO_KWH(cap_BTUperHr) * (minutesToRun) / min_per_hr, @@ -534,7 +532,7 @@ void HPWH::HeatSource::addHeat(double externalT_C, double minutesToRun) runtime_min = (1. - (leftoverCap_kJ / cap_kJ)) * minutesToRun; #if 1 // error check, 1-22-2017; updated 12-6-2023 if (runtime_min < -TOL_MINVALUE) - if (hpwh->hpwhVerbosity >= VRB_reluctant) + if (hpwh->verbosity >= VRB_reluctant) hpwh->msg("Internal error: Negative runtime = %0.3f min\n", runtime_min); #endif } @@ -577,7 +575,7 @@ double HPWH::HeatSource::getTankTemp() const // Note that condensity is normalized. ++j; } - if (hpwh->hpwhVerbosity >= VRB_typical) + if (hpwh->verbosity >= VRB_typical) { hpwh->msg("tank temp %.2lf \n", tankTemp_C); } @@ -670,7 +668,7 @@ void HPWH::HeatSource::getCapacity(double externalT_C, inputPower_T2_Watts += perfMap[i_next].inputPower_coeffs[2] * condenserTemp_F * condenserTemp_F; - if (hpwh->hpwhVerbosity >= VRB_emetic) + if (hpwh->verbosity >= VRB_emetic) { hpwh->msg("inputPower_T1_constant_W linear_WperF quadratic_WperF2 \t%.2lf " "%.2lf %.2lf \n", @@ -734,7 +732,7 @@ void HPWH::HeatSource::getCapacity(double externalT_C, cap_BTUperHr = cop * input_BTUperHr; - if (hpwh->hpwhVerbosity >= VRB_emetic) + if (hpwh->verbosity >= VRB_emetic) { hpwh->msg("externalT_F: %.2lf, Tout_F: %.2lf, condenserTemp_F: %.2lf\n", externalT_F, @@ -755,7 +753,7 @@ void HPWH::HeatSource::getCapacity(double externalT_C, double airflow = 375 * airflowFreedom; cop *= 0.00056 * airflow + 0.79; } - if (hpwh->hpwhVerbosity >= VRB_typical) + if (hpwh->verbosity >= VRB_typical) { hpwh->msg("cop: %.2lf \tinput_BTUperHr: %.2lf \tcap_BTUperHr: %.2lf \n", cop, @@ -832,7 +830,7 @@ void HPWH::HeatSource::getCapacityMP(double externalT_C, { input_BTUperHr += KW_TO_BTUperH(resDefrost.inputPwr_kW); } - if (hpwh->hpwhVerbosity >= VRB_emetic) + if (hpwh->verbosity >= VRB_emetic) { hpwh->msg("externalT_F: %.2lf, condenserTemp_F: %.2lf\n", externalT_F, condenserTemp_F); hpwh->msg("input_BTUperHr: %.2lf , cop: %.2lf, cap_BTUperHr: %.2lf \n", @@ -960,7 +958,7 @@ double HPWH::HeatSource::addHeatExternal(double externalT_C, do { - if (hpwh->hpwhVerbosity >= VRB_emetic) + if (hpwh->verbosity >= VRB_emetic) { hpwh->msg("bottom tank temp: %.2lf \n", hpwh->tankTemps_C[0]); } @@ -994,14 +992,14 @@ double HPWH::HeatSource::addHeatExternal(double externalT_C, capTemp_BTUperHr, copTemp); heatingCapacity_kJ = BTU_TO_KJ(capTemp_BTUperHr * (minutesToRun / min_per_hr)); - if (hpwh->hpwhVerbosity >= VRB_emetic) + if (hpwh->verbosity >= VRB_emetic) { hpwh->msg("\theatingCapacity_kJ stepwise: %.2lf \n", heatingCapacity_kJ); } // adjust capacity for how much time is left in this step heatingCapacity_kJ *= (timeRemaining_min / minutesToRun); - if (hpwh->hpwhVerbosity >= VRB_emetic) + if (hpwh->verbosity >= VRB_emetic) { hpwh->msg("\theatingCapacity_kJ remaining this node: %.2lf \n", heatingCapacity_kJ); } @@ -1026,7 +1024,7 @@ double HPWH::HeatSource::addHeatExternal(double externalT_C, nodeFrac = heatingCapacity_kJ / nodeHeat_kJperNode; } - if (hpwh->hpwhVerbosity >= VRB_emetic) + if (hpwh->verbosity >= VRB_emetic) { hpwh->msg( "nodeHeat_kJperNode: %.2lf nodeFrac: %.2lf \n\n", nodeHeat_kJperNode, nodeFrac); @@ -1105,7 +1103,7 @@ double HPWH::HeatSource::addHeatExternal(double externalT_C, hpwh->condenserOutlet_C /= timeRun; } - if (hpwh->hpwhVerbosity >= VRB_emetic) + if (hpwh->verbosity >= VRB_emetic) { hpwh->msg("final remaining time: %.2lf \n", timeRemaining_min); } diff --git a/src/HPWHHeatingLogics.cc b/src/HPWHHeatingLogics.cc index e2f1838d..f21b1da1 100644 --- a/src/HPWHHeatingLogics.cc +++ b/src/HPWHHeatingLogics.cc @@ -121,7 +121,7 @@ const double HPWH::SoCBasedHeatingLogic::getFractToMeetComparisonExternal() (hpwh->tankTemps_C[calcNode] - hpwh->tankTemps_C[calcNode - 1]); fractNextNode += HPWH::TOL_MINVALUE; - if (hpwh->hpwhVerbosity >= VRB_emetic) + if (hpwh->verbosity >= VRB_emetic) { double smallestSoCChangeWhenHeatingNextNode = 1. / maxSoC * diff --git a/src/HPWHSimulator.cc b/src/HPWHSimulator.cc new file mode 100644 index 00000000..f7f9183b --- /dev/null +++ b/src/HPWHSimulator.cc @@ -0,0 +1,639 @@ +/* + * Implementation of class HPWH::Simulator + */ + +#include +#include +#include +#include + +#include "HPWH.hh" + +HPWH::Simulator::Simulator() : verbosity(VRB_typical) {} + +HPWH::Simulator::Simulator(const Simulator& simulator) { *this = simulator; } + +HPWH::Simulator& HPWH::Simulator::operator=(const Simulator& simulator_in) +{ + if (this == &simulator_in) + { + return *this; + } + return *this; +} + +bool HPWH::Simulator::openFileText(std::ifstream& fileStream, const std::string& sFilename) +{ + // std::string fileToOpen = testDirectory + "/" + "testInfo.txt"; + // Read the test control file + fileStream.open(sFilename.c_str()); + if (!fileStream.is_open()) + { + if (verbosity >= VRB_reluctant) + { + msg("Could not open control file %s\n", sFilename.c_str()); + } + return false; + } + return true; +} + +bool HPWH::Simulator::openResourceText(std::istream& resourceStream, const std::string& sFilename) +{ + std::ifstream* controlFile = static_cast(&resourceStream); + // std::string fileToOpen = testDirectory + "/" + "testInfo.txt"; + // Read the test control file + controlFile->open(sFilename.c_str()); + if (!controlFile->is_open()) + { + if (verbosity >= VRB_reluctant) + { + msg("Could not open control file %s\n", sFilename.c_str()); + } + return false; + } + return true; +} + +//----------------------------------------------------------------------------- +/// @brief Reads the control info for a test from file "testInfo.txt" +/// @param[in] testDirectory path to directory containing test files +/// @param[out] controlInfo data structure containing control info +/// @return true if successful, false otherwise +//----------------------------------------------------------------------------- +bool HPWH::Simulator::readControlInfo(std::istream& controlStream, ControlInfo& controlInfo) +{ + controlInfo.outputCode = 0; + controlInfo.timeToRun_min = 0; + controlInfo.setpointT_C = 0.; + controlInfo.initialTankT_C = nullptr; + controlInfo.doConduction = true; + controlInfo.doInversionMixing = true; + controlInfo.inletH = nullptr; + controlInfo.tankSize_gal = nullptr; + controlInfo.tot_limit = nullptr; + controlInfo.useSoC = false; + controlInfo.temperatureUnits = "C"; + controlInfo.recordMinuteData = false; + controlInfo.recordYearData = false; + controlInfo.modifyDraw = false; + + std::string token; + std::string sValue; + while (controlStream >> token >> sValue) + { + if (token == "setpoint") + { // If a setpoint was specified then override the default + controlInfo.setpointT_C = std::stod(sValue); + } + else if (token == "length_of_test") + { + controlInfo.timeToRun_min = std::stoi(sValue); + } + else if (token == "doInversionMixing") + { + controlInfo.doInversionMixing = getBool(sValue); + } + else if (token == "doConduction") + { + controlInfo.doConduction = getBool(sValue); + } + else if (token == "inletH") + { + controlInfo.inletH = std::unique_ptr(new double(std::stod(sValue))); + } + else if (token == "tanksize") + { + controlInfo.tankSize_gal = std::unique_ptr(new double(std::stod(sValue))); + } + else if (token == "tot_limit") + { + controlInfo.tot_limit = std::unique_ptr(new double(std::stod(sValue))); + } + else if (token == "useSoC") + { + controlInfo.useSoC = getBool(sValue); + } + else if (token == "initialTankT_C") + { // Initialize at this temperature instead of setpoint + controlInfo.initialTankT_C = std::unique_ptr(new double(std::stod(sValue))); + } + else if (token == "temperature_units") + { // Initialize at this temperature instead of setpoint + controlInfo.temperatureUnits = sValue; + } + else + { + if (verbosity >= VRB_reluctant) + { + msg("Unrecognized key in %s\n", token.c_str()); + } + } + } + + if (controlInfo.temperatureUnits == "F") + { + controlInfo.setpointT_C = F_TO_C(controlInfo.setpointT_C); + if (controlInfo.initialTankT_C != nullptr) + *controlInfo.initialTankT_C = F_TO_C(*controlInfo.initialTankT_C); + } + + if (controlInfo.timeToRun_min == 0) + { + if (verbosity >= VRB_reluctant) + { + msg("Error: record length_of_test not found in testInfo.txt file\n"); + } + return false; + } + + return true; +} + +//----------------------------------------------------------------------------- +/// @brief Reads a named schedule +/// @param[out] schedule schedule values +/// @param[in] scheduleName name of schedule to read +/// @param[in] testLength_min length of test (min) +/// @return true if successful, false otherwise +//----------------------------------------------------------------------------- +bool HPWH::Simulator::readSchedule(Schedule& schedule, + const std::string& scheduleName, + std::istream& scheduleStream, + long testLength_min) +{ + int minuteHrTmp; + bool hourInput; + std::string line, snippet, s, minORhr; + double valTmp; + + scheduleStream >> snippet >> valTmp; + + if (snippet != "default") + { + if (verbosity >= VRB_reluctant) + { + msg("First line of %s must specify default\n", scheduleName.c_str()); + } + return false; + } + + // Fill with the default value + schedule.assign(testLength_min, valTmp); + + // Burn the first two lines + std::getline(scheduleStream, line); + std::getline(scheduleStream, line); + + std::stringstream ss(line); // Will parse with a stringstream + // Grab the first token, which is the minute or hour marker + ss >> minORhr; + if (minORhr.empty()) + { // If nothing left in the file + return true; + } + hourInput = tolower(minORhr.at(0)) == 'h'; + char c; // for commas + while (scheduleStream >> minuteHrTmp >> c >> valTmp) + { + if (minuteHrTmp >= static_cast(schedule.size())) + { + if (verbosity >= VRB_reluctant) + { + msg("Input file for %s has more minutes than test definition\n", + scheduleName.c_str()); + } + return false; + } + // update the value + if (!hourInput) + { + schedule[minuteHrTmp] = valTmp; + } + else if (hourInput) + { + for (int j = minuteHrTmp * 60; j < (minuteHrTmp + 1) * 60; j++) + { + schedule[j] = valTmp; + } + } + } + + return true; +} + +//----------------------------------------------------------------------------- +/// @brief Reads the schedules for a test +/// @param[in] testDirectory path to directory containing test files +/// @param[in] controlInfo data structure containing control info +/// @param[out] allSchedules collection of test schedules read +/// @return true if successful, false otherwise +//----------------------------------------------------------------------------- +bool HPWH::Simulator::readSchedules(const bool isResource, + const std::string& testName, + const ControlInfo& controlInfo, + std::vector& allSchedules) +{ + std::vector scheduleNames; + scheduleNames.push_back("inletT"); + scheduleNames.push_back("draw"); + scheduleNames.push_back("ambientT"); + scheduleNames.push_back("evaporatorT"); + scheduleNames.push_back("DR"); + scheduleNames.push_back("setpoint"); + scheduleNames.push_back("SoC"); + + long outputCode = controlInfo.outputCode; + allSchedules.reserve(scheduleNames.size()); + for (auto i = 0; i < scheduleNames.size(); i++) + { + Schedule schedule; + if (isResource) + { + } + else + { + std::ifstream fileStream; + std::string sFilename = testName + "/" + scheduleNames[i] + "schedule.csv"; + if (openFileText(fileStream, sFilename)) + { + + if (readSchedule(schedule, scheduleNames[i], fileStream, controlInfo.timeToRun_min)) + { + fileStream.close(); + } + else + { + msg("Unable to read schedule file %s\n", scheduleNames[i].c_str()); + return false; + } + } + else if (scheduleNames[i] != "setpoint" && scheduleNames[i] != "SoC") + { + if (verbosity >= VRB_reluctant) + { + msg("Unable to open schedule file %s\n", scheduleNames[i].c_str()); + } + return false; + } + allSchedules.push_back(schedule); + } + } + + if (controlInfo.temperatureUnits == "F") + { + for (auto& T : allSchedules[0]) + { + T = F_TO_C(T); + } + for (auto& T : allSchedules[2]) + { + T = F_TO_C(T); + } + for (auto& T : allSchedules[3]) + { + T = F_TO_C(T); + } + for (auto& T : allSchedules[5]) + { + T = F_TO_C(T); + } + } + + if (outputCode != 0) + { + if (verbosity >= VRB_reluctant) + { + msg("Control file testInfo.txt has unsettable specifics in it. \n"); + } + return false; + } + return true; +} + +//----------------------------------------------------------------------------- +/// @brief Runs a simulation +/// @param[in] testDesc data structure containing test description +/// @param[in] outputDirectory destination path for test results (filename based on testDesc) +/// @param[in] controlInfo data structure containing control info +/// @param[in] allSchedules collection of test schedules +/// @param[in] airT_C air temperature (degC) used for temperature depression +/// @param[in] doTempDepress whether to apply temperature depression +/// @param[out] testResults data structure containing test results +/// @return true if successful, false otherwise +//----------------------------------------------------------------------------- +bool HPWH::Simulator::run(HPWH& hpwh, + const TestDesc& testDesc, + const std::string& outputDirectory, + const ControlInfo& controlInfo, + std::vector& allSchedules, + double airT_C, + const bool doTempDepress, + TestResults& testResults) +{ + const double energyBalThreshold = 0.0001; // 0.1 % + const int nTestTCouples = 6; + + hpwh.setDoInversionMixing(controlInfo.doInversionMixing); + hpwh.setDoConduction(controlInfo.doConduction); + + if (controlInfo.setpointT_C > 0.) + { + if (!allSchedules[5].empty()) + { + hpwh.setSetpoint(allSchedules[5][0]); // expect this to fail sometimes + if (controlInfo.initialTankT_C != nullptr) + hpwh.setTankToTemperature(*controlInfo.initialTankT_C); + else + hpwh.resetTankToSetpoint(); + } + else + { + hpwh.setSetpoint(controlInfo.setpointT_C); + if (controlInfo.initialTankT_C != nullptr) + hpwh.setTankToTemperature(*controlInfo.initialTankT_C); + else + hpwh.resetTankToSetpoint(); + } + } + + if (controlInfo.inletH != nullptr) + { + hpwh.setInletByFraction(*controlInfo.inletH); + } + if (controlInfo.tankSize_gal != nullptr) + { + hpwh.setTankSize(*controlInfo.tankSize_gal, HPWH::UNITS_GAL); + } + if (controlInfo.tot_limit != nullptr) + { + hpwh.setTimerLimitTOT(*controlInfo.tot_limit); + } + if (controlInfo.useSoC) + { + if (allSchedules[6].empty()) + { + if (verbosity >= VRB_reluctant) + { + msg("If useSoC is true need an SoCschedule.csv file. \n"); + } + } + const double soCMinTUse_C = F_TO_C(110.); + const double soCMains_C = F_TO_C(65.); + hpwh.switchToSoCControls(1., .05, soCMinTUse_C, true, soCMains_C); + } + + // UEF data + testResults = {false, 0., 0.}; + + FILE* yearOutputFile = NULL; + if (controlInfo.recordYearData) + { + std::string sOutputFilename = outputDirectory + "/DHW_YRLY.csv"; + if (fopen_s(&yearOutputFile, sOutputFilename.c_str(), "a+") != 0) + { + if (hpwh.verbosity >= VRB_reluctant) + { + msg("Could not open output file \n", sOutputFilename.c_str()); + } + return false; + } + } + + FILE* minuteOutputFile = NULL; + if (controlInfo.recordMinuteData) + { + std::string sOutputFilename = outputDirectory + "/" + testDesc.testName + "_" + + testDesc.presetOrFile + "_" + testDesc.modelName + ".csv"; + if (fopen_s(&minuteOutputFile, sOutputFilename.c_str(), "w+") != 0) + { + if (hpwh.verbosity >= VRB_reluctant) + { + msg("Could not open output file \n", sOutputFilename.c_str()); + } + return false; + } + } + + if (controlInfo.recordMinuteData) + { + std::string sHeader = "minutes,Ta,Tsetpoint,inletT,draw,"; + if (hpwh.isCompressoExternalMultipass()) + { + sHeader += "condenserInletT,condenserOutletT,externalVolGPM,"; + } + if (controlInfo.useSoC) + { + sHeader += "targetSoCFract,soCFract,"; + } + hpwh.WriteCSVHeading(minuteOutputFile, sHeader.c_str(), nTestTCouples, CSVOPT_NONE); + } + + double cumulativeEnergyIn_kWh[3] = {0., 0., 0.}; + double cumulativeEnergyOut_kWh[3] = {0., 0., 0.}; + + bool doChangeSetpoint = (!allSchedules[5].empty()) && (!hpwh.isSetpointFixed()); + + // ------------------------------------- Simulate --------------------------------------- // + if (verbosity >= VRB_reluctant) + { + msg("Now Simulating %d Minutes of the Test\n", controlInfo.timeToRun_min); + } + + // run simulation in 1-min steps + for (int i = 0; i < controlInfo.timeToRun_min; i++) + { + + double inletT_C = allSchedules[0][i]; + double drawVolume_L = GAL_TO_L(allSchedules[1][i]); + double ambientT_C = doTempDepress ? airT_C : allSchedules[2][i]; + double externalT_C = allSchedules[3][i]; + HPWH::DRMODES drStatus = static_cast(int(allSchedules[4][i])); + + // change setpoint if specified in schedule + if (doChangeSetpoint) + { + hpwh.setSetpoint(allSchedules[5][i]); // expect this to fail sometimes + } + + // change SoC schedule + if (controlInfo.useSoC) + { + if (hpwh.setTargetSoCFraction(allSchedules[6][i]) != 0) + { + if (verbosity >= VRB_reluctant) + { + msg("ERROR: Can not set the target state of charge fraction.\n"); + } + return false; + } + } + + if (controlInfo.modifyDraw) + { + const double mixT_C = F_TO_C(125.); + if (hpwh.getSetpoint() <= mixT_C) + { // do a simple mix down of the draw for the cold-water temperature + drawVolume_L *= + (mixT_C - inletT_C) / + (hpwh.getTankNodeTemp(hpwh.getNumNodes() - 1, HPWH::UNITS_C) - inletT_C); + } + } + + double inletT2_C = inletT_C; + double drawVolume2_L = drawVolume_L; + + double previousTankHeatContent_kJ = hpwh.getTankHeatContent_kJ(); + + // run a step + int runResult = + hpwh.runOneStep(inletT_C, // inlet water temperature (C) + drawVolume_L, // draw volume (L) + ambientT_C, // ambient Temp (C) + externalT_C, // external Temp (C) + drStatus, // DDR Status (now an enum. Fixed for now as allow) + drawVolume2_L, // inlet-2 volume (L) + inletT2_C, // inlet-2 Temp (C) + NULL); // no extra heat + + if (runResult != 0) + { + if (verbosity >= VRB_reluctant) + { + msg("ERROR: Run failed.\n"); + } + return false; + } + + if (!hpwh.isEnergyBalanced( + drawVolume_L, inletT_C, previousTankHeatContent_kJ, energyBalThreshold)) + { + if (verbosity >= VRB_reluctant) + { + msg("WARNING: On minute %i, HPWH has an energy balance error.\n", i); + } + // return false; // fails on ModelTest.testREGoesTo93C.TamScalable_SP.Preset; issue + // in addHeatExternal + } + + // check timing + for (int iHS = 0; iHS < hpwh.getNumHeatSources(); iHS++) + { + if (hpwh.getNthHeatSourceRunTime(iHS) > 1.) + { + if (verbosity >= VRB_reluctant) + { + msg("ERROR: On minute %i, heat source %i ran for %i min.\n", + iHS, + hpwh.getNthHeatSourceRunTime(iHS)); + } + return false; + } + } + + // check flow for external MP + if (hpwh.isCompressoExternalMultipass()) + { + double volumeHeated_gal = hpwh.getExternalVolumeHeated(HPWH::UNITS_GAL); + double mpFlowVolume_gal = hpwh.getExternalMPFlowRate(HPWH::UNITS_GPM) * + hpwh.getNthHeatSourceRunTime(hpwh.getCompressorIndex()); + if (fabs(volumeHeated_gal - mpFlowVolume_gal) > 0.000001) + { + if (verbosity >= VRB_reluctant) + { + msg("ERROR: Externally heated volumes are inconsistent! Volume Heated " + "[gal]: " + "%d, mpFlowRate in 1 min [gal] %d\n", + volumeHeated_gal, + mpFlowVolume_gal); + } + return false; + } + } + + // location temperature reported with temperature depression, instead of ambient + // temperature + if (doTempDepress) + { + ambientT_C = hpwh.getLocationTemp_C(); + } + + // write minute summary + if (controlInfo.recordMinuteData) + { + std::string sPreamble = std::to_string(i) + ", " + std::to_string(ambientT_C) + ", " + + std::to_string(hpwh.getSetpoint()) + ", " + + std::to_string(allSchedules[0][i]) + ", " + + std::to_string(allSchedules[1][i]) + ", "; + // Add some more outputs for mp tests + if (hpwh.isCompressoExternalMultipass()) + { + sPreamble += std::to_string(hpwh.getCondenserWaterInletTemp()) + ", " + + std::to_string(hpwh.getCondenserWaterOutletTemp()) + ", " + + std::to_string(hpwh.getExternalVolumeHeated(HPWH::UNITS_GAL)) + ", "; + } + if (controlInfo.useSoC) + { + sPreamble += std::to_string(allSchedules[6][i]) + ", " + + std::to_string(hpwh.getSoCFraction()) + ", "; + } + int csvOptions = CSVOPT_NONE; + if (allSchedules[1][i] > 0.) + { + csvOptions |= CSVOPT_IS_DRAWING; + } + hpwh.WriteCSVRow(minuteOutputFile, sPreamble.c_str(), nTestTCouples, csvOptions); + } + + // accumulate energy and draw + double energyIn_kJ = 0.; + for (int iHS = 0; iHS < hpwh.getNumHeatSources(); iHS++) + { + double heatSourceEnergyIn_kJ = hpwh.getNthHeatSourceEnergyInput(iHS, HPWH::UNITS_KJ); + energyIn_kJ += heatSourceEnergyIn_kJ; + + cumulativeEnergyIn_kWh[iHS] += KJ_TO_KWH(heatSourceEnergyIn_kJ) * 1000.; + cumulativeEnergyOut_kWh[iHS] += + hpwh.getNthHeatSourceEnergyOutput(iHS, HPWH::UNITS_KWH) * 1000.; + } + testResults.totalEnergyConsumed_kJ += energyIn_kJ; + testResults.totalVolumeRemoved_L += drawVolume_L; + } + // -----Simulation complete-------------------------------------- // + + if (controlInfo.recordMinuteData) + { + fclose(minuteOutputFile); + } + + // write year summary + if (controlInfo.recordYearData) + { + std::string firstCol = + testDesc.testName + "," + testDesc.presetOrFile + "," + testDesc.modelName; + fprintf(yearOutputFile, "%s", firstCol.c_str()); + double totalEnergyIn_kWh = 0, totalEnergyOut_kWh = 0; + for (int iHS = 0; iHS < 3; iHS++) + { + fprintf(yearOutputFile, + ",%0.0f,%0.0f", + cumulativeEnergyIn_kWh[iHS], + cumulativeEnergyOut_kWh[iHS]); + totalEnergyIn_kWh += cumulativeEnergyIn_kWh[iHS]; + totalEnergyOut_kWh += cumulativeEnergyOut_kWh[iHS]; + } + fprintf(yearOutputFile, ",%0.0f,%0.0f", totalEnergyIn_kWh, totalEnergyOut_kWh); + for (int iHS = 0; iHS < 3; iHS++) + { + fprintf(yearOutputFile, + ",%0.2f", + cumulativeEnergyOut_kWh[iHS] / cumulativeEnergyIn_kWh[iHS]); + } + fprintf(yearOutputFile, ",%0.2f", totalEnergyOut_kWh / totalEnergyIn_kWh); + fprintf(yearOutputFile, "\n"); + fclose(yearOutputFile); + } + + testResults.passed = true; + return true; +} diff --git a/src/HPWHpresets.cc b/src/HPWHpresets.cc index cf6e7625..2170026d 100644 --- a/src/HPWHpresets.cc +++ b/src/HPWHpresets.cc @@ -27,7 +27,7 @@ int HPWH::HPWHinit_resTank(double tankVol_L, // low power element will cause divide by zero/negative UA in EF -> UA conversion if (lowerPower_W < 550) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Resistance tank lower element wattage below 550 W. DOES NOT COMPUTE\n"); } @@ -35,7 +35,7 @@ int HPWH::HPWHinit_resTank(double tankVol_L, } if (upperPower_W < 0.) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Upper resistance tank wattage below 0 W. DOES NOT COMPUTE\n"); } @@ -43,7 +43,7 @@ int HPWH::HPWHinit_resTank(double tankVol_L, } if (energyFactor <= 0.) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Energy Factor less than zero. DOES NOT COMPUTE\n"); } @@ -111,7 +111,7 @@ int HPWH::HPWHinit_resTank(double tankVol_L, if (tankUA_kJperHrC < 0.) { - if (hpwhVerbosity >= VRB_reluctant && tankUA_kJperHrC < -0.1) + if (verbosity >= VRB_reluctant && tankUA_kJperHrC < -0.1) { msg("Computed tankUA_kJperHrC is less than 0, and is reset to 0."); } @@ -136,7 +136,7 @@ int HPWH::HPWHinit_resTank(double tankVol_L, heatSources[i].sortPerformanceMap(); } - if (hpwhVerbosity >= VRB_emetic) + if (verbosity >= VRB_emetic) { for (int i = 0; i < getNumHeatSources(); i++) { @@ -163,7 +163,7 @@ int HPWH::HPWHinit_resTankGeneric(double tankVol_L, // low power element will cause divide by zero/negative UA in EF -> UA conversion if (lowerPower_W < 0) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Lower resistance tank wattage below 0 W. DOES NOT COMPUTE\n"); } @@ -171,7 +171,7 @@ int HPWH::HPWHinit_resTankGeneric(double tankVol_L, } if (upperPower_W < 0.) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Upper resistance tank wattage below 0 W. DOES NOT COMPUTE\n"); } @@ -179,7 +179,7 @@ int HPWH::HPWHinit_resTankGeneric(double tankVol_L, } if (rValue_M2KperW <= 0.) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("R-Value is equal to or below 0. DOES NOT COMPUTE\n"); } @@ -241,7 +241,7 @@ int HPWH::HPWHinit_resTankGeneric(double tankVol_L, if (tankUA_kJperHrC < 0.) { - if (hpwhVerbosity >= VRB_reluctant && tankUA_kJperHrC < -0.1) + if (verbosity >= VRB_reluctant && tankUA_kJperHrC < -0.1) { msg("Computed tankUA_kJperHrC is less than 0, and is reset to 0."); } @@ -266,7 +266,7 @@ int HPWH::HPWHinit_resTankGeneric(double tankVol_L, source.sortPerformanceMap(); } - if (hpwhVerbosity >= VRB_emetic) + if (verbosity >= VRB_emetic) { for (int i = 0; i < getNumHeatSources(); i++) { @@ -363,7 +363,7 @@ int HPWH::HPWHinit_genericHPWH(double tankVol_L, double energyFactor, double res int failure = this->setTankSize(tankVol_L); if (failure == HPWH_ABORT) { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Failure to set tank size in generic hpwh init."); } @@ -437,7 +437,7 @@ int HPWH::HPWHinit_genericHPWH(double tankVol_L, double energyFactor, double res heatSources[i].sortPerformanceMap(); } - if (hpwhVerbosity >= VRB_emetic) + if (verbosity >= VRB_emetic) { for (int i = 0; i < getNumHeatSources(); i++) { @@ -4223,7 +4223,7 @@ int HPWH::HPWHinit_presets(MODELS presetNum) } else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("Incorrect model specification. \n"); } @@ -4554,7 +4554,7 @@ int HPWH::HPWHinit_presets(MODELS presetNum) } else { - if (hpwhVerbosity >= VRB_reluctant) + if (verbosity >= VRB_reluctant) { msg("You have tried to select a preset model which does not exist. \n"); } @@ -4586,7 +4586,7 @@ int HPWH::HPWHinit_presets(MODELS presetNum) heatSources[i].sortPerformanceMap(); } - if (hpwhVerbosity >= VRB_emetic) + if (verbosity >= VRB_emetic) { for (int i = 0; i < getNumHeatSources(); i++) { diff --git a/test/24hr67_high/DRschedule.csv b/test/24hr67_high/DRschedule.csv new file mode 100644 index 00000000..bd79ca27 --- /dev/null +++ b/test/24hr67_high/DRschedule.csv @@ -0,0 +1,2 @@ +default 0, +minutes,OnOff \ No newline at end of file diff --git a/test/24hr67_high/ambientTschedule.csv b/test/24hr67_high/ambientTschedule.csv new file mode 100644 index 00000000..1e6b51c2 --- /dev/null +++ b/test/24hr67_high/ambientTschedule.csv @@ -0,0 +1,3 @@ +default 67.5, +minutes,temperature +1,67.5 diff --git a/test/24hr67_high/drawschedule.csv b/test/24hr67_high/drawschedule.csv new file mode 100644 index 00000000..5d00073c --- /dev/null +++ b/test/24hr67_high/drawschedule.csv @@ -0,0 +1,58 @@ +default 0, +minutes,flow +1,3 +2,3 +3,3 +4,3 +5,3 +6,3 +7,3 +8,3 +9,3 +10,0 +31,1 +32,1 +33,0 +41,1 +42,0 +101,1.7 +102,1.7 +103,1.7 +104,1.7 +105,1.7 +106,0.5 +107,0 +631,3 +632,3 +633,3 +634,3 +635,3 +636,0 +691,1.7 +692,1.7 +693,1.6 +694,0 +721,1 +722,0 +766,1 +767,0 +771,1 +772,0 +961,1 +962,1 +963,0 +976,1 +977,1 +978,0 +991,1.7 +992,0.3 +993,0 +1006,1.7 +1007,0.3 +1008,0 +1021,3 +1022,3 +1023,3 +1024,3 +1025,2 +1026,0 diff --git a/test/24hr67_high/evaporatorTschedule.csv b/test/24hr67_high/evaporatorTschedule.csv new file mode 100644 index 00000000..1e6b51c2 --- /dev/null +++ b/test/24hr67_high/evaporatorTschedule.csv @@ -0,0 +1,3 @@ +default 67.5, +minutes,temperature +1,67.5 diff --git a/test/24hr67_high/inletTschedule.csv b/test/24hr67_high/inletTschedule.csv new file mode 100644 index 00000000..0bf6a3ca --- /dev/null +++ b/test/24hr67_high/inletTschedule.csv @@ -0,0 +1,3 @@ +default 58, +minutes,temperature +1,58 diff --git a/test/24hr67_high/testInfo.txt b/test/24hr67_high/testInfo.txt new file mode 100644 index 00000000..6905b702 --- /dev/null +++ b/test/24hr67_high/testInfo.txt @@ -0,0 +1,3 @@ +setpoint 125 +length_of_test 1440 +temperature_units F diff --git a/test/24hr67_low/DRschedule.csv b/test/24hr67_low/DRschedule.csv new file mode 100644 index 00000000..bd79ca27 --- /dev/null +++ b/test/24hr67_low/DRschedule.csv @@ -0,0 +1,2 @@ +default 0, +minutes,OnOff \ No newline at end of file diff --git a/test/24hr67_low/ambientTschedule.csv b/test/24hr67_low/ambientTschedule.csv new file mode 100644 index 00000000..1e6b51c2 --- /dev/null +++ b/test/24hr67_low/ambientTschedule.csv @@ -0,0 +1,3 @@ +default 67.5, +minutes,temperature +1,67.5 diff --git a/test/24hr67_low/drawschedule.csv b/test/24hr67_low/drawschedule.csv new file mode 100644 index 00000000..c80c0ebe --- /dev/null +++ b/test/24hr67_low/drawschedule.csv @@ -0,0 +1,47 @@ +default 0, +minutes,flow +1,1.7 +2,1.7 +3,1.7 +4,1.7 +5,1.7 +6,1.7 +7,1.7 +8,1.7 +9,1.4 +10,0 +31,1 +32,1 +33,0 +61,1 +62,0 +631,1.7 +632,1.7 +633,1.7 +634,0.9 +635,0 +691,1.7 +692,1.7 +693,0.6 +694,0 +721,1 +722,0 +766,1 +767,0 +771,1 +772,0 +976,1 +977,1 +978,0 +991,0 +992,0 +993,0 +1006,1.7 +1007,0.3 +1008,0 +1021,1.7 +1022,1.3 +1023,0 +1024,0 +1025,0 +1026,0 diff --git a/test/24hr67_low/evaporatorTschedule.csv b/test/24hr67_low/evaporatorTschedule.csv new file mode 100644 index 00000000..1e6b51c2 --- /dev/null +++ b/test/24hr67_low/evaporatorTschedule.csv @@ -0,0 +1,3 @@ +default 67.5, +minutes,temperature +1,67.5 diff --git a/test/24hr67_low/inletTschedule.csv b/test/24hr67_low/inletTschedule.csv new file mode 100644 index 00000000..0bf6a3ca --- /dev/null +++ b/test/24hr67_low/inletTschedule.csv @@ -0,0 +1,3 @@ +default 58, +minutes,temperature +1,58 diff --git a/test/24hr67_low/testInfo.txt b/test/24hr67_low/testInfo.txt new file mode 100644 index 00000000..6905b702 --- /dev/null +++ b/test/24hr67_low/testInfo.txt @@ -0,0 +1,3 @@ +setpoint 125 +length_of_test 1440 +temperature_units F diff --git a/test/24hr67_medium/DRschedule.csv b/test/24hr67_medium/DRschedule.csv new file mode 100644 index 00000000..bd79ca27 --- /dev/null +++ b/test/24hr67_medium/DRschedule.csv @@ -0,0 +1,2 @@ +default 0, +minutes,OnOff \ No newline at end of file diff --git a/test/24hr67_medium/ambientTschedule.csv b/test/24hr67_medium/ambientTschedule.csv new file mode 100644 index 00000000..1e6b51c2 --- /dev/null +++ b/test/24hr67_medium/ambientTschedule.csv @@ -0,0 +1,3 @@ +default 67.5, +minutes,temperature +1,67.5 diff --git a/test/24hr67_medium/drawschedule.csv b/test/24hr67_medium/drawschedule.csv new file mode 100644 index 00000000..cfe871d1 --- /dev/null +++ b/test/24hr67_medium/drawschedule.csv @@ -0,0 +1,59 @@ +default 0, +minutes,flow +1,1.7 +2,1.7 +3,1.7 +4,1.7 +5,1.7 +6,1.7 +7,1.7 +8,1.7 +9,1.4 +10,0 +31,1 +32,1 +33,0 +41,0 +42,0 +101,1.7 +102,1.7 +103,1.7 +104,1.7 +105,1.7 +106,0.5 +107,0 +631,1.7 +632,1.7 +633,1.7 +634,1.7 +635,1.7 +636,0.5 +637,0 +691,1.7 +692,1.7 +693,1.6 +694,0 +721,1 +722,0 +766,1 +767,0 +771,1 +772,0 +961,1 +962,0 +963,0 +976,1 +977,1 +978,0 +991,0 +992,0 +993,0 +1006,1.7 +1007,0.3 +1008,0 +1021,1.7 +1022,1.7 +1023,1.7 +1024,1.7 +1025,0.2 +1026,0 diff --git a/test/24hr67_medium/evaporatorTschedule.csv b/test/24hr67_medium/evaporatorTschedule.csv new file mode 100644 index 00000000..1e6b51c2 --- /dev/null +++ b/test/24hr67_medium/evaporatorTschedule.csv @@ -0,0 +1,3 @@ +default 67.5, +minutes,temperature +1,67.5 diff --git a/test/24hr67_medium/inletTschedule.csv b/test/24hr67_medium/inletTschedule.csv new file mode 100644 index 00000000..0bf6a3ca --- /dev/null +++ b/test/24hr67_medium/inletTschedule.csv @@ -0,0 +1,3 @@ +default 58, +minutes,temperature +1,58 diff --git a/test/24hr67_medium/testInfo.txt b/test/24hr67_medium/testInfo.txt new file mode 100644 index 00000000..6905b702 --- /dev/null +++ b/test/24hr67_medium/testInfo.txt @@ -0,0 +1,3 @@ +setpoint 125 +length_of_test 1440 +temperature_units F diff --git a/test/24hr67_vsmall/DRschedule.csv b/test/24hr67_vsmall/DRschedule.csv new file mode 100644 index 00000000..bd79ca27 --- /dev/null +++ b/test/24hr67_vsmall/DRschedule.csv @@ -0,0 +1,2 @@ +default 0, +minutes,OnOff \ No newline at end of file diff --git a/test/24hr67_vsmall/ambientTschedule.csv b/test/24hr67_vsmall/ambientTschedule.csv new file mode 100644 index 00000000..1e6b51c2 --- /dev/null +++ b/test/24hr67_vsmall/ambientTschedule.csv @@ -0,0 +1,3 @@ +default 67.5, +minutes,temperature +1,67.5 diff --git a/test/24hr67_vsmall/drawschedule.csv b/test/24hr67_vsmall/drawschedule.csv new file mode 100644 index 00000000..a6472594 --- /dev/null +++ b/test/24hr67_vsmall/drawschedule.csv @@ -0,0 +1,14 @@ +default 0, +minutes,flow +1,1 +2,1 +61,1 +66,0.5 +71,0.5 +76,0.5 +481,1 +496,1 +497,1 +541,1 +542,0.5 +556,1 diff --git a/test/24hr67_vsmall/evaporatorTschedule.csv b/test/24hr67_vsmall/evaporatorTschedule.csv new file mode 100644 index 00000000..1e6b51c2 --- /dev/null +++ b/test/24hr67_vsmall/evaporatorTschedule.csv @@ -0,0 +1,3 @@ +default 67.5, +minutes,temperature +1,67.5 diff --git a/test/24hr67_vsmall/inletTschedule.csv b/test/24hr67_vsmall/inletTschedule.csv new file mode 100644 index 00000000..0bf6a3ca --- /dev/null +++ b/test/24hr67_vsmall/inletTschedule.csv @@ -0,0 +1,3 @@ +default 58, +minutes,temperature +1,58 diff --git a/test/24hr67_vsmall/testInfo.txt b/test/24hr67_vsmall/testInfo.txt new file mode 100644 index 00000000..6905b702 --- /dev/null +++ b/test/24hr67_vsmall/testInfo.txt @@ -0,0 +1,3 @@ +setpoint 125 +length_of_test 1440 +temperature_units F diff --git a/test/AquaThermAire.txt b/test/AquaThermAire.txt index 04f47fa4..a53730a3 100644 --- a/test/AquaThermAire.txt +++ b/test/AquaThermAire.txt @@ -1,4 +1,3 @@ -verbosity silent numNodes 12 #number of nodes setpoint 50 C volume 54.4 gal diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index b87a097e..d1c25f2a 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 @@ -28,6 +29,7 @@ target_link_libraries(testPerformanceMaps ${libs}) target_link_libraries(testStateOfChargeFcts ${libs}) target_link_libraries(testHeatingLogics ${libs}) target_link_libraries(testEnergyBalance ${libs}) +target_link_libraries(testCalcUEF ${libs}) # Add output directory for test results add_custom_target(results_directory ALL COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_CURRENT_BINARY_DIR}/output") diff --git a/test/main.cc b/test/main.cc index 057a4c0b..76eef7e5 100644 --- a/test/main.cc +++ b/test/main.cc @@ -22,63 +22,19 @@ using std::cout; using std::endl; using std::ifstream; using std::string; -// using std::ofstream; - -typedef std::vector schedule; - -int readSchedule(schedule& scheduleArray, string scheduleFileName, long minutesOfTest); int main(int argc, char* argv[]) { HPWH hpwh; + HPWH::Simulator simulator; - HPWH::DRMODES drStatus = HPWH::DR_ALLOW; - HPWH::MODELS model; - // HPWH::CSVOPTIONS IP = HPWH::CSVOPT_IPUNITS; // CSVOPT_NONE or CSVOPT_IPUNITS - // HPWH::UNITS units = HPWH::UNITS_F; - - const double EBALTHRESHOLD = 0.005; - - const int nTestTCouples = 6; - - const double soCMinTUse_C = F_TO_C(110.); - const double soCMains_C = F_TO_C(65.); - - // Schedule stuff - std::vector scheduleNames; - std::vector allSchedules(7); + const long maximumDurationNormalTest_min = 500000; - string testDirectory, fileToOpen, fileToOpen2, scheduleName, var1, input1, input2, input3, - inputFile, outputDirectory; - string inputVariableName, firstCol; - double testVal, newSetpoint, airTemp, airTemp2, tempDepressThresh, inletH, newTankSize, - tot_limit, initialTankT_C; - bool useSoC; - int i, outputCode; - long minutesToRun; - - double cumHeatIn[3] = {0, 0, 0}; - double cumHeatOut[3] = {0, 0, 0}; - - bool HPWH_doTempDepress; - int doInvMix, doCondu; - - FILE* outputFile = NULL; - FILE* yearOutFile = NULL; - ifstream controlFile; - - string strPreamble; - string strHead = "minutes,Ta,Tsetpoint,inletT,draw,"; - string strHeadMP = "condenserInletT,condenserOutletT,externalVolGPM,"; - string strHeadSoC = "targetSoCFract,soCFract,"; #if defined _DEBUG hpwh.setVerbosity(HPWH::VRB_reluctant); #endif - //....................................... // process command line arguments - //....................................... - cout << "Testing HPWHsim version " << HPWH::getVersion() << endl; // Obvious wrong number of command line arguments @@ -89,21 +45,25 @@ int main(int argc, char* argv[]) "output directory\n"; exit(1); } - // Help message + + // parse inputs + std::string input1, input2, input3, input4; if (argc > 1) { input1 = argv[1]; input2 = argv[2]; input3 = argv[3]; - outputDirectory = argv[4]; + input4 = argv[4]; } else { input1 = "asdf"; // Makes the next conditional not crash... a little clumsy but whatever input2 = "def"; input3 = "ghi"; - outputDirectory = "."; + input4 = "."; } + + // display help message if (argc < 5 || (argc > 6) || (input1 == "?") || (input1 == "help")) { cout << "Standard usage: \"hpwhTestTool.x [model spec type Preset/File] [model spec Name] " @@ -115,484 +75,87 @@ int main(int argc, char* argv[]) exit(1); } - if (argc == 6) - { - airTemp = std::stoi(argv[5]); - HPWH_doTempDepress = true; - } - else - { - airTemp = 0; - HPWH_doTempDepress = false; - } - - // Only input file specified -- don't suffix with .csv - testDirectory = input3; + HPWH::Simulator::TestDesc testDesc; + testDesc.presetOrFile = input1; + testDesc.modelName = input2; + testDesc.testName = input3; + std::string outputDirectory = input4; // Parse the model - newSetpoint = 0; - if (input1 == "Preset") + if (testDesc.presetOrFile == "Preset") { - inputFile = ""; - - if (getHPWHObject(hpwh, input2) == HPWH::HPWH_ABORT) + if (getHPWHObject(hpwh, testDesc.modelName) == HPWH::HPWH_ABORT) { cout << "Error, preset model did not initialize.\n"; exit(1); } - - model = static_cast(hpwh.getHPWHModel()); - - if (model == HPWH::MODELS_Sanden80 || model == HPWH::MODELS_Sanden40) - { - newSetpoint = (149 - 32) / 1.8; - } } - else if (input1 == "File") + else if (testDesc.presetOrFile == "File") { - inputFile = input2 + ".txt"; + std::string inputFile = testDesc.modelName + ".txt"; if (hpwh.HPWHinit_file(inputFile) != 0) + { exit(1); + } } else { - cout << "Invalid argument, received '" << input1 << "', expected 'Preset' or 'File'.\n"; + cout << "Invalid argument, received '" << testDesc.presetOrFile + << "', expected 'Preset' or 'File'.\n"; exit(1); } - // hpwh.HPWHinit_resSwingTank(80., .95, 0., 10000., F_TO_C(125.)); + double airT_C = 0.; + bool doTempDepress = false; + if (argc == 6) + { // air temperature specified on command line + airT_C = F_TO_C(std::stoi(argv[5])); + doTempDepress = true; + } // Use the built-in temperature depression for the lockout test. Set the temp depression of 4C // to better try and trigger the lockout and hysteresis conditions - tempDepressThresh = 4; - hpwh.setMaxTempDepression(tempDepressThresh); - hpwh.setDoTempDepression(HPWH_doTempDepress); + hpwh.setMaxTempDepression(4.); + hpwh.setDoTempDepression(doTempDepress); - // Read the test control file - fileToOpen = testDirectory + "/" + "testInfo.txt"; - controlFile.open(fileToOpen.c_str()); - if (!controlFile.is_open()) - { - cout << "Could not open control file " << fileToOpen << "\n"; - exit(1); - } - outputCode = 0; - minutesToRun = 0; - newSetpoint = 0.; - initialTankT_C = 0.; - doCondu = 1; - doInvMix = 1; - inletH = 0.; - newTankSize = 0.; - tot_limit = 0.; - useSoC = false; - bool hasInitialTankTemp = false; - cout << "Running: " << input2 << ", " << input1 << ", " << input3 << endl; - - while (controlFile >> var1 >> testVal) - { - if (var1 == "setpoint") - { // If a setpoint was specified then override the default - newSetpoint = testVal; - } - else if (var1 == "length_of_test") - { - minutesToRun = (int)testVal; - } - else if (var1 == "doInversionMixing") - { - doInvMix = (testVal > 0.0) ? 1 : 0; - } - else if (var1 == "doConduction") - { - doCondu = (testVal > 0.0) ? 1 : 0; - } - else if (var1 == "inletH") - { - inletH = testVal; - } - else if (var1 == "tanksize") - { - newTankSize = testVal; - } - else if (var1 == "tot_limit") - { - tot_limit = testVal; - } - else if (var1 == "useSoC") - { - useSoC = (bool)testVal; - } - else if (var1 == "initialTankT_C") - { // Initialize at this temperature instead of setpoint - initialTankT_C = testVal; - hasInitialTankTemp = true; - } - else - { - cout << var1 << " in testInfo.txt is an unrecogized key.\n"; - } - } + HPWH::Simulator::ControlInfo controlInfo; + std::ifstream fileStream; - if (minutesToRun == 0) + if (!simulator.openFileText(fileStream, testDesc.testName + "/" + "testInfo.txt")) { - cout << "Error, must record length_of_test in testInfo.txt file\n"; exit(1); } - // ------------------------------------- Read Schedules--------------------------------------- - // // - scheduleNames.push_back("inletT"); - scheduleNames.push_back("draw"); - scheduleNames.push_back("ambientT"); - scheduleNames.push_back("evaporatorT"); - scheduleNames.push_back("DR"); - scheduleNames.push_back("setpoint"); - scheduleNames.push_back("SoC"); - - for (i = 0; (unsigned)i < scheduleNames.size(); i++) - { - fileToOpen = testDirectory + "/" + scheduleNames[i] + "schedule.csv"; - outputCode = readSchedule(allSchedules[i], fileToOpen, minutesToRun); - if (outputCode != 0) - { - if (scheduleNames[i] != "setpoint" && scheduleNames[i] != "SoC") - { - cout << "readSchedule returns an error on " << scheduleNames[i] << " schedule!\n"; - exit(1); - } - else - { - outputCode = 0; - } - } - } - - if (doInvMix == 0) - { - outputCode += hpwh.setDoInversionMixing(false); - } - - if (doCondu == 0) - { - outputCode += hpwh.setDoConduction(false); - } - if (newSetpoint > 0) - { - if (!allSchedules[5].empty()) - { - hpwh.setSetpoint(allSchedules[5][0]); // expect this to fail sometimes - if (hasInitialTankTemp) - hpwh.setTankToTemperature(initialTankT_C); - else - hpwh.resetTankToSetpoint(); - } - else - { - hpwh.setSetpoint(newSetpoint); - if (hasInitialTankTemp) - hpwh.setTankToTemperature(initialTankT_C); - else - hpwh.resetTankToSetpoint(); - } - } - if (inletH > 0) - { - outputCode += hpwh.setInletByFraction(inletH); - } - if (newTankSize > 0) - { - hpwh.setTankSize(newTankSize, HPWH::UNITS_GAL); - } - if (tot_limit > 0) - { - outputCode += hpwh.setTimerLimitTOT(tot_limit); - } - if (useSoC) - { - if (allSchedules[6].empty()) - { - cout << "If useSoC is true need an SoCschedule.csv file \n"; - } - outputCode += hpwh.switchToSoCControls(1., .05, soCMinTUse_C, true, soCMains_C); - } - - if (outputCode != 0) + if (!simulator.readControlInfo(fileStream, controlInfo)) { - cout << "Control file testInfo.txt has unsettable specifics in it. \n"; exit(1); } - // ----------------------Open the Output Files and Print the Header---------------------------- - // // - - if (minutesToRun > 500000.) + std::vector allSchedules; + if (!simulator.readSchedules(false, testDesc.testName, controlInfo, allSchedules)) { - fileToOpen = outputDirectory + "/DHW_YRLY.csv"; - - if (fopen_s(&yearOutFile, fileToOpen.c_str(), "a+") != 0) - { - cout << "Could not open output file " << fileToOpen << "\n"; - exit(1); - } - } - else - { - fileToOpen = outputDirectory + "/" + input3 + "_" + input1 + "_" + input2 + ".csv"; - - if (fopen_s(&outputFile, fileToOpen.c_str(), "w+") != 0) - { - cout << "Could not open output file " << fileToOpen << "\n"; - exit(1); - } - - string header = strHead; - if (hpwh.isCompressoExternalMultipass()) - { - header += strHeadMP; - } - if (useSoC) - { - header += strHeadSoC; - } - int csvOptions = HPWH::CSVOPT_NONE; - hpwh.WriteCSVHeading(outputFile, header.c_str(), nTestTCouples, csvOptions); - } - - // ------------------------------------- Simulate --------------------------------------- // - cout << "Now Simulating " << minutesToRun << " Minutes of the Test\n"; - - std::vector nodeExtraHeat_W; - std::vector* vectptr = NULL; - // Loop over the minutes in the test - for (i = 0; i < minutesToRun; i++) - { - -#if defined _DEBUG && 0 - cout << "Now on minute: " << i << "\n"; -#endif - - if (HPWH_doTempDepress) - { - airTemp2 = F_TO_C(airTemp); - } - else - { - airTemp2 = allSchedules[2][i]; - } - - double tankHCStart = hpwh.getTankHeatContent_kJ(); - - // Process the dr status - drStatus = static_cast(int(allSchedules[4][i])); - - // Change setpoint if there is a setpoint schedule. - if (!allSchedules[5].empty() && !hpwh.isSetpointFixed()) - { - hpwh.setSetpoint(allSchedules[5][i]); // expect this to fail sometimes - } - - // Change SoC schedule - if (useSoC) - { - if (hpwh.setTargetSoCFraction(allSchedules[6][i]) != 0) - { - cout << "ERROR: Can not set the target state of charge fraction. \n"; - exit(1); - } - } - - // Mix down for yearly tests with large compressors - if (hpwh.getHPWHModel() >= 210 && minutesToRun > 500000.) - { - // Do a simple mix down of the draw for the cold water temperature - if (hpwh.getSetpoint() <= 125.) - { - allSchedules[1][i] *= (125. - allSchedules[0][i]) / - (hpwh.getTankNodeTemp(hpwh.getNumNodes() - 1, HPWH::UNITS_F) - - allSchedules[0][i]); - } - } - - // Run the step - hpwh.runOneStep(allSchedules[0][i], // Inlet water temperature (C) - GAL_TO_L(allSchedules[1][i]), // Flow in gallons - airTemp2, // Ambient Temp (C) - allSchedules[3][i], // External Temp (C) - drStatus, // DDR Status (now an enum. Fixed for now as allow) - 1. * GAL_TO_L(allSchedules[1][i]), - allSchedules[0][i], - vectptr); - - if (!hpwh.isEnergyBalanced( - GAL_TO_L(allSchedules[1][i]), allSchedules[0][i], tankHCStart, EBALTHRESHOLD)) - { - cout << "WARNING: On minute " << i << " HPWH has an energy balance error.\n"; - } - - // Check timing - for (int iHS = 0; iHS < hpwh.getNumHeatSources(); iHS++) - { - if (hpwh.getNthHeatSourceRunTime(iHS) > 1) - { - cout << "ERROR: On minute " << i << " heat source " << iHS << " ran for " - << hpwh.getNthHeatSourceRunTime(iHS) << "minutes" - << "\n"; - exit(1); - } - } - // Check flow for external MP - if (hpwh.isCompressoExternalMultipass()) - { - double volumeHeated_Gal = hpwh.getExternalVolumeHeated(HPWH::UNITS_GAL); - double mpFlowVolume_Gal = hpwh.getExternalMPFlowRate(HPWH::UNITS_GPM) * - hpwh.getNthHeatSourceRunTime(hpwh.getCompressorIndex()); - if (fabs(volumeHeated_Gal - mpFlowVolume_Gal) > 0.000001) - { - cout << "ERROR: Externally heated volumes are inconsistent! Volume Heated [Gal]: " - << volumeHeated_Gal << ", mpFlowRate in 1 minute [Gal]: " << mpFlowVolume_Gal - << "\n"; - exit(1); - } - } - // Recording - if (minutesToRun < 500000.) - { - // Copy current status into the output file - if (HPWH_doTempDepress) - { - airTemp2 = hpwh.getLocationTemp_C(); - } - strPreamble = std::to_string(i) + ", " + std::to_string(airTemp2) + ", " + - std::to_string(hpwh.getSetpoint()) + ", " + - std::to_string(allSchedules[0][i]) + ", " + - std::to_string(allSchedules[1][i]) + ", "; - // Add some more outputs for mp tests - if (hpwh.isCompressoExternalMultipass()) - { - strPreamble += std::to_string(hpwh.getCondenserWaterInletTemp()) + ", " + - std::to_string(hpwh.getCondenserWaterOutletTemp()) + ", " + - std::to_string(hpwh.getExternalVolumeHeated(HPWH::UNITS_GAL)) + ", "; - } - if (useSoC) - { - strPreamble += std::to_string(allSchedules[6][i]) + ", " + - std::to_string(hpwh.getSoCFraction()) + ", "; - } - int csvOptions = HPWH::CSVOPT_NONE; - if (allSchedules[1][i] > 0.) - { - csvOptions |= HPWH::CSVOPT_IS_DRAWING; - } - hpwh.WriteCSVRow(outputFile, strPreamble.c_str(), nTestTCouples, csvOptions); - } - else - { - for (int iHS = 0; iHS < hpwh.getNumHeatSources(); iHS++) - { - cumHeatIn[iHS] += hpwh.getNthHeatSourceEnergyInput(iHS, HPWH::UNITS_KWH) * 1000.; - cumHeatOut[iHS] += hpwh.getNthHeatSourceEnergyOutput(iHS, HPWH::UNITS_KWH) * 1000.; - } - } - } - - if (minutesToRun > 500000.) - { - firstCol = input3 + "," + input1 + "," + input2; - fprintf(yearOutFile, "%s", firstCol.c_str()); - double totalIn = 0, totalOut = 0; - for (int iHS = 0; iHS < 3; iHS++) - { - fprintf(yearOutFile, ",%0.0f,%0.0f", cumHeatIn[iHS], cumHeatOut[iHS]); - totalIn += cumHeatIn[iHS]; - totalOut += cumHeatOut[iHS]; - } - fprintf(yearOutFile, ",%0.0f,%0.0f", totalIn, totalOut); - for (int iHS = 0; iHS < 3; iHS++) - { - fprintf(yearOutFile, ",%0.2f", cumHeatOut[iHS] / cumHeatIn[iHS]); - } - fprintf(yearOutFile, ",%0.2f", totalOut / totalIn); - fprintf(yearOutFile, "\n"); - fclose(yearOutFile); - } - else - { - fclose(outputFile); - } - controlFile.close(); - - return 0; -} - -// this function reads the named schedule into the provided array -int readSchedule(schedule& scheduleArray, string scheduleFileName, long minutesOfTest) -{ - int minuteHrTmp; - bool hourInput; - string line, snippet, s, minORhr; - double valTmp; - ifstream inputFile(scheduleFileName.c_str()); - // open the schedule file provided - cout << "Opening " << scheduleFileName << '\n'; - - if (!inputFile.is_open()) - { - return 1; - } - - inputFile >> snippet >> valTmp; - // cout << "snippet " << snippet << " valTmp"<< valTmp<<'\n'; - - if (snippet != "default") - { - cout << "First line of " << scheduleFileName << " must specify default\n"; - return 1; + exit(1); } - // cout << valTmp << " minutes = " << minutesOfTest << "\n"; - // Fill with the default value - scheduleArray.assign(minutesOfTest, valTmp); + controlInfo.recordMinuteData = (controlInfo.timeToRun_min <= maximumDurationNormalTest_min); + controlInfo.recordYearData = (controlInfo.timeToRun_min > maximumDurationNormalTest_min); - // Burn the first two lines - std::getline(inputFile, line); - std::getline(inputFile, line); + controlInfo.modifyDraw = ( // mix down large-compressor models for yearly tests + (hpwh.getHPWHModel() >= HPWH::MODELS_ColmacCxV_5_SP) && + (hpwh.getHPWHModel() <= HPWH::MODELS_RHEEM_HPHD135VNU_483_MP) && + (controlInfo.timeToRun_min > maximumDurationNormalTest_min)); - std::stringstream ss(line); // Will parse with a stringstream - // Grab the first token, which is the minute or hour marker - ss >> minORhr; - if (minORhr.empty()) - { // If nothing left in the file - return 0; - } - hourInput = tolower(minORhr.at(0)) == 'h'; - char c; // to eat the commas nom nom - // Read all the exceptions to the default value - while (inputFile >> minuteHrTmp >> c >> valTmp) + HPWH::Simulator::TestResults testResults; + if (!simulator.run(hpwh, + testDesc, + outputDirectory, + controlInfo, + allSchedules, + airT_C, + doTempDepress, + testResults)) { - - if (minuteHrTmp >= (int)scheduleArray.size()) - { - cout << "In " << scheduleFileName - << " the input file has more minutes than the test was defined with\n"; - return 1; - } - // Update the value - if (!hourInput) - { - scheduleArray[minuteHrTmp] = valTmp; - } - else if (hourInput) - { - for (int j = minuteHrTmp * 60; j < (minuteHrTmp + 1) * 60; j++) - { - scheduleArray[j] = valTmp; - // cout << "minute " << j-(minuteHrTmp) * 60 << " of hour" << (minuteHrTmp)<<"\n"; - } - } + exit(1); } - - inputFile.close(); - return 0; } diff --git a/test/ref/DHW_YRLY.csv b/test/ref/DHW_YRLY.csv index 1fd19101..67aaf57e 100644 --- a/test/ref/DHW_YRLY.csv +++ b/test/ref/DHW_YRLY.csv @@ -4,9 +4,9 @@ testCA_3BR_CTZ15,Preset,GE502014,55875,55875,0,0,565517,2071441,621392,2127316,1 testCA_3BR_CTZ15,Preset,Rheem2020Prem40,43073,43073,0,0,537835,2245943,580908,2289016,1.00,-nan(ind),4.18,3.94 testCA_3BR_CTZ15,Preset,Rheem2020Prem50,21934,21934,0,0,533295,2224941,555229,2246875,1.00,-nan(ind),4.17,4.05 testCA_3BR_CTZ15,Preset,Rheem2020Build50,18422,18422,0,0,616009,2241746,634431,2260168,1.00,-nan(ind),3.64,3.56 -testCA_3BR_CTZ15,Preset,RheemPlugInDedicated50,686585,2277144,0,0,0,0,686585,2277144,3.32,-nan(ind),-nan(ind),3.32 -testCA_3BR_CTZ15,Preset,RheemPlugInShared40,557168,2339586,0,0,0,0,557168,2339586,4.20,-nan(ind),-nan(ind),4.20 -testCA_3BR_CTZ15,Preset,RheemPlugInShared50,550351,2305883,0,0,0,0,550351,2305883,4.19,-nan(ind),-nan(ind),4.19 +testCA_3BR_CTZ15,Preset,RheemPlugInDedicated50,679065,2251443,0,0,0,0,679065,2251443,3.32,-nan(ind),-nan(ind),3.32 +testCA_3BR_CTZ15,Preset,RheemPlugInShared40,543402,2272386,0,0,0,0,543402,2272386,4.18,-nan(ind),-nan(ind),4.18 +testCA_3BR_CTZ15,Preset,RheemPlugInShared50,536712,2240578,0,0,0,0,536712,2240578,4.17,-nan(ind),-nan(ind),4.17 testCA_3BR_CTZ15,Preset,AOSmithCAHP120,0,0,2475,2475,677748,2365264,680223,2367738,-nan(ind),1.00,3.49,3.48 testCA_3BR_CTZ15,Preset,AWHSTier3Generic80,17550,17550,0,0,695306,2264199,712856,2281749,1.00,-nan(ind),3.26,3.20 testCA_3BR_CTZ16,Preset,AOSmithHPTU80,6088,6088,1179534,1179534,690914,2297398,1876536,3483020,1.00,1.00,3.33,1.86 @@ -15,29 +15,29 @@ testCA_3BR_CTZ16,Preset,GE502014,130275,130275,353792,353792,898211,2756543,1382 testCA_3BR_CTZ16,Preset,Rheem2020Prem40,132342,132342,278799,278799,844628,3058799,1255769,3469941,1.00,1.00,3.62,2.76 testCA_3BR_CTZ16,Preset,Rheem2020Prem50,89483,89483,279666,279666,842085,3042790,1211235,3411939,1.00,1.00,3.61,2.82 testCA_3BR_CTZ16,Preset,Rheem2020Build50,73993,73993,281985,281985,931391,3066657,1287370,3422636,1.00,1.00,3.29,2.66 -testCA_3BR_CTZ16,Preset,RheemPlugInDedicated50,1075466,3298078,0,0,0,0,1075466,3298078,3.07,-nan(ind),-nan(ind),3.07 -testCA_3BR_CTZ16,Preset,RheemPlugInShared40,902116,3357097,0,0,0,0,902116,3357097,3.72,-nan(ind),-nan(ind),3.72 -testCA_3BR_CTZ16,Preset,RheemPlugInShared50,905228,3337523,0,0,0,0,905228,3337523,3.69,-nan(ind),-nan(ind),3.69 +testCA_3BR_CTZ16,Preset,RheemPlugInDedicated50,1057618,3238988,0,0,0,0,1057618,3238988,3.06,-nan(ind),-nan(ind),3.06 +testCA_3BR_CTZ16,Preset,RheemPlugInShared40,883664,3247384,0,0,0,0,883664,3247384,3.67,-nan(ind),-nan(ind),3.67 +testCA_3BR_CTZ16,Preset,RheemPlugInShared50,885671,3232546,0,0,0,0,885671,3232546,3.65,-nan(ind),-nan(ind),3.65 testCA_3BR_CTZ16,Preset,AOSmithCAHP120,0,0,1691018,1691018,540738,1798679,2231756,3489697,-nan(ind),1.00,3.33,1.56 testCA_3BR_CTZ16,Preset,AWHSTier3Generic80,41850,41850,1063562,1063562,852285,2430196,1957697,3535608,1.00,1.00,2.85,1.81 -testCA_36Unit_CTZ12,Preset,QAHV_N136TAU_HPB_SP,25579199,96336852,0,0,0,0,25579199,96336852,3.77,-nan(ind),-nan(ind),3.77 -testCA_36Unit_CTZ12,Preset,ColmacCxV_5_SP,29810230,93675724,0,0,0,0,29810230,93675724,3.14,-nan(ind),-nan(ind),3.14 -testCA_36Unit_CTZ12,Preset,ColmacCxA_10_SP,29863357,97002089,0,0,0,0,29863357,97002089,3.25,-nan(ind),-nan(ind),3.25 -testCA_36Unit_CTZ12,Preset,ColmacCxA_15_SP,37099048,97207160,0,0,0,0,37099048,97207160,2.62,-nan(ind),-nan(ind),2.62 -testCA_36Unit_CTZ12,Preset,ColmacCxA_20_SP,32819045,97554042,0,0,0,0,32819045,97554042,2.97,-nan(ind),-nan(ind),2.97 -testCA_36Unit_CTZ12,Preset,ColmacCxA_25_SP,34181024,97826810,0,0,0,0,34181024,97826810,2.86,-nan(ind),-nan(ind),2.86 -testCA_36Unit_CTZ12,Preset,ColmacCxA_30_SP,34200636,98139446,0,0,0,0,34200636,98139446,2.87,-nan(ind),-nan(ind),2.87 -testCA_36Unit_CTZ12,Preset,NyleC60A_SP,30073563,94790929,0,0,0,0,30073563,94790929,3.15,-nan(ind),-nan(ind),3.15 -testCA_36Unit_CTZ12,Preset,NyleC90A_SP,29066682,96788017,0,0,0,0,29066682,96788017,3.33,-nan(ind),-nan(ind),3.33 -testCA_36Unit_CTZ12,Preset,NyleC185A_SP,29660784,97554366,0,0,0,0,29660784,97554366,3.29,-nan(ind),-nan(ind),3.29 -testCA_36Unit_CTZ12,Preset,NyleC250A_SP,25595635,97547619,0,0,0,0,25595635,97547619,3.81,-nan(ind),-nan(ind),3.81 -testCA_36Unit_CTZ12,Preset,ColmacCxV_5_MP,31681534,87668021,0,0,0,0,31681534,87668021,2.77,-nan(ind),-nan(ind),2.77 -testCA_36Unit_CTZ12,Preset,ColmacCxA_15_MP,44752575,95899338,0,0,0,0,44752575,95899338,2.14,-nan(ind),-nan(ind),2.14 -testCA_36Unit_CTZ12,Preset,ColmacCxA_20_MP,37878323,97052064,0,0,0,0,37878323,97052064,2.56,-nan(ind),-nan(ind),2.56 -testCA_36Unit_CTZ12,Preset,NyleC60A_MP,40596680,89031773,0,0,0,0,40596680,89031773,2.19,-nan(ind),-nan(ind),2.19 -testCA_36Unit_CTZ12,Preset,NyleC185A_MP,42450434,97449918,0,0,0,0,42450434,97449918,2.30,-nan(ind),-nan(ind),2.30 -testCA_36Unit_CTZ12,Preset,NyleC250A_MP,34266642,97496299,0,0,0,0,34266642,97496299,2.85,-nan(ind),-nan(ind),2.85 -testCA_36Unit_CTZ12,Preset,RheemHPHD60,25796227,87357476,0,0,0,0,25796227,87357476,3.39,-nan(ind),-nan(ind),3.39 -testCA_36Unit_CTZ12,Preset,RheemHPHD135,34754223,95520122,0,0,0,0,34754223,95520122,2.75,-nan(ind),-nan(ind),2.75 +testCA_36Unit_CTZ12,Preset,QAHV_N136TAU_HPB_SP,28887817,109306091,0,0,0,0,28887817,109306091,3.78,-nan(ind),-nan(ind),3.78 +testCA_36Unit_CTZ12,Preset,ColmacCxV_5_SP,32850589,103410352,0,0,0,0,32850589,103410352,3.15,-nan(ind),-nan(ind),3.15 +testCA_36Unit_CTZ12,Preset,ColmacCxA_10_SP,33760216,109801866,0,0,0,0,33760216,109801866,3.25,-nan(ind),-nan(ind),3.25 +testCA_36Unit_CTZ12,Preset,ColmacCxA_15_SP,41954094,110051476,0,0,0,0,41954094,110051476,2.62,-nan(ind),-nan(ind),2.62 +testCA_36Unit_CTZ12,Preset,ColmacCxA_20_SP,37097541,110367945,0,0,0,0,37097541,110367945,2.98,-nan(ind),-nan(ind),2.98 +testCA_36Unit_CTZ12,Preset,ColmacCxA_25_SP,38614950,110609486,0,0,0,0,38614950,110609486,2.86,-nan(ind),-nan(ind),2.86 +testCA_36Unit_CTZ12,Preset,ColmacCxA_30_SP,38597500,110853106,0,0,0,0,38597500,110853106,2.87,-nan(ind),-nan(ind),2.87 +testCA_36Unit_CTZ12,Preset,NyleC60A_SP,33096290,104833977,0,0,0,0,33096290,104833977,3.17,-nan(ind),-nan(ind),3.17 +testCA_36Unit_CTZ12,Preset,NyleC90A_SP,32772566,109564452,0,0,0,0,32772566,109564452,3.34,-nan(ind),-nan(ind),3.34 +testCA_36Unit_CTZ12,Preset,NyleC185A_SP,33433462,110368635,0,0,0,0,33433462,110368635,3.30,-nan(ind),-nan(ind),3.30 +testCA_36Unit_CTZ12,Preset,NyleC250A_SP,28833891,110356894,0,0,0,0,28833891,110356894,3.83,-nan(ind),-nan(ind),3.83 +testCA_36Unit_CTZ12,Preset,ColmacCxV_5_MP,33287650,90596527,0,0,0,0,33287650,90596527,2.72,-nan(ind),-nan(ind),2.72 +testCA_36Unit_CTZ12,Preset,ColmacCxA_15_MP,49091287,105226890,0,0,0,0,49091287,105226890,2.14,-nan(ind),-nan(ind),2.14 +testCA_36Unit_CTZ12,Preset,ColmacCxA_20_MP,42053550,107837541,0,0,0,0,42053550,107837541,2.56,-nan(ind),-nan(ind),2.56 +testCA_36Unit_CTZ12,Preset,NyleC60A_MP,42678771,91755367,0,0,0,0,42678771,91755367,2.15,-nan(ind),-nan(ind),2.15 +testCA_36Unit_CTZ12,Preset,NyleC185A_MP,47216895,108462724,0,0,0,0,47216895,108462724,2.30,-nan(ind),-nan(ind),2.30 +testCA_36Unit_CTZ12,Preset,NyleC250A_MP,38205322,108713094,0,0,0,0,38205322,108713094,2.85,-nan(ind),-nan(ind),2.85 +testCA_36Unit_CTZ12,Preset,RheemHPHD60,27078847,89802997,0,0,0,0,27078847,89802997,3.32,-nan(ind),-nan(ind),3.32 +testCA_36Unit_CTZ12,Preset,RheemHPHD135,38056812,104589760,0,0,0,0,38056812,104589760,2.75,-nan(ind),-nan(ind),2.75 testCA_36Unit_CTZ12,Preset,TamScalable_SP,1000,1000,0,0,43439261,110163246,43440261,110164246,1.00,-nan(ind),2.54,2.54 testCA_36Unit_CTZ12,Preset,Scalable_MP,500,500,779200,779200,51100212,104284026,51879912,105063726,1.00,1.00,2.04,2.03 diff --git a/test/testCalcUEF.cc b/test/testCalcUEF.cc new file mode 100644 index 00000000..e9ae6e43 --- /dev/null +++ b/test/testCalcUEF.cc @@ -0,0 +1,126 @@ +/* + * calculate UEF for specified HPWH model + */ +#include "HPWH.hh" +#include "testUtilityFcts.cc" + +#include +#include +#include + +const std::vector + sProfileNames({"24hr67_vsmall", "24hr67_low", "24hr67_medium", "24hr67_high"}); + +static bool runTest(const HPWH::Simulator::TestDesc testDesc, + HPWH::Simulator::TestResults& testResults, + double airT_C = 0., + bool doTempDepress = false) +{ + HPWH hpwh; + +#if defined _DEBUG + hpwh.setVerbosity(HPWH::VRB_reluctant); +#endif + + getHPWHObject(hpwh, testDesc.modelName); + + std::string sOutputDirectory = "../build/test/output"; + + // create the model + bool result = true; + if (testDesc.presetOrFile == "Preset") + { + result = (getHPWHObject(hpwh, testDesc.modelName) != HPWH::HPWH_ABORT); + } + else if (testDesc.presetOrFile == "File") + { + std::string inputFile = testDesc.modelName + ".txt"; + result = (hpwh.HPWHinit_file(inputFile) != HPWH::HPWH_ABORT); + } + ASSERTTRUE(result); + + // Use the built-in temperature depression for the lockout test. Set the temp depression of 4C + // to better try and trigger the lockout and hysteresis conditions + hpwh.setMaxTempDepression(4.); + hpwh.setDoTempDepression(doTempDepress); + + HPWH::Simulator simulator; + HPWH::Simulator::ControlInfo controlInfo; + std::ifstream fileStream; + + result = simulator.openFileText(fileStream, testDesc.testName + "/" + "testInfo.txt"); + ASSERTTRUE(result); + + result = simulator.readControlInfo(fileStream, controlInfo); + ASSERTTRUE(result); + + std::vector allSchedules; + result = simulator.readSchedules(false, testDesc.testName, controlInfo, allSchedules); + ASSERTTRUE(result); + + controlInfo.recordMinuteData = false; + controlInfo.recordYearData = false; + result = simulator.run(hpwh, + testDesc, + sOutputDirectory, + controlInfo, + allSchedules, + airT_C, + doTempDepress, + testResults); + ASSERTTRUE(result); + + return result; +} + +/* Evaluate UEF based on simulations using standard profiles */ +static bool +runUEFTestSuite(const std::string& sModelName, const std::string& sPresetOrFile, double& UEF) +{ + + HPWH::Simulator::TestDesc testDesc; + testDesc.modelName = sModelName; + testDesc.presetOrFile = sPresetOrFile; + + double totalEnergyConsumed_kJ = 0.; + double totalVolumeRemoved_L = 0.; + + bool result = true; + for (auto& sProfileName : sProfileNames) + { + HPWH::Simulator::TestResults testResults; + testDesc.testName = sProfileName; + result &= runTest(testDesc, testResults); + + totalEnergyConsumed_kJ += testResults.totalEnergyConsumed_kJ; + totalVolumeRemoved_L += testResults.totalVolumeRemoved_L; + } + 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 result; +} + +int main(int argc, char* argv[]) +{ + // process command line arguments + if ((argc != 3)) + { + cout << "Invalid input. This program takes TWO arguments: model type (i.e., Preset or " + "File), model name (i.e., Sanden80)\n"; + exit(1); + } + + std::string sPresetOrFile = argv[1]; + std::string sModelName = argv[2]; + + double UEF = 0.; + if (runUEFTestSuite(sModelName, sPresetOrFile, UEF)) + { + std::cout << "UEF: " << UEF << "\n"; + } + + return 0; +} diff --git a/test/testScaleHPWH.cc b/test/testScaleHPWH.cc index f199c633..f6ee350b 100644 --- a/test/testScaleHPWH.cc +++ b/test/testScaleHPWH.cc @@ -23,8 +23,7 @@ void getCompressorPerformance( HPWH& hpwh, performance& point, double waterTempC, double airTempC, double setpointC) { if (hpwh.isCompressorMultipass()) - { // Multipass capacity looks at the average of the - // temperature of the lift + { // Multipass capacity looks at the average of the temperature of the lift hpwh.setSetpoint((waterTempC + setpointC) / 2.); } else